From de2a54eb9e11cb79049faadda6894c6c950bfaa9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Fri, 11 Nov 2016 12:14:46 +0200 Subject: Add attachment accessor as pointer to RenderTargetOutput It allows resource accessor to return it as handle. Change-Id: Ia3f1af7ca806e1e5d3e48191fb863926a069c5bb Reviewed-by: Paul Lemire Reviewed-by: Sean Harmer --- src/render/backend/attachmentpack.cpp | 2 +- src/render/backend/rendertargetoutput.cpp | 9 +++++++-- src/render/backend/rendertargetoutput_p.h | 3 ++- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/render/backend/attachmentpack.cpp b/src/render/backend/attachmentpack.cpp index d2bb5ee9a..6dee7587b 100644 --- a/src/render/backend/attachmentpack.cpp +++ b/src/render/backend/attachmentpack.cpp @@ -60,7 +60,7 @@ AttachmentPack::AttachmentPack(const RenderTargetSelector *selector, const Rende for (Qt3DCore::QNodeId outputId : outputIds) { const RenderTargetOutput *output = attachmentManager->lookupResource(outputId); if (output) - m_attachments.append(output->attachment()); + m_attachments.append(*output->attachment()); } // Create actual DrawBuffers list that is used for glDrawBuffers diff --git a/src/render/backend/rendertargetoutput.cpp b/src/render/backend/rendertargetoutput.cpp index faebfacb6..cba92596d 100644 --- a/src/render/backend/rendertargetoutput.cpp +++ b/src/render/backend/rendertargetoutput.cpp @@ -121,9 +121,14 @@ void RenderTargetOutput::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) BackendNode::sceneChangeEvent(e); } -Attachment RenderTargetOutput::attachment() const +Qt3DRender::Render::Attachment *RenderTargetOutput::attachment() { - return m_attachmentData; + return &m_attachmentData; +} + +const Attachment *RenderTargetOutput::attachment() const +{ + return &m_attachmentData; } } // namespace Render diff --git a/src/render/backend/rendertargetoutput_p.h b/src/render/backend/rendertargetoutput_p.h index 14daa84e9..b7867c2cb 100644 --- a/src/render/backend/rendertargetoutput_p.h +++ b/src/render/backend/rendertargetoutput_p.h @@ -77,7 +77,8 @@ public: QAbstractTexture::CubeMapFace face() const; QRenderTargetOutput::AttachmentPoint point() const; void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_OVERRIDE; - Attachment attachment() const; + Attachment *attachment(); + const Attachment *attachment() const; private: void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL; -- cgit v1.2.3 From 6cd186a31f0e8d2bf38089da543128816bd1e2a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Fri, 21 Oct 2016 09:51:00 +0300 Subject: Give access to AbstractRenderer from BackendNode Change-Id: Ib3c1ffc0494545516b5c8c44375a415dd0a0443d Reviewed-by: Sean Harmer --- src/render/backend/backendnode.cpp | 5 +++++ src/render/backend/backendnode_p.h | 1 + 2 files changed, 6 insertions(+) diff --git a/src/render/backend/backendnode.cpp b/src/render/backend/backendnode.cpp index 7054db6a4..606016092 100644 --- a/src/render/backend/backendnode.cpp +++ b/src/render/backend/backendnode.cpp @@ -61,6 +61,11 @@ void BackendNode::setRenderer(AbstractRenderer *renderer) m_renderer = renderer; } +AbstractRenderer *BackendNode::renderer() const +{ + return m_renderer; +} + void BackendNode::markDirty(AbstractRenderer::BackendNodeDirtySet changes) { Q_ASSERT(m_renderer); diff --git a/src/render/backend/backendnode_p.h b/src/render/backend/backendnode_p.h index 5688c2412..1273144a4 100644 --- a/src/render/backend/backendnode_p.h +++ b/src/render/backend/backendnode_p.h @@ -68,6 +68,7 @@ public: ~BackendNode(); void setRenderer(AbstractRenderer *renderer); + AbstractRenderer *renderer() const; protected: void markDirty(AbstractRenderer::BackendNodeDirtySet changes); -- cgit v1.2.3 From 18b34e2a7868faec90b429ff299da27a7111e71c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Fri, 21 Oct 2016 11:50:50 +0300 Subject: Allow textureLock to texture Change-Id: I3904c4512c695b1a2c84482ca2a0184c90f179d9 Reviewed-by: Sean Harmer --- src/render/texture/gltexture_p.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/render/texture/gltexture_p.h b/src/render/texture/gltexture_p.h index 424e77854..d9ce32a9f 100644 --- a/src/render/texture/gltexture_p.h +++ b/src/render/texture/gltexture_p.h @@ -148,6 +148,16 @@ public: m_dirty |= TextureData; } + bool isDirty() + { + QMutexLocker locker(&m_dirtyFlagMutex); + return m_dirty == 0 ? false : true; + } + + QMutex *textureLock() + { + return &m_dirtyFlagMutex; + } protected: template -- cgit v1.2.3 From 206199f94fb3c59abc27cd4bd25c3c22ea3d8a33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Fri, 21 Oct 2016 09:54:42 +0300 Subject: Add scene2d to quick3drender RenderQmlToTexture will eventually be renamed to Scene2D and moved here. Change-Id: I7ed0637eefa7d7621f710cbe9ff453d6d75e90ed Reviewed-by: Kevin Ottens --- src/quick3d/quick3drender/quick3drender.pro | 1 + src/quick3d/quick3drender/scene2d/scene2d.pri | 5 +++++ 2 files changed, 6 insertions(+) create mode 100644 src/quick3d/quick3drender/scene2d/scene2d.pri diff --git a/src/quick3d/quick3drender/quick3drender.pro b/src/quick3d/quick3drender/quick3drender.pro index 88d7a9556..989f5615b 100644 --- a/src/quick3d/quick3drender/quick3drender.pro +++ b/src/quick3d/quick3drender/quick3drender.pro @@ -25,5 +25,6 @@ HEADERS += \ win32-g++*:QMAKE_CXXFLAGS_CXX11 = -std=gnu++0x include(./items/items.pri) +include(./scene2d/scene2d.pri) load(qt_module) diff --git a/src/quick3d/quick3drender/scene2d/scene2d.pri b/src/quick3d/quick3drender/scene2d/scene2d.pri new file mode 100644 index 000000000..05ab6b83f --- /dev/null +++ b/src/quick3d/quick3drender/scene2d/scene2d.pri @@ -0,0 +1,5 @@ +HEADERS += \ + +SOURCES += \ + +INCLUDEPATH += $$PWD -- cgit v1.2.3 From 42175321749ff876c6271f60e111ca7b83049c4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Fri, 21 Oct 2016 09:46:31 +0300 Subject: Add shared context to renderer Allows other contexts to access resources created by Qt3D backend. Needed by Render-qml-to-texture render thread, which requires it's own context. Change-Id: Ib1886301a8d2fffa03befeabe38e92ad5c9606d5 Reviewed-by: Kevin Ottens --- src/render/backend/abstractrenderer_p.h | 3 +++ src/render/backend/renderer.cpp | 18 ++++++++++++++++++ src/render/backend/renderer_p.h | 2 ++ 3 files changed, 23 insertions(+) diff --git a/src/render/backend/abstractrenderer_p.h b/src/render/backend/abstractrenderer_p.h index 8b17cbf45..f8d9850e7 100644 --- a/src/render/backend/abstractrenderer_p.h +++ b/src/render/backend/abstractrenderer_p.h @@ -56,6 +56,8 @@ #include #include +#include + QT_BEGIN_NAMESPACE class QSurface; @@ -153,6 +155,7 @@ public: virtual void setOffscreenSurfaceHelper(OffscreenSurfaceHelper *helper) = 0; virtual QSurfaceFormat format() = 0; + virtual QOpenGLContext *shareContext() const = 0; }; Q_DECLARE_OPERATORS_FOR_FLAGS(AbstractRenderer::BackendNodeDirtySet) diff --git a/src/render/backend/renderer.cpp b/src/render/backend/renderer.cpp index e1b1ee873..191e70392 100644 --- a/src/render/backend/renderer.cpp +++ b/src/render/backend/renderer.cpp @@ -153,6 +153,7 @@ Renderer::Renderer(QRenderAspect::RenderType type) , m_waitForInitializationToBeCompleted(0) , m_pickEventFilter(new PickEventFilter()) , m_exposed(0) + , m_shareContext(nullptr) , m_changeSet(0) , m_lastFrameCorrect(0) , m_glContext(nullptr) @@ -261,6 +262,17 @@ NodeManagers *Renderer::nodeManagers() const return m_nodesManager; } +/*! + \internal + + Return context which can be used to share resources safely + with qt3d main render context. +*/ +QOpenGLContext *Renderer::shareContext() const +{ + return m_shareContext ? m_shareContext : m_graphicsContext->openGLContext(); +} + void Renderer::setOpenGLContext(QOpenGLContext *context) { m_glContext = context; @@ -302,6 +314,10 @@ void Renderer::initialize() // Context is not owned by us, so we need to know if it gets destroyed m_contextConnection = QObject::connect(m_glContext, &QOpenGLContext::aboutToBeDestroyed, [this] { releaseGraphicsResources(); }); + m_shareContext = new QOpenGLContext; + m_shareContext->setFormat(m_glContext->format()); + m_shareContext->setShareContext(m_glContext); + m_shareContext->create(); } // Note: we don't have a surface at this point @@ -400,6 +416,8 @@ void Renderer::releaseGraphicsResources() if (m_ownedContext) delete context; + if (m_shareContext) + delete m_shareContext; m_graphicsContext.reset(nullptr); qCDebug(Backend) << Q_FUNC_INFO << "Renderer properly shutdown"; diff --git a/src/render/backend/renderer_p.h b/src/render/backend/renderer_p.h index c7c8e247a..344565173 100644 --- a/src/render/backend/renderer_p.h +++ b/src/render/backend/renderer_p.h @@ -205,6 +205,7 @@ public: virtual void setSettings(RenderSettings *settings) Q_DECL_OVERRIDE; virtual RenderSettings *settings() const Q_DECL_OVERRIDE; + QOpenGLContext *shareContext() const Q_DECL_OVERRIDE; void updateGLResources(); void updateTexture(Texture *texture); @@ -296,6 +297,7 @@ private: BackendNodeDirtySet m_changeSet; QAtomicInt m_lastFrameCorrect; QOpenGLContext *m_glContext; + QOpenGLContext *m_shareContext; PickBoundingVolumeJobPtr m_pickBoundingVolumeJob; qint64 m_time; -- cgit v1.2.3 From 28236a292be0f26b2f46b58249e498e153f286dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Mon, 14 Nov 2016 09:54:26 +0200 Subject: Add sharecontext to testrender Change-Id: I9cd67d7d1fe19a7a617c9752ecc40f6c24a1a1c3 Reviewed-by: Kevin Ottens --- tests/auto/render/commons/testrenderer.cpp | 5 +++++ tests/auto/render/commons/testrenderer.h | 1 + 2 files changed, 6 insertions(+) diff --git a/tests/auto/render/commons/testrenderer.cpp b/tests/auto/render/commons/testrenderer.cpp index 87e60a263..f318797ca 100644 --- a/tests/auto/render/commons/testrenderer.cpp +++ b/tests/auto/render/commons/testrenderer.cpp @@ -76,4 +76,9 @@ QSurfaceFormat TestRenderer::format() return QSurfaceFormat(); } +QOpenGLContext *TestRenderer::shareContext() const +{ + return nullptr; +} + QT_END_NAMESPACE diff --git a/tests/auto/render/commons/testrenderer.h b/tests/auto/render/commons/testrenderer.h index 2e572582e..ecbec4aa3 100644 --- a/tests/auto/render/commons/testrenderer.h +++ b/tests/auto/render/commons/testrenderer.h @@ -74,6 +74,7 @@ public: void resetDirty(); QVariant executeCommand(const QStringList &args) Q_DECL_OVERRIDE; + QOpenGLContext *shareContext() const Q_DECL_OVERRIDE; void setOffscreenSurfaceHelper(Qt3DRender::Render::OffscreenSurfaceHelper *helper) Q_DECL_OVERRIDE; QSurfaceFormat format() Q_DECL_OVERRIDE; -- cgit v1.2.3 From 3aafff6a72ca6a1f9c408f33fc18f28edf07a645 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Wed, 2 Nov 2016 11:52:35 +0200 Subject: Add resource accessor Change-Id: Ibeef96469e7bb3bc523300ea72d55a283e13ff79 Reviewed-by: Kevin Ottens --- src/render/backend/render-backend.pri | 6 ++- src/render/backend/resourceaccessor.cpp | 94 +++++++++++++++++++++++++++++++++ src/render/backend/resourceaccessor_p.h | 93 ++++++++++++++++++++++++++++++++ 3 files changed, 191 insertions(+), 2 deletions(-) create mode 100644 src/render/backend/resourceaccessor.cpp create mode 100644 src/render/backend/resourceaccessor_p.h diff --git a/src/render/backend/render-backend.pri b/src/render/backend/render-backend.pri index 8cd904efd..91efe9cd2 100644 --- a/src/render/backend/render-backend.pri +++ b/src/render/backend/render-backend.pri @@ -40,7 +40,8 @@ HEADERS += \ $$PWD/shaderparameterpack_p.h \ $$PWD/renderviewbuilder_p.h \ $$PWD/frameprofiler_p.h \ - $$PWD/offscreensurfacehelper_p.h + $$PWD/offscreensurfacehelper_p.h \ + $$PWD/resourceaccessor_p.h SOURCES += \ $$PWD/renderthread.cpp \ @@ -73,5 +74,6 @@ SOURCES += \ $$PWD/uniform.cpp \ $$PWD/shaderparameterpack.cpp \ $$PWD/renderviewbuilder.cpp \ - $$PWD/offscreensurfacehelper.cpp + $$PWD/offscreensurfacehelper.cpp \ + $$PWD/resourceaccessor.cpp diff --git a/src/render/backend/resourceaccessor.cpp b/src/render/backend/resourceaccessor.cpp new file mode 100644 index 000000000..c02130aa9 --- /dev/null +++ b/src/render/backend/resourceaccessor.cpp @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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 "resourceaccessor_p.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { +namespace Render { + +ResourceAccessor::ResourceAccessor(NodeManagers *mgr) + : m_textureManager(mgr->textureManager()) + , m_attachmentManager(mgr->attachmentManager()) + , m_glTextureManager(mgr->glTextureManager()) +{ + +} + +// called by render plugins from arbitrary thread +bool ResourceAccessor::accessResource(Qt3DCore::QNodeId nodeId, void **handle, QMutex **lock) +{ + Texture *tex = m_textureManager->lookupResource(nodeId); + if (!tex) { + RenderTargetOutput *output = m_attachmentManager->lookupResource(nodeId); + if (!output) + return false; + + Attachment **attachmentData = reinterpret_cast(handle); + *attachmentData = output->attachment(); + return true; + } + GLTexture *glTex = m_glTextureManager->lookupResource(tex->peerId()); + if (!glTex) + return false; + + if (glTex->isDirty()) + return false; + + QOpenGLTexture** glTextureHandle = reinterpret_cast(handle); + *glTextureHandle = glTex->getOrCreateGLTexture(); + *lock = glTex->textureLock(); + return true; +} + +} // namespace Render +} // namespace Qt3DRender + +QT_END_NAMESPACE diff --git a/src/render/backend/resourceaccessor_p.h b/src/render/backend/resourceaccessor_p.h new file mode 100644 index 000000000..653a8adda --- /dev/null +++ b/src/render/backend/resourceaccessor_p.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd and/or its subsidiary(-ies). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3DRENDER_RENDER_RESOURCEACCESSOR_P_H +#define QT3DRENDER_RENDER_RESOURCEACCESSOR_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +#include + +QT_BEGIN_NAMESPACE + +class QMutex; + +namespace Qt3DRender +{ +namespace Render { + +class TextureManager; +class AttachmentManager; +class GLTextureManager; +class NodeManagers; + +class RenderBackendResourceAccessor +{ +public: + virtual bool accessResource(Qt3DCore::QNodeId nodeId, void **handle, QMutex **lock) = 0; +}; + +class QT3DRENDERSHARED_PRIVATE_EXPORT ResourceAccessor : public RenderBackendResourceAccessor +{ +public: + ResourceAccessor(NodeManagers *mgr); + bool accessResource(Qt3DCore::QNodeId nodeId, void **handle, QMutex **lock) Q_DECL_FINAL; +private: + GLTextureManager *m_glTextureManager; + TextureManager *m_textureManager; + AttachmentManager *m_attachmentManager; +}; + +} // namespace Render +} // namespace Qt3DRender + +QT_END_NAMESPACE + +#endif // QT3DRENDER_RENDER_RESOURCEACCESSOR_P_H -- cgit v1.2.3 From 72c555c231c69d13f9924b0aeb2ce199890e9a88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Wed, 2 Nov 2016 14:51:46 +0200 Subject: Add resource accessor to backend node and nodemanagers Change-Id: I483483ac0bb43dd7cb76c971a1141f0e4af64b34 Reviewed-by: Kevin Ottens --- src/render/backend/backendnode.cpp | 11 ++++++++++- src/render/backend/backendnode_p.h | 4 ++++ src/render/backend/nodemanagers.cpp | 7 +++++++ src/render/backend/nodemanagers_p.h | 6 ++++++ 4 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/render/backend/backendnode.cpp b/src/render/backend/backendnode.cpp index 606016092..0dc8da237 100644 --- a/src/render/backend/backendnode.cpp +++ b/src/render/backend/backendnode.cpp @@ -37,7 +37,10 @@ ** ****************************************************************************/ -#include "backendnode_p.h" +#include +#include +#include +#include QT_BEGIN_NAMESPACE @@ -72,6 +75,12 @@ void BackendNode::markDirty(AbstractRenderer::BackendNodeDirtySet changes) m_renderer->markDirty(changes, this); } +QSharedPointer BackendNode::resourceAccessor() +{ + Render::Renderer *r = static_cast(renderer()); + return r->nodeManagers()->resourceAccessor(); +} + } // namespace Render } // namespace Qt3DRender diff --git a/src/render/backend/backendnode_p.h b/src/render/backend/backendnode_p.h index 1273144a4..05bea3266 100644 --- a/src/render/backend/backendnode_p.h +++ b/src/render/backend/backendnode_p.h @@ -61,6 +61,8 @@ namespace Qt3DRender { namespace Render { +class RenderBackendResourceAccessor; + class Q_AUTOTEST_EXPORT BackendNode : public Qt3DCore::QBackendNode { public: @@ -70,6 +72,8 @@ public: void setRenderer(AbstractRenderer *renderer); AbstractRenderer *renderer() const; + QSharedPointer resourceAccessor(); + protected: void markDirty(AbstractRenderer::BackendNodeDirtySet changes); AbstractRenderer *m_renderer; diff --git a/src/render/backend/nodemanagers.cpp b/src/render/backend/nodemanagers.cpp index 0234db979..534bb4b9f 100644 --- a/src/render/backend/nodemanagers.cpp +++ b/src/render/backend/nodemanagers.cpp @@ -46,6 +46,7 @@ #include #include #include +#include #include @@ -89,6 +90,7 @@ NodeManagers::NodeManagers() , m_lightManager(new LightManager()) , m_computeJobManager(new ComputeCommandManager()) , m_renderStateManager(new RenderStateManager()) + , m_resourceAccessor(new ResourceAccessor(this)) { } @@ -129,6 +131,11 @@ NodeManagers::~NodeManagers() delete m_renderNodesManager; } +QSharedPointer NodeManagers::resourceAccessor() +{ + return m_resourceAccessor; +} + template<> CameraManager *NodeManagers::manager() const Q_DECL_NOTHROW { diff --git a/src/render/backend/nodemanagers_p.h b/src/render/backend/nodemanagers_p.h index 7e1259a1d..a57628607 100644 --- a/src/render/backend/nodemanagers_p.h +++ b/src/render/backend/nodemanagers_p.h @@ -129,6 +129,8 @@ class Light; class ComputeCommand; class RenderStateNode; +class ResourceAccessor; + class QT3DRENDERSHARED_PRIVATE_EXPORT NodeManagers { public: @@ -203,6 +205,8 @@ public: inline ComputeCommandManager *computeJobManager() const Q_DECL_NOEXCEPT { return m_computeJobManager; } inline RenderStateManager *renderStateManager() const Q_DECL_NOEXCEPT { return m_renderStateManager; } + QSharedPointer resourceAccessor(); + private: CameraManager *m_cameraManager; EntityManager *m_renderNodesManager; @@ -237,6 +241,8 @@ private: LightManager *m_lightManager; ComputeCommandManager *m_computeJobManager; RenderStateManager *m_renderStateManager; + + QSharedPointer m_resourceAccessor; }; // Specializations -- cgit v1.2.3 From 3e31736ad632316797ba05517a283123d4b12be1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Wed, 7 Dec 2016 14:28:04 +0200 Subject: Change backendnode export It needs to be private export so that scene2d compiles when autotests are not compiled in. Change-Id: Ia9765badc0c797f63320bf6deda4a2cc0fb196ca Reviewed-by: Kevin Ottens --- src/render/backend/backendnode_p.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/render/backend/backendnode_p.h b/src/render/backend/backendnode_p.h index 05bea3266..8db68b11d 100644 --- a/src/render/backend/backendnode_p.h +++ b/src/render/backend/backendnode_p.h @@ -54,6 +54,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE @@ -63,7 +64,7 @@ namespace Render { class RenderBackendResourceAccessor; -class Q_AUTOTEST_EXPORT BackendNode : public Qt3DCore::QBackendNode +class QT3DRENDERSHARED_PRIVATE_EXPORT BackendNode : public Qt3DCore::QBackendNode { public: BackendNode(Qt3DCore::QBackendNode::Mode mode = ReadOnly); -- cgit v1.2.3 From e24179c3711eb93e7a2b8a205ab958bce53ef966 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Fri, 21 Oct 2016 11:59:45 +0300 Subject: Add RenderQmlToTexture implementation This contains the implementation from the old patch. It will be modified in later commits. Change-Id: I84afdeec684ea9f6b64353eda731484fdb354798 Reviewed-by: Sean Harmer --- src/render/framegraph/qrenderqmltotexture.cpp | 620 ++++++++++++++++++++++++++ src/render/framegraph/qrenderqmltotexture.h | 96 ++++ src/render/framegraph/qrenderqmltotexture_p.h | 212 +++++++++ src/render/framegraph/renderqmltotexture.cpp | 304 +++++++++++++ src/render/framegraph/renderqmltotexture_p.h | 116 +++++ 5 files changed, 1348 insertions(+) create mode 100644 src/render/framegraph/qrenderqmltotexture.cpp create mode 100644 src/render/framegraph/qrenderqmltotexture.h create mode 100644 src/render/framegraph/qrenderqmltotexture_p.h create mode 100644 src/render/framegraph/renderqmltotexture.cpp create mode 100644 src/render/framegraph/renderqmltotexture_p.h diff --git a/src/render/framegraph/qrenderqmltotexture.cpp b/src/render/framegraph/qrenderqmltotexture.cpp new file mode 100644 index 000000000..d4fa41874 --- /dev/null +++ b/src/render/framegraph/qrenderqmltotexture.cpp @@ -0,0 +1,620 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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 "qrenderqmltotexture.h" +#include "qrenderqmltotexture_p.h" + +#include + +#include + +QT_BEGIN_NAMESPACE + +using namespace Qt3DCore; + +namespace Qt3DRender { + + +/*! + \class Qt3DRender::QRenderQmlToTexture + \inmodule Qt3DRender + + \brief This class enables rendering qml into a texture, which then can be + used as a part of 3D scene. + + The component uses QQuickRenderControl to render the given QML source into an + offscreen surface, which is attached to a texture provided by the user. This allows the + component to directly render into the texture without intermediate copy and the user to + freely specify how the texture is used in the 3D scene. + + \since 5.9 +*/ + +/*! + \qmltype RenderQmlToTexture + \inqmlmodule Qt3D.Render + \since 5.9 + \inherits + \instantiates Qt3DRender::QRenderQmlToTexture + \brief RenderQmlToTexture + */ + +/*! + \qmlproperty Qt3DRender::QAbstractTexture Qt3D.Render::RenderQmlToTexture::texture + Holds the texture being rendered to. + */ + +/*! + \qmlproperty QUrl Qt3D.Render::RenderQmlToTexture::source + Holds the qml source url. + */ + +/*! + \qmlproperty bool Qt3D.Render::RenderQmlToTexture::renderOnce + Holds whether the first rendered image to the texture is also the last, after which the + renderer releases resources needed for the rendering and the rendering is no longer possible + with this RenderQmlToTexture object. + */ + +/*! + \qmlproperty bool Qt3D.Render::RenderQmlToTexture::loaded + Hold whether the source has been loaded. + */ + +class RenderControl : public QQuickRenderControl +{ +public: + RenderControl(QWindow *w) : m_window(w) { } + QWindow *renderWindow(QPoint *offset) Q_DECL_OVERRIDE; + +private: + QWindow *m_window; +}; + +QWindow *RenderControl::renderWindow(QPoint *offset) +{ + if (offset) + *offset = QPoint(0, 0); + return m_window; +} + +/*! + \internal + Constructs object shared by the front-end and back-end to synchronize the rendering. + */ +RenderQmlToTextureSharedObject::RenderQmlToTextureSharedObject(RenderQmlToTextureManager *manager) + : m_quit(false) + , m_requestSync(false) + , m_prepared(false) + , m_initialized(false) + , m_renderControl(nullptr) + , m_quickWindow(nullptr) + , m_renderManager(manager) + , m_surface(nullptr) + , m_renderObject(nullptr) + , m_disallowed(false) +{ +} + +RenderQmlToTextureSharedObject::~RenderQmlToTextureSharedObject() +{ +} + +void RenderQmlToTextureSharedObject::cleanup() +{ + delete m_renderControl; + delete m_quickWindow; + delete m_surface; + m_renderControl = nullptr; + m_quickWindow = nullptr; + m_surface = nullptr; + m_initialized = false; +} + +bool RenderQmlToTextureSharedObject::canRender() const +{ + return m_initialized && m_prepared && !m_disallowed; +} + +bool RenderQmlToTextureSharedObject::isInitialized() const +{ + return m_initialized; +} + +void RenderQmlToTextureSharedObject::disallowRender() +{ + m_disallowed = true; +} + +void RenderQmlToTextureSharedObject::setInitialized() +{ + m_initialized = true; +} + +bool RenderQmlToTextureSharedObject::isPrepared() const +{ + return m_prepared; +} + +void RenderQmlToTextureSharedObject::setPrepared() +{ + m_prepared = true; +} + +// not protected, call only from main thread +bool RenderQmlToTextureSharedObject::isQuit() const +{ + Q_ASSERT(QThread::currentThread() == QCoreApplication::instance()->thread()); + return m_quit; +} + +// not protected, call only from main thread +void RenderQmlToTextureSharedObject::requestQuit() +{ + Q_ASSERT(QThread::currentThread() == QCoreApplication::instance()->thread()); + m_quit = true; + QCoreApplication::postEvent(m_renderObject, new QEvent(QUIT)); +} + +bool RenderQmlToTextureSharedObject::isSyncRequested() const +{ + return m_requestSync; +} + +void RenderQmlToTextureSharedObject::requestRender(bool sync) +{ + m_requestSync = sync; + QCoreApplication::postEvent(m_renderObject, new QEvent(RENDER)); +} + +void RenderQmlToTextureSharedObject::waitRender() +{ + m_cond.wait(&m_mutex); +} + +void RenderQmlToTextureSharedObject::wakeWaiting() +{ + m_cond.wakeOne(); +} + +void RenderQmlToTextureSharedObject::clearSyncRequest() +{ + m_requestSync = false; +} + +/*! + \internal + Constructs qml render manager. + */ +RenderQmlToTextureManager::RenderQmlToTextureManager(QRenderQmlToTexturePrivate *priv) + : m_priv(priv) + , m_qmlEngine(nullptr) + , m_qmlComponent(nullptr) + , m_rootItem(nullptr) + , m_source(nullptr) + , m_texture(nullptr) + , m_requested(false) + , m_initialized(false) + , m_renderSyncRequested(false) + , m_sharedObject(new RenderQmlToTextureSharedObject(this)) + , m_renderOnce(false) + , m_backendInitialized(false) +{ + setFormat(QSurfaceFormat::defaultFormat()); + + m_sharedObject->m_surface = new QOffscreenSurface; + m_sharedObject->m_surface->setFormat(QSurfaceFormat::defaultFormat()); + m_sharedObject->m_surface->create(); + + // Create render control + m_sharedObject->m_renderControl = new RenderControl(this); + + // Create window to render the QML with + m_sharedObject->m_quickWindow = new QQuickWindow(m_sharedObject->m_renderControl); + m_sharedObject->m_quickWindow->setClearBeforeRendering(true); + m_sharedObject->m_quickWindow->setDefaultAlphaBuffer(true); + + // Create a QML engine. + m_qmlEngine = new QQmlEngine; + if (!m_qmlEngine->incubationController()) + m_qmlEngine->setIncubationController(m_sharedObject->m_quickWindow->incubationController()); + + connect(m_sharedObject->m_renderControl, &QQuickRenderControl::renderRequested, + this, &RenderQmlToTextureManager::requestRender); + connect(m_sharedObject->m_renderControl, &QQuickRenderControl::sceneChanged, + this, &RenderQmlToTextureManager::requestRenderSync); +} + +RenderQmlToTextureManager::~RenderQmlToTextureManager() +{ + m_sharedObject = nullptr; +} + +void RenderQmlToTextureManager::requestRender() +{ + // Don't request render until the backend is initialized. + if (m_sharedObject->canRender()) { + if (!m_requested) { + m_requested = true; + QCoreApplication::postEvent(this, new QEvent(RENDER)); + } + } +} + +void RenderQmlToTextureManager::requestRenderSync() +{ + // Don't request render until the backed is initialized. + if (m_sharedObject->canRender()) { + if (!m_requested) { + m_requested = true; + QCoreApplication::postEvent(this, new QEvent(RENDERSYNC)); + } + } else { + m_renderSyncRequested = true; + } +} + +void RenderQmlToTextureManager::startIfInitialized() +{ + if (!m_initialized) { + if (m_backendInitialized && m_source.isValid()) { + m_qmlComponent = new QQmlComponent(m_qmlEngine, m_source); + if (m_qmlComponent->isLoading()) { + connect(m_qmlComponent, &QQmlComponent::statusChanged, + this, &RenderQmlToTextureManager::run); + } else { + run(); + } + } + } +} + +void RenderQmlToTextureManager::stopAndClean() +{ + if (m_sharedObject->isInitialized()) { + QMutexLocker lock(&m_sharedObject->m_mutex); + m_sharedObject->requestQuit(); + m_sharedObject->m_renderThread->wait(); + m_sharedObject->cleanup(); + delete m_qmlEngine; + delete m_qmlComponent; + m_qmlEngine = nullptr; + m_qmlComponent = nullptr; + } +} + +void RenderQmlToTextureManager::run() +{ + disconnect(m_qmlComponent, &QQmlComponent::statusChanged, this, &RenderQmlToTextureManager::run); + + if (m_qmlComponent->isError()) { + QList errorList = m_qmlComponent->errors(); + for (const QQmlError &error: errorList) + qWarning() << error.url() << error.line() << error; + return; + } + + QObject *rootObject = m_qmlComponent->create(); + if (m_qmlComponent->isError()) { + QList errorList = m_qmlComponent->errors(); + for (const QQmlError &error: errorList) + qWarning() << error.url() << error.line() << error; + return; + } + + m_rootItem = qobject_cast(rootObject); + if (!m_rootItem) { + qWarning("QRenderQmlToTexture: Root item is not a QQuickItem."); + delete rootObject; + return; + } + + // The root item is ready. Associate it with the window. + m_rootItem->setParentItem(m_sharedObject->m_quickWindow->contentItem()); + + // Update window size. + updateSizes(); + + m_initialized = true; + m_sharedObject->setInitialized(); + + emit onLoadedChanged(); +} + +void RenderQmlToTextureManager::updateSizes() +{ + const int width = m_rootItem->width(); + const int height = m_rootItem->height(); + if (width == 0 || height == 0) { + qWarning() << "QRenderQmlToTexture: Root item size not set."; + return; + } + resize(width, height); + m_sharedObject->m_quickWindow->setGeometry(0, 0, width, height); +} + +void RenderQmlToTextureManager::setTexture(QAbstractTexture *texture) +{ + m_texture = texture; + startIfInitialized(); +} + +void RenderQmlToTextureManager::setSource(const QUrl &url) +{ + m_source = url; + startIfInitialized(); +} + +bool RenderQmlToTextureManager::event(QEvent *e) +{ + switch (e->type()) { + + case RENDER: { + // just render request, don't need to call sync in render thread + QMutexLocker lock(&m_sharedObject->m_mutex); + m_sharedObject->requestRender(false); + + Qt3DCore::QPropertyUpdatedChangePtr change(new Qt3DCore::QPropertyUpdatedChange(m_priv->m_id)); + change->setPropertyName("dirty"); + change->setValue(QVariant::fromValue(true)); + m_priv->notifyObservers(change); + + m_requested = false; + return true; + } + + case RENDERSYNC: { + // sync and render request, main and render threads must be synchronized + if (!m_sharedObject->isQuit()) + doRenderSync(); + m_requested = false; + return true; + } + + case PREPARE: { + m_sharedObject->m_renderControl->prepareThread(m_sharedObject->m_renderThread); + m_sharedObject->setPrepared(); + + if (m_renderSyncRequested) { + if (!m_requested) { + m_requested = true; + QCoreApplication::postEvent(this, new QEvent(RENDERSYNC)); + } + m_renderSyncRequested = false; + } + return true; + } + + case INITIALIZED: { + // backend is initialized, start the qml + m_backendInitialized = true; + startIfInitialized(); + return true; + } + + case RENDERED: { + // render is done, excellent, now clean anything not needed anymore. + stopAndClean(); + return true; + } + + default: + break; + } + return QWindow::event(e); +} + +void RenderQmlToTextureManager::doRenderSync() +{ + QMutexLocker lock(&m_sharedObject->m_mutex); + + m_sharedObject->requestRender(true); + m_sharedObject->m_renderControl->polishItems(); + + Qt3DCore::QPropertyUpdatedChangePtr change(new Qt3DCore::QPropertyUpdatedChange(m_priv->m_id)); + + change->setPropertyName("dirty"); + change->setValue(QVariant::fromValue(true)); + m_priv->notifyObservers(change); + + // begin waiting render thread + m_sharedObject->waitRender(); + m_requested = false; +} + +void RenderQmlToTextureManager::cleanup() +{ + stopAndClean(); +} + + +QRenderQmlToTexturePrivate::QRenderQmlToTexturePrivate() + : QFrameGraphNodePrivate() + , m_renderManager(new RenderQmlToTextureManager(this)) +{ +} + +QRenderQmlToTexturePrivate::~QRenderQmlToTexturePrivate() +{ + m_renderManager->cleanup(); + delete m_renderManager; +} + + +RenderQmlToTextureSharedObject *QRenderQmlToTexturePrivate::getSharedObject(QRenderQmlToTexture *rqtt) +{ + return rqtt->d_func()->m_renderManager->m_sharedObject.data(); +} + + +/*! + The constructor creates an instance with the specified \a parent. + */ +QRenderQmlToTexture::QRenderQmlToTexture(Qt3DCore::QNode *parent) + : QFrameGraphNode(*new QRenderQmlToTexturePrivate, parent) +{ + Q_D(QRenderQmlToTexture); + connect(d->m_renderManager, &RenderQmlToTextureManager::onLoadedChanged, + this, &QRenderQmlToTexture::sourceLoaded); +} + +/*! + Destructor. + */ +QRenderQmlToTexture::~QRenderQmlToTexture() +{ +} + +bool QRenderQmlToTexture::loaded() const +{ + Q_D(const QRenderQmlToTexture); + return d->m_renderManager->m_initialized; +} + +/*! + \property QRenderQmlToTexture::source + \brief Specifies the url for the qml. + * + This property specifies the url to the qml being rendered to the texture. + The source must specify QQuickItem as a root. The item must specify width + and height. The rendered qml is scaled to the texture size. + The property can not be changed after the rendering has been initialized. + */ +QUrl QRenderQmlToTexture::source() const +{ + Q_D(const QRenderQmlToTexture); + return d->m_renderManager->m_source; +} + +void QRenderQmlToTexture::setSource(const QUrl &url) +{ + Q_D(QRenderQmlToTexture); + if (d->m_renderManager->m_initialized) { + qWarning() << "Unable to set source after initialization."; + return; + } + d->m_renderManager->setSource(url); + emit sourceChanged(url); +} + +/*! + \property QRenderQmlToTexture::renderOnce + \brief Property to specify if the texture will be rendered only once. + * + This property specifies that the texture will be rendered only one time. + Once the rendering has been done, resources reserved for rendering will be + released and the QRenderQmlToTexture will become unusable. + If set to false, which is the default, the rendering is continuous. + */ +bool QRenderQmlToTexture::renderOnce() const +{ + Q_D(const QRenderQmlToTexture); + return d->m_renderManager->m_renderOnce; +} + +void QRenderQmlToTexture::setRenderOnce(bool once) +{ + Q_D(const QRenderQmlToTexture); + if (d->m_renderManager->m_renderOnce != once) { + d->m_renderManager->m_renderOnce = once; + emit renderOnceChanged(once); + } +} + +/*! + \property QRenderQmlToTexture::texture + \brief The texture being rendered to. + * + This property specifies the texture being rendered to. Once the texture has been + set and the rendering begins, the texture can not be changed anymore. + */ +QAbstractTexture *QRenderQmlToTexture::texture() const +{ + Q_D(const QRenderQmlToTexture); + return d->m_renderManager->m_texture; +} + +void QRenderQmlToTexture::setTexture(QAbstractTexture *texture) +{ + Q_D(QRenderQmlToTexture); + if (d->m_renderManager->m_initialized) { + qWarning() << "Unable to set texture after initialization."; + return; + } + if (d->m_renderManager->m_texture != texture) { + if (d->m_renderManager->m_texture) + QObject::disconnect(d->m_textureDestroyedConnection); + if (texture && !texture->parent()) + texture->setParent(this); + d->m_renderManager->setTexture(texture); + if (texture) + d->m_textureDestroyedConnection + = QObject::connect(texture, &QAbstractTexture::destroyed, + this, &QRenderQmlToTexture::textureDestroyed); + emit textureChanged(texture); + } +} + +void QRenderQmlToTexture::textureDestroyed(QObject *object) +{ + Q_D(QRenderQmlToTexture); + Q_UNUSED(object); + d->m_renderManager->setTexture(nullptr); +} + +Qt3DCore::QNodeCreatedChangeBasePtr QRenderQmlToTexture::createNodeCreationChange() const +{ + auto creationChange = Qt3DCore::QNodeCreatedChangePtr::create(this); + auto &data = creationChange->data; + Q_D(const QRenderQmlToTexture); + data.renderOnce = d->m_renderManager->m_renderOnce; + data.textureId = d->m_renderManager->m_texture + ? d->m_renderManager->m_texture->id() : Qt3DCore::QNodeId(); + data.sharedObject = d->m_renderManager->m_sharedObject; + return creationChange; +} + +/*! + \internal + */ +void QRenderQmlToTexture::sourceLoaded() +{ + emit loadedChanged(true); +} + +} // namespace Qt3DRender + +QT_END_NAMESPACE diff --git a/src/render/framegraph/qrenderqmltotexture.h b/src/render/framegraph/qrenderqmltotexture.h new file mode 100644 index 000000000..044e4e721 --- /dev/null +++ b/src/render/framegraph/qrenderqmltotexture.h @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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$ +** +****************************************************************************/ + +#ifndef QT3DRENDER_QRENDERQMLTOTEXTURE_H +#define QT3DRENDER_QRENDERQMLTOTEXTURE_H + +#include +#include + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +class QRenderQmlToTexturePrivate; + +class QT3DRENDERSHARED_EXPORT QRenderQmlToTexture : public Qt3DRender::QFrameGraphNode +{ + Q_OBJECT + + Q_PROPERTY(Qt3DRender::QAbstractTexture *texture READ texture WRITE setTexture NOTIFY textureChanged) + Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged) + Q_PROPERTY(bool renderOnce READ renderOnce WRITE setRenderOnce NOTIFY renderOnceChanged) + Q_PROPERTY(bool loaded READ loaded NOTIFY loadedChanged) + +public: + explicit QRenderQmlToTexture(Qt3DCore::QNode *parent = nullptr); + ~QRenderQmlToTexture(); + + QUrl source() const; + QAbstractTexture *texture() const; + bool loaded() const; + bool renderOnce() const; + +public Q_SLOTS: + void setSource(const QUrl &url); + void setTexture(QAbstractTexture *texture); + void setRenderOnce(bool once); + +Q_SIGNALS: + void sourceChanged(const QUrl &url); + void textureChanged(QAbstractTexture *texture); + void loadedChanged(bool loaded); + void renderOnceChanged(bool once); + +protected: + Q_DECLARE_PRIVATE(QRenderQmlToTexture) + +private: + Qt3DCore::QNodeCreatedChangeBasePtr createNodeCreationChange() const Q_DECL_OVERRIDE; + void textureDestroyed(QObject *object); + + void sourceLoaded(); +}; + +} // namespace Qt3DRender + +QT_END_NAMESPACE + +#endif // QT3DRENDER_QRENDERQMLTOTEXTURE_H diff --git a/src/render/framegraph/qrenderqmltotexture_p.h b/src/render/framegraph/qrenderqmltotexture_p.h new file mode 100644 index 000000000..f9acf5368 --- /dev/null +++ b/src/render/framegraph/qrenderqmltotexture_p.h @@ -0,0 +1,212 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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$ +** +****************************************************************************/ + +#ifndef QT3DRENDER_QRENDERQMLTOTEXTURE_P_H +#define QT3DRENDER_QRENDERQMLTOTEXTURE_P_H + + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +class QRenderQmlToTexture; +class RenderQmlToTextureManager; + +// render thread -> render thread +static const QEvent::Type INITIALIZE = QEvent::Type(QEvent::User + 1); + +// main thread -> main thread, render thread +static const QEvent::Type RENDER = QEvent::Type(QEvent::User + 2); + +// main thread -> main thread +static const QEvent::Type RENDERSYNC = QEvent::Type(QEvent::User + 3); + +// render thread -> main thread +static const QEvent::Type PREPARE = QEvent::Type(QEvent::User + 4); +static const QEvent::Type INITIALIZED = QEvent::Type(QEvent::User + 5); +static const QEvent::Type RENDERED = QEvent::Type(QEvent::User + 6); + +// main thread -> render thread +static const QEvent::Type QUIT = QEvent::Type(QEvent::User + 7); + +class Q_AUTOTEST_EXPORT RenderQmlToTextureSharedObject +{ +public: + RenderQmlToTextureSharedObject(RenderQmlToTextureManager *manager); + ~RenderQmlToTextureSharedObject(); + + QQuickRenderControl *m_renderControl; + QQuickWindow *m_quickWindow; + RenderQmlToTextureManager *m_renderManager; + QOffscreenSurface *m_surface; + + QThread *m_renderThread; + QObject *m_renderObject; + + QWaitCondition m_cond; + QMutex m_mutex; + + bool isInitialized() const; + void setInitialized(); + + void requestQuit(); + bool isQuit() const; + + void requestRender(bool sync); + + bool isSyncRequested() const; + void clearSyncRequest(); + + void waitRender(); + void wakeWaiting(); + + bool isPrepared() const; + void setPrepared(); + + void disallowRender(); + bool canRender() const; + + void cleanup(); + +private: + + bool m_disallowed; + bool m_quit; + bool m_requestSync; + bool m_requestRender; + bool m_prepared; + bool m_initialized; +}; + +typedef QSharedPointer RenderQmlToTextureSharedObjectPtr; + +class Q_AUTOTEST_EXPORT QRenderQmlToTexturePrivate : public QFrameGraphNodePrivate +{ +public: + Q_DECLARE_PUBLIC(QRenderQmlToTexture) + + QRenderQmlToTexturePrivate(); + ~QRenderQmlToTexturePrivate(); + + static RenderQmlToTextureSharedObject *getSharedObject(QRenderQmlToTexture *rqtt); + + RenderQmlToTextureManager *m_renderManager; + QMetaObject::Connection m_textureDestroyedConnection; +}; + +struct QRenderQmlToTextureData +{ + bool renderOnce; + Qt3DCore::QNodeId textureId; + RenderQmlToTextureSharedObjectPtr sharedObject; +}; + + +class RenderQmlToTextureManager : public QWindow +{ + Q_OBJECT +public: + RenderQmlToTextureManager(QRenderQmlToTexturePrivate *priv); + ~RenderQmlToTextureManager(); + + QQmlEngine *m_qmlEngine; + QQmlComponent *m_qmlComponent; + QQuickItem *m_rootItem; + QRenderQmlToTexturePrivate *m_priv; + QSharedPointer m_sharedObject; + + QAbstractTexture *m_texture; + QUrl m_source; + Qt3DCore::QNodeId m_id; + + bool m_requested; + bool m_initialized; + bool m_renderSyncRequested; + bool m_renderOnce; + bool m_backendInitialized; + + void requestRender(); + void requestRenderSync(); + void doRenderSync(); + void startIfInitialized(); + void stopAndClean(); + void run(); + void updateSizes(); + + void setTexture(QAbstractTexture *texture); + void setSource(const QUrl &url); + + bool event(QEvent *e) Q_DECL_OVERRIDE; + + Q_SIGNAL void onLoadedChanged(); + + void cleanup(); +}; + + +} // namespace Qt3DRender + +QT_END_NAMESPACE + + +#endif // QT3DRENDER_QRENDERQMLTOTEXTURE_P_H diff --git a/src/render/framegraph/renderqmltotexture.cpp b/src/render/framegraph/renderqmltotexture.cpp new file mode 100644 index 000000000..91f8639c3 --- /dev/null +++ b/src/render/framegraph/renderqmltotexture.cpp @@ -0,0 +1,304 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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 +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +namespace Render { + +RenderQmlEventHandler::RenderQmlEventHandler(RenderQmlToTexture *node) + : QObject() + , m_node(node) +{ +} + +// Event handler for the RenderQmlToTexture::renderThread +bool RenderQmlEventHandler::event(QEvent *e) +{ + switch (e->type()) { + + case RENDER: { + m_node->render(); + return true; + } + + case INITIALIZE: { + m_node->initializeRender(); + return true; + } + + case QUIT: { + m_node->cleanup(); + return true; + } + + default: + break; + } + return QObject::event(e); +} + +RenderQmlToTexture::RenderQmlToTexture() + : FrameGraphNode(FrameGraphNode::InvalidNodeType) + , m_context(nullptr) + , m_sharedObject(nullptr) + , m_renderThread(nullptr) + , m_graphicsContext(nullptr) + , m_texture(nullptr) + , m_initialized(false) + , m_renderInitialized(false) + , m_renderOnce(false) +{ + +} + +RenderQmlToTexture::~RenderQmlToTexture() +{ + // this gets called from aspect thread. Wait for the render thread then delete it. + if (m_renderThread) { + m_renderThread->wait(1000); + delete m_renderThread; + } +} + +void RenderQmlToTexture::setTexture(Qt3DCore::QNodeId textureId) +{ + m_textureId = textureId; + attach(); + checkInitialized(); +} + +void RenderQmlToTexture::checkInitialized() +{ + if (!m_initialized && m_textureId != Qt3DCore::QNodeId()) { + + // Create render thread + m_renderThread = new QThread(); + m_renderThread->setObjectName(QStringLiteral("RenderQmlToTexture::renderThread")); + m_sharedObject->m_renderThread = m_renderThread; + + // Create event handler for the render thread + m_sharedObject->m_renderObject = new RenderQmlEventHandler(this); + m_sharedObject->m_renderObject->moveToThread(m_sharedObject->m_renderThread); + m_sharedObject->m_renderThread->start(); + + // Notify main thread we have been initialized + QCoreApplication::postEvent(m_sharedObject->m_renderManager, new QEvent(INITIALIZED)); + + // Initialize render thread + QCoreApplication::postEvent(m_sharedObject->m_renderObject, new QEvent(INITIALIZE)); + + m_initialized = true; + } +} + +void RenderQmlToTexture::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) +{ + const auto typedChange = qSharedPointerCast>(change); + const auto &data = typedChange->data; + m_renderOnce = m_renderOnce; + setSharedObject(data.sharedObject); + setTexture(data.textureId); +} + +void RenderQmlToTexture::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) +{ + if (e->type() == Qt3DCore::PropertyUpdated) { + Qt3DCore::QPropertyUpdatedChangePtr propertyChange + = qSharedPointerCast(e); + if (propertyChange->propertyName() == QByteArrayLiteral("enabled")) + setEnabled(propertyChange->value().toBool()); + else if (propertyChange->propertyName() == QByteArrayLiteral("dirty")) { + // sent to trigger backend update when the texture gets rendered + // so do nothing here + } + else if (propertyChange->propertyName() == QByteArrayLiteral("renderOnce")) + m_renderOnce = propertyChange->value().toBool(); + else if (propertyChange->propertyName() == QByteArrayLiteral("texture")) { + Qt3DCore::QNodeId textureId = propertyChange->value().value(); + setTexture(textureId); + } + markDirty(AbstractRenderer::AllDirty); + } + FrameGraphNode::sceneChangeEvent(e); +} + +void RenderQmlToTexture::setSharedObject(Qt3DRender::RenderQmlToTextureSharedObjectPtr sharedObject) +{ + m_sharedObject = sharedObject; +} + +void RenderQmlToTexture::initializeRender() +{ + if (!m_renderInitialized) { + Qt3DRender::Render::Renderer *renderer + = static_cast(this->renderer()); + if (!renderer) + return; + + QSurfaceFormat format; + format.setDepthBufferSize(24); + format.setStencilBufferSize(8); + + m_context = new QOpenGLContext(); + m_context->setFormat(format); + + m_context->setShareContext(renderer->shareContext()); + m_context->create(); + + m_graphicsContext = new GraphicsContext(); + m_graphicsContext->setOpenGLContext(m_context); + m_graphicsContext->setRenderer(renderer); + + m_graphicsContext->makeCurrent(m_sharedObject->m_surface); + m_sharedObject->m_renderControl->initialize(m_context); + m_graphicsContext->doneCurrent(); + + QCoreApplication::postEvent(m_sharedObject->m_renderManager, new QEvent(PREPARE)); + m_renderInitialized = true; + } +} + +void RenderQmlToTexture::attach() +{ + m_attachments = AttachmentPack(); + Attachment attach; + attach.m_mipLevel = 0; + attach.m_textureUuid = m_textureId; + attach.m_point = QRenderTargetOutput::AttachmentPoint::Color0; + +// m_attachments.addAttachment(attach); +} + +void RenderQmlToTexture::render() +{ + if (m_initialized && m_sharedObject && this->isEnabled()) { + + QMutexLocker lock(&m_sharedObject->m_mutex); + + // Lookup backend texture + if (m_texture == nullptr) { + m_texture = renderer()->nodeManagers()->textureManager()->lookupResource(m_textureId); + if (!m_texture) { + qCDebug(Render::Framegraph) << Q_FUNC_INFO << "Texture not set"; + return; + } + } + + m_graphicsContext->makeCurrent(m_sharedObject->m_surface); + + // Don't create the OpenGL texture in this thread. + const bool canUseTexture = !m_texture->isTextureReset(); + + if (canUseTexture) { + // Activate fbo for the texture + QOpenGLTexture *glTex = m_texture->getOrCreateGLTexture(); + const QSize textureSize = QSize(glTex->width(), glTex->height()); + + // TODO: create fbo from the texture. + GLuint fbo = 0;//m_graphicsContext->activateRenderTargetForQmlRender(this, m_attachments, 0); + + if (fbo != m_sharedObject->m_quickWindow->renderTargetId()) + m_sharedObject->m_quickWindow->setRenderTarget(fbo, textureSize); + + m_texture->textureLock()->lock(); + } + // Call disallow rendering while mutex is locked + if (canUseTexture && m_renderOnce) + m_sharedObject->disallowRender(); + + // Need to call sync even if the texture is not in use + if (m_sharedObject->isSyncRequested()) { + + m_sharedObject->clearSyncRequest(); + + m_sharedObject->m_renderControl->sync(); + + // gui thread can now continue + m_sharedObject->wakeWaiting(); + lock.unlock(); + } + + if (canUseTexture) { + + // Render + m_sharedObject->m_renderControl->render(); + + // Tell main thread we are done so it can begin cleanup + if (m_renderOnce) + QCoreApplication::postEvent(m_sharedObject->m_renderManager, new QEvent(RENDERED)); + + m_sharedObject->m_quickWindow->resetOpenGLState(); + m_context->functions()->glFlush(); + m_texture->textureLock()->unlock(); + } + m_graphicsContext->doneCurrent(); + } +} + +void RenderQmlToTexture::cleanup() +{ + if (m_renderInitialized && m_initialized) { + m_context->makeCurrent(m_sharedObject->m_surface); + m_sharedObject->m_renderControl->invalidate(); + m_context->doneCurrent(); + m_sharedObject->m_renderThread->quit(); + delete m_sharedObject->m_renderObject; + m_sharedObject->m_renderObject = nullptr; + delete m_context; + m_context = nullptr; + m_sharedObject = nullptr; + delete m_graphicsContext; + m_graphicsContext = nullptr; + m_renderInitialized = false; + m_initialized = false; + } +} + +} // namespace Render + +} // namespace Qt3DRender + +QT_END_NAMESPACE diff --git a/src/render/framegraph/renderqmltotexture_p.h b/src/render/framegraph/renderqmltotexture_p.h new file mode 100644 index 000000000..49913bcd9 --- /dev/null +++ b/src/render/framegraph/renderqmltotexture_p.h @@ -0,0 +1,116 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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$ +** +****************************************************************************/ + +#ifndef QT3DRENDER_RENDER_RENDERQMLTOTEXTURE_P_H +#define QT3DRENDER_RENDER_RENDERQMLTOTEXTURE_P_H + + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +#include +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +namespace Render { + +class GraphicsContext; +class RenderQmlToTexture; + +class RenderQmlEventHandler : public QObject +{ + Q_OBJECT +public: + RenderQmlEventHandler(RenderQmlToTexture *node); + bool event(QEvent *e) Q_DECL_OVERRIDE; + +private: + RenderQmlToTexture *m_node; +}; + +class Q_AUTOTEST_EXPORT RenderQmlToTexture : public FrameGraphNode +{ +public: + RenderQmlToTexture(); + ~RenderQmlToTexture(); + + void attach(); + void render(); + void initializeRender(); + void setSharedObject(RenderQmlToTextureSharedObjectPtr sharedObject); + void cleanup(); + void setTexture(Qt3DCore::QNodeId textureId); + void checkInitialized(); + + void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_OVERRIDE; + void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL; + + QOpenGLContext *m_context; + GraphicsContext *m_graphicsContext; + QThread *m_renderThread; + Qt3DCore::QNodeId m_textureId; + QSharedPointer m_sharedObject; + AttachmentPack m_attachments; + Texture *m_texture; + + bool m_initialized; + bool m_renderInitialized; + bool m_renderOnce; +}; + +} // Render + +} // Qt3DRender + +QT_END_NAMESPACE + +#endif // QT3DRENDER_RENDER_RENDERQMLTOTEXTURE_P_H -- cgit v1.2.3 From 1e0913cc267cea8da114ea1b903c4f3a0c675c5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Fri, 21 Oct 2016 13:23:37 +0300 Subject: Rename RenderQmlToTexture to Scene2D Change-Id: I1e66f588c8e174d9e24f7050bc3d2c3c7c63b6e9 Reviewed-by: Sean Harmer --- src/render/framegraph/qrenderqmltotexture.cpp | 620 ------------------------- src/render/framegraph/qrenderqmltotexture.h | 96 ---- src/render/framegraph/qrenderqmltotexture_p.h | 212 --------- src/render/framegraph/qscene2d.cpp | 621 ++++++++++++++++++++++++++ src/render/framegraph/qscene2d.h | 96 ++++ src/render/framegraph/qscene2d_p.h | 211 +++++++++ src/render/framegraph/renderqmltotexture.cpp | 304 ------------- src/render/framegraph/renderqmltotexture_p.h | 116 ----- src/render/framegraph/scene2d.cpp | 303 +++++++++++++ src/render/framegraph/scene2d_p.h | 115 +++++ 10 files changed, 1346 insertions(+), 1348 deletions(-) delete mode 100644 src/render/framegraph/qrenderqmltotexture.cpp delete mode 100644 src/render/framegraph/qrenderqmltotexture.h delete mode 100644 src/render/framegraph/qrenderqmltotexture_p.h create mode 100644 src/render/framegraph/qscene2d.cpp create mode 100644 src/render/framegraph/qscene2d.h create mode 100644 src/render/framegraph/qscene2d_p.h delete mode 100644 src/render/framegraph/renderqmltotexture.cpp delete mode 100644 src/render/framegraph/renderqmltotexture_p.h create mode 100644 src/render/framegraph/scene2d.cpp create mode 100644 src/render/framegraph/scene2d_p.h diff --git a/src/render/framegraph/qrenderqmltotexture.cpp b/src/render/framegraph/qrenderqmltotexture.cpp deleted file mode 100644 index d4fa41874..000000000 --- a/src/render/framegraph/qrenderqmltotexture.cpp +++ /dev/null @@ -1,620 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 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 "qrenderqmltotexture.h" -#include "qrenderqmltotexture_p.h" - -#include - -#include - -QT_BEGIN_NAMESPACE - -using namespace Qt3DCore; - -namespace Qt3DRender { - - -/*! - \class Qt3DRender::QRenderQmlToTexture - \inmodule Qt3DRender - - \brief This class enables rendering qml into a texture, which then can be - used as a part of 3D scene. - - The component uses QQuickRenderControl to render the given QML source into an - offscreen surface, which is attached to a texture provided by the user. This allows the - component to directly render into the texture without intermediate copy and the user to - freely specify how the texture is used in the 3D scene. - - \since 5.9 -*/ - -/*! - \qmltype RenderQmlToTexture - \inqmlmodule Qt3D.Render - \since 5.9 - \inherits - \instantiates Qt3DRender::QRenderQmlToTexture - \brief RenderQmlToTexture - */ - -/*! - \qmlproperty Qt3DRender::QAbstractTexture Qt3D.Render::RenderQmlToTexture::texture - Holds the texture being rendered to. - */ - -/*! - \qmlproperty QUrl Qt3D.Render::RenderQmlToTexture::source - Holds the qml source url. - */ - -/*! - \qmlproperty bool Qt3D.Render::RenderQmlToTexture::renderOnce - Holds whether the first rendered image to the texture is also the last, after which the - renderer releases resources needed for the rendering and the rendering is no longer possible - with this RenderQmlToTexture object. - */ - -/*! - \qmlproperty bool Qt3D.Render::RenderQmlToTexture::loaded - Hold whether the source has been loaded. - */ - -class RenderControl : public QQuickRenderControl -{ -public: - RenderControl(QWindow *w) : m_window(w) { } - QWindow *renderWindow(QPoint *offset) Q_DECL_OVERRIDE; - -private: - QWindow *m_window; -}; - -QWindow *RenderControl::renderWindow(QPoint *offset) -{ - if (offset) - *offset = QPoint(0, 0); - return m_window; -} - -/*! - \internal - Constructs object shared by the front-end and back-end to synchronize the rendering. - */ -RenderQmlToTextureSharedObject::RenderQmlToTextureSharedObject(RenderQmlToTextureManager *manager) - : m_quit(false) - , m_requestSync(false) - , m_prepared(false) - , m_initialized(false) - , m_renderControl(nullptr) - , m_quickWindow(nullptr) - , m_renderManager(manager) - , m_surface(nullptr) - , m_renderObject(nullptr) - , m_disallowed(false) -{ -} - -RenderQmlToTextureSharedObject::~RenderQmlToTextureSharedObject() -{ -} - -void RenderQmlToTextureSharedObject::cleanup() -{ - delete m_renderControl; - delete m_quickWindow; - delete m_surface; - m_renderControl = nullptr; - m_quickWindow = nullptr; - m_surface = nullptr; - m_initialized = false; -} - -bool RenderQmlToTextureSharedObject::canRender() const -{ - return m_initialized && m_prepared && !m_disallowed; -} - -bool RenderQmlToTextureSharedObject::isInitialized() const -{ - return m_initialized; -} - -void RenderQmlToTextureSharedObject::disallowRender() -{ - m_disallowed = true; -} - -void RenderQmlToTextureSharedObject::setInitialized() -{ - m_initialized = true; -} - -bool RenderQmlToTextureSharedObject::isPrepared() const -{ - return m_prepared; -} - -void RenderQmlToTextureSharedObject::setPrepared() -{ - m_prepared = true; -} - -// not protected, call only from main thread -bool RenderQmlToTextureSharedObject::isQuit() const -{ - Q_ASSERT(QThread::currentThread() == QCoreApplication::instance()->thread()); - return m_quit; -} - -// not protected, call only from main thread -void RenderQmlToTextureSharedObject::requestQuit() -{ - Q_ASSERT(QThread::currentThread() == QCoreApplication::instance()->thread()); - m_quit = true; - QCoreApplication::postEvent(m_renderObject, new QEvent(QUIT)); -} - -bool RenderQmlToTextureSharedObject::isSyncRequested() const -{ - return m_requestSync; -} - -void RenderQmlToTextureSharedObject::requestRender(bool sync) -{ - m_requestSync = sync; - QCoreApplication::postEvent(m_renderObject, new QEvent(RENDER)); -} - -void RenderQmlToTextureSharedObject::waitRender() -{ - m_cond.wait(&m_mutex); -} - -void RenderQmlToTextureSharedObject::wakeWaiting() -{ - m_cond.wakeOne(); -} - -void RenderQmlToTextureSharedObject::clearSyncRequest() -{ - m_requestSync = false; -} - -/*! - \internal - Constructs qml render manager. - */ -RenderQmlToTextureManager::RenderQmlToTextureManager(QRenderQmlToTexturePrivate *priv) - : m_priv(priv) - , m_qmlEngine(nullptr) - , m_qmlComponent(nullptr) - , m_rootItem(nullptr) - , m_source(nullptr) - , m_texture(nullptr) - , m_requested(false) - , m_initialized(false) - , m_renderSyncRequested(false) - , m_sharedObject(new RenderQmlToTextureSharedObject(this)) - , m_renderOnce(false) - , m_backendInitialized(false) -{ - setFormat(QSurfaceFormat::defaultFormat()); - - m_sharedObject->m_surface = new QOffscreenSurface; - m_sharedObject->m_surface->setFormat(QSurfaceFormat::defaultFormat()); - m_sharedObject->m_surface->create(); - - // Create render control - m_sharedObject->m_renderControl = new RenderControl(this); - - // Create window to render the QML with - m_sharedObject->m_quickWindow = new QQuickWindow(m_sharedObject->m_renderControl); - m_sharedObject->m_quickWindow->setClearBeforeRendering(true); - m_sharedObject->m_quickWindow->setDefaultAlphaBuffer(true); - - // Create a QML engine. - m_qmlEngine = new QQmlEngine; - if (!m_qmlEngine->incubationController()) - m_qmlEngine->setIncubationController(m_sharedObject->m_quickWindow->incubationController()); - - connect(m_sharedObject->m_renderControl, &QQuickRenderControl::renderRequested, - this, &RenderQmlToTextureManager::requestRender); - connect(m_sharedObject->m_renderControl, &QQuickRenderControl::sceneChanged, - this, &RenderQmlToTextureManager::requestRenderSync); -} - -RenderQmlToTextureManager::~RenderQmlToTextureManager() -{ - m_sharedObject = nullptr; -} - -void RenderQmlToTextureManager::requestRender() -{ - // Don't request render until the backend is initialized. - if (m_sharedObject->canRender()) { - if (!m_requested) { - m_requested = true; - QCoreApplication::postEvent(this, new QEvent(RENDER)); - } - } -} - -void RenderQmlToTextureManager::requestRenderSync() -{ - // Don't request render until the backed is initialized. - if (m_sharedObject->canRender()) { - if (!m_requested) { - m_requested = true; - QCoreApplication::postEvent(this, new QEvent(RENDERSYNC)); - } - } else { - m_renderSyncRequested = true; - } -} - -void RenderQmlToTextureManager::startIfInitialized() -{ - if (!m_initialized) { - if (m_backendInitialized && m_source.isValid()) { - m_qmlComponent = new QQmlComponent(m_qmlEngine, m_source); - if (m_qmlComponent->isLoading()) { - connect(m_qmlComponent, &QQmlComponent::statusChanged, - this, &RenderQmlToTextureManager::run); - } else { - run(); - } - } - } -} - -void RenderQmlToTextureManager::stopAndClean() -{ - if (m_sharedObject->isInitialized()) { - QMutexLocker lock(&m_sharedObject->m_mutex); - m_sharedObject->requestQuit(); - m_sharedObject->m_renderThread->wait(); - m_sharedObject->cleanup(); - delete m_qmlEngine; - delete m_qmlComponent; - m_qmlEngine = nullptr; - m_qmlComponent = nullptr; - } -} - -void RenderQmlToTextureManager::run() -{ - disconnect(m_qmlComponent, &QQmlComponent::statusChanged, this, &RenderQmlToTextureManager::run); - - if (m_qmlComponent->isError()) { - QList errorList = m_qmlComponent->errors(); - for (const QQmlError &error: errorList) - qWarning() << error.url() << error.line() << error; - return; - } - - QObject *rootObject = m_qmlComponent->create(); - if (m_qmlComponent->isError()) { - QList errorList = m_qmlComponent->errors(); - for (const QQmlError &error: errorList) - qWarning() << error.url() << error.line() << error; - return; - } - - m_rootItem = qobject_cast(rootObject); - if (!m_rootItem) { - qWarning("QRenderQmlToTexture: Root item is not a QQuickItem."); - delete rootObject; - return; - } - - // The root item is ready. Associate it with the window. - m_rootItem->setParentItem(m_sharedObject->m_quickWindow->contentItem()); - - // Update window size. - updateSizes(); - - m_initialized = true; - m_sharedObject->setInitialized(); - - emit onLoadedChanged(); -} - -void RenderQmlToTextureManager::updateSizes() -{ - const int width = m_rootItem->width(); - const int height = m_rootItem->height(); - if (width == 0 || height == 0) { - qWarning() << "QRenderQmlToTexture: Root item size not set."; - return; - } - resize(width, height); - m_sharedObject->m_quickWindow->setGeometry(0, 0, width, height); -} - -void RenderQmlToTextureManager::setTexture(QAbstractTexture *texture) -{ - m_texture = texture; - startIfInitialized(); -} - -void RenderQmlToTextureManager::setSource(const QUrl &url) -{ - m_source = url; - startIfInitialized(); -} - -bool RenderQmlToTextureManager::event(QEvent *e) -{ - switch (e->type()) { - - case RENDER: { - // just render request, don't need to call sync in render thread - QMutexLocker lock(&m_sharedObject->m_mutex); - m_sharedObject->requestRender(false); - - Qt3DCore::QPropertyUpdatedChangePtr change(new Qt3DCore::QPropertyUpdatedChange(m_priv->m_id)); - change->setPropertyName("dirty"); - change->setValue(QVariant::fromValue(true)); - m_priv->notifyObservers(change); - - m_requested = false; - return true; - } - - case RENDERSYNC: { - // sync and render request, main and render threads must be synchronized - if (!m_sharedObject->isQuit()) - doRenderSync(); - m_requested = false; - return true; - } - - case PREPARE: { - m_sharedObject->m_renderControl->prepareThread(m_sharedObject->m_renderThread); - m_sharedObject->setPrepared(); - - if (m_renderSyncRequested) { - if (!m_requested) { - m_requested = true; - QCoreApplication::postEvent(this, new QEvent(RENDERSYNC)); - } - m_renderSyncRequested = false; - } - return true; - } - - case INITIALIZED: { - // backend is initialized, start the qml - m_backendInitialized = true; - startIfInitialized(); - return true; - } - - case RENDERED: { - // render is done, excellent, now clean anything not needed anymore. - stopAndClean(); - return true; - } - - default: - break; - } - return QWindow::event(e); -} - -void RenderQmlToTextureManager::doRenderSync() -{ - QMutexLocker lock(&m_sharedObject->m_mutex); - - m_sharedObject->requestRender(true); - m_sharedObject->m_renderControl->polishItems(); - - Qt3DCore::QPropertyUpdatedChangePtr change(new Qt3DCore::QPropertyUpdatedChange(m_priv->m_id)); - - change->setPropertyName("dirty"); - change->setValue(QVariant::fromValue(true)); - m_priv->notifyObservers(change); - - // begin waiting render thread - m_sharedObject->waitRender(); - m_requested = false; -} - -void RenderQmlToTextureManager::cleanup() -{ - stopAndClean(); -} - - -QRenderQmlToTexturePrivate::QRenderQmlToTexturePrivate() - : QFrameGraphNodePrivate() - , m_renderManager(new RenderQmlToTextureManager(this)) -{ -} - -QRenderQmlToTexturePrivate::~QRenderQmlToTexturePrivate() -{ - m_renderManager->cleanup(); - delete m_renderManager; -} - - -RenderQmlToTextureSharedObject *QRenderQmlToTexturePrivate::getSharedObject(QRenderQmlToTexture *rqtt) -{ - return rqtt->d_func()->m_renderManager->m_sharedObject.data(); -} - - -/*! - The constructor creates an instance with the specified \a parent. - */ -QRenderQmlToTexture::QRenderQmlToTexture(Qt3DCore::QNode *parent) - : QFrameGraphNode(*new QRenderQmlToTexturePrivate, parent) -{ - Q_D(QRenderQmlToTexture); - connect(d->m_renderManager, &RenderQmlToTextureManager::onLoadedChanged, - this, &QRenderQmlToTexture::sourceLoaded); -} - -/*! - Destructor. - */ -QRenderQmlToTexture::~QRenderQmlToTexture() -{ -} - -bool QRenderQmlToTexture::loaded() const -{ - Q_D(const QRenderQmlToTexture); - return d->m_renderManager->m_initialized; -} - -/*! - \property QRenderQmlToTexture::source - \brief Specifies the url for the qml. - * - This property specifies the url to the qml being rendered to the texture. - The source must specify QQuickItem as a root. The item must specify width - and height. The rendered qml is scaled to the texture size. - The property can not be changed after the rendering has been initialized. - */ -QUrl QRenderQmlToTexture::source() const -{ - Q_D(const QRenderQmlToTexture); - return d->m_renderManager->m_source; -} - -void QRenderQmlToTexture::setSource(const QUrl &url) -{ - Q_D(QRenderQmlToTexture); - if (d->m_renderManager->m_initialized) { - qWarning() << "Unable to set source after initialization."; - return; - } - d->m_renderManager->setSource(url); - emit sourceChanged(url); -} - -/*! - \property QRenderQmlToTexture::renderOnce - \brief Property to specify if the texture will be rendered only once. - * - This property specifies that the texture will be rendered only one time. - Once the rendering has been done, resources reserved for rendering will be - released and the QRenderQmlToTexture will become unusable. - If set to false, which is the default, the rendering is continuous. - */ -bool QRenderQmlToTexture::renderOnce() const -{ - Q_D(const QRenderQmlToTexture); - return d->m_renderManager->m_renderOnce; -} - -void QRenderQmlToTexture::setRenderOnce(bool once) -{ - Q_D(const QRenderQmlToTexture); - if (d->m_renderManager->m_renderOnce != once) { - d->m_renderManager->m_renderOnce = once; - emit renderOnceChanged(once); - } -} - -/*! - \property QRenderQmlToTexture::texture - \brief The texture being rendered to. - * - This property specifies the texture being rendered to. Once the texture has been - set and the rendering begins, the texture can not be changed anymore. - */ -QAbstractTexture *QRenderQmlToTexture::texture() const -{ - Q_D(const QRenderQmlToTexture); - return d->m_renderManager->m_texture; -} - -void QRenderQmlToTexture::setTexture(QAbstractTexture *texture) -{ - Q_D(QRenderQmlToTexture); - if (d->m_renderManager->m_initialized) { - qWarning() << "Unable to set texture after initialization."; - return; - } - if (d->m_renderManager->m_texture != texture) { - if (d->m_renderManager->m_texture) - QObject::disconnect(d->m_textureDestroyedConnection); - if (texture && !texture->parent()) - texture->setParent(this); - d->m_renderManager->setTexture(texture); - if (texture) - d->m_textureDestroyedConnection - = QObject::connect(texture, &QAbstractTexture::destroyed, - this, &QRenderQmlToTexture::textureDestroyed); - emit textureChanged(texture); - } -} - -void QRenderQmlToTexture::textureDestroyed(QObject *object) -{ - Q_D(QRenderQmlToTexture); - Q_UNUSED(object); - d->m_renderManager->setTexture(nullptr); -} - -Qt3DCore::QNodeCreatedChangeBasePtr QRenderQmlToTexture::createNodeCreationChange() const -{ - auto creationChange = Qt3DCore::QNodeCreatedChangePtr::create(this); - auto &data = creationChange->data; - Q_D(const QRenderQmlToTexture); - data.renderOnce = d->m_renderManager->m_renderOnce; - data.textureId = d->m_renderManager->m_texture - ? d->m_renderManager->m_texture->id() : Qt3DCore::QNodeId(); - data.sharedObject = d->m_renderManager->m_sharedObject; - return creationChange; -} - -/*! - \internal - */ -void QRenderQmlToTexture::sourceLoaded() -{ - emit loadedChanged(true); -} - -} // namespace Qt3DRender - -QT_END_NAMESPACE diff --git a/src/render/framegraph/qrenderqmltotexture.h b/src/render/framegraph/qrenderqmltotexture.h deleted file mode 100644 index 044e4e721..000000000 --- a/src/render/framegraph/qrenderqmltotexture.h +++ /dev/null @@ -1,96 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 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$ -** -****************************************************************************/ - -#ifndef QT3DRENDER_QRENDERQMLTOTEXTURE_H -#define QT3DRENDER_QRENDERQMLTOTEXTURE_H - -#include -#include - -#include -#include -#include - -QT_BEGIN_NAMESPACE - -namespace Qt3DRender { - -class QRenderQmlToTexturePrivate; - -class QT3DRENDERSHARED_EXPORT QRenderQmlToTexture : public Qt3DRender::QFrameGraphNode -{ - Q_OBJECT - - Q_PROPERTY(Qt3DRender::QAbstractTexture *texture READ texture WRITE setTexture NOTIFY textureChanged) - Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged) - Q_PROPERTY(bool renderOnce READ renderOnce WRITE setRenderOnce NOTIFY renderOnceChanged) - Q_PROPERTY(bool loaded READ loaded NOTIFY loadedChanged) - -public: - explicit QRenderQmlToTexture(Qt3DCore::QNode *parent = nullptr); - ~QRenderQmlToTexture(); - - QUrl source() const; - QAbstractTexture *texture() const; - bool loaded() const; - bool renderOnce() const; - -public Q_SLOTS: - void setSource(const QUrl &url); - void setTexture(QAbstractTexture *texture); - void setRenderOnce(bool once); - -Q_SIGNALS: - void sourceChanged(const QUrl &url); - void textureChanged(QAbstractTexture *texture); - void loadedChanged(bool loaded); - void renderOnceChanged(bool once); - -protected: - Q_DECLARE_PRIVATE(QRenderQmlToTexture) - -private: - Qt3DCore::QNodeCreatedChangeBasePtr createNodeCreationChange() const Q_DECL_OVERRIDE; - void textureDestroyed(QObject *object); - - void sourceLoaded(); -}; - -} // namespace Qt3DRender - -QT_END_NAMESPACE - -#endif // QT3DRENDER_QRENDERQMLTOTEXTURE_H diff --git a/src/render/framegraph/qrenderqmltotexture_p.h b/src/render/framegraph/qrenderqmltotexture_p.h deleted file mode 100644 index f9acf5368..000000000 --- a/src/render/framegraph/qrenderqmltotexture_p.h +++ /dev/null @@ -1,212 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 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$ -** -****************************************************************************/ - -#ifndef QT3DRENDER_QRENDERQMLTOTEXTURE_P_H -#define QT3DRENDER_QRENDERQMLTOTEXTURE_P_H - - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of other Qt classes. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE - -namespace Qt3DRender { - -class QRenderQmlToTexture; -class RenderQmlToTextureManager; - -// render thread -> render thread -static const QEvent::Type INITIALIZE = QEvent::Type(QEvent::User + 1); - -// main thread -> main thread, render thread -static const QEvent::Type RENDER = QEvent::Type(QEvent::User + 2); - -// main thread -> main thread -static const QEvent::Type RENDERSYNC = QEvent::Type(QEvent::User + 3); - -// render thread -> main thread -static const QEvent::Type PREPARE = QEvent::Type(QEvent::User + 4); -static const QEvent::Type INITIALIZED = QEvent::Type(QEvent::User + 5); -static const QEvent::Type RENDERED = QEvent::Type(QEvent::User + 6); - -// main thread -> render thread -static const QEvent::Type QUIT = QEvent::Type(QEvent::User + 7); - -class Q_AUTOTEST_EXPORT RenderQmlToTextureSharedObject -{ -public: - RenderQmlToTextureSharedObject(RenderQmlToTextureManager *manager); - ~RenderQmlToTextureSharedObject(); - - QQuickRenderControl *m_renderControl; - QQuickWindow *m_quickWindow; - RenderQmlToTextureManager *m_renderManager; - QOffscreenSurface *m_surface; - - QThread *m_renderThread; - QObject *m_renderObject; - - QWaitCondition m_cond; - QMutex m_mutex; - - bool isInitialized() const; - void setInitialized(); - - void requestQuit(); - bool isQuit() const; - - void requestRender(bool sync); - - bool isSyncRequested() const; - void clearSyncRequest(); - - void waitRender(); - void wakeWaiting(); - - bool isPrepared() const; - void setPrepared(); - - void disallowRender(); - bool canRender() const; - - void cleanup(); - -private: - - bool m_disallowed; - bool m_quit; - bool m_requestSync; - bool m_requestRender; - bool m_prepared; - bool m_initialized; -}; - -typedef QSharedPointer RenderQmlToTextureSharedObjectPtr; - -class Q_AUTOTEST_EXPORT QRenderQmlToTexturePrivate : public QFrameGraphNodePrivate -{ -public: - Q_DECLARE_PUBLIC(QRenderQmlToTexture) - - QRenderQmlToTexturePrivate(); - ~QRenderQmlToTexturePrivate(); - - static RenderQmlToTextureSharedObject *getSharedObject(QRenderQmlToTexture *rqtt); - - RenderQmlToTextureManager *m_renderManager; - QMetaObject::Connection m_textureDestroyedConnection; -}; - -struct QRenderQmlToTextureData -{ - bool renderOnce; - Qt3DCore::QNodeId textureId; - RenderQmlToTextureSharedObjectPtr sharedObject; -}; - - -class RenderQmlToTextureManager : public QWindow -{ - Q_OBJECT -public: - RenderQmlToTextureManager(QRenderQmlToTexturePrivate *priv); - ~RenderQmlToTextureManager(); - - QQmlEngine *m_qmlEngine; - QQmlComponent *m_qmlComponent; - QQuickItem *m_rootItem; - QRenderQmlToTexturePrivate *m_priv; - QSharedPointer m_sharedObject; - - QAbstractTexture *m_texture; - QUrl m_source; - Qt3DCore::QNodeId m_id; - - bool m_requested; - bool m_initialized; - bool m_renderSyncRequested; - bool m_renderOnce; - bool m_backendInitialized; - - void requestRender(); - void requestRenderSync(); - void doRenderSync(); - void startIfInitialized(); - void stopAndClean(); - void run(); - void updateSizes(); - - void setTexture(QAbstractTexture *texture); - void setSource(const QUrl &url); - - bool event(QEvent *e) Q_DECL_OVERRIDE; - - Q_SIGNAL void onLoadedChanged(); - - void cleanup(); -}; - - -} // namespace Qt3DRender - -QT_END_NAMESPACE - - -#endif // QT3DRENDER_QRENDERQMLTOTEXTURE_P_H diff --git a/src/render/framegraph/qscene2d.cpp b/src/render/framegraph/qscene2d.cpp new file mode 100644 index 000000000..62e766684 --- /dev/null +++ b/src/render/framegraph/qscene2d.cpp @@ -0,0 +1,621 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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 "qscene2d.h" +#include "qscene2d_p.h" + +#include + +#include + +QT_BEGIN_NAMESPACE + +using namespace Qt3DCore; + +namespace Qt3DRender { + + +/*! + \class Qt3DRender::QScene2D + \inmodule Qt3DRender + + \brief This class enables rendering qml into a texture, which then can be + used as a part of 3D scene. + + The component uses QQuickRenderControl to render the given QML source into an + offscreen surface, which is attached to a texture provided by the user. This allows the + component to directly render into the texture without intermediate copy and the user to + freely specify how the texture is used in the 3D scene. + + \since 5.9 +*/ + +/*! + \qmltype Scene2D + \inqmlmodule Qt3D.Render + \since + \ingroup + \instantiates Qt3DRender::QScene2D + \brief Scene2D + * + */ + +/*! + \qmlproperty Qt3DRender::QAbstractTexture Qt3D.Render::Scene2D::texture + Holds the texture being rendered to. + */ + +/*! + \qmlproperty QUrl Qt3D.Render::Scene2D::source + Holds the qml source url. + */ + +/*! + \qmlproperty bool Qt3D.Render::Scene2D::renderOnce + Holds whether the first rendered image to the texture is also the last, after which the + renderer releases resources needed for the rendering and the rendering is no longer possible + with this Scene2D object. + */ + +/*! + \qmlproperty bool Qt3D.Render::Scene2D::loaded + Holds whether the source has been loaded. + */ + +class RenderControl : public QQuickRenderControl +{ +public: + RenderControl(QWindow *w) : m_window(w) { } + QWindow *renderWindow(QPoint *offset) Q_DECL_OVERRIDE; + +private: + QWindow *m_window; +}; + +QWindow *RenderControl::renderWindow(QPoint *offset) +{ + if (offset) + *offset = QPoint(0, 0); + return m_window; +} + +/*! + \internal + Constructs object shared by the front-end and back-end to synchronize the rendering. + */ +Scene2DSharedObject::Scene2DSharedObject(Scene2DManager *manager) + : m_quit(false) + , m_requestSync(false) + , m_prepared(false) + , m_initialized(false) + , m_renderControl(nullptr) + , m_quickWindow(nullptr) + , m_renderManager(manager) + , m_surface(nullptr) + , m_renderObject(nullptr) + , m_disallowed(false) +{ +} + +Scene2DSharedObject::~Scene2DSharedObject() +{ +} + +void Scene2DSharedObject::cleanup() +{ + delete m_renderControl; + delete m_quickWindow; + delete m_surface; + m_renderControl = nullptr; + m_quickWindow = nullptr; + m_surface = nullptr; + m_initialized = false; +} + +bool Scene2DSharedObject::canRender() const +{ + return m_initialized && m_prepared && !m_disallowed; +} + +bool Scene2DSharedObject::isInitialized() const +{ + return m_initialized; +} + +void Scene2DSharedObject::disallowRender() +{ + m_disallowed = true; +} + +void Scene2DSharedObject::setInitialized() +{ + m_initialized = true; +} + +bool Scene2DSharedObject::isPrepared() const +{ + return m_prepared; +} + +void Scene2DSharedObject::setPrepared() +{ + m_prepared = true; +} + +// not protected, call only from main thread +bool Scene2DSharedObject::isQuit() const +{ + Q_ASSERT(QThread::currentThread() == QCoreApplication::instance()->thread()); + return m_quit; +} + +// not protected, call only from main thread +void Scene2DSharedObject::requestQuit() +{ + Q_ASSERT(QThread::currentThread() == QCoreApplication::instance()->thread()); + m_quit = true; + QCoreApplication::postEvent(m_renderObject, new QEvent(QUIT)); +} + +bool Scene2DSharedObject::isSyncRequested() const +{ + return m_requestSync; +} + +void Scene2DSharedObject::requestRender(bool sync) +{ + m_requestSync = sync; + QCoreApplication::postEvent(m_renderObject, new QEvent(RENDER)); +} + +void Scene2DSharedObject::waitRender() +{ + m_cond.wait(&m_mutex); +} + +void Scene2DSharedObject::wakeWaiting() +{ + m_cond.wakeOne(); +} + +void Scene2DSharedObject::clearSyncRequest() +{ + m_requestSync = false; +} + +/*! + \internal + Constructs qml render manager. + */ +Scene2DManager::Scene2DManager(QScene2DPrivate *priv) + : m_priv(priv) + , m_qmlEngine(nullptr) + , m_qmlComponent(nullptr) + , m_rootItem(nullptr) + , m_source(nullptr) + , m_texture(nullptr) + , m_requested(false) + , m_initialized(false) + , m_renderSyncRequested(false) + , m_sharedObject(new Scene2DSharedObject(this)) + , m_renderOnce(false) + , m_backendInitialized(false) +{ + setFormat(QSurfaceFormat::defaultFormat()); + + m_sharedObject->m_surface = new QOffscreenSurface; + m_sharedObject->m_surface->setFormat(QSurfaceFormat::defaultFormat()); + m_sharedObject->m_surface->create(); + + // Create render control + m_sharedObject->m_renderControl = new RenderControl(this); + + // Create window to render the QML with + m_sharedObject->m_quickWindow = new QQuickWindow(m_sharedObject->m_renderControl); + m_sharedObject->m_quickWindow->setClearBeforeRendering(true); + m_sharedObject->m_quickWindow->setDefaultAlphaBuffer(true); + + // Create a QML engine. + m_qmlEngine = new QQmlEngine; + if (!m_qmlEngine->incubationController()) + m_qmlEngine->setIncubationController(m_sharedObject->m_quickWindow->incubationController()); + + connect(m_sharedObject->m_renderControl, &QQuickRenderControl::renderRequested, + this, &Scene2DManager::requestRender); + connect(m_sharedObject->m_renderControl, &QQuickRenderControl::sceneChanged, + this, &Scene2DManager::requestRenderSync); +} + +Scene2DManager::~Scene2DManager() +{ + m_sharedObject = nullptr; +} + +void Scene2DManager::requestRender() +{ + // Don't request render until the backend is initialized. + if (m_sharedObject->canRender()) { + if (!m_requested) { + m_requested = true; + QCoreApplication::postEvent(this, new QEvent(RENDER)); + } + } +} + +void Scene2DManager::requestRenderSync() +{ + // Don't request render until the backed is initialized. + if (m_sharedObject->canRender()) { + if (!m_requested) { + m_requested = true; + QCoreApplication::postEvent(this, new QEvent(RENDERSYNC)); + } + } else { + m_renderSyncRequested = true; + } +} + +void Scene2DManager::startIfInitialized() +{ + if (!m_initialized) { + if (m_backendInitialized && m_source.isValid()) { + m_qmlComponent = new QQmlComponent(m_qmlEngine, m_source); + if (m_qmlComponent->isLoading()) { + connect(m_qmlComponent, &QQmlComponent::statusChanged, + this, &Scene2DManager::run); + } else { + run(); + } + } + } +} + +void Scene2DManager::stopAndClean() +{ + if (m_sharedObject->isInitialized()) { + QMutexLocker lock(&m_sharedObject->m_mutex); + m_sharedObject->requestQuit(); + m_sharedObject->m_renderThread->wait(); + m_sharedObject->cleanup(); + delete m_qmlEngine; + delete m_qmlComponent; + m_qmlEngine = nullptr; + m_qmlComponent = nullptr; + } +} + +void Scene2DManager::run() +{ + disconnect(m_qmlComponent, &QQmlComponent::statusChanged, this, &Scene2DManager::run); + + if (m_qmlComponent->isError()) { + QList errorList = m_qmlComponent->errors(); + for (const QQmlError &error: errorList) + qWarning() << error.url() << error.line() << error; + return; + } + + QObject *rootObject = m_qmlComponent->create(); + if (m_qmlComponent->isError()) { + QList errorList = m_qmlComponent->errors(); + for (const QQmlError &error: errorList) + qWarning() << error.url() << error.line() << error; + return; + } + + m_rootItem = qobject_cast(rootObject); + if (!m_rootItem) { + qWarning("QScene2D: Root item is not a QQuickItem."); + delete rootObject; + return; + } + + // The root item is ready. Associate it with the window. + m_rootItem->setParentItem(m_sharedObject->m_quickWindow->contentItem()); + + // Update window size. + updateSizes(); + + m_initialized = true; + m_sharedObject->setInitialized(); + + emit onLoadedChanged(); +} + +void Scene2DManager::updateSizes() +{ + const int width = m_rootItem->width(); + const int height = m_rootItem->height(); + if (width == 0 || height == 0) { + qWarning() << "QScene2D: Root item size not set."; + return; + } + resize(width, height); + m_sharedObject->m_quickWindow->setGeometry(0, 0, width, height); +} + +void Scene2DManager::setTexture(QAbstractTexture *texture) +{ + m_texture = texture; + startIfInitialized(); +} + +void Scene2DManager::setSource(const QUrl &url) +{ + m_source = url; + startIfInitialized(); +} + +bool Scene2DManager::event(QEvent *e) +{ + switch (e->type()) { + + case RENDER: { + // just render request, don't need to call sync in render thread + QMutexLocker lock(&m_sharedObject->m_mutex); + m_sharedObject->requestRender(false); + + Qt3DCore::QPropertyUpdatedChangePtr change(new Qt3DCore::QPropertyUpdatedChange(m_priv->m_id)); + change->setPropertyName("dirty"); + change->setValue(QVariant::fromValue(true)); + m_priv->notifyObservers(change); + + m_requested = false; + return true; + } + + case RENDERSYNC: { + // sync and render request, main and render threads must be synchronized + if (!m_sharedObject->isQuit()) + doRenderSync(); + m_requested = false; + return true; + } + + case PREPARE: { + m_sharedObject->m_renderControl->prepareThread(m_sharedObject->m_renderThread); + m_sharedObject->setPrepared(); + + if (m_renderSyncRequested) { + if (!m_requested) { + m_requested = true; + QCoreApplication::postEvent(this, new QEvent(RENDERSYNC)); + } + m_renderSyncRequested = false; + } + return true; + } + + case INITIALIZED: { + // backend is initialized, start the qml + m_backendInitialized = true; + startIfInitialized(); + return true; + } + + case RENDERED: { + // render is done, excellent, now clean anything not needed anymore. + stopAndClean(); + return true; + } + + default: + break; + } + return QWindow::event(e); +} + +void Scene2DManager::doRenderSync() +{ + QMutexLocker lock(&m_sharedObject->m_mutex); + + m_sharedObject->requestRender(true); + m_sharedObject->m_renderControl->polishItems(); + + Qt3DCore::QPropertyUpdatedChangePtr change(new Qt3DCore::QPropertyUpdatedChange(m_priv->m_id)); + + change->setPropertyName("dirty"); + change->setValue(QVariant::fromValue(true)); + m_priv->notifyObservers(change); + + // begin waiting render thread + m_sharedObject->waitRender(); + m_requested = false; +} + +void Scene2DManager::cleanup() +{ + stopAndClean(); +} + + +QScene2DPrivate::QScene2DPrivate() + : QFrameGraphNodePrivate() + , m_renderManager(new Scene2DManager(this)) +{ +} + +QScene2DPrivate::~QScene2DPrivate() +{ + m_renderManager->cleanup(); + delete m_renderManager; +} + + +Scene2DSharedObject *QScene2DPrivate::getSharedObject(QScene2D *rqtt) +{ + return rqtt->d_func()->m_renderManager->m_sharedObject.data(); +} + + +/*! + The constructor creates an instance with the specified \a parent. + */ +QScene2D::QScene2D(Qt3DCore::QNode *parent) + : QFrameGraphNode(*new QScene2DPrivate, parent) +{ + Q_D(QScene2D); + connect(d->m_renderManager, &Scene2DManager::onLoadedChanged, + this, &QScene2D::sourceLoaded); +} + +/*! + Destructor. + */ +QScene2D::~QScene2D() +{ +} + +bool QScene2D::loaded() const +{ + Q_D(const QScene2D); + return d->m_renderManager->m_initialized; +} + +/*! + \property QScene2D::source + \brief Specifies the url for the qml. + + This property specifies the url to the qml being rendered to the texture. + The source must specify QQuickItem as a root. The item must specify width + and height. The rendered qml is scaled to the texture size. + The property can not be changed after the rendering has been initialized. + */ +QUrl QScene2D::source() const +{ + Q_D(const QScene2D); + return d->m_renderManager->m_source; +} + +void QScene2D::setSource(const QUrl &url) +{ + Q_D(QScene2D); + if (d->m_renderManager->m_initialized) { + qWarning() << "Unable to set source after initialization."; + return; + } + d->m_renderManager->setSource(url); + emit sourceChanged(url); +} + +/*! + \property QScene2D::renderOnce + \brief Property to specify if the texture will be rendered only once. + + This property specifies that the texture will be rendered only one time. + Once the rendering has been done, resources reserved for rendering will be + released and the QScene2D will become unusable. + If set to false, which is the default, the rendering is continuous. + */ +bool QScene2D::renderOnce() const +{ + Q_D(const QScene2D); + return d->m_renderManager->m_renderOnce; +} + +void QScene2D::setRenderOnce(bool once) +{ + Q_D(const QScene2D); + if (d->m_renderManager->m_renderOnce != once) { + d->m_renderManager->m_renderOnce = once; + emit renderOnceChanged(once); + } +} + +/*! + \property QScene2D::texture + \brief The texture being rendered to. + + This property specifies the texture being rendered to. Once the texture has been + set and the rendering begins, the texture can not be changed anymore. + */ +QAbstractTexture *QScene2D::texture() const +{ + Q_D(const QScene2D); + return d->m_renderManager->m_texture; +} + +void QScene2D::setTexture(QAbstractTexture *texture) +{ + Q_D(QScene2D); + if (d->m_renderManager->m_initialized) { + qWarning() << "Unable to set texture after initialization."; + return; + } + if (d->m_renderManager->m_texture != texture) { + if (d->m_renderManager->m_texture) + QObject::disconnect(d->m_textureDestroyedConnection); + if (texture && !texture->parent()) + texture->setParent(this); + d->m_renderManager->setTexture(texture); + if (texture) + d->m_textureDestroyedConnection + = QObject::connect(texture, &QAbstractTexture::destroyed, + this, &QScene2D::textureDestroyed); + emit textureChanged(texture); + } +} + +void QScene2D::textureDestroyed(QObject *object) +{ + Q_D(QScene2D); + Q_UNUSED(object); + d->m_renderManager->setTexture(nullptr); +} + +Qt3DCore::QNodeCreatedChangeBasePtr QScene2D::createNodeCreationChange() const +{ + auto creationChange = Qt3DCore::QNodeCreatedChangePtr::create(this); + auto &data = creationChange->data; + Q_D(const QScene2D); + data.renderOnce = d->m_renderManager->m_renderOnce; + data.textureId = d->m_renderManager->m_texture + ? d->m_renderManager->m_texture->id() : Qt3DCore::QNodeId(); + data.sharedObject = d->m_renderManager->m_sharedObject; + return creationChange; +} + +/*! + \internal + */ +void QScene2D::sourceLoaded() +{ + emit loadedChanged(true); +} + +} // namespace Qt3DRender + +QT_END_NAMESPACE diff --git a/src/render/framegraph/qscene2d.h b/src/render/framegraph/qscene2d.h new file mode 100644 index 000000000..18e65a5ca --- /dev/null +++ b/src/render/framegraph/qscene2d.h @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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$ +** +****************************************************************************/ + +#ifndef QT3DRENDER_QSCENE2D_H +#define QT3DRENDER_QSCENE2D_H + +#include +#include + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +class QScene2DPrivate; + +class QT3DRENDERSHARED_EXPORT QScene2D : public Qt3DRender::QFrameGraphNode +{ + Q_OBJECT + + Q_PROPERTY(Qt3DRender::QAbstractTexture *texture READ texture WRITE setTexture NOTIFY textureChanged) + Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged) + Q_PROPERTY(bool renderOnce READ renderOnce WRITE setRenderOnce NOTIFY renderOnceChanged) + Q_PROPERTY(bool loaded READ loaded NOTIFY loadedChanged) + +public: + explicit QScene2D(Qt3DCore::QNode *parent = nullptr); + ~QScene2D(); + + QUrl source() const; + QAbstractTexture *texture() const; + bool loaded() const; + bool renderOnce() const; + +public Q_SLOTS: + void setSource(const QUrl &url); + void setTexture(QAbstractTexture *texture); + void setRenderOnce(bool once); + +Q_SIGNALS: + void sourceChanged(const QUrl &url); + void textureChanged(QAbstractTexture *texture); + void loadedChanged(bool loaded); + void renderOnceChanged(bool once); + +protected: + Q_DECLARE_PRIVATE(QScene2D) + +private: + Qt3DCore::QNodeCreatedChangeBasePtr createNodeCreationChange() const Q_DECL_OVERRIDE; + void textureDestroyed(QObject *object); + + void sourceLoaded(); +}; + +} // namespace Qt3DRender + +QT_END_NAMESPACE + +#endif // QT3DRENDER_QSCENE2D_H diff --git a/src/render/framegraph/qscene2d_p.h b/src/render/framegraph/qscene2d_p.h new file mode 100644 index 000000000..1020c1264 --- /dev/null +++ b/src/render/framegraph/qscene2d_p.h @@ -0,0 +1,211 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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$ +** +****************************************************************************/ + +#ifndef QT3DRENDER_QSCENE2D_P_H +#define QT3DRENDER_QSCENE2D_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +class QScene2D; +class Scene2DManager; + +// render thread -> render thread +static const QEvent::Type INITIALIZE = QEvent::Type(QEvent::User + 1); + +// main thread -> main thread, render thread +static const QEvent::Type RENDER = QEvent::Type(QEvent::User + 2); + +// main thread -> main thread +static const QEvent::Type RENDERSYNC = QEvent::Type(QEvent::User + 3); + +// render thread -> main thread +static const QEvent::Type PREPARE = QEvent::Type(QEvent::User + 4); +static const QEvent::Type INITIALIZED = QEvent::Type(QEvent::User + 5); +static const QEvent::Type RENDERED = QEvent::Type(QEvent::User + 6); + +// main thread -> render thread +static const QEvent::Type QUIT = QEvent::Type(QEvent::User + 7); + +class Q_AUTOTEST_EXPORT Scene2DSharedObject +{ +public: + Scene2DSharedObject(Scene2DManager *manager); + ~Scene2DSharedObject(); + + QQuickRenderControl *m_renderControl; + QQuickWindow *m_quickWindow; + Scene2DManager *m_renderManager; + QOffscreenSurface *m_surface; + + QThread *m_renderThread; + QObject *m_renderObject; + + QWaitCondition m_cond; + QMutex m_mutex; + + bool isInitialized() const; + void setInitialized(); + + void requestQuit(); + bool isQuit() const; + + void requestRender(bool sync); + + bool isSyncRequested() const; + void clearSyncRequest(); + + void waitRender(); + void wakeWaiting(); + + bool isPrepared() const; + void setPrepared(); + + void disallowRender(); + bool canRender() const; + + void cleanup(); + +private: + + bool m_disallowed; + bool m_quit; + bool m_requestSync; + bool m_requestRender; + bool m_prepared; + bool m_initialized; +}; + +typedef QSharedPointer Scene2DSharedObjectPtr; + +class Q_AUTOTEST_EXPORT QScene2DPrivate : public QFrameGraphNodePrivate +{ +public: + Q_DECLARE_PUBLIC(QScene2D) + + QScene2DPrivate(); + ~QScene2DPrivate(); + + static Scene2DSharedObject *getSharedObject(QScene2D *rqtt); + + Scene2DManager *m_renderManager; + QMetaObject::Connection m_textureDestroyedConnection; +}; + +struct QScene2DData +{ + bool renderOnce; + Qt3DCore::QNodeId textureId; + Scene2DSharedObjectPtr sharedObject; +}; + + +class Scene2DManager : public QWindow +{ + Q_OBJECT +public: + Scene2DManager(QScene2DPrivate *priv); + ~Scene2DManager(); + + QQmlEngine *m_qmlEngine; + QQmlComponent *m_qmlComponent; + QQuickItem *m_rootItem; + + QScene2DPrivate *m_priv; + QSharedPointer m_sharedObject; + + QAbstractTexture *m_texture; + QUrl m_source; + Qt3DCore::QNodeId m_id; + + bool m_requested; + bool m_initialized; + bool m_renderSyncRequested; + bool m_renderOnce; + bool m_backendInitialized; + + void requestRender(); + void requestRenderSync(); + void doRenderSync(); + void startIfInitialized(); + void stopAndClean(); + void run(); + void updateSizes(); + + void setTexture(QAbstractTexture *texture); + void setSource(const QUrl &url); + + bool event(QEvent *e) Q_DECL_OVERRIDE; + + Q_SIGNAL void onLoadedChanged(); + + void cleanup(); +}; + + +} // namespace Qt3DRender + +QT_END_NAMESPACE + +#endif // QT3DRENDER_QSCENE2D_P_H diff --git a/src/render/framegraph/renderqmltotexture.cpp b/src/render/framegraph/renderqmltotexture.cpp deleted file mode 100644 index 91f8639c3..000000000 --- a/src/render/framegraph/renderqmltotexture.cpp +++ /dev/null @@ -1,304 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 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 -#include -#include -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE - -namespace Qt3DRender { - -namespace Render { - -RenderQmlEventHandler::RenderQmlEventHandler(RenderQmlToTexture *node) - : QObject() - , m_node(node) -{ -} - -// Event handler for the RenderQmlToTexture::renderThread -bool RenderQmlEventHandler::event(QEvent *e) -{ - switch (e->type()) { - - case RENDER: { - m_node->render(); - return true; - } - - case INITIALIZE: { - m_node->initializeRender(); - return true; - } - - case QUIT: { - m_node->cleanup(); - return true; - } - - default: - break; - } - return QObject::event(e); -} - -RenderQmlToTexture::RenderQmlToTexture() - : FrameGraphNode(FrameGraphNode::InvalidNodeType) - , m_context(nullptr) - , m_sharedObject(nullptr) - , m_renderThread(nullptr) - , m_graphicsContext(nullptr) - , m_texture(nullptr) - , m_initialized(false) - , m_renderInitialized(false) - , m_renderOnce(false) -{ - -} - -RenderQmlToTexture::~RenderQmlToTexture() -{ - // this gets called from aspect thread. Wait for the render thread then delete it. - if (m_renderThread) { - m_renderThread->wait(1000); - delete m_renderThread; - } -} - -void RenderQmlToTexture::setTexture(Qt3DCore::QNodeId textureId) -{ - m_textureId = textureId; - attach(); - checkInitialized(); -} - -void RenderQmlToTexture::checkInitialized() -{ - if (!m_initialized && m_textureId != Qt3DCore::QNodeId()) { - - // Create render thread - m_renderThread = new QThread(); - m_renderThread->setObjectName(QStringLiteral("RenderQmlToTexture::renderThread")); - m_sharedObject->m_renderThread = m_renderThread; - - // Create event handler for the render thread - m_sharedObject->m_renderObject = new RenderQmlEventHandler(this); - m_sharedObject->m_renderObject->moveToThread(m_sharedObject->m_renderThread); - m_sharedObject->m_renderThread->start(); - - // Notify main thread we have been initialized - QCoreApplication::postEvent(m_sharedObject->m_renderManager, new QEvent(INITIALIZED)); - - // Initialize render thread - QCoreApplication::postEvent(m_sharedObject->m_renderObject, new QEvent(INITIALIZE)); - - m_initialized = true; - } -} - -void RenderQmlToTexture::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) -{ - const auto typedChange = qSharedPointerCast>(change); - const auto &data = typedChange->data; - m_renderOnce = m_renderOnce; - setSharedObject(data.sharedObject); - setTexture(data.textureId); -} - -void RenderQmlToTexture::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) -{ - if (e->type() == Qt3DCore::PropertyUpdated) { - Qt3DCore::QPropertyUpdatedChangePtr propertyChange - = qSharedPointerCast(e); - if (propertyChange->propertyName() == QByteArrayLiteral("enabled")) - setEnabled(propertyChange->value().toBool()); - else if (propertyChange->propertyName() == QByteArrayLiteral("dirty")) { - // sent to trigger backend update when the texture gets rendered - // so do nothing here - } - else if (propertyChange->propertyName() == QByteArrayLiteral("renderOnce")) - m_renderOnce = propertyChange->value().toBool(); - else if (propertyChange->propertyName() == QByteArrayLiteral("texture")) { - Qt3DCore::QNodeId textureId = propertyChange->value().value(); - setTexture(textureId); - } - markDirty(AbstractRenderer::AllDirty); - } - FrameGraphNode::sceneChangeEvent(e); -} - -void RenderQmlToTexture::setSharedObject(Qt3DRender::RenderQmlToTextureSharedObjectPtr sharedObject) -{ - m_sharedObject = sharedObject; -} - -void RenderQmlToTexture::initializeRender() -{ - if (!m_renderInitialized) { - Qt3DRender::Render::Renderer *renderer - = static_cast(this->renderer()); - if (!renderer) - return; - - QSurfaceFormat format; - format.setDepthBufferSize(24); - format.setStencilBufferSize(8); - - m_context = new QOpenGLContext(); - m_context->setFormat(format); - - m_context->setShareContext(renderer->shareContext()); - m_context->create(); - - m_graphicsContext = new GraphicsContext(); - m_graphicsContext->setOpenGLContext(m_context); - m_graphicsContext->setRenderer(renderer); - - m_graphicsContext->makeCurrent(m_sharedObject->m_surface); - m_sharedObject->m_renderControl->initialize(m_context); - m_graphicsContext->doneCurrent(); - - QCoreApplication::postEvent(m_sharedObject->m_renderManager, new QEvent(PREPARE)); - m_renderInitialized = true; - } -} - -void RenderQmlToTexture::attach() -{ - m_attachments = AttachmentPack(); - Attachment attach; - attach.m_mipLevel = 0; - attach.m_textureUuid = m_textureId; - attach.m_point = QRenderTargetOutput::AttachmentPoint::Color0; - -// m_attachments.addAttachment(attach); -} - -void RenderQmlToTexture::render() -{ - if (m_initialized && m_sharedObject && this->isEnabled()) { - - QMutexLocker lock(&m_sharedObject->m_mutex); - - // Lookup backend texture - if (m_texture == nullptr) { - m_texture = renderer()->nodeManagers()->textureManager()->lookupResource(m_textureId); - if (!m_texture) { - qCDebug(Render::Framegraph) << Q_FUNC_INFO << "Texture not set"; - return; - } - } - - m_graphicsContext->makeCurrent(m_sharedObject->m_surface); - - // Don't create the OpenGL texture in this thread. - const bool canUseTexture = !m_texture->isTextureReset(); - - if (canUseTexture) { - // Activate fbo for the texture - QOpenGLTexture *glTex = m_texture->getOrCreateGLTexture(); - const QSize textureSize = QSize(glTex->width(), glTex->height()); - - // TODO: create fbo from the texture. - GLuint fbo = 0;//m_graphicsContext->activateRenderTargetForQmlRender(this, m_attachments, 0); - - if (fbo != m_sharedObject->m_quickWindow->renderTargetId()) - m_sharedObject->m_quickWindow->setRenderTarget(fbo, textureSize); - - m_texture->textureLock()->lock(); - } - // Call disallow rendering while mutex is locked - if (canUseTexture && m_renderOnce) - m_sharedObject->disallowRender(); - - // Need to call sync even if the texture is not in use - if (m_sharedObject->isSyncRequested()) { - - m_sharedObject->clearSyncRequest(); - - m_sharedObject->m_renderControl->sync(); - - // gui thread can now continue - m_sharedObject->wakeWaiting(); - lock.unlock(); - } - - if (canUseTexture) { - - // Render - m_sharedObject->m_renderControl->render(); - - // Tell main thread we are done so it can begin cleanup - if (m_renderOnce) - QCoreApplication::postEvent(m_sharedObject->m_renderManager, new QEvent(RENDERED)); - - m_sharedObject->m_quickWindow->resetOpenGLState(); - m_context->functions()->glFlush(); - m_texture->textureLock()->unlock(); - } - m_graphicsContext->doneCurrent(); - } -} - -void RenderQmlToTexture::cleanup() -{ - if (m_renderInitialized && m_initialized) { - m_context->makeCurrent(m_sharedObject->m_surface); - m_sharedObject->m_renderControl->invalidate(); - m_context->doneCurrent(); - m_sharedObject->m_renderThread->quit(); - delete m_sharedObject->m_renderObject; - m_sharedObject->m_renderObject = nullptr; - delete m_context; - m_context = nullptr; - m_sharedObject = nullptr; - delete m_graphicsContext; - m_graphicsContext = nullptr; - m_renderInitialized = false; - m_initialized = false; - } -} - -} // namespace Render - -} // namespace Qt3DRender - -QT_END_NAMESPACE diff --git a/src/render/framegraph/renderqmltotexture_p.h b/src/render/framegraph/renderqmltotexture_p.h deleted file mode 100644 index 49913bcd9..000000000 --- a/src/render/framegraph/renderqmltotexture_p.h +++ /dev/null @@ -1,116 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 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$ -** -****************************************************************************/ - -#ifndef QT3DRENDER_RENDER_RENDERQMLTOTEXTURE_P_H -#define QT3DRENDER_RENDER_RENDERQMLTOTEXTURE_P_H - - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of other Qt classes. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include - -#include -#include - -#include -#include - -QT_BEGIN_NAMESPACE - -namespace Qt3DRender { - -namespace Render { - -class GraphicsContext; -class RenderQmlToTexture; - -class RenderQmlEventHandler : public QObject -{ - Q_OBJECT -public: - RenderQmlEventHandler(RenderQmlToTexture *node); - bool event(QEvent *e) Q_DECL_OVERRIDE; - -private: - RenderQmlToTexture *m_node; -}; - -class Q_AUTOTEST_EXPORT RenderQmlToTexture : public FrameGraphNode -{ -public: - RenderQmlToTexture(); - ~RenderQmlToTexture(); - - void attach(); - void render(); - void initializeRender(); - void setSharedObject(RenderQmlToTextureSharedObjectPtr sharedObject); - void cleanup(); - void setTexture(Qt3DCore::QNodeId textureId); - void checkInitialized(); - - void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_OVERRIDE; - void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL; - - QOpenGLContext *m_context; - GraphicsContext *m_graphicsContext; - QThread *m_renderThread; - Qt3DCore::QNodeId m_textureId; - QSharedPointer m_sharedObject; - AttachmentPack m_attachments; - Texture *m_texture; - - bool m_initialized; - bool m_renderInitialized; - bool m_renderOnce; -}; - -} // Render - -} // Qt3DRender - -QT_END_NAMESPACE - -#endif // QT3DRENDER_RENDER_RENDERQMLTOTEXTURE_P_H diff --git a/src/render/framegraph/scene2d.cpp b/src/render/framegraph/scene2d.cpp new file mode 100644 index 000000000..edf4fd643 --- /dev/null +++ b/src/render/framegraph/scene2d.cpp @@ -0,0 +1,303 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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 +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +namespace Render { + +RenderQmlEventHandler::RenderQmlEventHandler(Scene2D *node) + : QObject() + , m_node(node) +{ +} + +// Event handler for the RenderQmlToTexture::renderThread +bool RenderQmlEventHandler::event(QEvent *e) +{ + switch (e->type()) { + + case RENDER: { + m_node->render(); + return true; + } + + case INITIALIZE: { + m_node->initializeRender(); + return true; + } + + case QUIT: { + m_node->cleanup(); + return true; + } + + default: + break; + } + return QObject::event(e); +} + +Scene2D::Scene2D() + : FrameGraphNode(FrameGraphNode::InvalidNodeType) + , m_context(nullptr) + , m_sharedObject(nullptr) + , m_renderThread(nullptr) + , m_graphicsContext(nullptr) + , m_texture(nullptr) + , m_initialized(false) + , m_renderInitialized(false) + , m_renderOnce(false) +{ + +} + +Scene2D::~Scene2D() +{ + // this gets called from aspect thread. Wait for the render thread then delete it. + if (m_renderThread) { + m_renderThread->wait(1000); + delete m_renderThread; + } +} + +void Scene2D::setTexture(Qt3DCore::QNodeId textureId) +{ + m_textureId = textureId; + attach(); + checkInitialized(); +} + +void Scene2D::checkInitialized() +{ + if (!m_initialized && m_textureId != Qt3DCore::QNodeId()) { + + // Create render thread + m_renderThread = new QThread(); + m_renderThread->setObjectName(QStringLiteral("Scene2D::renderThread")); + m_sharedObject->m_renderThread = m_renderThread; + + // Create event handler for the render thread + m_sharedObject->m_renderObject = new RenderQmlEventHandler(this); + m_sharedObject->m_renderObject->moveToThread(m_sharedObject->m_renderThread); + m_sharedObject->m_renderThread->start(); + + // Notify main thread we have been initialized + QCoreApplication::postEvent(m_sharedObject->m_renderManager, new QEvent(INITIALIZED)); + + // Initialize render thread + QCoreApplication::postEvent(m_sharedObject->m_renderObject, new QEvent(INITIALIZE)); + + m_initialized = true; + } +} + +void Scene2D::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) +{ + const auto typedChange = qSharedPointerCast>(change); + const auto &data = typedChange->data; + m_renderOnce = m_renderOnce; + setSharedObject(data.sharedObject); + setTexture(data.textureId); +} + +void Scene2D::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) +{ + if (e->type() == Qt3DCore::PropertyUpdated) { + Qt3DCore::QPropertyUpdatedChangePtr propertyChange + = qSharedPointerCast(e); + if (propertyChange->propertyName() == QByteArrayLiteral("enabled")) + setEnabled(propertyChange->value().toBool()); + else if (propertyChange->propertyName() == QByteArrayLiteral("dirty")) { + // sent to trigger backend update when the texture gets rendered + // so do nothing here + } + else if (propertyChange->propertyName() == QByteArrayLiteral("renderOnce")) + m_renderOnce = propertyChange->value().toBool(); + else if (propertyChange->propertyName() == QByteArrayLiteral("texture")) { + Qt3DCore::QNodeId textureId = propertyChange->value().value(); + setTexture(textureId); + } + markDirty(AbstractRenderer::AllDirty); + } + FrameGraphNode::sceneChangeEvent(e); +} + +void Scene2D::setSharedObject(Qt3DRender::Scene2DSharedObjectPtr sharedObject) +{ + m_sharedObject = sharedObject; +} + +void Scene2D::initializeRender() +{ + if (!m_renderInitialized) { + Qt3DRender::Render::Renderer *renderer + = static_cast(this->renderer()); + if (!renderer) + return; + + QSurfaceFormat format; + format.setDepthBufferSize(24); + format.setStencilBufferSize(8); + + m_context = new QOpenGLContext(); + m_context->setFormat(format); + + m_context->setShareContext(renderer->shareContext()); + m_context->create(); + + m_graphicsContext = new GraphicsContext(); + m_graphicsContext->setOpenGLContext(m_context); + m_graphicsContext->setRenderer(renderer); + + m_graphicsContext->makeCurrent(m_sharedObject->m_surface); + m_sharedObject->m_renderControl->initialize(m_context); + m_graphicsContext->doneCurrent(); + + QCoreApplication::postEvent(m_sharedObject->m_renderManager, new QEvent(PREPARE)); + m_renderInitialized = true; + } +} + +void Scene2D::attach() +{ + m_attachments = AttachmentPack(); + Attachment attach; + attach.m_mipLevel = 0; + attach.m_textureUuid = m_textureId; + attach.m_point = QRenderTargetOutput::AttachmentPoint::Color0; + +// m_attachments.addAttachment(attach); +} + +void Scene2D::render() +{ + if (m_initialized && m_sharedObject && this->isEnabled()) { + + QMutexLocker lock(&m_sharedObject->m_mutex); + + // Lookup backend texture + if (m_texture == nullptr) { + m_texture = renderer()->nodeManagers()->textureManager()->lookupResource(m_textureId); + if (!m_texture) { + qCDebug(Render::Framegraph) << Q_FUNC_INFO << "Texture not set"; + return; + } + } + + m_graphicsContext->makeCurrent(m_sharedObject->m_surface); + + // Don't create the OpenGL texture in this thread. + const bool canUseTexture = !m_texture->isTextureReset(); + + if (canUseTexture) { + // Activate fbo for the texture + QOpenGLTexture *glTex = m_texture->getOrCreateGLTexture(); + const QSize textureSize = QSize(glTex->width(), glTex->height()); + + GLuint fbo = 0; //m_graphicsContext->activateRenderTargetForQmlRender(this, m_attachments, 0); + + if (fbo != m_sharedObject->m_quickWindow->renderTargetId()) + m_sharedObject->m_quickWindow->setRenderTarget(fbo, textureSize); + + m_texture->textureLock()->lock(); + } + // Call disallow rendering while mutex is locked + if (canUseTexture && m_renderOnce) + m_sharedObject->disallowRender(); + + // Need to call sync even if the texture is not in use + if (m_sharedObject->isSyncRequested()) { + + m_sharedObject->clearSyncRequest(); + + m_sharedObject->m_renderControl->sync(); + + // gui thread can now continue + m_sharedObject->wakeWaiting(); + lock.unlock(); + } + + if (canUseTexture) { + + // Render + m_sharedObject->m_renderControl->render(); + + // Tell main thread we are done so it can begin cleanup + if (m_renderOnce) + QCoreApplication::postEvent(m_sharedObject->m_renderManager, new QEvent(RENDERED)); + + m_sharedObject->m_quickWindow->resetOpenGLState(); + m_context->functions()->glFlush(); + m_texture->textureLock()->unlock(); + } + m_graphicsContext->doneCurrent(); + } +} + +void Scene2D::cleanup() +{ + if (m_renderInitialized && m_initialized) { + m_context->makeCurrent(m_sharedObject->m_surface); + m_sharedObject->m_renderControl->invalidate(); + m_context->doneCurrent(); + m_sharedObject->m_renderThread->quit(); + delete m_sharedObject->m_renderObject; + m_sharedObject->m_renderObject = nullptr; + delete m_context; + m_context = nullptr; + m_sharedObject = nullptr; + delete m_graphicsContext; + m_graphicsContext = nullptr; + m_renderInitialized = false; + m_initialized = false; + } +} + +} // namespace Render + +} // namespace Qt3DRender + +QT_END_NAMESPACE diff --git a/src/render/framegraph/scene2d_p.h b/src/render/framegraph/scene2d_p.h new file mode 100644 index 000000000..f6e3f8903 --- /dev/null +++ b/src/render/framegraph/scene2d_p.h @@ -0,0 +1,115 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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$ +** +****************************************************************************/ + +#ifndef QT3DRENDER_RENDER_SCENE2D_P_H +#define QT3DRENDER_RENDER_SCENE2D_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +#include +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +namespace Render { + +class GraphicsContext; +class Scene2D; + +class RenderQmlEventHandler : public QObject +{ + Q_OBJECT +public: + RenderQmlEventHandler(Scene2D *node); + bool event(QEvent *e) Q_DECL_OVERRIDE; + +private: + Scene2D *m_node; +}; + +class Q_AUTOTEST_EXPORT Scene2D : public FrameGraphNode +{ +public: + Scene2D(); + ~Scene2D(); + + void attach(); + void render(); + void initializeRender(); + void setSharedObject(Scene2DSharedObjectPtr sharedObject); + void cleanup(); + void setTexture(Qt3DCore::QNodeId textureId); + void checkInitialized(); + + void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_OVERRIDE; + void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL; + + QOpenGLContext *m_context; + GraphicsContext *m_graphicsContext; + QThread *m_renderThread; + Qt3DCore::QNodeId m_textureId; + QSharedPointer m_sharedObject; + AttachmentPack m_attachments; + Texture *m_texture; + + bool m_initialized; + bool m_renderInitialized; + bool m_renderOnce; +}; + +} // Render + +} // Qt3DRender + +QT_END_NAMESPACE + +#endif // QT3DRENDER_RENDER_SCENE2D_P_H -- cgit v1.2.3 From cea496ca35625d96d11185293a07ce600c3ff369 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Fri, 21 Oct 2016 13:24:59 +0300 Subject: Move scene2d to quick3drender Change-Id: Id3decbf809e69fe0957a168b3675b83933670641 Reviewed-by: Sean Harmer --- src/quick3d/quick3drender/scene2d/qscene2d.cpp | 621 +++++++++++++++++++++++++ src/quick3d/quick3drender/scene2d/qscene2d.h | 96 ++++ src/quick3d/quick3drender/scene2d/qscene2d_p.h | 211 +++++++++ src/quick3d/quick3drender/scene2d/scene2d.cpp | 303 ++++++++++++ src/quick3d/quick3drender/scene2d/scene2d_p.h | 115 +++++ src/render/framegraph/qscene2d.cpp | 621 ------------------------- src/render/framegraph/qscene2d.h | 96 ---- src/render/framegraph/qscene2d_p.h | 211 --------- src/render/framegraph/scene2d.cpp | 303 ------------ src/render/framegraph/scene2d_p.h | 115 ----- 10 files changed, 1346 insertions(+), 1346 deletions(-) create mode 100644 src/quick3d/quick3drender/scene2d/qscene2d.cpp create mode 100644 src/quick3d/quick3drender/scene2d/qscene2d.h create mode 100644 src/quick3d/quick3drender/scene2d/qscene2d_p.h create mode 100644 src/quick3d/quick3drender/scene2d/scene2d.cpp create mode 100644 src/quick3d/quick3drender/scene2d/scene2d_p.h delete mode 100644 src/render/framegraph/qscene2d.cpp delete mode 100644 src/render/framegraph/qscene2d.h delete mode 100644 src/render/framegraph/qscene2d_p.h delete mode 100644 src/render/framegraph/scene2d.cpp delete mode 100644 src/render/framegraph/scene2d_p.h diff --git a/src/quick3d/quick3drender/scene2d/qscene2d.cpp b/src/quick3d/quick3drender/scene2d/qscene2d.cpp new file mode 100644 index 000000000..62e766684 --- /dev/null +++ b/src/quick3d/quick3drender/scene2d/qscene2d.cpp @@ -0,0 +1,621 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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 "qscene2d.h" +#include "qscene2d_p.h" + +#include + +#include + +QT_BEGIN_NAMESPACE + +using namespace Qt3DCore; + +namespace Qt3DRender { + + +/*! + \class Qt3DRender::QScene2D + \inmodule Qt3DRender + + \brief This class enables rendering qml into a texture, which then can be + used as a part of 3D scene. + + The component uses QQuickRenderControl to render the given QML source into an + offscreen surface, which is attached to a texture provided by the user. This allows the + component to directly render into the texture without intermediate copy and the user to + freely specify how the texture is used in the 3D scene. + + \since 5.9 +*/ + +/*! + \qmltype Scene2D + \inqmlmodule Qt3D.Render + \since + \ingroup + \instantiates Qt3DRender::QScene2D + \brief Scene2D + * + */ + +/*! + \qmlproperty Qt3DRender::QAbstractTexture Qt3D.Render::Scene2D::texture + Holds the texture being rendered to. + */ + +/*! + \qmlproperty QUrl Qt3D.Render::Scene2D::source + Holds the qml source url. + */ + +/*! + \qmlproperty bool Qt3D.Render::Scene2D::renderOnce + Holds whether the first rendered image to the texture is also the last, after which the + renderer releases resources needed for the rendering and the rendering is no longer possible + with this Scene2D object. + */ + +/*! + \qmlproperty bool Qt3D.Render::Scene2D::loaded + Holds whether the source has been loaded. + */ + +class RenderControl : public QQuickRenderControl +{ +public: + RenderControl(QWindow *w) : m_window(w) { } + QWindow *renderWindow(QPoint *offset) Q_DECL_OVERRIDE; + +private: + QWindow *m_window; +}; + +QWindow *RenderControl::renderWindow(QPoint *offset) +{ + if (offset) + *offset = QPoint(0, 0); + return m_window; +} + +/*! + \internal + Constructs object shared by the front-end and back-end to synchronize the rendering. + */ +Scene2DSharedObject::Scene2DSharedObject(Scene2DManager *manager) + : m_quit(false) + , m_requestSync(false) + , m_prepared(false) + , m_initialized(false) + , m_renderControl(nullptr) + , m_quickWindow(nullptr) + , m_renderManager(manager) + , m_surface(nullptr) + , m_renderObject(nullptr) + , m_disallowed(false) +{ +} + +Scene2DSharedObject::~Scene2DSharedObject() +{ +} + +void Scene2DSharedObject::cleanup() +{ + delete m_renderControl; + delete m_quickWindow; + delete m_surface; + m_renderControl = nullptr; + m_quickWindow = nullptr; + m_surface = nullptr; + m_initialized = false; +} + +bool Scene2DSharedObject::canRender() const +{ + return m_initialized && m_prepared && !m_disallowed; +} + +bool Scene2DSharedObject::isInitialized() const +{ + return m_initialized; +} + +void Scene2DSharedObject::disallowRender() +{ + m_disallowed = true; +} + +void Scene2DSharedObject::setInitialized() +{ + m_initialized = true; +} + +bool Scene2DSharedObject::isPrepared() const +{ + return m_prepared; +} + +void Scene2DSharedObject::setPrepared() +{ + m_prepared = true; +} + +// not protected, call only from main thread +bool Scene2DSharedObject::isQuit() const +{ + Q_ASSERT(QThread::currentThread() == QCoreApplication::instance()->thread()); + return m_quit; +} + +// not protected, call only from main thread +void Scene2DSharedObject::requestQuit() +{ + Q_ASSERT(QThread::currentThread() == QCoreApplication::instance()->thread()); + m_quit = true; + QCoreApplication::postEvent(m_renderObject, new QEvent(QUIT)); +} + +bool Scene2DSharedObject::isSyncRequested() const +{ + return m_requestSync; +} + +void Scene2DSharedObject::requestRender(bool sync) +{ + m_requestSync = sync; + QCoreApplication::postEvent(m_renderObject, new QEvent(RENDER)); +} + +void Scene2DSharedObject::waitRender() +{ + m_cond.wait(&m_mutex); +} + +void Scene2DSharedObject::wakeWaiting() +{ + m_cond.wakeOne(); +} + +void Scene2DSharedObject::clearSyncRequest() +{ + m_requestSync = false; +} + +/*! + \internal + Constructs qml render manager. + */ +Scene2DManager::Scene2DManager(QScene2DPrivate *priv) + : m_priv(priv) + , m_qmlEngine(nullptr) + , m_qmlComponent(nullptr) + , m_rootItem(nullptr) + , m_source(nullptr) + , m_texture(nullptr) + , m_requested(false) + , m_initialized(false) + , m_renderSyncRequested(false) + , m_sharedObject(new Scene2DSharedObject(this)) + , m_renderOnce(false) + , m_backendInitialized(false) +{ + setFormat(QSurfaceFormat::defaultFormat()); + + m_sharedObject->m_surface = new QOffscreenSurface; + m_sharedObject->m_surface->setFormat(QSurfaceFormat::defaultFormat()); + m_sharedObject->m_surface->create(); + + // Create render control + m_sharedObject->m_renderControl = new RenderControl(this); + + // Create window to render the QML with + m_sharedObject->m_quickWindow = new QQuickWindow(m_sharedObject->m_renderControl); + m_sharedObject->m_quickWindow->setClearBeforeRendering(true); + m_sharedObject->m_quickWindow->setDefaultAlphaBuffer(true); + + // Create a QML engine. + m_qmlEngine = new QQmlEngine; + if (!m_qmlEngine->incubationController()) + m_qmlEngine->setIncubationController(m_sharedObject->m_quickWindow->incubationController()); + + connect(m_sharedObject->m_renderControl, &QQuickRenderControl::renderRequested, + this, &Scene2DManager::requestRender); + connect(m_sharedObject->m_renderControl, &QQuickRenderControl::sceneChanged, + this, &Scene2DManager::requestRenderSync); +} + +Scene2DManager::~Scene2DManager() +{ + m_sharedObject = nullptr; +} + +void Scene2DManager::requestRender() +{ + // Don't request render until the backend is initialized. + if (m_sharedObject->canRender()) { + if (!m_requested) { + m_requested = true; + QCoreApplication::postEvent(this, new QEvent(RENDER)); + } + } +} + +void Scene2DManager::requestRenderSync() +{ + // Don't request render until the backed is initialized. + if (m_sharedObject->canRender()) { + if (!m_requested) { + m_requested = true; + QCoreApplication::postEvent(this, new QEvent(RENDERSYNC)); + } + } else { + m_renderSyncRequested = true; + } +} + +void Scene2DManager::startIfInitialized() +{ + if (!m_initialized) { + if (m_backendInitialized && m_source.isValid()) { + m_qmlComponent = new QQmlComponent(m_qmlEngine, m_source); + if (m_qmlComponent->isLoading()) { + connect(m_qmlComponent, &QQmlComponent::statusChanged, + this, &Scene2DManager::run); + } else { + run(); + } + } + } +} + +void Scene2DManager::stopAndClean() +{ + if (m_sharedObject->isInitialized()) { + QMutexLocker lock(&m_sharedObject->m_mutex); + m_sharedObject->requestQuit(); + m_sharedObject->m_renderThread->wait(); + m_sharedObject->cleanup(); + delete m_qmlEngine; + delete m_qmlComponent; + m_qmlEngine = nullptr; + m_qmlComponent = nullptr; + } +} + +void Scene2DManager::run() +{ + disconnect(m_qmlComponent, &QQmlComponent::statusChanged, this, &Scene2DManager::run); + + if (m_qmlComponent->isError()) { + QList errorList = m_qmlComponent->errors(); + for (const QQmlError &error: errorList) + qWarning() << error.url() << error.line() << error; + return; + } + + QObject *rootObject = m_qmlComponent->create(); + if (m_qmlComponent->isError()) { + QList errorList = m_qmlComponent->errors(); + for (const QQmlError &error: errorList) + qWarning() << error.url() << error.line() << error; + return; + } + + m_rootItem = qobject_cast(rootObject); + if (!m_rootItem) { + qWarning("QScene2D: Root item is not a QQuickItem."); + delete rootObject; + return; + } + + // The root item is ready. Associate it with the window. + m_rootItem->setParentItem(m_sharedObject->m_quickWindow->contentItem()); + + // Update window size. + updateSizes(); + + m_initialized = true; + m_sharedObject->setInitialized(); + + emit onLoadedChanged(); +} + +void Scene2DManager::updateSizes() +{ + const int width = m_rootItem->width(); + const int height = m_rootItem->height(); + if (width == 0 || height == 0) { + qWarning() << "QScene2D: Root item size not set."; + return; + } + resize(width, height); + m_sharedObject->m_quickWindow->setGeometry(0, 0, width, height); +} + +void Scene2DManager::setTexture(QAbstractTexture *texture) +{ + m_texture = texture; + startIfInitialized(); +} + +void Scene2DManager::setSource(const QUrl &url) +{ + m_source = url; + startIfInitialized(); +} + +bool Scene2DManager::event(QEvent *e) +{ + switch (e->type()) { + + case RENDER: { + // just render request, don't need to call sync in render thread + QMutexLocker lock(&m_sharedObject->m_mutex); + m_sharedObject->requestRender(false); + + Qt3DCore::QPropertyUpdatedChangePtr change(new Qt3DCore::QPropertyUpdatedChange(m_priv->m_id)); + change->setPropertyName("dirty"); + change->setValue(QVariant::fromValue(true)); + m_priv->notifyObservers(change); + + m_requested = false; + return true; + } + + case RENDERSYNC: { + // sync and render request, main and render threads must be synchronized + if (!m_sharedObject->isQuit()) + doRenderSync(); + m_requested = false; + return true; + } + + case PREPARE: { + m_sharedObject->m_renderControl->prepareThread(m_sharedObject->m_renderThread); + m_sharedObject->setPrepared(); + + if (m_renderSyncRequested) { + if (!m_requested) { + m_requested = true; + QCoreApplication::postEvent(this, new QEvent(RENDERSYNC)); + } + m_renderSyncRequested = false; + } + return true; + } + + case INITIALIZED: { + // backend is initialized, start the qml + m_backendInitialized = true; + startIfInitialized(); + return true; + } + + case RENDERED: { + // render is done, excellent, now clean anything not needed anymore. + stopAndClean(); + return true; + } + + default: + break; + } + return QWindow::event(e); +} + +void Scene2DManager::doRenderSync() +{ + QMutexLocker lock(&m_sharedObject->m_mutex); + + m_sharedObject->requestRender(true); + m_sharedObject->m_renderControl->polishItems(); + + Qt3DCore::QPropertyUpdatedChangePtr change(new Qt3DCore::QPropertyUpdatedChange(m_priv->m_id)); + + change->setPropertyName("dirty"); + change->setValue(QVariant::fromValue(true)); + m_priv->notifyObservers(change); + + // begin waiting render thread + m_sharedObject->waitRender(); + m_requested = false; +} + +void Scene2DManager::cleanup() +{ + stopAndClean(); +} + + +QScene2DPrivate::QScene2DPrivate() + : QFrameGraphNodePrivate() + , m_renderManager(new Scene2DManager(this)) +{ +} + +QScene2DPrivate::~QScene2DPrivate() +{ + m_renderManager->cleanup(); + delete m_renderManager; +} + + +Scene2DSharedObject *QScene2DPrivate::getSharedObject(QScene2D *rqtt) +{ + return rqtt->d_func()->m_renderManager->m_sharedObject.data(); +} + + +/*! + The constructor creates an instance with the specified \a parent. + */ +QScene2D::QScene2D(Qt3DCore::QNode *parent) + : QFrameGraphNode(*new QScene2DPrivate, parent) +{ + Q_D(QScene2D); + connect(d->m_renderManager, &Scene2DManager::onLoadedChanged, + this, &QScene2D::sourceLoaded); +} + +/*! + Destructor. + */ +QScene2D::~QScene2D() +{ +} + +bool QScene2D::loaded() const +{ + Q_D(const QScene2D); + return d->m_renderManager->m_initialized; +} + +/*! + \property QScene2D::source + \brief Specifies the url for the qml. + + This property specifies the url to the qml being rendered to the texture. + The source must specify QQuickItem as a root. The item must specify width + and height. The rendered qml is scaled to the texture size. + The property can not be changed after the rendering has been initialized. + */ +QUrl QScene2D::source() const +{ + Q_D(const QScene2D); + return d->m_renderManager->m_source; +} + +void QScene2D::setSource(const QUrl &url) +{ + Q_D(QScene2D); + if (d->m_renderManager->m_initialized) { + qWarning() << "Unable to set source after initialization."; + return; + } + d->m_renderManager->setSource(url); + emit sourceChanged(url); +} + +/*! + \property QScene2D::renderOnce + \brief Property to specify if the texture will be rendered only once. + + This property specifies that the texture will be rendered only one time. + Once the rendering has been done, resources reserved for rendering will be + released and the QScene2D will become unusable. + If set to false, which is the default, the rendering is continuous. + */ +bool QScene2D::renderOnce() const +{ + Q_D(const QScene2D); + return d->m_renderManager->m_renderOnce; +} + +void QScene2D::setRenderOnce(bool once) +{ + Q_D(const QScene2D); + if (d->m_renderManager->m_renderOnce != once) { + d->m_renderManager->m_renderOnce = once; + emit renderOnceChanged(once); + } +} + +/*! + \property QScene2D::texture + \brief The texture being rendered to. + + This property specifies the texture being rendered to. Once the texture has been + set and the rendering begins, the texture can not be changed anymore. + */ +QAbstractTexture *QScene2D::texture() const +{ + Q_D(const QScene2D); + return d->m_renderManager->m_texture; +} + +void QScene2D::setTexture(QAbstractTexture *texture) +{ + Q_D(QScene2D); + if (d->m_renderManager->m_initialized) { + qWarning() << "Unable to set texture after initialization."; + return; + } + if (d->m_renderManager->m_texture != texture) { + if (d->m_renderManager->m_texture) + QObject::disconnect(d->m_textureDestroyedConnection); + if (texture && !texture->parent()) + texture->setParent(this); + d->m_renderManager->setTexture(texture); + if (texture) + d->m_textureDestroyedConnection + = QObject::connect(texture, &QAbstractTexture::destroyed, + this, &QScene2D::textureDestroyed); + emit textureChanged(texture); + } +} + +void QScene2D::textureDestroyed(QObject *object) +{ + Q_D(QScene2D); + Q_UNUSED(object); + d->m_renderManager->setTexture(nullptr); +} + +Qt3DCore::QNodeCreatedChangeBasePtr QScene2D::createNodeCreationChange() const +{ + auto creationChange = Qt3DCore::QNodeCreatedChangePtr::create(this); + auto &data = creationChange->data; + Q_D(const QScene2D); + data.renderOnce = d->m_renderManager->m_renderOnce; + data.textureId = d->m_renderManager->m_texture + ? d->m_renderManager->m_texture->id() : Qt3DCore::QNodeId(); + data.sharedObject = d->m_renderManager->m_sharedObject; + return creationChange; +} + +/*! + \internal + */ +void QScene2D::sourceLoaded() +{ + emit loadedChanged(true); +} + +} // namespace Qt3DRender + +QT_END_NAMESPACE diff --git a/src/quick3d/quick3drender/scene2d/qscene2d.h b/src/quick3d/quick3drender/scene2d/qscene2d.h new file mode 100644 index 000000000..18e65a5ca --- /dev/null +++ b/src/quick3d/quick3drender/scene2d/qscene2d.h @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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$ +** +****************************************************************************/ + +#ifndef QT3DRENDER_QSCENE2D_H +#define QT3DRENDER_QSCENE2D_H + +#include +#include + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +class QScene2DPrivate; + +class QT3DRENDERSHARED_EXPORT QScene2D : public Qt3DRender::QFrameGraphNode +{ + Q_OBJECT + + Q_PROPERTY(Qt3DRender::QAbstractTexture *texture READ texture WRITE setTexture NOTIFY textureChanged) + Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged) + Q_PROPERTY(bool renderOnce READ renderOnce WRITE setRenderOnce NOTIFY renderOnceChanged) + Q_PROPERTY(bool loaded READ loaded NOTIFY loadedChanged) + +public: + explicit QScene2D(Qt3DCore::QNode *parent = nullptr); + ~QScene2D(); + + QUrl source() const; + QAbstractTexture *texture() const; + bool loaded() const; + bool renderOnce() const; + +public Q_SLOTS: + void setSource(const QUrl &url); + void setTexture(QAbstractTexture *texture); + void setRenderOnce(bool once); + +Q_SIGNALS: + void sourceChanged(const QUrl &url); + void textureChanged(QAbstractTexture *texture); + void loadedChanged(bool loaded); + void renderOnceChanged(bool once); + +protected: + Q_DECLARE_PRIVATE(QScene2D) + +private: + Qt3DCore::QNodeCreatedChangeBasePtr createNodeCreationChange() const Q_DECL_OVERRIDE; + void textureDestroyed(QObject *object); + + void sourceLoaded(); +}; + +} // namespace Qt3DRender + +QT_END_NAMESPACE + +#endif // QT3DRENDER_QSCENE2D_H diff --git a/src/quick3d/quick3drender/scene2d/qscene2d_p.h b/src/quick3d/quick3drender/scene2d/qscene2d_p.h new file mode 100644 index 000000000..1020c1264 --- /dev/null +++ b/src/quick3d/quick3drender/scene2d/qscene2d_p.h @@ -0,0 +1,211 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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$ +** +****************************************************************************/ + +#ifndef QT3DRENDER_QSCENE2D_P_H +#define QT3DRENDER_QSCENE2D_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +class QScene2D; +class Scene2DManager; + +// render thread -> render thread +static const QEvent::Type INITIALIZE = QEvent::Type(QEvent::User + 1); + +// main thread -> main thread, render thread +static const QEvent::Type RENDER = QEvent::Type(QEvent::User + 2); + +// main thread -> main thread +static const QEvent::Type RENDERSYNC = QEvent::Type(QEvent::User + 3); + +// render thread -> main thread +static const QEvent::Type PREPARE = QEvent::Type(QEvent::User + 4); +static const QEvent::Type INITIALIZED = QEvent::Type(QEvent::User + 5); +static const QEvent::Type RENDERED = QEvent::Type(QEvent::User + 6); + +// main thread -> render thread +static const QEvent::Type QUIT = QEvent::Type(QEvent::User + 7); + +class Q_AUTOTEST_EXPORT Scene2DSharedObject +{ +public: + Scene2DSharedObject(Scene2DManager *manager); + ~Scene2DSharedObject(); + + QQuickRenderControl *m_renderControl; + QQuickWindow *m_quickWindow; + Scene2DManager *m_renderManager; + QOffscreenSurface *m_surface; + + QThread *m_renderThread; + QObject *m_renderObject; + + QWaitCondition m_cond; + QMutex m_mutex; + + bool isInitialized() const; + void setInitialized(); + + void requestQuit(); + bool isQuit() const; + + void requestRender(bool sync); + + bool isSyncRequested() const; + void clearSyncRequest(); + + void waitRender(); + void wakeWaiting(); + + bool isPrepared() const; + void setPrepared(); + + void disallowRender(); + bool canRender() const; + + void cleanup(); + +private: + + bool m_disallowed; + bool m_quit; + bool m_requestSync; + bool m_requestRender; + bool m_prepared; + bool m_initialized; +}; + +typedef QSharedPointer Scene2DSharedObjectPtr; + +class Q_AUTOTEST_EXPORT QScene2DPrivate : public QFrameGraphNodePrivate +{ +public: + Q_DECLARE_PUBLIC(QScene2D) + + QScene2DPrivate(); + ~QScene2DPrivate(); + + static Scene2DSharedObject *getSharedObject(QScene2D *rqtt); + + Scene2DManager *m_renderManager; + QMetaObject::Connection m_textureDestroyedConnection; +}; + +struct QScene2DData +{ + bool renderOnce; + Qt3DCore::QNodeId textureId; + Scene2DSharedObjectPtr sharedObject; +}; + + +class Scene2DManager : public QWindow +{ + Q_OBJECT +public: + Scene2DManager(QScene2DPrivate *priv); + ~Scene2DManager(); + + QQmlEngine *m_qmlEngine; + QQmlComponent *m_qmlComponent; + QQuickItem *m_rootItem; + + QScene2DPrivate *m_priv; + QSharedPointer m_sharedObject; + + QAbstractTexture *m_texture; + QUrl m_source; + Qt3DCore::QNodeId m_id; + + bool m_requested; + bool m_initialized; + bool m_renderSyncRequested; + bool m_renderOnce; + bool m_backendInitialized; + + void requestRender(); + void requestRenderSync(); + void doRenderSync(); + void startIfInitialized(); + void stopAndClean(); + void run(); + void updateSizes(); + + void setTexture(QAbstractTexture *texture); + void setSource(const QUrl &url); + + bool event(QEvent *e) Q_DECL_OVERRIDE; + + Q_SIGNAL void onLoadedChanged(); + + void cleanup(); +}; + + +} // namespace Qt3DRender + +QT_END_NAMESPACE + +#endif // QT3DRENDER_QSCENE2D_P_H diff --git a/src/quick3d/quick3drender/scene2d/scene2d.cpp b/src/quick3d/quick3drender/scene2d/scene2d.cpp new file mode 100644 index 000000000..edf4fd643 --- /dev/null +++ b/src/quick3d/quick3drender/scene2d/scene2d.cpp @@ -0,0 +1,303 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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 +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +namespace Render { + +RenderQmlEventHandler::RenderQmlEventHandler(Scene2D *node) + : QObject() + , m_node(node) +{ +} + +// Event handler for the RenderQmlToTexture::renderThread +bool RenderQmlEventHandler::event(QEvent *e) +{ + switch (e->type()) { + + case RENDER: { + m_node->render(); + return true; + } + + case INITIALIZE: { + m_node->initializeRender(); + return true; + } + + case QUIT: { + m_node->cleanup(); + return true; + } + + default: + break; + } + return QObject::event(e); +} + +Scene2D::Scene2D() + : FrameGraphNode(FrameGraphNode::InvalidNodeType) + , m_context(nullptr) + , m_sharedObject(nullptr) + , m_renderThread(nullptr) + , m_graphicsContext(nullptr) + , m_texture(nullptr) + , m_initialized(false) + , m_renderInitialized(false) + , m_renderOnce(false) +{ + +} + +Scene2D::~Scene2D() +{ + // this gets called from aspect thread. Wait for the render thread then delete it. + if (m_renderThread) { + m_renderThread->wait(1000); + delete m_renderThread; + } +} + +void Scene2D::setTexture(Qt3DCore::QNodeId textureId) +{ + m_textureId = textureId; + attach(); + checkInitialized(); +} + +void Scene2D::checkInitialized() +{ + if (!m_initialized && m_textureId != Qt3DCore::QNodeId()) { + + // Create render thread + m_renderThread = new QThread(); + m_renderThread->setObjectName(QStringLiteral("Scene2D::renderThread")); + m_sharedObject->m_renderThread = m_renderThread; + + // Create event handler for the render thread + m_sharedObject->m_renderObject = new RenderQmlEventHandler(this); + m_sharedObject->m_renderObject->moveToThread(m_sharedObject->m_renderThread); + m_sharedObject->m_renderThread->start(); + + // Notify main thread we have been initialized + QCoreApplication::postEvent(m_sharedObject->m_renderManager, new QEvent(INITIALIZED)); + + // Initialize render thread + QCoreApplication::postEvent(m_sharedObject->m_renderObject, new QEvent(INITIALIZE)); + + m_initialized = true; + } +} + +void Scene2D::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) +{ + const auto typedChange = qSharedPointerCast>(change); + const auto &data = typedChange->data; + m_renderOnce = m_renderOnce; + setSharedObject(data.sharedObject); + setTexture(data.textureId); +} + +void Scene2D::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) +{ + if (e->type() == Qt3DCore::PropertyUpdated) { + Qt3DCore::QPropertyUpdatedChangePtr propertyChange + = qSharedPointerCast(e); + if (propertyChange->propertyName() == QByteArrayLiteral("enabled")) + setEnabled(propertyChange->value().toBool()); + else if (propertyChange->propertyName() == QByteArrayLiteral("dirty")) { + // sent to trigger backend update when the texture gets rendered + // so do nothing here + } + else if (propertyChange->propertyName() == QByteArrayLiteral("renderOnce")) + m_renderOnce = propertyChange->value().toBool(); + else if (propertyChange->propertyName() == QByteArrayLiteral("texture")) { + Qt3DCore::QNodeId textureId = propertyChange->value().value(); + setTexture(textureId); + } + markDirty(AbstractRenderer::AllDirty); + } + FrameGraphNode::sceneChangeEvent(e); +} + +void Scene2D::setSharedObject(Qt3DRender::Scene2DSharedObjectPtr sharedObject) +{ + m_sharedObject = sharedObject; +} + +void Scene2D::initializeRender() +{ + if (!m_renderInitialized) { + Qt3DRender::Render::Renderer *renderer + = static_cast(this->renderer()); + if (!renderer) + return; + + QSurfaceFormat format; + format.setDepthBufferSize(24); + format.setStencilBufferSize(8); + + m_context = new QOpenGLContext(); + m_context->setFormat(format); + + m_context->setShareContext(renderer->shareContext()); + m_context->create(); + + m_graphicsContext = new GraphicsContext(); + m_graphicsContext->setOpenGLContext(m_context); + m_graphicsContext->setRenderer(renderer); + + m_graphicsContext->makeCurrent(m_sharedObject->m_surface); + m_sharedObject->m_renderControl->initialize(m_context); + m_graphicsContext->doneCurrent(); + + QCoreApplication::postEvent(m_sharedObject->m_renderManager, new QEvent(PREPARE)); + m_renderInitialized = true; + } +} + +void Scene2D::attach() +{ + m_attachments = AttachmentPack(); + Attachment attach; + attach.m_mipLevel = 0; + attach.m_textureUuid = m_textureId; + attach.m_point = QRenderTargetOutput::AttachmentPoint::Color0; + +// m_attachments.addAttachment(attach); +} + +void Scene2D::render() +{ + if (m_initialized && m_sharedObject && this->isEnabled()) { + + QMutexLocker lock(&m_sharedObject->m_mutex); + + // Lookup backend texture + if (m_texture == nullptr) { + m_texture = renderer()->nodeManagers()->textureManager()->lookupResource(m_textureId); + if (!m_texture) { + qCDebug(Render::Framegraph) << Q_FUNC_INFO << "Texture not set"; + return; + } + } + + m_graphicsContext->makeCurrent(m_sharedObject->m_surface); + + // Don't create the OpenGL texture in this thread. + const bool canUseTexture = !m_texture->isTextureReset(); + + if (canUseTexture) { + // Activate fbo for the texture + QOpenGLTexture *glTex = m_texture->getOrCreateGLTexture(); + const QSize textureSize = QSize(glTex->width(), glTex->height()); + + GLuint fbo = 0; //m_graphicsContext->activateRenderTargetForQmlRender(this, m_attachments, 0); + + if (fbo != m_sharedObject->m_quickWindow->renderTargetId()) + m_sharedObject->m_quickWindow->setRenderTarget(fbo, textureSize); + + m_texture->textureLock()->lock(); + } + // Call disallow rendering while mutex is locked + if (canUseTexture && m_renderOnce) + m_sharedObject->disallowRender(); + + // Need to call sync even if the texture is not in use + if (m_sharedObject->isSyncRequested()) { + + m_sharedObject->clearSyncRequest(); + + m_sharedObject->m_renderControl->sync(); + + // gui thread can now continue + m_sharedObject->wakeWaiting(); + lock.unlock(); + } + + if (canUseTexture) { + + // Render + m_sharedObject->m_renderControl->render(); + + // Tell main thread we are done so it can begin cleanup + if (m_renderOnce) + QCoreApplication::postEvent(m_sharedObject->m_renderManager, new QEvent(RENDERED)); + + m_sharedObject->m_quickWindow->resetOpenGLState(); + m_context->functions()->glFlush(); + m_texture->textureLock()->unlock(); + } + m_graphicsContext->doneCurrent(); + } +} + +void Scene2D::cleanup() +{ + if (m_renderInitialized && m_initialized) { + m_context->makeCurrent(m_sharedObject->m_surface); + m_sharedObject->m_renderControl->invalidate(); + m_context->doneCurrent(); + m_sharedObject->m_renderThread->quit(); + delete m_sharedObject->m_renderObject; + m_sharedObject->m_renderObject = nullptr; + delete m_context; + m_context = nullptr; + m_sharedObject = nullptr; + delete m_graphicsContext; + m_graphicsContext = nullptr; + m_renderInitialized = false; + m_initialized = false; + } +} + +} // namespace Render + +} // namespace Qt3DRender + +QT_END_NAMESPACE diff --git a/src/quick3d/quick3drender/scene2d/scene2d_p.h b/src/quick3d/quick3drender/scene2d/scene2d_p.h new file mode 100644 index 000000000..f6e3f8903 --- /dev/null +++ b/src/quick3d/quick3drender/scene2d/scene2d_p.h @@ -0,0 +1,115 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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$ +** +****************************************************************************/ + +#ifndef QT3DRENDER_RENDER_SCENE2D_P_H +#define QT3DRENDER_RENDER_SCENE2D_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +#include +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +namespace Render { + +class GraphicsContext; +class Scene2D; + +class RenderQmlEventHandler : public QObject +{ + Q_OBJECT +public: + RenderQmlEventHandler(Scene2D *node); + bool event(QEvent *e) Q_DECL_OVERRIDE; + +private: + Scene2D *m_node; +}; + +class Q_AUTOTEST_EXPORT Scene2D : public FrameGraphNode +{ +public: + Scene2D(); + ~Scene2D(); + + void attach(); + void render(); + void initializeRender(); + void setSharedObject(Scene2DSharedObjectPtr sharedObject); + void cleanup(); + void setTexture(Qt3DCore::QNodeId textureId); + void checkInitialized(); + + void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_OVERRIDE; + void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL; + + QOpenGLContext *m_context; + GraphicsContext *m_graphicsContext; + QThread *m_renderThread; + Qt3DCore::QNodeId m_textureId; + QSharedPointer m_sharedObject; + AttachmentPack m_attachments; + Texture *m_texture; + + bool m_initialized; + bool m_renderInitialized; + bool m_renderOnce; +}; + +} // Render + +} // Qt3DRender + +QT_END_NAMESPACE + +#endif // QT3DRENDER_RENDER_SCENE2D_P_H diff --git a/src/render/framegraph/qscene2d.cpp b/src/render/framegraph/qscene2d.cpp deleted file mode 100644 index 62e766684..000000000 --- a/src/render/framegraph/qscene2d.cpp +++ /dev/null @@ -1,621 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 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 "qscene2d.h" -#include "qscene2d_p.h" - -#include - -#include - -QT_BEGIN_NAMESPACE - -using namespace Qt3DCore; - -namespace Qt3DRender { - - -/*! - \class Qt3DRender::QScene2D - \inmodule Qt3DRender - - \brief This class enables rendering qml into a texture, which then can be - used as a part of 3D scene. - - The component uses QQuickRenderControl to render the given QML source into an - offscreen surface, which is attached to a texture provided by the user. This allows the - component to directly render into the texture without intermediate copy and the user to - freely specify how the texture is used in the 3D scene. - - \since 5.9 -*/ - -/*! - \qmltype Scene2D - \inqmlmodule Qt3D.Render - \since - \ingroup - \instantiates Qt3DRender::QScene2D - \brief Scene2D - * - */ - -/*! - \qmlproperty Qt3DRender::QAbstractTexture Qt3D.Render::Scene2D::texture - Holds the texture being rendered to. - */ - -/*! - \qmlproperty QUrl Qt3D.Render::Scene2D::source - Holds the qml source url. - */ - -/*! - \qmlproperty bool Qt3D.Render::Scene2D::renderOnce - Holds whether the first rendered image to the texture is also the last, after which the - renderer releases resources needed for the rendering and the rendering is no longer possible - with this Scene2D object. - */ - -/*! - \qmlproperty bool Qt3D.Render::Scene2D::loaded - Holds whether the source has been loaded. - */ - -class RenderControl : public QQuickRenderControl -{ -public: - RenderControl(QWindow *w) : m_window(w) { } - QWindow *renderWindow(QPoint *offset) Q_DECL_OVERRIDE; - -private: - QWindow *m_window; -}; - -QWindow *RenderControl::renderWindow(QPoint *offset) -{ - if (offset) - *offset = QPoint(0, 0); - return m_window; -} - -/*! - \internal - Constructs object shared by the front-end and back-end to synchronize the rendering. - */ -Scene2DSharedObject::Scene2DSharedObject(Scene2DManager *manager) - : m_quit(false) - , m_requestSync(false) - , m_prepared(false) - , m_initialized(false) - , m_renderControl(nullptr) - , m_quickWindow(nullptr) - , m_renderManager(manager) - , m_surface(nullptr) - , m_renderObject(nullptr) - , m_disallowed(false) -{ -} - -Scene2DSharedObject::~Scene2DSharedObject() -{ -} - -void Scene2DSharedObject::cleanup() -{ - delete m_renderControl; - delete m_quickWindow; - delete m_surface; - m_renderControl = nullptr; - m_quickWindow = nullptr; - m_surface = nullptr; - m_initialized = false; -} - -bool Scene2DSharedObject::canRender() const -{ - return m_initialized && m_prepared && !m_disallowed; -} - -bool Scene2DSharedObject::isInitialized() const -{ - return m_initialized; -} - -void Scene2DSharedObject::disallowRender() -{ - m_disallowed = true; -} - -void Scene2DSharedObject::setInitialized() -{ - m_initialized = true; -} - -bool Scene2DSharedObject::isPrepared() const -{ - return m_prepared; -} - -void Scene2DSharedObject::setPrepared() -{ - m_prepared = true; -} - -// not protected, call only from main thread -bool Scene2DSharedObject::isQuit() const -{ - Q_ASSERT(QThread::currentThread() == QCoreApplication::instance()->thread()); - return m_quit; -} - -// not protected, call only from main thread -void Scene2DSharedObject::requestQuit() -{ - Q_ASSERT(QThread::currentThread() == QCoreApplication::instance()->thread()); - m_quit = true; - QCoreApplication::postEvent(m_renderObject, new QEvent(QUIT)); -} - -bool Scene2DSharedObject::isSyncRequested() const -{ - return m_requestSync; -} - -void Scene2DSharedObject::requestRender(bool sync) -{ - m_requestSync = sync; - QCoreApplication::postEvent(m_renderObject, new QEvent(RENDER)); -} - -void Scene2DSharedObject::waitRender() -{ - m_cond.wait(&m_mutex); -} - -void Scene2DSharedObject::wakeWaiting() -{ - m_cond.wakeOne(); -} - -void Scene2DSharedObject::clearSyncRequest() -{ - m_requestSync = false; -} - -/*! - \internal - Constructs qml render manager. - */ -Scene2DManager::Scene2DManager(QScene2DPrivate *priv) - : m_priv(priv) - , m_qmlEngine(nullptr) - , m_qmlComponent(nullptr) - , m_rootItem(nullptr) - , m_source(nullptr) - , m_texture(nullptr) - , m_requested(false) - , m_initialized(false) - , m_renderSyncRequested(false) - , m_sharedObject(new Scene2DSharedObject(this)) - , m_renderOnce(false) - , m_backendInitialized(false) -{ - setFormat(QSurfaceFormat::defaultFormat()); - - m_sharedObject->m_surface = new QOffscreenSurface; - m_sharedObject->m_surface->setFormat(QSurfaceFormat::defaultFormat()); - m_sharedObject->m_surface->create(); - - // Create render control - m_sharedObject->m_renderControl = new RenderControl(this); - - // Create window to render the QML with - m_sharedObject->m_quickWindow = new QQuickWindow(m_sharedObject->m_renderControl); - m_sharedObject->m_quickWindow->setClearBeforeRendering(true); - m_sharedObject->m_quickWindow->setDefaultAlphaBuffer(true); - - // Create a QML engine. - m_qmlEngine = new QQmlEngine; - if (!m_qmlEngine->incubationController()) - m_qmlEngine->setIncubationController(m_sharedObject->m_quickWindow->incubationController()); - - connect(m_sharedObject->m_renderControl, &QQuickRenderControl::renderRequested, - this, &Scene2DManager::requestRender); - connect(m_sharedObject->m_renderControl, &QQuickRenderControl::sceneChanged, - this, &Scene2DManager::requestRenderSync); -} - -Scene2DManager::~Scene2DManager() -{ - m_sharedObject = nullptr; -} - -void Scene2DManager::requestRender() -{ - // Don't request render until the backend is initialized. - if (m_sharedObject->canRender()) { - if (!m_requested) { - m_requested = true; - QCoreApplication::postEvent(this, new QEvent(RENDER)); - } - } -} - -void Scene2DManager::requestRenderSync() -{ - // Don't request render until the backed is initialized. - if (m_sharedObject->canRender()) { - if (!m_requested) { - m_requested = true; - QCoreApplication::postEvent(this, new QEvent(RENDERSYNC)); - } - } else { - m_renderSyncRequested = true; - } -} - -void Scene2DManager::startIfInitialized() -{ - if (!m_initialized) { - if (m_backendInitialized && m_source.isValid()) { - m_qmlComponent = new QQmlComponent(m_qmlEngine, m_source); - if (m_qmlComponent->isLoading()) { - connect(m_qmlComponent, &QQmlComponent::statusChanged, - this, &Scene2DManager::run); - } else { - run(); - } - } - } -} - -void Scene2DManager::stopAndClean() -{ - if (m_sharedObject->isInitialized()) { - QMutexLocker lock(&m_sharedObject->m_mutex); - m_sharedObject->requestQuit(); - m_sharedObject->m_renderThread->wait(); - m_sharedObject->cleanup(); - delete m_qmlEngine; - delete m_qmlComponent; - m_qmlEngine = nullptr; - m_qmlComponent = nullptr; - } -} - -void Scene2DManager::run() -{ - disconnect(m_qmlComponent, &QQmlComponent::statusChanged, this, &Scene2DManager::run); - - if (m_qmlComponent->isError()) { - QList errorList = m_qmlComponent->errors(); - for (const QQmlError &error: errorList) - qWarning() << error.url() << error.line() << error; - return; - } - - QObject *rootObject = m_qmlComponent->create(); - if (m_qmlComponent->isError()) { - QList errorList = m_qmlComponent->errors(); - for (const QQmlError &error: errorList) - qWarning() << error.url() << error.line() << error; - return; - } - - m_rootItem = qobject_cast(rootObject); - if (!m_rootItem) { - qWarning("QScene2D: Root item is not a QQuickItem."); - delete rootObject; - return; - } - - // The root item is ready. Associate it with the window. - m_rootItem->setParentItem(m_sharedObject->m_quickWindow->contentItem()); - - // Update window size. - updateSizes(); - - m_initialized = true; - m_sharedObject->setInitialized(); - - emit onLoadedChanged(); -} - -void Scene2DManager::updateSizes() -{ - const int width = m_rootItem->width(); - const int height = m_rootItem->height(); - if (width == 0 || height == 0) { - qWarning() << "QScene2D: Root item size not set."; - return; - } - resize(width, height); - m_sharedObject->m_quickWindow->setGeometry(0, 0, width, height); -} - -void Scene2DManager::setTexture(QAbstractTexture *texture) -{ - m_texture = texture; - startIfInitialized(); -} - -void Scene2DManager::setSource(const QUrl &url) -{ - m_source = url; - startIfInitialized(); -} - -bool Scene2DManager::event(QEvent *e) -{ - switch (e->type()) { - - case RENDER: { - // just render request, don't need to call sync in render thread - QMutexLocker lock(&m_sharedObject->m_mutex); - m_sharedObject->requestRender(false); - - Qt3DCore::QPropertyUpdatedChangePtr change(new Qt3DCore::QPropertyUpdatedChange(m_priv->m_id)); - change->setPropertyName("dirty"); - change->setValue(QVariant::fromValue(true)); - m_priv->notifyObservers(change); - - m_requested = false; - return true; - } - - case RENDERSYNC: { - // sync and render request, main and render threads must be synchronized - if (!m_sharedObject->isQuit()) - doRenderSync(); - m_requested = false; - return true; - } - - case PREPARE: { - m_sharedObject->m_renderControl->prepareThread(m_sharedObject->m_renderThread); - m_sharedObject->setPrepared(); - - if (m_renderSyncRequested) { - if (!m_requested) { - m_requested = true; - QCoreApplication::postEvent(this, new QEvent(RENDERSYNC)); - } - m_renderSyncRequested = false; - } - return true; - } - - case INITIALIZED: { - // backend is initialized, start the qml - m_backendInitialized = true; - startIfInitialized(); - return true; - } - - case RENDERED: { - // render is done, excellent, now clean anything not needed anymore. - stopAndClean(); - return true; - } - - default: - break; - } - return QWindow::event(e); -} - -void Scene2DManager::doRenderSync() -{ - QMutexLocker lock(&m_sharedObject->m_mutex); - - m_sharedObject->requestRender(true); - m_sharedObject->m_renderControl->polishItems(); - - Qt3DCore::QPropertyUpdatedChangePtr change(new Qt3DCore::QPropertyUpdatedChange(m_priv->m_id)); - - change->setPropertyName("dirty"); - change->setValue(QVariant::fromValue(true)); - m_priv->notifyObservers(change); - - // begin waiting render thread - m_sharedObject->waitRender(); - m_requested = false; -} - -void Scene2DManager::cleanup() -{ - stopAndClean(); -} - - -QScene2DPrivate::QScene2DPrivate() - : QFrameGraphNodePrivate() - , m_renderManager(new Scene2DManager(this)) -{ -} - -QScene2DPrivate::~QScene2DPrivate() -{ - m_renderManager->cleanup(); - delete m_renderManager; -} - - -Scene2DSharedObject *QScene2DPrivate::getSharedObject(QScene2D *rqtt) -{ - return rqtt->d_func()->m_renderManager->m_sharedObject.data(); -} - - -/*! - The constructor creates an instance with the specified \a parent. - */ -QScene2D::QScene2D(Qt3DCore::QNode *parent) - : QFrameGraphNode(*new QScene2DPrivate, parent) -{ - Q_D(QScene2D); - connect(d->m_renderManager, &Scene2DManager::onLoadedChanged, - this, &QScene2D::sourceLoaded); -} - -/*! - Destructor. - */ -QScene2D::~QScene2D() -{ -} - -bool QScene2D::loaded() const -{ - Q_D(const QScene2D); - return d->m_renderManager->m_initialized; -} - -/*! - \property QScene2D::source - \brief Specifies the url for the qml. - - This property specifies the url to the qml being rendered to the texture. - The source must specify QQuickItem as a root. The item must specify width - and height. The rendered qml is scaled to the texture size. - The property can not be changed after the rendering has been initialized. - */ -QUrl QScene2D::source() const -{ - Q_D(const QScene2D); - return d->m_renderManager->m_source; -} - -void QScene2D::setSource(const QUrl &url) -{ - Q_D(QScene2D); - if (d->m_renderManager->m_initialized) { - qWarning() << "Unable to set source after initialization."; - return; - } - d->m_renderManager->setSource(url); - emit sourceChanged(url); -} - -/*! - \property QScene2D::renderOnce - \brief Property to specify if the texture will be rendered only once. - - This property specifies that the texture will be rendered only one time. - Once the rendering has been done, resources reserved for rendering will be - released and the QScene2D will become unusable. - If set to false, which is the default, the rendering is continuous. - */ -bool QScene2D::renderOnce() const -{ - Q_D(const QScene2D); - return d->m_renderManager->m_renderOnce; -} - -void QScene2D::setRenderOnce(bool once) -{ - Q_D(const QScene2D); - if (d->m_renderManager->m_renderOnce != once) { - d->m_renderManager->m_renderOnce = once; - emit renderOnceChanged(once); - } -} - -/*! - \property QScene2D::texture - \brief The texture being rendered to. - - This property specifies the texture being rendered to. Once the texture has been - set and the rendering begins, the texture can not be changed anymore. - */ -QAbstractTexture *QScene2D::texture() const -{ - Q_D(const QScene2D); - return d->m_renderManager->m_texture; -} - -void QScene2D::setTexture(QAbstractTexture *texture) -{ - Q_D(QScene2D); - if (d->m_renderManager->m_initialized) { - qWarning() << "Unable to set texture after initialization."; - return; - } - if (d->m_renderManager->m_texture != texture) { - if (d->m_renderManager->m_texture) - QObject::disconnect(d->m_textureDestroyedConnection); - if (texture && !texture->parent()) - texture->setParent(this); - d->m_renderManager->setTexture(texture); - if (texture) - d->m_textureDestroyedConnection - = QObject::connect(texture, &QAbstractTexture::destroyed, - this, &QScene2D::textureDestroyed); - emit textureChanged(texture); - } -} - -void QScene2D::textureDestroyed(QObject *object) -{ - Q_D(QScene2D); - Q_UNUSED(object); - d->m_renderManager->setTexture(nullptr); -} - -Qt3DCore::QNodeCreatedChangeBasePtr QScene2D::createNodeCreationChange() const -{ - auto creationChange = Qt3DCore::QNodeCreatedChangePtr::create(this); - auto &data = creationChange->data; - Q_D(const QScene2D); - data.renderOnce = d->m_renderManager->m_renderOnce; - data.textureId = d->m_renderManager->m_texture - ? d->m_renderManager->m_texture->id() : Qt3DCore::QNodeId(); - data.sharedObject = d->m_renderManager->m_sharedObject; - return creationChange; -} - -/*! - \internal - */ -void QScene2D::sourceLoaded() -{ - emit loadedChanged(true); -} - -} // namespace Qt3DRender - -QT_END_NAMESPACE diff --git a/src/render/framegraph/qscene2d.h b/src/render/framegraph/qscene2d.h deleted file mode 100644 index 18e65a5ca..000000000 --- a/src/render/framegraph/qscene2d.h +++ /dev/null @@ -1,96 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 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$ -** -****************************************************************************/ - -#ifndef QT3DRENDER_QSCENE2D_H -#define QT3DRENDER_QSCENE2D_H - -#include -#include - -#include -#include -#include - -QT_BEGIN_NAMESPACE - -namespace Qt3DRender { - -class QScene2DPrivate; - -class QT3DRENDERSHARED_EXPORT QScene2D : public Qt3DRender::QFrameGraphNode -{ - Q_OBJECT - - Q_PROPERTY(Qt3DRender::QAbstractTexture *texture READ texture WRITE setTexture NOTIFY textureChanged) - Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged) - Q_PROPERTY(bool renderOnce READ renderOnce WRITE setRenderOnce NOTIFY renderOnceChanged) - Q_PROPERTY(bool loaded READ loaded NOTIFY loadedChanged) - -public: - explicit QScene2D(Qt3DCore::QNode *parent = nullptr); - ~QScene2D(); - - QUrl source() const; - QAbstractTexture *texture() const; - bool loaded() const; - bool renderOnce() const; - -public Q_SLOTS: - void setSource(const QUrl &url); - void setTexture(QAbstractTexture *texture); - void setRenderOnce(bool once); - -Q_SIGNALS: - void sourceChanged(const QUrl &url); - void textureChanged(QAbstractTexture *texture); - void loadedChanged(bool loaded); - void renderOnceChanged(bool once); - -protected: - Q_DECLARE_PRIVATE(QScene2D) - -private: - Qt3DCore::QNodeCreatedChangeBasePtr createNodeCreationChange() const Q_DECL_OVERRIDE; - void textureDestroyed(QObject *object); - - void sourceLoaded(); -}; - -} // namespace Qt3DRender - -QT_END_NAMESPACE - -#endif // QT3DRENDER_QSCENE2D_H diff --git a/src/render/framegraph/qscene2d_p.h b/src/render/framegraph/qscene2d_p.h deleted file mode 100644 index 1020c1264..000000000 --- a/src/render/framegraph/qscene2d_p.h +++ /dev/null @@ -1,211 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 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$ -** -****************************************************************************/ - -#ifndef QT3DRENDER_QSCENE2D_P_H -#define QT3DRENDER_QSCENE2D_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of other Qt classes. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE - -namespace Qt3DRender { - -class QScene2D; -class Scene2DManager; - -// render thread -> render thread -static const QEvent::Type INITIALIZE = QEvent::Type(QEvent::User + 1); - -// main thread -> main thread, render thread -static const QEvent::Type RENDER = QEvent::Type(QEvent::User + 2); - -// main thread -> main thread -static const QEvent::Type RENDERSYNC = QEvent::Type(QEvent::User + 3); - -// render thread -> main thread -static const QEvent::Type PREPARE = QEvent::Type(QEvent::User + 4); -static const QEvent::Type INITIALIZED = QEvent::Type(QEvent::User + 5); -static const QEvent::Type RENDERED = QEvent::Type(QEvent::User + 6); - -// main thread -> render thread -static const QEvent::Type QUIT = QEvent::Type(QEvent::User + 7); - -class Q_AUTOTEST_EXPORT Scene2DSharedObject -{ -public: - Scene2DSharedObject(Scene2DManager *manager); - ~Scene2DSharedObject(); - - QQuickRenderControl *m_renderControl; - QQuickWindow *m_quickWindow; - Scene2DManager *m_renderManager; - QOffscreenSurface *m_surface; - - QThread *m_renderThread; - QObject *m_renderObject; - - QWaitCondition m_cond; - QMutex m_mutex; - - bool isInitialized() const; - void setInitialized(); - - void requestQuit(); - bool isQuit() const; - - void requestRender(bool sync); - - bool isSyncRequested() const; - void clearSyncRequest(); - - void waitRender(); - void wakeWaiting(); - - bool isPrepared() const; - void setPrepared(); - - void disallowRender(); - bool canRender() const; - - void cleanup(); - -private: - - bool m_disallowed; - bool m_quit; - bool m_requestSync; - bool m_requestRender; - bool m_prepared; - bool m_initialized; -}; - -typedef QSharedPointer Scene2DSharedObjectPtr; - -class Q_AUTOTEST_EXPORT QScene2DPrivate : public QFrameGraphNodePrivate -{ -public: - Q_DECLARE_PUBLIC(QScene2D) - - QScene2DPrivate(); - ~QScene2DPrivate(); - - static Scene2DSharedObject *getSharedObject(QScene2D *rqtt); - - Scene2DManager *m_renderManager; - QMetaObject::Connection m_textureDestroyedConnection; -}; - -struct QScene2DData -{ - bool renderOnce; - Qt3DCore::QNodeId textureId; - Scene2DSharedObjectPtr sharedObject; -}; - - -class Scene2DManager : public QWindow -{ - Q_OBJECT -public: - Scene2DManager(QScene2DPrivate *priv); - ~Scene2DManager(); - - QQmlEngine *m_qmlEngine; - QQmlComponent *m_qmlComponent; - QQuickItem *m_rootItem; - - QScene2DPrivate *m_priv; - QSharedPointer m_sharedObject; - - QAbstractTexture *m_texture; - QUrl m_source; - Qt3DCore::QNodeId m_id; - - bool m_requested; - bool m_initialized; - bool m_renderSyncRequested; - bool m_renderOnce; - bool m_backendInitialized; - - void requestRender(); - void requestRenderSync(); - void doRenderSync(); - void startIfInitialized(); - void stopAndClean(); - void run(); - void updateSizes(); - - void setTexture(QAbstractTexture *texture); - void setSource(const QUrl &url); - - bool event(QEvent *e) Q_DECL_OVERRIDE; - - Q_SIGNAL void onLoadedChanged(); - - void cleanup(); -}; - - -} // namespace Qt3DRender - -QT_END_NAMESPACE - -#endif // QT3DRENDER_QSCENE2D_P_H diff --git a/src/render/framegraph/scene2d.cpp b/src/render/framegraph/scene2d.cpp deleted file mode 100644 index edf4fd643..000000000 --- a/src/render/framegraph/scene2d.cpp +++ /dev/null @@ -1,303 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 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 -#include -#include -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE - -namespace Qt3DRender { - -namespace Render { - -RenderQmlEventHandler::RenderQmlEventHandler(Scene2D *node) - : QObject() - , m_node(node) -{ -} - -// Event handler for the RenderQmlToTexture::renderThread -bool RenderQmlEventHandler::event(QEvent *e) -{ - switch (e->type()) { - - case RENDER: { - m_node->render(); - return true; - } - - case INITIALIZE: { - m_node->initializeRender(); - return true; - } - - case QUIT: { - m_node->cleanup(); - return true; - } - - default: - break; - } - return QObject::event(e); -} - -Scene2D::Scene2D() - : FrameGraphNode(FrameGraphNode::InvalidNodeType) - , m_context(nullptr) - , m_sharedObject(nullptr) - , m_renderThread(nullptr) - , m_graphicsContext(nullptr) - , m_texture(nullptr) - , m_initialized(false) - , m_renderInitialized(false) - , m_renderOnce(false) -{ - -} - -Scene2D::~Scene2D() -{ - // this gets called from aspect thread. Wait for the render thread then delete it. - if (m_renderThread) { - m_renderThread->wait(1000); - delete m_renderThread; - } -} - -void Scene2D::setTexture(Qt3DCore::QNodeId textureId) -{ - m_textureId = textureId; - attach(); - checkInitialized(); -} - -void Scene2D::checkInitialized() -{ - if (!m_initialized && m_textureId != Qt3DCore::QNodeId()) { - - // Create render thread - m_renderThread = new QThread(); - m_renderThread->setObjectName(QStringLiteral("Scene2D::renderThread")); - m_sharedObject->m_renderThread = m_renderThread; - - // Create event handler for the render thread - m_sharedObject->m_renderObject = new RenderQmlEventHandler(this); - m_sharedObject->m_renderObject->moveToThread(m_sharedObject->m_renderThread); - m_sharedObject->m_renderThread->start(); - - // Notify main thread we have been initialized - QCoreApplication::postEvent(m_sharedObject->m_renderManager, new QEvent(INITIALIZED)); - - // Initialize render thread - QCoreApplication::postEvent(m_sharedObject->m_renderObject, new QEvent(INITIALIZE)); - - m_initialized = true; - } -} - -void Scene2D::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) -{ - const auto typedChange = qSharedPointerCast>(change); - const auto &data = typedChange->data; - m_renderOnce = m_renderOnce; - setSharedObject(data.sharedObject); - setTexture(data.textureId); -} - -void Scene2D::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) -{ - if (e->type() == Qt3DCore::PropertyUpdated) { - Qt3DCore::QPropertyUpdatedChangePtr propertyChange - = qSharedPointerCast(e); - if (propertyChange->propertyName() == QByteArrayLiteral("enabled")) - setEnabled(propertyChange->value().toBool()); - else if (propertyChange->propertyName() == QByteArrayLiteral("dirty")) { - // sent to trigger backend update when the texture gets rendered - // so do nothing here - } - else if (propertyChange->propertyName() == QByteArrayLiteral("renderOnce")) - m_renderOnce = propertyChange->value().toBool(); - else if (propertyChange->propertyName() == QByteArrayLiteral("texture")) { - Qt3DCore::QNodeId textureId = propertyChange->value().value(); - setTexture(textureId); - } - markDirty(AbstractRenderer::AllDirty); - } - FrameGraphNode::sceneChangeEvent(e); -} - -void Scene2D::setSharedObject(Qt3DRender::Scene2DSharedObjectPtr sharedObject) -{ - m_sharedObject = sharedObject; -} - -void Scene2D::initializeRender() -{ - if (!m_renderInitialized) { - Qt3DRender::Render::Renderer *renderer - = static_cast(this->renderer()); - if (!renderer) - return; - - QSurfaceFormat format; - format.setDepthBufferSize(24); - format.setStencilBufferSize(8); - - m_context = new QOpenGLContext(); - m_context->setFormat(format); - - m_context->setShareContext(renderer->shareContext()); - m_context->create(); - - m_graphicsContext = new GraphicsContext(); - m_graphicsContext->setOpenGLContext(m_context); - m_graphicsContext->setRenderer(renderer); - - m_graphicsContext->makeCurrent(m_sharedObject->m_surface); - m_sharedObject->m_renderControl->initialize(m_context); - m_graphicsContext->doneCurrent(); - - QCoreApplication::postEvent(m_sharedObject->m_renderManager, new QEvent(PREPARE)); - m_renderInitialized = true; - } -} - -void Scene2D::attach() -{ - m_attachments = AttachmentPack(); - Attachment attach; - attach.m_mipLevel = 0; - attach.m_textureUuid = m_textureId; - attach.m_point = QRenderTargetOutput::AttachmentPoint::Color0; - -// m_attachments.addAttachment(attach); -} - -void Scene2D::render() -{ - if (m_initialized && m_sharedObject && this->isEnabled()) { - - QMutexLocker lock(&m_sharedObject->m_mutex); - - // Lookup backend texture - if (m_texture == nullptr) { - m_texture = renderer()->nodeManagers()->textureManager()->lookupResource(m_textureId); - if (!m_texture) { - qCDebug(Render::Framegraph) << Q_FUNC_INFO << "Texture not set"; - return; - } - } - - m_graphicsContext->makeCurrent(m_sharedObject->m_surface); - - // Don't create the OpenGL texture in this thread. - const bool canUseTexture = !m_texture->isTextureReset(); - - if (canUseTexture) { - // Activate fbo for the texture - QOpenGLTexture *glTex = m_texture->getOrCreateGLTexture(); - const QSize textureSize = QSize(glTex->width(), glTex->height()); - - GLuint fbo = 0; //m_graphicsContext->activateRenderTargetForQmlRender(this, m_attachments, 0); - - if (fbo != m_sharedObject->m_quickWindow->renderTargetId()) - m_sharedObject->m_quickWindow->setRenderTarget(fbo, textureSize); - - m_texture->textureLock()->lock(); - } - // Call disallow rendering while mutex is locked - if (canUseTexture && m_renderOnce) - m_sharedObject->disallowRender(); - - // Need to call sync even if the texture is not in use - if (m_sharedObject->isSyncRequested()) { - - m_sharedObject->clearSyncRequest(); - - m_sharedObject->m_renderControl->sync(); - - // gui thread can now continue - m_sharedObject->wakeWaiting(); - lock.unlock(); - } - - if (canUseTexture) { - - // Render - m_sharedObject->m_renderControl->render(); - - // Tell main thread we are done so it can begin cleanup - if (m_renderOnce) - QCoreApplication::postEvent(m_sharedObject->m_renderManager, new QEvent(RENDERED)); - - m_sharedObject->m_quickWindow->resetOpenGLState(); - m_context->functions()->glFlush(); - m_texture->textureLock()->unlock(); - } - m_graphicsContext->doneCurrent(); - } -} - -void Scene2D::cleanup() -{ - if (m_renderInitialized && m_initialized) { - m_context->makeCurrent(m_sharedObject->m_surface); - m_sharedObject->m_renderControl->invalidate(); - m_context->doneCurrent(); - m_sharedObject->m_renderThread->quit(); - delete m_sharedObject->m_renderObject; - m_sharedObject->m_renderObject = nullptr; - delete m_context; - m_context = nullptr; - m_sharedObject = nullptr; - delete m_graphicsContext; - m_graphicsContext = nullptr; - m_renderInitialized = false; - m_initialized = false; - } -} - -} // namespace Render - -} // namespace Qt3DRender - -QT_END_NAMESPACE diff --git a/src/render/framegraph/scene2d_p.h b/src/render/framegraph/scene2d_p.h deleted file mode 100644 index f6e3f8903..000000000 --- a/src/render/framegraph/scene2d_p.h +++ /dev/null @@ -1,115 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 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$ -** -****************************************************************************/ - -#ifndef QT3DRENDER_RENDER_SCENE2D_P_H -#define QT3DRENDER_RENDER_SCENE2D_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of other Qt classes. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include - -#include -#include - -#include -#include - -QT_BEGIN_NAMESPACE - -namespace Qt3DRender { - -namespace Render { - -class GraphicsContext; -class Scene2D; - -class RenderQmlEventHandler : public QObject -{ - Q_OBJECT -public: - RenderQmlEventHandler(Scene2D *node); - bool event(QEvent *e) Q_DECL_OVERRIDE; - -private: - Scene2D *m_node; -}; - -class Q_AUTOTEST_EXPORT Scene2D : public FrameGraphNode -{ -public: - Scene2D(); - ~Scene2D(); - - void attach(); - void render(); - void initializeRender(); - void setSharedObject(Scene2DSharedObjectPtr sharedObject); - void cleanup(); - void setTexture(Qt3DCore::QNodeId textureId); - void checkInitialized(); - - void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_OVERRIDE; - void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL; - - QOpenGLContext *m_context; - GraphicsContext *m_graphicsContext; - QThread *m_renderThread; - Qt3DCore::QNodeId m_textureId; - QSharedPointer m_sharedObject; - AttachmentPack m_attachments; - Texture *m_texture; - - bool m_initialized; - bool m_renderInitialized; - bool m_renderOnce; -}; - -} // Render - -} // Qt3DRender - -QT_END_NAMESPACE - -#endif // QT3DRENDER_RENDER_SCENE2D_P_H -- cgit v1.2.3 From b5af580c823372e3d6f956a860e092018a066766 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Fri, 21 Oct 2016 15:02:54 +0300 Subject: Change namespace Change-Id: I53e86f988f14a4e5748c1a13599461effb8d8462 Reviewed-by: Sean Harmer --- src/quick3d/quick3drender/scene2d/qscene2d.cpp | 3 +++ src/quick3d/quick3drender/scene2d/qscene2d.h | 13 ++++++++----- src/quick3d/quick3drender/scene2d/qscene2d_p.h | 11 +++++++---- src/quick3d/quick3drender/scene2d/scene2d.cpp | 22 +++++++++++++++------- src/quick3d/quick3drender/scene2d/scene2d_p.h | 19 +++++++++++-------- 5 files changed, 44 insertions(+), 24 deletions(-) diff --git a/src/quick3d/quick3drender/scene2d/qscene2d.cpp b/src/quick3d/quick3drender/scene2d/qscene2d.cpp index 62e766684..5c20db184 100644 --- a/src/quick3d/quick3drender/scene2d/qscene2d.cpp +++ b/src/quick3d/quick3drender/scene2d/qscene2d.cpp @@ -47,6 +47,7 @@ using namespace Qt3DCore; namespace Qt3DRender { +namespace Quick { /*! \class Qt3DRender::QScene2D @@ -616,6 +617,8 @@ void QScene2D::sourceLoaded() emit loadedChanged(true); } +} // namespace Quick + } // namespace Qt3DRender QT_END_NAMESPACE diff --git a/src/quick3d/quick3drender/scene2d/qscene2d.h b/src/quick3d/quick3drender/scene2d/qscene2d.h index 18e65a5ca..a00e7b06b 100644 --- a/src/quick3d/quick3drender/scene2d/qscene2d.h +++ b/src/quick3d/quick3drender/scene2d/qscene2d.h @@ -34,23 +34,25 @@ ** ****************************************************************************/ -#ifndef QT3DRENDER_QSCENE2D_H -#define QT3DRENDER_QSCENE2D_H +#ifndef QT3DRENDER_QUICK3DRENDER_QSCENE2D_H +#define QT3DRENDER_QUICK3DRENDER_QSCENE2D_H #include #include #include #include -#include +#include QT_BEGIN_NAMESPACE namespace Qt3DRender { +namespace Quick { + class QScene2DPrivate; -class QT3DRENDERSHARED_EXPORT QScene2D : public Qt3DRender::QFrameGraphNode +class QT3DQUICKRENDERSHARED_EXPORT QScene2D : public Qt3DRender::QFrameGraphNode { Q_OBJECT @@ -89,8 +91,9 @@ private: void sourceLoaded(); }; +} // namespace Quick } // namespace Qt3DRender QT_END_NAMESPACE -#endif // QT3DRENDER_QSCENE2D_H +#endif // QT3DRENDER_QUICK3DRENDER_QSCENE2D_H diff --git a/src/quick3d/quick3drender/scene2d/qscene2d_p.h b/src/quick3d/quick3drender/scene2d/qscene2d_p.h index 1020c1264..165a54b72 100644 --- a/src/quick3d/quick3drender/scene2d/qscene2d_p.h +++ b/src/quick3d/quick3drender/scene2d/qscene2d_p.h @@ -34,8 +34,8 @@ ** ****************************************************************************/ -#ifndef QT3DRENDER_QSCENE2D_P_H -#define QT3DRENDER_QSCENE2D_P_H +#ifndef QT3DRENDER_QUICK3DRENDER_QSCENE2D_P_H +#define QT3DRENDER_QUICK3DRENDER_QSCENE2D_P_H // // W A R N I N G @@ -51,7 +51,7 @@ #include #include -#include +#include #include #include @@ -68,6 +68,8 @@ QT_BEGIN_NAMESPACE namespace Qt3DRender { +namespace Quick { + class QScene2D; class Scene2DManager; @@ -203,9 +205,10 @@ public: void cleanup(); }; +} // namespace Quick } // namespace Qt3DRender QT_END_NAMESPACE -#endif // QT3DRENDER_QSCENE2D_P_H +#endif // QT3DRENDER_QUICK3DRENDER_QSCENE2D_P_H diff --git a/src/quick3d/quick3drender/scene2d/scene2d.cpp b/src/quick3d/quick3drender/scene2d/scene2d.cpp index edf4fd643..210cc5f0f 100644 --- a/src/quick3d/quick3drender/scene2d/scene2d.cpp +++ b/src/quick3d/quick3drender/scene2d/scene2d.cpp @@ -34,20 +34,26 @@ ** ****************************************************************************/ -#include -#include -#include -#include -#include -#include #include +#include + +#include +#include +#include +#include +#include + QT_BEGIN_NAMESPACE +using namespace Qt3DRender::Quick; + namespace Qt3DRender { namespace Render { +namespace Quick { + RenderQmlEventHandler::RenderQmlEventHandler(Scene2D *node) : QObject() , m_node(node) @@ -165,7 +171,7 @@ void Scene2D::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) FrameGraphNode::sceneChangeEvent(e); } -void Scene2D::setSharedObject(Qt3DRender::Scene2DSharedObjectPtr sharedObject) +void Scene2D::setSharedObject(Qt3DRender::Quick::Scene2DSharedObjectPtr sharedObject) { m_sharedObject = sharedObject; } @@ -296,6 +302,8 @@ void Scene2D::cleanup() } } +} // namespace Quick + } // namespace Render } // namespace Qt3DRender diff --git a/src/quick3d/quick3drender/scene2d/scene2d_p.h b/src/quick3d/quick3drender/scene2d/scene2d_p.h index f6e3f8903..950ddaa5b 100644 --- a/src/quick3d/quick3drender/scene2d/scene2d_p.h +++ b/src/quick3d/quick3drender/scene2d/scene2d_p.h @@ -34,8 +34,8 @@ ** ****************************************************************************/ -#ifndef QT3DRENDER_RENDER_SCENE2D_P_H -#define QT3DRENDER_RENDER_SCENE2D_P_H +#ifndef QT3DRENDER_RENDER_QUICK_SCENE2D_P_H +#define QT3DRENDER_RENDER_QUICK_SCENE2D_P_H // // W A R N I N G @@ -50,8 +50,8 @@ #include -#include -#include +#include +#include #include #include @@ -63,6 +63,9 @@ namespace Qt3DRender { namespace Render { class GraphicsContext; + +namespace Quick { + class Scene2D; class RenderQmlEventHandler : public QObject @@ -85,7 +88,7 @@ public: void attach(); void render(); void initializeRender(); - void setSharedObject(Scene2DSharedObjectPtr sharedObject); + void setSharedObject(Qt3DRender::Quick::Scene2DSharedObjectPtr sharedObject); void cleanup(); void setTexture(Qt3DCore::QNodeId textureId); void checkInitialized(); @@ -97,7 +100,7 @@ public: GraphicsContext *m_graphicsContext; QThread *m_renderThread; Qt3DCore::QNodeId m_textureId; - QSharedPointer m_sharedObject; + QSharedPointer m_sharedObject; AttachmentPack m_attachments; Texture *m_texture; @@ -106,10 +109,10 @@ public: bool m_renderOnce; }; +} // Quick } // Render - } // Qt3DRender QT_END_NAMESPACE -#endif // QT3DRENDER_RENDER_SCENE2D_P_H +#endif // QT3DRENDER_RENDER_QUICK_SCENE2D_P_H -- cgit v1.2.3 From 1a3b74a1794e727457df8dcd1d42754d584c7562 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Mon, 24 Oct 2016 16:07:52 +0300 Subject: Add QEventForward frontend node MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implementation of QEventForward frontend node. It sends events from the object picker to the receiving object. This is needed in order to interact with the QScene2D QML. Change-Id: Icd464e28387ec5a362d6371ebdbaba6d0cd8e5d7 Reviewed-by: Tomi Korpipää Reviewed-by: Sean Harmer --- src/render/picking/picking.pri | 7 +- src/render/picking/qeventforward.cpp | 227 +++++++++++++++++++++++++++++++++++ src/render/picking/qeventforward.h | 97 +++++++++++++++ src/render/picking/qeventforward_p.h | 97 +++++++++++++++ 4 files changed, 426 insertions(+), 2 deletions(-) create mode 100644 src/render/picking/qeventforward.cpp create mode 100644 src/render/picking/qeventforward.h create mode 100644 src/render/picking/qeventforward_p.h diff --git a/src/render/picking/picking.pri b/src/render/picking/picking.pri index c4c188a82..29eabe15d 100644 --- a/src/render/picking/picking.pri +++ b/src/render/picking/picking.pri @@ -7,11 +7,14 @@ HEADERS += \ $$PWD/qpicktriangleevent.h \ $$PWD/objectpicker_p.h \ $$PWD/pickeventfilter_p.h \ - $$PWD/qobjectpicker_p.h + $$PWD/qobjectpicker_p.h \ + $$PWD/qeventforward.h \ + $$PWD/qeventforward_p.h SOURCES += \ $$PWD/qobjectpicker.cpp \ $$PWD/qpickevent.cpp \ $$PWD/qpicktriangleevent.cpp \ $$PWD/objectpicker.cpp \ - $$PWD/pickeventfilter.cpp + $$PWD/pickeventfilter.cpp \ + $$PWD/qeventforward.cpp diff --git a/src/render/picking/qeventforward.cpp b/src/render/picking/qeventforward.cpp new file mode 100644 index 000000000..74b52989e --- /dev/null +++ b/src/render/picking/qeventforward.cpp @@ -0,0 +1,227 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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 "qeventforward.h" +#include "qeventforward_p.h" + +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +/*! + \class Qt3DRender::QEventForward + \inmodule Qt3DRender + + \brief The QEventForward class instantiates a node that can + be used to forward events from the scene. + + An QEventForward class can be used to forward pick events and keyboard events + from entities having a QObjectPicker. When the QObjectPicker handles pick event, + it hands it to the QEventForward, which converts it to QMouseEvent. The event + mouse coordinates are calculated by interpolating the given coordinate attribute + on the position the pick ray intersected the triangle, and then multiplying the + interpolated coordinate with the given transformation matrix. The event is then + sent and to the target object. + + \since 5.9 +*/ + +/*! + \qmltype EventForward + \instantiates Qt3DRender::QEventForward + \inherits Node + \inqmlmodule Qt3D.Render + \brief The EventForward type instantiates a node that can + be used to forward events from the scene. + + An EventForward type can be used to forward pick events and keyboard events + from entities having a ObjectPicker. When the ObjectPicker handles pick event, + it hands it to the EventForward, which converts it to MouseEvent. The event + mouse coordinates are calculated by interpolating the given coordinate attribute + on the position the pick ray intersected the triangle, and then multiplying the + interpolated coordinate with the given transformation matrix. The event is then + sent and to the target object. + + */ + +/*! + \qmlproperty Object Qt3D.Render::EventForward::target + Holds the object the events are sent to. +*/ +/*! + \qmlproperty bool Qt3D.Render::EventForward::forwardMouseEvents + Holds whether mouse event forwarding is enabled. +*/ +/*! + \qmlproperty bool Qt3D.Render::EventForward::forwardKeyboardEvents + Holds whether keyboard event forwarding is enabled. +*/ +/*! + \qmlproperty Matrix4x4 Qt3D.Render::EventForward::coordinateTransform + Holds the coordinate transformation. +*/ +/*! + \qmlproperty string Qt3D.Render::EventForward::coordinateAttribute + Holds the name of the coordinate attribute the mouse coordinates are calculated from. +*/ + +/*! + \property QEventForward::target + Holds the object the events are sent to. +*/ +/*! + \property QEventForward::forwardMouseEvents + Holds whether mouse event forwarding is enabled. +*/ +/*! + \property QEventForward::forwardKeyboardEvents + Holds whether keyboard event forwarding is enabled. +*/ +/*! + \property QEventForward::coordinateTransform + Holds the coordinate transformation. +*/ +/*! + \property QEventForward::coordinateAttribute + Holds the name of the coordinate attribute the mouse coordinates are calculated from. +*/ + +QEventForward::QEventForward(Qt3DCore::QNode *parent) + : Qt3DCore::QNode(*new QEventForwardPrivate(), parent) +{ +} + +/*! \internal */ +QEventForward::~QEventForward() +{ +} + +QObject *QEventForward::target() const +{ + Q_D(const QEventForward); + return d->m_target; +} + +void QEventForward::setTarget(QObject *target) +{ + Q_D(QEventForward); + if (target != d->m_target) { + d->m_target = target; + emit targetChanged(target); + } +} + +QMatrix4x4 QEventForward::coordinateTransform() const +{ + Q_D(const QEventForward); + return d->m_transform; +} + +void QEventForward::setCoordinateTransform(const QMatrix4x4 &coordinateTransform) +{ + Q_D(QEventForward); + if (coordinateTransform != d->m_transform) { + d->m_transform = coordinateTransform; + emit coordinateTransformChanged(coordinateTransform); + } +} + +QString QEventForward::coordinateAttribute() const +{ + Q_D(const QEventForward); + return d->m_attribute; +} + +void QEventForward::setCoordinateAttribute(const QString &coordinateAttribute) +{ + Q_D(QEventForward); + if (coordinateAttribute != d->m_attribute) { + d->m_attribute = coordinateAttribute; + emit coordinateAttributeChanged(coordinateAttribute); + } +} + +bool QEventForward::forwardMouseEvents() const +{ + Q_D(const QEventForward); + return d->m_forwardMouseEvents; +} + +void QEventForward::setForwardMouseEvents(bool forward) +{ + Q_D(QEventForward); + if (forward != d->m_forwardMouseEvents) { + d->m_forwardMouseEvents = forward; + emit forwardMouseEventsChanged(forward); + } +} + +bool QEventForward::forwardKeyboardEvents() const +{ + Q_D(const QEventForward); + return d->m_forwardKeyboardEvents; +} + +void QEventForward::setForwardKeyboardEvents(bool forward) +{ + Q_D(QEventForward); + if (forward != d->m_forwardKeyboardEvents) { + d->m_forwardKeyboardEvents = forward; + emit forwardKeyboardEventsChanged(forward); + } +} + +/*! + \internal + */ +Qt3DCore::QNodeCreatedChangeBasePtr QEventForward::createNodeCreationChange() const +{ + auto creationChange = Qt3DCore::QNodeCreatedChangePtr::create(this); + auto &data = creationChange->data; + Q_D(const QEventForward); + data.target = d->m_target; + data.coordinateTransform = d->m_transform; + data.coordinateAttribute = d->m_attribute; + data.forwardMouseEvents = d->m_forwardMouseEvents; + data.forwardKeyboardEvents = d->m_forwardKeyboardEvents; + return creationChange; +} + +} // Qt3DRender + +QT_END_NAMESPACE diff --git a/src/render/picking/qeventforward.h b/src/render/picking/qeventforward.h new file mode 100644 index 000000000..694ad0d2d --- /dev/null +++ b/src/render/picking/qeventforward.h @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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$ +** +****************************************************************************/ + +#ifndef QT3DRENDER_QEVENTFORWARD_H +#define QT3DRENDER_QEVENTFORWARD_H + +#include + +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +class QEventForwardPrivate; + +class QT3DRENDERSHARED_EXPORT QEventForward : public Qt3DCore::QNode +{ + Q_OBJECT + Q_PROPERTY(QObject *target READ target WRITE setTarget NOTIFY targetChanged) + Q_PROPERTY(bool forwardMouseEvents READ forwardMouseEvents WRITE setForwardMouseEvents NOTIFY forwardMouseEventsChanged) + Q_PROPERTY(bool forwardKeyboardEvents READ forwardKeyboardEvents WRITE setForwardKeyboardEvents NOTIFY forwardKeyboardEventsChanged) + Q_PROPERTY(QMatrix4x4 coordinateTransform READ coordinateTransform WRITE setCoordinateTransform NOTIFY coordinateTransformChanged) + Q_PROPERTY(QString coordinateAttribute READ coordinateAttribute WRITE setCoordinateAttribute NOTIFY coordinateAttributeChanged) + +public: + explicit QEventForward(Qt3DCore::QNode *parent = nullptr); + ~QEventForward(); + + QObject *target() const; + QMatrix4x4 coordinateTransform() const; + QString coordinateAttribute() const; + bool forwardMouseEvents() const; + bool forwardKeyboardEvents() const; + +public Q_SLOTS: + void setTarget(QObject *target); + void setCoordinateTransform(const QMatrix4x4 &coordinateTransform); + void setCoordinateAttribute(const QString &coordinateAttribute); + void setForwardMouseEvents(bool forward); + void setForwardKeyboardEvents(bool forward); + +Q_SIGNALS: + void targetChanged(QObject *target); + void coordinateTransformChanged(const QMatrix4x4 &coordinateTransform); + void coordinateAttributeChanged(const QString &coordinateAttribute); + void forwardMouseEventsChanged(bool forward); + void forwardKeyboardEventsChanged(bool forward); + +private: + Q_DECLARE_PRIVATE(QEventForward) + Qt3DCore::QNodeCreatedChangeBasePtr createNodeCreationChange() const Q_DECL_OVERRIDE; +}; + +} // Qt3DRender + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(Qt3DRender::QEventForward*) + +#endif // QT3DRENDER_QEVENTFORWARD_H diff --git a/src/render/picking/qeventforward_p.h b/src/render/picking/qeventforward_p.h new file mode 100644 index 000000000..be2e832d8 --- /dev/null +++ b/src/render/picking/qeventforward_p.h @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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$ +** +****************************************************************************/ + +#ifndef QT3DRENDER_QEVENTFORWARD_P_H +#define QT3DRENDER_QEVENTFORWARD_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +/*! + \internal +*/ +class QEventForwardPrivate : public Qt3DCore::QNodePrivate +{ +public: + QEventForwardPrivate() + : QNodePrivate() + , m_target(nullptr) + , m_attribute("default") + , m_forwardMouseEvents(true) + , m_forwardKeyboardEvents(false) + { + + } + + Q_DECLARE_PUBLIC(QEventForward) + + QObject *m_target; + QMatrix4x4 m_transform; + QString m_attribute; + bool m_forwardMouseEvents; + bool m_forwardKeyboardEvents; +}; + +struct QEventForwardData +{ + QObject *target; + QMatrix4x4 coordinateTransform; + QString coordinateAttribute; + bool forwardMouseEvents; + bool forwardKeyboardEvents; +}; + +} // namespace Qt3DRender + +QT_END_NAMESPACE + +#endif // QT3DRENDER_QEVENTFORWARD_P_H -- cgit v1.2.3 From 1c09f953e0b54e7e9b76775179320b975252eb61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Mon, 24 Oct 2016 16:18:23 +0300 Subject: Add EventForward backend node MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit EventForward backend node implementation Change-Id: Idee9d74204038d9bb3611e41e6b02403d89f2c85 Reviewed-by: Tomi Korpipää Reviewed-by: Sean Harmer --- src/render/picking/eventforward.cpp | 180 ++++++++++++++++++++++++++++++++++++ src/render/picking/eventforward_p.h | 104 +++++++++++++++++++++ src/render/picking/picking.pri | 6 +- 3 files changed, 288 insertions(+), 2 deletions(-) create mode 100644 src/render/picking/eventforward.cpp create mode 100644 src/render/picking/eventforward_p.h diff --git a/src/render/picking/eventforward.cpp b/src/render/picking/eventforward.cpp new file mode 100644 index 000000000..7e24557ab --- /dev/null +++ b/src/render/picking/eventforward.cpp @@ -0,0 +1,180 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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 +#include +#include + +#include +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +namespace Render { + +EventForward::EventForward() + : m_target(nullptr) + , m_forwardMouseEvents(false) + , m_forwardKeyboardEvents(false) +{ + +} + +EventForward::~EventForward() +{ + +} + +void EventForward::cleanup() +{ + setEnabled(false); + m_target = nullptr; + m_coordinateAttribute = ""; + m_coordinateTransform.setToIdentity(); + m_forwardMouseEvents = false; + m_forwardKeyboardEvents = false; +} + +QObject *EventForward::target() const +{ + return m_target; +} + +QString EventForward::coordinateAttribute() const +{ + return m_coordinateAttribute; +} + +QMatrix4x4 EventForward::coordinateTransform() const +{ + return m_coordinateTransform; +} + +bool EventForward::forwardMouseEvents() const +{ + return m_forwardMouseEvents; +} + +bool EventForward::forwardKeyboardEvents() const +{ + return m_forwardKeyboardEvents; +} + +void EventForward::setTarget(QObject *target) +{ + m_target = target; +} + +void EventForward::setCoordinateTransform(const QMatrix4x4 &transform) +{ + m_coordinateTransform = transform; +} + +void EventForward::setCoordinateAttribute(const QString &attribute) +{ + m_coordinateAttribute = attribute; +} + +void EventForward::setForwardMouseEvents(bool enabled) +{ + m_forwardMouseEvents = enabled; +} + +void EventForward::setForwardKeyboardEvents(bool enabled) +{ + m_forwardKeyboardEvents = enabled; +} + +void EventForward::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) +{ + const auto typedChange = qSharedPointerCast>(change); + const auto &data = typedChange->data; + setTarget(data.target); + setCoordinateAttribute(data.coordinateAttribute); + setCoordinateTransform(data.coordinateTransform); + setForwardMouseEvents(data.forwardMouseEvents); + setForwardKeyboardEvents(data.forwardKeyboardEvents); +} + +void EventForward::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) +{ + if (e->type() == Qt3DCore::PropertyUpdated) { + const Qt3DCore::QPropertyUpdatedChangePtr propertyChange + = qSharedPointerCast(e); + + if (propertyChange->propertyName() == QByteArrayLiteral("target")) + setTarget(propertyChange->value().value()); + else if (propertyChange->propertyName() == QByteArrayLiteral("coordinateTransform")) + setCoordinateTransform(propertyChange->value().value()); + else if (propertyChange->propertyName() == QByteArrayLiteral("coordinateAttribute")) + setCoordinateAttribute(propertyChange->value().toString()); + else if (propertyChange->propertyName() == QByteArrayLiteral("forwardMouseEvents")) + setForwardMouseEvents(propertyChange->value().toBool()); + else if (propertyChange->propertyName() == QByteArrayLiteral("forwardKeyboardEvents")) + setForwardKeyboardEvents(propertyChange->value().toBool()); + } + + BackendNode::sceneChangeEvent(e); +} + +void EventForward::forward(const QMouseEvent &event, const QVector4D &coordinate) +{ + const QVector4D transformedCoordinate = m_coordinateTransform * coordinate; + const QPointF local = QPointF(transformedCoordinate.x(), transformedCoordinate.y()); + QMouseEvent *mouseEvent = new QMouseEvent(event.type(), local, local, local, event.button(), + event.buttons(), event.modifiers(), + Qt::MouseEventSynthesizedByApplication); + QCoreApplication::postEvent(m_target, mouseEvent); +} + +void EventForward::forward(const QList &events) +{ + for (const QKeyEvent &e : events) { + QKeyEvent *keyEvent = new QKeyEvent(e.type(), e.key(), e.modifiers(), e.nativeScanCode(), + e.nativeVirtualKey(), e.nativeModifiers()); + QCoreApplication::postEvent(m_target, keyEvent); + } +} + +} // Render +} // Qt3DRender + +QT_END_NAMESPACE diff --git a/src/render/picking/eventforward_p.h b/src/render/picking/eventforward_p.h new file mode 100644 index 000000000..1fc56ead2 --- /dev/null +++ b/src/render/picking/eventforward_p.h @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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$ +** +****************************************************************************/ + +#ifndef QT3DRENDER_RENDER_EVENTFORWARD_P_H +#define QT3DRENDER_RENDER_EVENTFORWARD_P_H + + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +namespace Render { + +class Q_AUTOTEST_EXPORT EventForward : public BackendNode +{ +public: + EventForward(); + ~EventForward(); + + void cleanup(); + + QObject *target() const; + QString coordinateAttribute() const; + QMatrix4x4 coordinateTransform() const; + bool forwardMouseEvents() const; + bool forwardKeyboardEvents() const; + + void setTarget(QObject *target); + void setCoordinateTransform(const QMatrix4x4 &transform); + void setCoordinateAttribute(const QString &attribute); + void setForwardMouseEvents(bool enabled); + void setForwardKeyboardEvents(bool enabled); + + void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_FINAL; + + void forward(const QMouseEvent &event, const QVector4D &coordinate); + void forward(const QList &events); + +private: + void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL; + + QObject *m_target; + QString m_coordinateAttribute; + QMatrix4x4 m_coordinateTransform; + bool m_forwardMouseEvents; + bool m_forwardKeyboardEvents; +}; + +} // Render +} // Qt3DRender + +QT_END_NAMESPACE + +#endif // QT3DRENDER_RENDER_EVENTFORWARD_P_H diff --git a/src/render/picking/picking.pri b/src/render/picking/picking.pri index 29eabe15d..e581a8f8a 100644 --- a/src/render/picking/picking.pri +++ b/src/render/picking/picking.pri @@ -9,7 +9,8 @@ HEADERS += \ $$PWD/pickeventfilter_p.h \ $$PWD/qobjectpicker_p.h \ $$PWD/qeventforward.h \ - $$PWD/qeventforward_p.h + $$PWD/qeventforward_p.h \ + $$PWD/eventforward_p.h SOURCES += \ $$PWD/qobjectpicker.cpp \ @@ -17,4 +18,5 @@ SOURCES += \ $$PWD/qpicktriangleevent.cpp \ $$PWD/objectpicker.cpp \ $$PWD/pickeventfilter.cpp \ - $$PWD/qeventforward.cpp + $$PWD/qeventforward.cpp \ + $$PWD/eventforward.cpp -- cgit v1.2.3 From 1ce5d53260ae1acc792b693a7af2288bbe3cb85a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Tue, 25 Oct 2016 09:20:16 +0300 Subject: Add CoordinateReader to triangle visitor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I6f8d3cb83e90db5a1bcb7e4c16ae60fa5ec12c45 Reviewed-by: Tomi Korpipää Reviewed-by: Sean Harmer --- src/render/backend/trianglesvisitor.cpp | 101 ++++++++++++++++++++++++++------ src/render/backend/trianglesvisitor_p.h | 42 +++++++++++++ 2 files changed, 125 insertions(+), 18 deletions(-) diff --git a/src/render/backend/trianglesvisitor.cpp b/src/render/backend/trianglesvisitor.cpp index 35cdecc29..5453661e0 100644 --- a/src/render/backend/trianglesvisitor.cpp +++ b/src/render/backend/trianglesvisitor.cpp @@ -71,24 +71,6 @@ bool isTriangleBased(Qt3DRender::QGeometryRenderer::PrimitiveType type) Q_DECL_N } } -struct BufferInfo -{ - BufferInfo() - : type(QAttribute::VertexBaseType::Float) - , dataSize(0) - , count(0) - , byteStride(0) - , byteOffset(0) - {} - - QByteArray data; - QAttribute::VertexBaseType type; - uint dataSize; - uint count; - uint byteStride; - uint byteOffset; -}; - // TO DO: Add methods for triangle strip adjacency // What about primitive restart ? @@ -328,6 +310,17 @@ void traverseTriangleAdjacency(Vertex *vertices, } } +template +QVector4D readCoordinate(const BufferInfo &info, Coordinate *coordinates, uint index) +{ + const uint stride = info.byteStride / sizeof(Coordinate); + QVector4D ret(0, 0, 0, 1.0f); + coordinates += stride * index; + for (uint e = 0; e < info.dataSize; ++e) + ret[e] = coordinates[e]; + return ret; +} + template struct EnumToType; template <> struct EnumToType { typedef const char type; }; @@ -370,6 +363,31 @@ void processBuffer(const BufferInfo &info, Func &f) } } +QVector4D readBuffer(const BufferInfo &info, uint index) +{ + switch (info.type) { + case QAttribute::Byte: + return readCoordinate(info, castToType(info.data, info.byteOffset), index); + case QAttribute::UnsignedByte: + return readCoordinate(info, castToType(info.data, info.byteOffset), index); + case QAttribute::Short: + return readCoordinate(info, castToType(info.data, info.byteOffset), index); + case QAttribute::UnsignedShort: + return readCoordinate(info, castToType(info.data, info.byteOffset), index); + case QAttribute::Int: + return readCoordinate(info, castToType(info.data, info.byteOffset), index); + case QAttribute::UnsignedInt: + return readCoordinate(info, castToType(info.data, info.byteOffset), index); + case QAttribute::Float: + return readCoordinate(info, castToType(info.data, info.byteOffset), index); + case QAttribute::Double: + return readCoordinate(info, castToType(info.data, info.byteOffset), index); + default: + break; + } + return QVector4D(); +} + template struct IndexedVertexExecutor { @@ -530,6 +548,53 @@ void TrianglesVisitor::apply(const GeometryRenderer *renderer, const Qt3DCore::Q } } +bool CoordinateReader::setGeometry(const GeometryRenderer *renderer, const QString &attributeName) +{ + if (renderer == nullptr || renderer->instanceCount() != 1 + || !isTriangleBased(renderer->primitiveType())) { + return false; + } + + Geometry *geom = m_manager->lookupResource(renderer->geometryId()); + + if (!geom) + return false; + + Attribute *attribute = nullptr; + + const auto attrIds = geom->attributes(); + for (const Qt3DCore::QNodeId attrId : attrIds) { + attribute = m_manager->lookupResource(attrId); + if (attribute){ + if (attribute->name() == attributeName + || (attributeName == QStringLiteral("default") + && attribute->name() == QAttribute::defaultTextureCoordinateAttributeName())) { + break; + } + } + attribute = nullptr; + } + + if (!attribute) + return false; + + m_attribute = attribute; + m_buffer = m_manager->lookupResource(attribute->bufferId()); + + m_bufferInfo.data = m_buffer->data(); + m_bufferInfo.type = m_attribute->vertexBaseType(); + m_bufferInfo.byteOffset = m_attribute->byteOffset(); + m_bufferInfo.byteStride = m_attribute->byteStride(); + m_bufferInfo.dataSize = m_attribute->vertexSize(); + m_bufferInfo.count = m_attribute->count(); + return true; +} + +QVector4D CoordinateReader::getCoordinate(uint vertexIndex) +{ + return readBuffer(m_bufferInfo, vertexIndex); +} + } // namespace Render } // namespace Qt3DRender diff --git a/src/render/backend/trianglesvisitor_p.h b/src/render/backend/trianglesvisitor_p.h index 5f7cff9c0..a0fa89efb 100644 --- a/src/render/backend/trianglesvisitor_p.h +++ b/src/render/backend/trianglesvisitor_p.h @@ -52,6 +52,7 @@ // #include +#include QT_BEGIN_NAMESPACE @@ -65,6 +66,26 @@ namespace Render { class GeometryRenderer; class NodeManagers; +class Attribute; +class Buffer; + +struct BufferInfo +{ + BufferInfo() + : type(QAttribute::VertexBaseType::Float) + , dataSize(0) + , count(0) + , byteStride(0) + , byteOffset(0) + {} + + QByteArray data; + QAttribute::VertexBaseType type; + uint dataSize; + uint count; + uint byteStride; + uint byteOffset; +}; class Q_AUTOTEST_EXPORT TrianglesVisitor { @@ -84,6 +105,27 @@ protected: Qt3DCore::QNodeId m_nodeId; }; +class Q_AUTOTEST_EXPORT CoordinateReader +{ +public: + explicit CoordinateReader(NodeManagers *manager) + : m_manager(manager) + , m_attribute(nullptr) + , m_buffer(nullptr) + { + } + + bool setGeometry(const GeometryRenderer *renderer, const QString &attributeName); + + QVector4D getCoordinate(uint vertexIndex); + +protected: + NodeManagers *m_manager; + Attribute *m_attribute; + Buffer *m_buffer; + BufferInfo m_bufferInfo; +}; + } // namespace Render } // namespace Qt3DRender -- cgit v1.2.3 From fc142f59a364c47818356fc6bf13471fec49ea99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Tue, 25 Oct 2016 10:12:58 +0300 Subject: Retrieve uvw parameters when picking MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The uvw can be used to interpolate coordinates on the intersection point. Change-Id: I725ef572a78ad7766000270622f3ac85edd11071 Reviewed-by: Tomi Korpipää Reviewed-by: Sean Harmer --- src/render/backend/triangleboundingvolume.cpp | 17 ++++++++++------- src/render/backend/triangleboundingvolume_p.h | 2 +- src/render/frontend/sphere.cpp | 3 ++- src/render/frontend/sphere_p.h | 2 +- src/render/jobs/pickboundingvolumeutils.cpp | 1 + .../raycasting/qabstractcollisionqueryservice.cpp | 6 ++++-- .../raycasting/qabstractcollisionqueryservice_p.h | 3 ++- src/render/raycasting/qboundingvolume_p.h | 3 ++- src/render/raycasting/qcollisionqueryresult.cpp | 5 +++-- src/render/raycasting/qcollisionqueryresult_p.h | 7 +++++-- src/render/raycasting/qraycastingservice.cpp | 8 +++++--- 11 files changed, 36 insertions(+), 21 deletions(-) diff --git a/src/render/backend/triangleboundingvolume.cpp b/src/render/backend/triangleboundingvolume.cpp index deef28a44..773bdd309 100644 --- a/src/render/backend/triangleboundingvolume.cpp +++ b/src/render/backend/triangleboundingvolume.cpp @@ -112,15 +112,18 @@ Qt3DCore::QNodeId TriangleBoundingVolume::id() const return m_id; } -bool TriangleBoundingVolume::intersects(const QRay3D &ray, QVector3D *q) const +bool TriangleBoundingVolume::intersects(const QRay3D &ray, QVector3D *q, QVector3D *uvw) const { float t = 0.0f; - QVector3D uvw; - const bool intersected = intersectsSegmentTriangle(ray, m_c, m_b, m_a, uvw, t); - - if (intersected && q != nullptr) - *q = ray.point(t * ray.distance()); - + QVector3D uvwr; + const float intersected = intersectsSegmentTriangle(ray, m_c, m_b, m_a, uvwr, t); + + if (intersected) { + if (q != nullptr) + *q = ray.point(t); + if (uvw != nullptr) + *uvw = uvwr; + } return intersected; } diff --git a/src/render/backend/triangleboundingvolume_p.h b/src/render/backend/triangleboundingvolume_p.h index cc394041b..7ee4e5384 100644 --- a/src/render/backend/triangleboundingvolume_p.h +++ b/src/render/backend/triangleboundingvolume_p.h @@ -78,7 +78,7 @@ public: const QVector3D &c); Qt3DCore::QNodeId id() const Q_DECL_FINAL; - bool intersects(const QRay3D &ray, QVector3D *q) const Q_DECL_FINAL; + bool intersects(const QRay3D &ray, QVector3D *q, QVector3D *uvw) const Q_DECL_FINAL; Type type() const Q_DECL_FINAL; QVector3D a() const; diff --git a/src/render/frontend/sphere.cpp b/src/render/frontend/sphere.cpp index 60e414c2e..6684d94cb 100644 --- a/src/render/frontend/sphere.cpp +++ b/src/render/frontend/sphere.cpp @@ -223,8 +223,9 @@ Qt3DCore::QNodeId Sphere::id() const return m_id; } -bool Sphere::intersects(const QRay3D &ray, QVector3D *q) const +bool Sphere::intersects(const QRay3D &ray, QVector3D *q, QVector3D *uvw) const { + Q_UNUSED(uvw); return intersectRaySphere(ray, *this, q); } diff --git a/src/render/frontend/sphere_p.h b/src/render/frontend/sphere_p.h index a30a12741..d5487386c 100644 --- a/src/render/frontend/sphere_p.h +++ b/src/render/frontend/sphere_p.h @@ -106,7 +106,7 @@ public: } Qt3DCore::QNodeId id() const Q_DECL_FINAL; - bool intersects(const QRay3D &ray, QVector3D *q) const Q_DECL_FINAL; + bool intersects(const QRay3D &ray, QVector3D *q, QVector3D *uvw = nullptr) const Q_DECL_FINAL; Type type() const Q_DECL_FINAL; static Sphere fromPoints(const QVector &points); diff --git a/src/render/jobs/pickboundingvolumeutils.cpp b/src/render/jobs/pickboundingvolumeutils.cpp index d0618866b..230667b7b 100644 --- a/src/render/jobs/pickboundingvolumeutils.cpp +++ b/src/render/jobs/pickboundingvolumeutils.cpp @@ -172,6 +172,7 @@ bool CollisionVisitor::intersectsSegmentTriangle(uint andx, const QVector3D &a, queryResult.m_vertexIndex[0] = andx; queryResult.m_vertexIndex[1] = bndx; queryResult.m_vertexIndex[2] = cndx; + queryResult.m_uvw = uvw; queryResult.m_intersection = m_ray.point(t * m_ray.distance()); queryResult.m_distance = m_ray.projectedDistance(queryResult.m_intersection); hits.push_back(queryResult); diff --git a/src/render/raycasting/qabstractcollisionqueryservice.cpp b/src/render/raycasting/qabstractcollisionqueryservice.cpp index 4c59b6aab..32878ebd0 100644 --- a/src/render/raycasting/qabstractcollisionqueryservice.cpp +++ b/src/render/raycasting/qabstractcollisionqueryservice.cpp @@ -60,9 +60,11 @@ void QAbstractCollisionQueryService::setResultHandle(QCollisionQueryResult &resu result.d_func()->setHandle(handle); } -void QAbstractCollisionQueryService::addEntityHit(QCollisionQueryResult &result, Qt3DCore::QNodeId entity, const QVector3D& intersection, float distance) +void QAbstractCollisionQueryService::addEntityHit(QCollisionQueryResult &result, Qt3DCore::QNodeId entity, + const QVector3D& intersection, float distance, + const QVector3D& uvw) { - result.d_func()->addEntityHit(entity, intersection, distance); + result.d_func()->addEntityHit(entity, intersection, distance, uvw); } } // Qt3DRender diff --git a/src/render/raycasting/qabstractcollisionqueryservice_p.h b/src/render/raycasting/qabstractcollisionqueryservice_p.h index d26eacb98..f6f3bf334 100644 --- a/src/render/raycasting/qabstractcollisionqueryservice_p.h +++ b/src/render/raycasting/qabstractcollisionqueryservice_p.h @@ -95,7 +95,8 @@ protected: QAbstractCollisionQueryService(QAbstractCollisionQueryServicePrivate &dd); void setResultHandle(QCollisionQueryResult &result, const QQueryHandle &handle); - void addEntityHit(QCollisionQueryResult &result, Qt3DCore::QNodeId entity, const QVector3D &intersection, float distance); + void addEntityHit(QCollisionQueryResult &result, Qt3DCore::QNodeId entity, const QVector3D &intersection, + float distance, const QVector3D &uvw); private: Q_DECLARE_PRIVATE(QAbstractCollisionQueryService) diff --git a/src/render/raycasting/qboundingvolume_p.h b/src/render/raycasting/qboundingvolume_p.h index a69530246..0e5f6e45d 100644 --- a/src/render/raycasting/qboundingvolume_p.h +++ b/src/render/raycasting/qboundingvolume_p.h @@ -70,7 +70,8 @@ public: }; virtual Qt3DCore::QNodeId id() const = 0; - virtual bool intersects(const QRay3D &ray, QVector3D *q = nullptr) const = 0; + virtual bool intersects(const QRay3D &ray, QVector3D *q = nullptr, + QVector3D *uvw = nullptr) const = 0; virtual Type type() const = 0; }; diff --git a/src/render/raycasting/qcollisionqueryresult.cpp b/src/render/raycasting/qcollisionqueryresult.cpp index e4a6afa69..ad150d9a2 100644 --- a/src/render/raycasting/qcollisionqueryresult.cpp +++ b/src/render/raycasting/qcollisionqueryresult.cpp @@ -55,9 +55,10 @@ QCollisionQueryResultPrivate::QCollisionQueryResultPrivate(const QCollisionQuery { } -void QCollisionQueryResultPrivate::addEntityHit(Qt3DCore::QNodeId entity, const QVector3D& intersection, float distance) +void QCollisionQueryResultPrivate::addEntityHit(Qt3DCore::QNodeId entity, const QVector3D& intersection, + float distance, const QVector3D& uvw) { - m_hits.append(QCollisionQueryResult::Hit(entity, intersection, distance)); + m_hits.append(QCollisionQueryResult::Hit(entity, intersection, distance, uvw)); } void QCollisionQueryResultPrivate::setHandle(const QQueryHandle &handle) diff --git a/src/render/raycasting/qcollisionqueryresult_p.h b/src/render/raycasting/qcollisionqueryresult_p.h index 81bca98b6..fe96bfe48 100644 --- a/src/render/raycasting/qcollisionqueryresult_p.h +++ b/src/render/raycasting/qcollisionqueryresult_p.h @@ -69,12 +69,14 @@ class QT3DRENDERSHARED_EXPORT QCollisionQueryResult public: struct Hit { Hit() : m_distance(-1.f), m_triangleIndex(0) { m_vertexIndex[0] = m_vertexIndex[1] = m_vertexIndex[2] = 0; } - Hit(Qt3DCore::QNodeId entity, const QVector3D &intersection, float distance) : m_entityId(entity), m_intersection(intersection), m_distance(distance) { } + Hit(Qt3DCore::QNodeId entity, const QVector3D &intersection, float distance, const QVector3D &uvw) + : m_entityId(entity), m_intersection(intersection), m_distance(distance), m_uvw(uvw) { } Qt3DCore::QNodeId m_entityId; QVector3D m_intersection; float m_distance; uint m_triangleIndex; uint m_vertexIndex[3]; + QVector3D m_uvw; }; QCollisionQueryResult(); @@ -122,7 +124,8 @@ public: explicit QCollisionQueryResultPrivate(const QCollisionQueryResultPrivate ©); void setHandle(const QQueryHandle &handle); - void addEntityHit(Qt3DCore::QNodeId entity, const QVector3D& intersection, float distance); + void addEntityHit(Qt3DCore::QNodeId entity, const QVector3D& intersection, float distance, + const QVector3D& uvw); QQueryHandle m_handle; QVector m_hits; diff --git a/src/render/raycasting/qraycastingservice.cpp b/src/render/raycasting/qraycastingservice.cpp index 6dfb1c57a..9f3a52380 100644 --- a/src/render/raycasting/qraycastingservice.cpp +++ b/src/render/raycasting/qraycastingservice.cpp @@ -67,6 +67,7 @@ struct Hit float distance; Qt3DCore::QNodeId id; QVector3D intersection; + QVector3D uvw; }; bool compareHitsDistance(const Hit &a, const Hit &b) @@ -77,7 +78,7 @@ bool compareHitsDistance(const Hit &a, const Hit &b) Hit volumeRayIntersection(const QBoundingVolume *volume, const QRay3D &ray) { Hit hit; - if ((hit.intersects = volume->intersects(ray, &hit.intersection))) { + if ((hit.intersects = volume->intersects(ray, &hit.intersection, &hit.uvw))) { hit.distance = ray.projectedDistance(hit.intersection); hit.id = volume->id(); } @@ -133,12 +134,12 @@ QCollisionQueryResult QRayCastingServicePrivate::collides(const QRay3D &ray, QBo if (mode == QAbstractCollisionQueryService::FirstHit) { Hit firstHit = QtConcurrent::blockingMappedReduced(volumes, gathererFunctor, reduceToFirstHit); if (firstHit.intersects) - q->addEntityHit(result, firstHit.id, firstHit.intersection, firstHit.distance); + q->addEntityHit(result, firstHit.id, firstHit.intersection, firstHit.distance, firstHit.uvw); } else { QVector hits = QtConcurrent::blockingMappedReduced >(volumes, gathererFunctor, reduceToAllHits); std::sort(hits.begin(), hits.end(), compareHitsDistance); for (const Hit &hit : qAsConst(hits)) - q->addEntityHit(result, hit.id, hit.intersection, hit.distance); + q->addEntityHit(result, hit.id, hit.intersection, hit.distance, hit.uvw); } return result; @@ -153,6 +154,7 @@ QCollisionQueryResult::Hit QRayCastingServicePrivate::collides(const QRay3D &ray result.m_distance = hit.distance; result.m_entityId = hit.id; result.m_intersection = hit.intersection; + result.m_uvw = hit.uvw; } return result; } -- cgit v1.2.3 From a60d19c1dba26debc3037c94b3b2c4e89716479d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Fri, 21 Oct 2016 12:04:25 +0300 Subject: Add the autotests for renderqmltotexture frontend node MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I072c9a86d7730f6c494cd1e7474f84bc76fbb28f Reviewed-by: Tomi Korpipää Reviewed-by: Sean Harmer --- .../qrenderqmltotexture/qrenderqmltotexture.pro | 11 + .../tst_qrenderqmltotexture.cpp | 284 +++++++++++++++++++++ 2 files changed, 295 insertions(+) create mode 100644 tests/auto/render/qrenderqmltotexture/qrenderqmltotexture.pro create mode 100644 tests/auto/render/qrenderqmltotexture/tst_qrenderqmltotexture.cpp diff --git a/tests/auto/render/qrenderqmltotexture/qrenderqmltotexture.pro b/tests/auto/render/qrenderqmltotexture/qrenderqmltotexture.pro new file mode 100644 index 000000000..8b2840929 --- /dev/null +++ b/tests/auto/render/qrenderqmltotexture/qrenderqmltotexture.pro @@ -0,0 +1,11 @@ +TEMPLATE = app + +TARGET = qrenderqmltotexture + +QT += 3dcore 3dcore-private 3drender 3drender-private testlib + +CONFIG += testcase + +SOURCES += tst_qrenderqmltotexture.cpp + +include(../commons/commons.pri) diff --git a/tests/auto/render/qrenderqmltotexture/tst_qrenderqmltotexture.cpp b/tests/auto/render/qrenderqmltotexture/tst_qrenderqmltotexture.cpp new file mode 100644 index 000000000..b337306be --- /dev/null +++ b/tests/auto/render/qrenderqmltotexture/tst_qrenderqmltotexture.cpp @@ -0,0 +1,284 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $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 +#include +#include +#include +#include +#include +#include +#include +#include +#include "testpostmanarbiter.h" + +class tst_QRenderQmlToTexture : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + + void checkDefaultConstruction() + { + // GIVEN + Qt3DRender::QRenderQmlToTexture renderQmlToTexture; + + // THEN + QCOMPARE(renderQmlToTexture.texture(), nullptr); + QCOMPARE(renderQmlToTexture.source(), QUrl(QStringLiteral(""))); + QCOMPARE(renderQmlToTexture.renderOnce(), false); + QCOMPARE(renderQmlToTexture.loaded(), false); + } + + void checkPropertyChanges() + { + // GIVEN + Qt3DRender::QRenderQmlToTexture renderQmlToTexture; + QScopedPointer texture(new Qt3DRender::QTexture2D()); + + { + // WHEN + QSignalSpy spy(&renderQmlToTexture, SIGNAL(textureChanged(Qt3DRender::QAbstractTexture *))); + Qt3DRender::QAbstractTexture * newValue = texture.data(); + renderQmlToTexture.setTexture(newValue); + + // THEN + QVERIFY(spy.isValid()); + QCOMPARE(renderQmlToTexture.texture(), newValue); + QCOMPARE(spy.count(), 1); + + // WHEN + spy.clear(); + renderQmlToTexture.setTexture(newValue); + + // THEN + QCOMPARE(renderQmlToTexture.texture(), newValue); + QCOMPARE(spy.count(), 0); + } + { + // WHEN + QSignalSpy spy(&renderQmlToTexture, SIGNAL(sourceChanged(QUrl))); + const QUrl newValue = QUrl(QStringLiteral("qrc://source.qml")); + renderQmlToTexture.setSource(newValue); + + // THEN + QVERIFY(spy.isValid()); + QCOMPARE(renderQmlToTexture.source(), newValue); + QCOMPARE(spy.count(), 1); + + // WHEN + spy.clear(); + renderQmlToTexture.setSource(newValue); + + // THEN + QCOMPARE(renderQmlToTexture.source(), newValue); + QCOMPARE(spy.count(), 0); + } + { + // WHEN + QSignalSpy spy(&renderQmlToTexture, SIGNAL(renderOnceChanged(bool))); + const bool newValue = true; + renderQmlToTexture.setRenderOnce(newValue); + + // THEN + QVERIFY(spy.isValid()); + QCOMPARE(renderQmlToTexture.renderOnce(), newValue); + QCOMPARE(spy.count(), 1); + + // WHEN + spy.clear(); + renderQmlToTexture.setRenderOnce(newValue); + + // THEN + QCOMPARE(renderQmlToTexture.renderOnce(), newValue); + QCOMPARE(spy.count(), 0); + } + } + + void checkCreationData() + { + // GIVEN + Qt3DRender::QRenderQmlToTexture renderQmlToTexture; + QScopedPointer texture(new Qt3DRender::QTexture2D()); + + renderQmlToTexture.setTexture(texture.data()); + renderQmlToTexture.setSource(QUrl(QStringLiteral("qrc://source.qml"))); + renderQmlToTexture.setRenderOnce(true); + + // WHEN + QVector creationChanges; + + { + Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&renderQmlToTexture); + creationChanges = creationChangeGenerator.creationChanges(); + } + + // THEN + { + QCOMPARE(creationChanges.size(), 1); + + const auto creationChangeData = qSharedPointerCast>(creationChanges.first()); + const Qt3DRender::QRenderQmlToTextureData cloneData = creationChangeData->data; + + QCOMPARE(renderQmlToTexture.texture()->id(), cloneData.textureId); + QCOMPARE(renderQmlToTexture.renderOnce(), cloneData.renderOnce); + QCOMPARE(renderQmlToTexture.id(), creationChangeData->subjectId()); + QCOMPARE(renderQmlToTexture.isEnabled(), true); + QCOMPARE(renderQmlToTexture.isEnabled(), creationChangeData->isNodeEnabled()); + QCOMPARE(renderQmlToTexture.metaObject(), creationChangeData->metaObject()); + } + + // WHEN + renderQmlToTexture.setEnabled(false); + + { + Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&renderQmlToTexture); + creationChanges = creationChangeGenerator.creationChanges(); + } + + // THEN + { + QCOMPARE(creationChanges.size(), 1); + + const auto creationChangeData = qSharedPointerCast>(creationChanges.first()); + const Qt3DRender::QRenderQmlToTextureData cloneData = creationChangeData->data; + + QCOMPARE(renderQmlToTexture.texture()->id(), cloneData.textureId); + QCOMPARE(renderQmlToTexture.renderOnce(), cloneData.renderOnce); + QCOMPARE(renderQmlToTexture.id(), creationChangeData->subjectId()); + QCOMPARE(renderQmlToTexture.isEnabled(), false); + QCOMPARE(renderQmlToTexture.isEnabled(), creationChangeData->isNodeEnabled()); + QCOMPARE(renderQmlToTexture.metaObject(), creationChangeData->metaObject()); + } + } + + void checkTextureUpdate() + { + // GIVEN + TestArbiter arbiter; + Qt3DRender::QRenderQmlToTexture renderQmlToTexture; + arbiter.setArbiterOnNode(&renderQmlToTexture); + QScopedPointer texture(new Qt3DRender::QTexture2D()); + + { + // WHEN + renderQmlToTexture.setTexture(texture.data()); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 1); + auto change = arbiter.events.first().staticCast(); + QCOMPARE(change->propertyName(), "texture"); + QCOMPARE(change->value().value(), renderQmlToTexture.texture()); + QCOMPARE(change->type(), Qt3DCore::PropertyUpdated); + + arbiter.events.clear(); + } + + { + // WHEN + renderQmlToTexture.setTexture(texture.data()); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 0); + } + + } + + void checkSourceUpdate() + { + // GIVEN + TestArbiter arbiter; + Qt3DRender::QRenderQmlToTexture renderQmlToTexture; + arbiter.setArbiterOnNode(&renderQmlToTexture); + + { + // WHEN + renderQmlToTexture.setSource(QUrl(QStringLiteral("qrc://source.qml"))); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 1); + auto change = arbiter.events.first().staticCast(); + QCOMPARE(change->propertyName(), "source"); + QCOMPARE(change->value().value(), renderQmlToTexture.source()); + QCOMPARE(change->type(), Qt3DCore::PropertyUpdated); + + arbiter.events.clear(); + } + + { + // WHEN + renderQmlToTexture.setSource(QUrl(QStringLiteral("qrc://source.qml"))); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 0); + } + + } + + void checkRenderOnceUpdate() + { + // GIVEN + TestArbiter arbiter; + Qt3DRender::QRenderQmlToTexture renderQmlToTexture; + arbiter.setArbiterOnNode(&renderQmlToTexture); + + { + // WHEN + renderQmlToTexture.setRenderOnce(true); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 1); + auto change = arbiter.events.first().staticCast(); + QCOMPARE(change->propertyName(), "renderOnce"); + QCOMPARE(change->value().value(), renderQmlToTexture.renderOnce()); + QCOMPARE(change->type(), Qt3DCore::PropertyUpdated); + + arbiter.events.clear(); + } + + { + // WHEN + renderQmlToTexture.setRenderOnce(true); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 0); + } + + } + +}; + +QTEST_MAIN(tst_QRenderQmlToTexture) + +#include "tst_qrenderqmltotexture.moc" -- cgit v1.2.3 From 70d10675b5cc5e1a42a6cb5a4e2da5a31e198a18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Fri, 21 Oct 2016 12:05:30 +0300 Subject: Add autotests for renderqmltotexture backend node MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I68871b18238eb5aa3c9387e8b5130d848af3ae79 Reviewed-by: Tomi Korpipää Reviewed-by: Sean Harmer --- .../renderqmltotexture/renderqmltotexture.pro | 12 ++ .../renderqmltotexture/tst_renderqmltotexture.cpp | 150 +++++++++++++++++++++ 2 files changed, 162 insertions(+) create mode 100644 tests/auto/render/renderqmltotexture/renderqmltotexture.pro create mode 100644 tests/auto/render/renderqmltotexture/tst_renderqmltotexture.cpp diff --git a/tests/auto/render/renderqmltotexture/renderqmltotexture.pro b/tests/auto/render/renderqmltotexture/renderqmltotexture.pro new file mode 100644 index 000000000..2c0f56391 --- /dev/null +++ b/tests/auto/render/renderqmltotexture/renderqmltotexture.pro @@ -0,0 +1,12 @@ +TEMPLATE = app + +TARGET = tst_renderqmltotexture + +QT += 3dcore 3dcore-private 3drender 3drender-private testlib + +CONFIG += testcase + +SOURCES += tst_renderqmltotexture.cpp + +include(../../core/common/common.pri) +include(../commons/commons.pri) diff --git a/tests/auto/render/renderqmltotexture/tst_renderqmltotexture.cpp b/tests/auto/render/renderqmltotexture/tst_renderqmltotexture.cpp new file mode 100644 index 000000000..b6148c514 --- /dev/null +++ b/tests/auto/render/renderqmltotexture/tst_renderqmltotexture.cpp @@ -0,0 +1,150 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $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 +#include +#include +#include +#include +#include +#include "testrenderer.h" + +class tst_RenderQmlToTexture : public Qt3DCore::QBackendNodeTester +{ + Q_OBJECT + +private Q_SLOTS: + + void checkInitialState() + { + // GIVEN + Qt3DRender::Render::RenderQmlToTexture backendRenderQmlToTexture; + + // THEN + QCOMPARE(backendRenderQmlToTexture.isEnabled(), false); + QVERIFY(backendRenderQmlToTexture.peerId().isNull()); + QCOMPARE(backendRenderQmlToTexture.m_context, nullptr); + QCOMPARE(backendRenderQmlToTexture.m_graphicsContext, nullptr); + QCOMPARE(backendRenderQmlToTexture.m_renderThread, nullptr); + QCOMPARE(backendRenderQmlToTexture.m_textureId, Qt3DCore::QNodeId()); + QCOMPARE(backendRenderQmlToTexture.m_texture, nullptr); + QCOMPARE(backendRenderQmlToTexture.m_initialized, false); + QCOMPARE(backendRenderQmlToTexture.m_renderInitialized, false); + QCOMPARE(backendRenderQmlToTexture.m_renderOnce, false); + } + + void checkInitializeFromPeer() + { + // GIVEN + Qt3DRender::QRenderQmlToTexture renderQmlToTexture; + + { + // WHEN + Qt3DRender::Render::RenderQmlToTexture backendRenderQmlToTexture; + simulateInitialization(&renderQmlToTexture, &backendRenderQmlToTexture); + + // THEN + QCOMPARE(backendRenderQmlToTexture.isEnabled(), true); + QCOMPARE(backendRenderQmlToTexture.peerId(), renderQmlToTexture.id()); + QCOMPARE(backendRenderQmlToTexture.m_textureId, Qt3DCore::QNodeId()); + QCOMPARE(backendRenderQmlToTexture.m_sharedObject.data(), nullptr); + QCOMPARE(backendRenderQmlToTexture.m_renderOnce, false); + } + { + // WHEN + Qt3DRender::Render::RenderQmlToTexture backendRenderQmlToTexture; + renderQmlToTexture.setEnabled(false); + simulateInitialization(&renderQmlToTexture, &backendRenderQmlToTexture); + + // THEN + QCOMPARE(backendRenderQmlToTexture.peerId(), renderQmlToTexture.id()); + QCOMPARE(backendRenderQmlToTexture.isEnabled(), false); + } + } + + void checkSceneChangeEvents() + { + // GIVEN + Qt3DRender::Render::RenderQmlToTexture backendRenderQmlToTexture; + TestRenderer renderer; + QScopedPointer texture(new Qt3DRender::QTexture2D()); + backendRenderQmlToTexture.setRenderer(&renderer); + + { + // WHEN + const bool newValue = false; + const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId()); + change->setPropertyName("enabled"); + change->setValue(newValue); + backendRenderQmlToTexture.sceneChangeEvent(change); + + // THEN + QCOMPARE(backendRenderQmlToTexture.isEnabled(), newValue); + } + { + // WHEN + const Qt3DCore::QNodeId newValue = texture.data()->id(); + const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId()); + change->setPropertyName("textureId"); + change->setValue(QVariant::fromValue(newValue)); + backendRenderQmlToTexture.sceneChangeEvent(change); + + // THEN + QCOMPARE(backendRenderQmlToTexture.m_textureId, newValue); + } + { + // WHEN + const QSharedPointer newValue + = QSharedPointer(new Qt3DRender::RenderQmlToTextureSharedObject(nullptr)); + const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId()); + change->setPropertyName("sharedObject"); + change->setValue(QVariant::fromValue(newValue)); + backendRenderQmlToTexture.sceneChangeEvent(change); + + // THEN + QCOMPARE(backendRenderQmlToTexture.m_sharedObject, newValue); + QCOMPARE(backendRenderQmlToTexture.m_sharedObject.data(), newValue.data()); + } + { + // WHEN + const bool newValue = true; + const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId()); + change->setPropertyName("renderOnce"); + change->setValue(QVariant::fromValue(newValue)); + backendRenderQmlToTexture.sceneChangeEvent(change); + + // THEN + QCOMPARE(backendRenderQmlToTexture.m_renderOnce, newValue); + } + } + +}; + +QTEST_MAIN(tst_RenderQmlToTexture) + +#include "tst_renderqmltotexture.moc" -- cgit v1.2.3 From 6b66636edab861a5eafa576305efd859f0d58395 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Mon, 24 Oct 2016 16:15:29 +0300 Subject: Add unit tests for the QEventForward frontend node MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I84c3d8e4bcca14f4aa0c5bde34d3f2e3c76ebaee Reviewed-by: Tomi Korpipää Reviewed-by: Sean Harmer --- tests/auto/render/qeventforward/qeventforward.pro | 12 + .../render/qeventforward/tst_qeventforward.cpp | 406 +++++++++++++++++++++ tests/auto/render/render.pro | 3 +- 3 files changed, 420 insertions(+), 1 deletion(-) create mode 100644 tests/auto/render/qeventforward/qeventforward.pro create mode 100644 tests/auto/render/qeventforward/tst_qeventforward.cpp diff --git a/tests/auto/render/qeventforward/qeventforward.pro b/tests/auto/render/qeventforward/qeventforward.pro new file mode 100644 index 000000000..2479b038c --- /dev/null +++ b/tests/auto/render/qeventforward/qeventforward.pro @@ -0,0 +1,12 @@ +TEMPLATE = app + +TARGET = tst_qeventforward + +QT += 3dcore 3dcore-private 3drender 3drender-private testlib + +CONFIG += testcase + +SOURCES += tst_qeventforward.cpp + +include(../../core/common/common.pri) +include(../commons/commons.pri) diff --git a/tests/auto/render/qeventforward/tst_qeventforward.cpp b/tests/auto/render/qeventforward/tst_qeventforward.cpp new file mode 100644 index 000000000..87ba114f2 --- /dev/null +++ b/tests/auto/render/qeventforward/tst_qeventforward.cpp @@ -0,0 +1,406 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $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 +#include +#include +#include +#include +#include +#include +#include +#include +#include "testpostmanarbiter.h" + +class tst_QEventForward : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + + void checkDefaultConstruction() + { + // GIVEN + Qt3DRender::QEventForward eventForward; + + // THEN + QCOMPARE(eventForward.target(), nullptr); + QCOMPARE(eventForward.forwardMouseEvents(), true); + QCOMPARE(eventForward.forwardKeyboardEvents(), false); + QCOMPARE(eventForward.coordinateTransform(), QMatrix4x4()); + QCOMPARE(eventForward.coordinateAttribute(), QStringLiteral("default")); + } + + void checkPropertyChanges() + { + // GIVEN + Qt3DRender::QEventForward eventForward; + + { + // WHEN + QScopedPointer obj(new QObject()); + QSignalSpy spy(&eventForward, SIGNAL(targetChanged(QObject*))); + QObject* newValue = obj.data(); + eventForward.setTarget(newValue); + + // THEN + QVERIFY(spy.isValid()); + QCOMPARE(eventForward.target(), newValue); + QCOMPARE(spy.count(), 1); + + // WHEN + spy.clear(); + eventForward.setTarget(newValue); + + // THEN + QCOMPARE(eventForward.target(), newValue); + QCOMPARE(spy.count(), 0); + } + { + // WHEN + QSignalSpy spy(&eventForward, SIGNAL(forwardMouseEventsChanged(bool))); + const bool newValue = false; + eventForward.setForwardMouseEvents(newValue); + + // THEN + QVERIFY(spy.isValid()); + QCOMPARE(eventForward.forwardMouseEvents(), newValue); + QCOMPARE(spy.count(), 1); + + // WHEN + spy.clear(); + eventForward.setForwardMouseEvents(newValue); + + // THEN + QCOMPARE(eventForward.forwardMouseEvents(), newValue); + QCOMPARE(spy.count(), 0); + } + { + // WHEN + QSignalSpy spy(&eventForward, SIGNAL(forwardKeyboardEventsChanged(bool))); + const bool newValue = true; + eventForward.setForwardKeyboardEvents(newValue); + + // THEN + QVERIFY(spy.isValid()); + QCOMPARE(eventForward.forwardKeyboardEvents(), newValue); + QCOMPARE(spy.count(), 1); + + // WHEN + spy.clear(); + eventForward.setForwardKeyboardEvents(newValue); + + // THEN + QCOMPARE(eventForward.forwardKeyboardEvents(), newValue); + QCOMPARE(spy.count(), 0); + } + { + // WHEN + QSignalSpy spy(&eventForward, SIGNAL(coordinateTransformChanged(QMatrix4x4))); + QMatrix4x4 newValue; + newValue.scale(3.0f); + eventForward.setCoordinateTransform(newValue); + + // THEN + QVERIFY(spy.isValid()); + QCOMPARE(eventForward.coordinateTransform(), newValue); + QCOMPARE(spy.count(), 1); + + // WHEN + spy.clear(); + eventForward.setCoordinateTransform(newValue); + + // THEN + QCOMPARE(eventForward.coordinateTransform(), newValue); + QCOMPARE(spy.count(), 0); + } + { + // WHEN + QSignalSpy spy(&eventForward, SIGNAL(coordinateAttributeChanged(QString))); + const QString newValue = Qt3DRender::QAttribute::defaultColorAttributeName(); + eventForward.setCoordinateAttribute(newValue); + + // THEN + QVERIFY(spy.isValid()); + QCOMPARE(eventForward.coordinateAttribute(), newValue); + QCOMPARE(spy.count(), 1); + + // WHEN + spy.clear(); + eventForward.setCoordinateAttribute(newValue); + + // THEN + QCOMPARE(eventForward.coordinateAttribute(), newValue); + QCOMPARE(spy.count(), 0); + } + } + + void checkCreationData() + { + // GIVEN + Qt3DRender::QEventForward eventForward; + QScopedPointer obj(new QObject()); + QMatrix4x4 transform; + transform.translate(1.0f, 2.0f, 3.0f); + + eventForward.setTarget(obj.data()); + eventForward.setForwardMouseEvents(true); + eventForward.setForwardKeyboardEvents(true); + eventForward.setCoordinateTransform(transform); + eventForward.setCoordinateAttribute(QStringLiteral("position")); + + // WHEN + QVector creationChanges; + + { + Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&eventForward); + creationChanges = creationChangeGenerator.creationChanges(); + } + + // THEN + { + QCOMPARE(creationChanges.size(), 1); + + const auto creationChangeData + = qSharedPointerCast>(creationChanges.first()); + const Qt3DRender::QEventForwardData cloneData = creationChangeData->data; + + QCOMPARE(eventForward.target(), cloneData.target); + QCOMPARE(eventForward.forwardMouseEvents(), cloneData.forwardMouseEvents); + QCOMPARE(eventForward.forwardKeyboardEvents(), cloneData.forwardKeyboardEvents); + QCOMPARE(eventForward.coordinateTransform(), cloneData.coordinateTransform); + QCOMPARE(eventForward.coordinateAttribute(), cloneData.coordinateAttribute); + QCOMPARE(eventForward.id(), creationChangeData->subjectId()); + QCOMPARE(eventForward.isEnabled(), true); + QCOMPARE(eventForward.isEnabled(), creationChangeData->isNodeEnabled()); + QCOMPARE(eventForward.metaObject(), creationChangeData->metaObject()); + } + + // WHEN + eventForward.setEnabled(false); + + { + Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&eventForward); + creationChanges = creationChangeGenerator.creationChanges(); + } + + // THEN + { + QCOMPARE(creationChanges.size(), 1); + + const auto creationChangeData + = qSharedPointerCast>(creationChanges.first()); + const Qt3DRender::QEventForwardData cloneData = creationChangeData->data; + + QCOMPARE(eventForward.target(), cloneData.target); + QCOMPARE(eventForward.forwardMouseEvents(), cloneData.forwardMouseEvents); + QCOMPARE(eventForward.forwardKeyboardEvents(), cloneData.forwardKeyboardEvents); + QCOMPARE(eventForward.coordinateTransform(), cloneData.coordinateTransform); + QCOMPARE(eventForward.coordinateAttribute(), cloneData.coordinateAttribute); + QCOMPARE(eventForward.id(), creationChangeData->subjectId()); + QCOMPARE(eventForward.isEnabled(), false); + QCOMPARE(eventForward.isEnabled(), creationChangeData->isNodeEnabled()); + QCOMPARE(eventForward.metaObject(), creationChangeData->metaObject()); + } + } + + void checkTargetUpdate() + { + // GIVEN + TestArbiter arbiter; + QScopedPointer obj(new QObject()); + Qt3DRender::QEventForward eventForward; + arbiter.setArbiterOnNode(&eventForward); + + { + // WHEN + eventForward.setTarget(obj.data()); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 1); + auto change = arbiter.events.first().staticCast(); + QCOMPARE(change->propertyName(), "target"); + QCOMPARE(change->value().value(), eventForward.target()); + QCOMPARE(change->type(), Qt3DCore::PropertyUpdated); + + arbiter.events.clear(); + } + + { + // WHEN + eventForward.setTarget(obj.data()); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 0); + } + + } + + void checkForwardMouseEventsUpdate() + { + // GIVEN + TestArbiter arbiter; + Qt3DRender::QEventForward eventForward; + arbiter.setArbiterOnNode(&eventForward); + + { + // WHEN + eventForward.setForwardMouseEvents(false); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 1); + auto change = arbiter.events.first().staticCast(); + QCOMPARE(change->propertyName(), "forwardMouseEvents"); + QCOMPARE(change->value().value(), eventForward.forwardMouseEvents()); + QCOMPARE(change->type(), Qt3DCore::PropertyUpdated); + + arbiter.events.clear(); + } + + { + // WHEN + eventForward.setForwardMouseEvents(false); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 0); + } + + } + + void checkForwardKeyboardEventsUpdate() + { + // GIVEN + TestArbiter arbiter; + Qt3DRender::QEventForward eventForward; + arbiter.setArbiterOnNode(&eventForward); + + { + // WHEN + eventForward.setForwardKeyboardEvents(true); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 1); + auto change = arbiter.events.first().staticCast(); + QCOMPARE(change->propertyName(), "forwardKeyboardEvents"); + QCOMPARE(change->value().value(), eventForward.forwardKeyboardEvents()); + QCOMPARE(change->type(), Qt3DCore::PropertyUpdated); + + arbiter.events.clear(); + } + + { + // WHEN + eventForward.setForwardKeyboardEvents(true); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 0); + } + + } + + void checkCoordinateTransformUpdate() + { + // GIVEN + TestArbiter arbiter; + QMatrix4x4 transform; + Qt3DRender::QEventForward eventForward; + arbiter.setArbiterOnNode(&eventForward); + transform.translate(2.0f, 1.0f, 4.0f); + + { + // WHEN + eventForward.setCoordinateTransform(transform); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 1); + auto change = arbiter.events.first().staticCast(); + QCOMPARE(change->propertyName(), "coordinateTransform"); + QCOMPARE(change->value().value(), eventForward.coordinateTransform()); + QCOMPARE(change->type(), Qt3DCore::PropertyUpdated); + + arbiter.events.clear(); + } + + { + // WHEN + eventForward.setCoordinateTransform(transform); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 0); + } + + } + + void checkCoordinateAttributeUpdate() + { + // GIVEN + TestArbiter arbiter; + Qt3DRender::QEventForward eventForward; + arbiter.setArbiterOnNode(&eventForward); + + { + // WHEN + eventForward.setCoordinateAttribute(QStringLiteral("normal")); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 1); + auto change = arbiter.events.first().staticCast(); + QCOMPARE(change->propertyName(), "coordinateAttribute"); + QCOMPARE(change->value().value(), eventForward.coordinateAttribute()); + QCOMPARE(change->type(), Qt3DCore::PropertyUpdated); + + arbiter.events.clear(); + } + + { + // WHEN + eventForward.setCoordinateAttribute(QStringLiteral("normal")); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 0); + } + + } + +}; + +QTEST_MAIN(tst_QEventForward) + +#include "tst_qeventforward.moc" diff --git a/tests/auto/render/render.pro b/tests/auto/render/render.pro index bb24205e4..c42d47e1f 100644 --- a/tests/auto/render/render.pro +++ b/tests/auto/render/render.pro @@ -96,7 +96,8 @@ qtConfig(private_tests) { filtercompatibletechniquejob \ rendercapture \ trianglevisitor \ - qmemorybarrier + qmemorybarrier \ + qeventforward !macos: SUBDIRS += graphicshelpergl4 } -- cgit v1.2.3 From 16e11dd7635c7d908a5fd8f97bff3ecddf63e899 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Mon, 24 Oct 2016 16:21:06 +0300 Subject: Add unit tests for the EventForward backend node MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I1b04c3a89e52923b31adbd60bc88c906c020a93a Reviewed-by: Tomi Korpipää Reviewed-by: Sean Harmer --- tests/auto/render/eventforward/eventforward.pro | 12 ++ .../auto/render/eventforward/tst_eventforward.cpp | 197 +++++++++++++++++++++ tests/auto/render/render.pro | 3 +- 3 files changed, 211 insertions(+), 1 deletion(-) create mode 100644 tests/auto/render/eventforward/eventforward.pro create mode 100644 tests/auto/render/eventforward/tst_eventforward.cpp diff --git a/tests/auto/render/eventforward/eventforward.pro b/tests/auto/render/eventforward/eventforward.pro new file mode 100644 index 000000000..22b481c77 --- /dev/null +++ b/tests/auto/render/eventforward/eventforward.pro @@ -0,0 +1,12 @@ +TEMPLATE = app + +TARGET = tst_eventforward + +QT += 3dcore 3dcore-private 3drender 3drender-private testlib + +CONFIG += testcase + +SOURCES += tst_eventforward.cpp + +include(../../core/common/common.pri) +include(../commons/commons.pri) diff --git a/tests/auto/render/eventforward/tst_eventforward.cpp b/tests/auto/render/eventforward/tst_eventforward.cpp new file mode 100644 index 000000000..9a87fc40f --- /dev/null +++ b/tests/auto/render/eventforward/tst_eventforward.cpp @@ -0,0 +1,197 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $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 +#include +#include +#include +#include +#include "qbackendnodetester.h" +#include "testrenderer.h" + +class tst_EventForward : public Qt3DCore::QBackendNodeTester +{ + Q_OBJECT + +private Q_SLOTS: + + void checkInitialState() + { + // GIVEN + Qt3DRender::Render::EventForward backendEventForward; + + // THEN + QCOMPARE(backendEventForward.isEnabled(), false); + QVERIFY(backendEventForward.peerId().isNull()); + QCOMPARE(backendEventForward.target(), nullptr); + QCOMPARE(backendEventForward.coordinateAttribute(), QStringLiteral("")); + QCOMPARE(backendEventForward.coordinateTransform(), QMatrix4x4()); + QCOMPARE(backendEventForward.forwardMouseEvents(), false); + QCOMPARE(backendEventForward.forwardKeyboardEvents(), false); + } + + void checkCleanupState() + { + // GIVEN + Qt3DRender::Render::EventForward backendEventForward; + QScopedPointer obj(new QObject()); + QMatrix4x4 transform; + transform.scale(1.0f, 2.0f, 3.0f); + + // WHEN + backendEventForward.setEnabled(true); + backendEventForward.setTarget(obj.data()); + backendEventForward.setCoordinateAttribute(QStringLiteral("default")); + backendEventForward.setCoordinateTransform(transform); + backendEventForward.setForwardMouseEvents(true); + backendEventForward.setForwardKeyboardEvents(true); + + backendEventForward.cleanup(); + + // THEN + QCOMPARE(backendEventForward.isEnabled(), false); + QCOMPARE(backendEventForward.target(), nullptr); + QCOMPARE(backendEventForward.coordinateAttribute(), QStringLiteral("")); + QCOMPARE(backendEventForward.coordinateTransform(), QMatrix4x4()); + QCOMPARE(backendEventForward.forwardMouseEvents(), false); + QCOMPARE(backendEventForward.forwardKeyboardEvents(), false); + } + + void checkInitializeFromPeer() + { + // GIVEN + Qt3DRender::QEventForward eventForward; + + { + // WHEN + Qt3DRender::Render::EventForward backendEventForward; + simulateInitialization(&eventForward, &backendEventForward); + + // THEN + QCOMPARE(backendEventForward.isEnabled(), true); + QCOMPARE(backendEventForward.peerId(), eventForward.id()); + QCOMPARE(backendEventForward.target(), nullptr); + QCOMPARE(backendEventForward.coordinateAttribute(), QStringLiteral("default")); + QCOMPARE(backendEventForward.coordinateTransform(), QMatrix4x4()); + QCOMPARE(backendEventForward.forwardMouseEvents(), true); + QCOMPARE(backendEventForward.forwardKeyboardEvents(), false); + } + { + // WHEN + Qt3DRender::Render::EventForward backendEventForward; + eventForward.setEnabled(false); + simulateInitialization(&eventForward, &backendEventForward); + + // THEN + QCOMPARE(backendEventForward.peerId(), eventForward.id()); + QCOMPARE(backendEventForward.isEnabled(), false); + } + } + + void checkSceneChangeEvents() + { + // GIVEN + Qt3DRender::Render::EventForward backendEventForward; + TestRenderer renderer; + backendEventForward.setRenderer(&renderer); + + { + // WHEN + const bool newValue = false; + const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId()); + change->setPropertyName("enabled"); + change->setValue(newValue); + backendEventForward.sceneChangeEvent(change); + + // THEN + QCOMPARE(backendEventForward.isEnabled(), newValue); + } + { + // WHEN + QScopedPointer obj(new Qt3DRender::QEventForward()); + Qt3DRender::QEventForward * newValue = obj.data(); + const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId()); + change->setPropertyName("target"); + change->setValue(QVariant::fromValue(newValue)); + backendEventForward.sceneChangeEvent(change); + + // THEN + QCOMPARE(backendEventForward.target(), newValue); + } + { + // WHEN + const QString newValue = QStringLiteral("position"); + const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId()); + change->setPropertyName("coordinateAttribute"); + change->setValue(QVariant::fromValue(newValue)); + backendEventForward.sceneChangeEvent(change); + + // THEN + QCOMPARE(backendEventForward.coordinateAttribute(), newValue); + } + { + // WHEN + QMatrix4x4 newValue; + newValue.rotate(2.0f, QVector3D(0, 0, 1.0f)); + const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId()); + change->setPropertyName("coordinateTransform"); + change->setValue(QVariant::fromValue(newValue)); + backendEventForward.sceneChangeEvent(change); + + // THEN + QCOMPARE(backendEventForward.coordinateTransform(), newValue); + } + { + // WHEN + const bool newValue = true; + const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId()); + change->setPropertyName("forwardMouseEvents"); + change->setValue(QVariant::fromValue(newValue)); + backendEventForward.sceneChangeEvent(change); + + // THEN + QCOMPARE(backendEventForward.forwardMouseEvents(), newValue); + } + { + // WHEN + const bool newValue = true; + const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId()); + change->setPropertyName("forwardKeyboardEvents"); + change->setValue(QVariant::fromValue(newValue)); + backendEventForward.sceneChangeEvent(change); + + // THEN + QCOMPARE(backendEventForward.forwardKeyboardEvents(), newValue); + } + } + +}; + +QTEST_MAIN(tst_EventForward) + +#include "tst_eventforward.moc" diff --git a/tests/auto/render/render.pro b/tests/auto/render/render.pro index c42d47e1f..34c07f7dc 100644 --- a/tests/auto/render/render.pro +++ b/tests/auto/render/render.pro @@ -97,7 +97,8 @@ qtConfig(private_tests) { rendercapture \ trianglevisitor \ qmemorybarrier \ - qeventforward + qeventforward \ + eventforward !macos: SUBDIRS += graphicshelpergl4 } -- cgit v1.2.3 From 54cc0cfbc44bcbd3e3508caaea561083293a1b76 Mon Sep 17 00:00:00 2001 From: Nico Vertriest Date: Tue, 24 Jan 2017 16:00:08 +0100 Subject: Doc: added doc for parameter \a other Undocumented parameter 'other' in Qt3DRender::QBufferDataGenerator::operator==() Change-Id: Iadeeec3316df86bb3681e707051e43683b7e9bbb Reviewed-by: Sean Harmer --- src/render/geometry/qbuffer.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/render/geometry/qbuffer.cpp b/src/render/geometry/qbuffer.cpp index 02417f978..03939aa05 100644 --- a/src/render/geometry/qbuffer.cpp +++ b/src/render/geometry/qbuffer.cpp @@ -189,7 +189,8 @@ QBufferPrivate::QBufferPrivate() /*! \fn Qt3DRender::QBufferDataGenerator::operator ==(const QBufferDataGenerator &other) const - Should be reimplemented to return true when two generators are identical, + Should be reimplemented to return true when two generators (the one you are + comparing against and the \a other generator) are identical, false otherwise. \note The renderer uses this comparison to decide whether data for a buffer -- cgit v1.2.3 From 7fdc481a1f9713edf9fa2e8f1d05f003bc7d462c Mon Sep 17 00:00:00 2001 From: Zeno Endemann Date: Thu, 17 Nov 2016 16:44:53 +0100 Subject: Mark newly loaded shader entities as dirty Needed for the onDemand renderer to draw after the shaders are ready. Change-Id: Ie25d5968ae94d1c557e444823c81523304bc22ab Reviewed-by: Paul Lemire Reviewed-by: Sean Harmer --- src/render/graphicshelpers/graphicscontext.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/render/graphicshelpers/graphicscontext.cpp b/src/render/graphicshelpers/graphicscontext.cpp index dea8c1fc6..8701e3a16 100644 --- a/src/render/graphicshelpers/graphicscontext.cpp +++ b/src/render/graphicshelpers/graphicscontext.cpp @@ -507,6 +507,7 @@ void GraphicsContext::loadShader(Shader *shader) shader->setGraphicsContext(this); shader->setLoaded(true); + shader->markDirty(AbstractRenderer::AllDirty); } } -- cgit v1.2.3 From 34ad7528652c9016548277331e0e393ab7a782c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Mon, 24 Oct 2016 16:32:34 +0300 Subject: Add QEventForward node manager MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I31cd1463b8c6fead18279754d99e876f6c71bb36 Reviewed-by: Tomi Korpipää Reviewed-by: Sean Harmer --- src/render/backend/managers_p.h | 10 ++++++++++ src/render/backend/nodemanagers.cpp | 8 ++++++++ src/render/backend/nodemanagers_p.h | 10 ++++++++++ 3 files changed, 28 insertions(+) diff --git a/src/render/backend/managers_p.h b/src/render/backend/managers_p.h index ed43fde13..04ac498ff 100644 --- a/src/render/backend/managers_p.h +++ b/src/render/backend/managers_p.h @@ -77,6 +77,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE @@ -347,6 +348,15 @@ class ObjectPickerManager : public Qt3DCore::QResourceManager< { }; +class EventForwardManager : public Qt3DCore::QResourceManager< + EventForward, + Qt3DCore::QNodeId, + 8, + Qt3DCore::ArrayAllocatingPolicy, + Qt3DCore::NonLockingPolicy> +{ +}; + #if 0 class BoundingVolumeDebugManager : public Qt3DCore::QResourceManager< BoundingVolumeDebug, diff --git a/src/render/backend/nodemanagers.cpp b/src/render/backend/nodemanagers.cpp index 534bb4b9f..898a2b869 100644 --- a/src/render/backend/nodemanagers.cpp +++ b/src/render/backend/nodemanagers.cpp @@ -90,6 +90,7 @@ NodeManagers::NodeManagers() , m_lightManager(new LightManager()) , m_computeJobManager(new ComputeCommandManager()) , m_renderStateManager(new RenderStateManager()) + , m_eventForwardManager(new EventForwardManager()) , m_resourceAccessor(new ResourceAccessor(this)) { } @@ -129,6 +130,7 @@ NodeManagers::~NodeManagers() delete m_computeJobManager; delete m_renderStateManager; delete m_renderNodesManager; + delete m_eventForwardManager; } QSharedPointer NodeManagers::resourceAccessor() @@ -322,6 +324,12 @@ RenderStateManager *NodeManagers::manager() const Q_DECL_NOTHRO return m_renderStateManager; } +template<> +EventForwardManager *NodeManagers::manager() const Q_DECL_NOTHROW +{ + return m_eventForwardManager; +} + } // Render } // Qt3DRender diff --git a/src/render/backend/nodemanagers_p.h b/src/render/backend/nodemanagers_p.h index a57628607..0e27b5d9e 100644 --- a/src/render/backend/nodemanagers_p.h +++ b/src/render/backend/nodemanagers_p.h @@ -98,6 +98,7 @@ class LayerManager; class LightManager; class ComputeCommandManager; class RenderStateManager; +class EventForwardManager; class FrameGraphNode; class Entity; @@ -124,6 +125,7 @@ class Attribute; class Geometry; class GeometryRenderer; class ObjectPicker; +class EventForward; //class BoundingVolumeDebug; class Light; class ComputeCommand; @@ -204,6 +206,7 @@ public: inline LightManager *lightManager() const Q_DECL_NOEXCEPT { return m_lightManager; } inline ComputeCommandManager *computeJobManager() const Q_DECL_NOEXCEPT { return m_computeJobManager; } inline RenderStateManager *renderStateManager() const Q_DECL_NOEXCEPT { return m_renderStateManager; } + inline EventForwardManager *eventForwardManager() const Q_DECL_NOEXCEPT { return m_eventForwardManager; } QSharedPointer resourceAccessor(); @@ -241,6 +244,7 @@ private: LightManager *m_lightManager; ComputeCommandManager *m_computeJobManager; RenderStateManager *m_renderStateManager; + EventForwardManager *m_eventForwardManager; QSharedPointer m_resourceAccessor; }; @@ -328,6 +332,9 @@ QT3DRENDERSHARED_PRIVATE_EXPORT GeometryRendererManager *NodeManagers::manager QT3DRENDERSHARED_PRIVATE_EXPORT ObjectPickerManager *NodeManagers::manager() const Q_DECL_NOEXCEPT; +template<> +QT3DRENDERSHARED_PRIVATE_EXPORT EventForwardManager *NodeManagers::manager() const Q_DECL_NOEXCEPT; + //template<> //QT3DRENDERSHARED_PRIVATE_EXPORT BoundingVolumeDebugManager *NodeManagers::manager() const Q_DECL_NOEXCEPT; @@ -340,6 +347,9 @@ QT3DRENDERSHARED_PRIVATE_EXPORT ComputeCommandManager *NodeManagers::manager QT3DRENDERSHARED_PRIVATE_EXPORT RenderStateManager *NodeManagers::manager() const Q_DECL_NOEXCEPT; +template<> +QT3DRENDERSHARED_PRIVATE_EXPORT EventForwardManager *NodeManagers::manager() const Q_DECL_NOEXCEPT; + } // Render } // Qt3DRender -- cgit v1.2.3 From 6f36bb5edecea1efb13450672be29af32e1f49e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Tue, 25 Oct 2016 11:36:38 +0300 Subject: Add QEventForward to QObjectPicker Change-Id: I3a1a7ffdf2c5ec765e9f9e10ed5f15e3902ae15d Reviewed-by: Sean Harmer --- src/render/picking/objectpicker.cpp | 15 +++++++++++++++ src/render/picking/objectpicker_p.h | 3 +++ src/render/picking/qobjectpicker.cpp | 33 +++++++++++++++++++++++++++++++++ src/render/picking/qobjectpicker.h | 6 ++++++ src/render/picking/qobjectpicker_p.h | 3 +++ 5 files changed, 60 insertions(+) diff --git a/src/render/picking/objectpicker.cpp b/src/render/picking/objectpicker.cpp index eff6e3b3c..2fb1752a4 100644 --- a/src/render/picking/objectpicker.cpp +++ b/src/render/picking/objectpicker.cpp @@ -70,6 +70,7 @@ void ObjectPicker::cleanup() m_isPressed = false; m_hoverEnabled = false; m_dragEnabled = false; + m_eventForward = Qt3DCore::QNodeId(); } void ObjectPicker::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) @@ -78,6 +79,7 @@ void ObjectPicker::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr const auto &data = typedChange->data; m_hoverEnabled = data.hoverEnabled; m_dragEnabled = data.dragEnabled; + m_eventForward = data.eventForward; m_isDirty = true; } @@ -92,6 +94,9 @@ void ObjectPicker::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) } else if (propertyChange->propertyName() == QByteArrayLiteral("dragEnabled")) { m_dragEnabled = propertyChange->value().toBool(); m_isDirty = true; + } else if (propertyChange->propertyName() == QByteArrayLiteral("eventForward")) { + m_eventForward = propertyChange->value().value(); + m_isDirty = true; } markDirty(AbstractRenderer::AllDirty); } @@ -129,6 +134,16 @@ bool ObjectPicker::isDragEnabled() const return m_dragEnabled; } +bool ObjectPicker::isEventForwardingEnabled() const +{ + return Qt3DCore::QNodeId() != m_eventForward; +} + +Qt3DCore::QNodeId ObjectPicker::eventForward() const +{ + return m_eventForward; +} + void ObjectPicker::onClicked(QPickEventPtr event) { auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId()); diff --git a/src/render/picking/objectpicker_p.h b/src/render/picking/objectpicker_p.h index f116aa332..a90b48e1d 100644 --- a/src/render/picking/objectpicker_p.h +++ b/src/render/picking/objectpicker_p.h @@ -76,6 +76,8 @@ public: void makeDirty(); bool isHoverEnabled() const; bool isDragEnabled() const; + bool isEventForwardingEnabled() const; + Qt3DCore::QNodeId eventForward() const; void onClicked(QPickEventPtr event); void onMoved(QPickEventPtr event); @@ -91,6 +93,7 @@ private: bool m_isPressed; bool m_hoverEnabled; bool m_dragEnabled; + Qt3DCore::QNodeId m_eventForward; }; } // Render diff --git a/src/render/picking/qobjectpicker.cpp b/src/render/picking/qobjectpicker.cpp index 1842b7fee..9fa8b774c 100644 --- a/src/render/picking/qobjectpicker.cpp +++ b/src/render/picking/qobjectpicker.cpp @@ -43,6 +43,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE @@ -202,6 +203,37 @@ void QObjectPicker::setDragEnabled(bool dragEnabled) } } +/*! + \qmlproperty EventForward Qt3D.Render::ObjectPicker::eventForward + Holds the EventForward type. +*/ +/*! + \property Qt3DRender::QObjectPicker::eventForward + Holds the EventForward type. + */ +QEventForward *QObjectPicker::eventForward() const +{ + Q_D(const QObjectPicker); + return d->m_eventForward; +} + +void QObjectPicker::setEventForward(QEventForward *eventForward) +{ + Q_D(QObjectPicker); + if (d->m_eventForward != eventForward) { + if (d->m_eventForward) + d->unregisterDestructionHelper(d->m_eventForward); + d->m_eventForward = eventForward; + if (eventForward) { + if (eventForward->parent() == nullptr) + eventForward->setParent(this); + d->registerDestructionHelper(eventForward, &QObjectPicker::setEventForward, + d->m_eventForward); + } + emit eventForwardChanged(eventForward); + } +} + /*! \qmlproperty bool Qt3D.Render::ObjectPicker::dragEnabled */ @@ -402,6 +434,7 @@ Qt3DCore::QNodeCreatedChangeBasePtr QObjectPicker::createNodeCreationChange() co Q_D(const QObjectPicker); data.hoverEnabled = d->m_hoverEnabled; data.dragEnabled = d->m_dragEnabled; + data.eventForward = Qt3DCore::qIdForNode(d->m_eventForward); return creationChange; } diff --git a/src/render/picking/qobjectpicker.h b/src/render/picking/qobjectpicker.h index 950fff2cc..b00178851 100644 --- a/src/render/picking/qobjectpicker.h +++ b/src/render/picking/qobjectpicker.h @@ -41,6 +41,7 @@ #define QT3DRENDER_QOBJECTPICKER_H #include +#include #include QT_BEGIN_NAMESPACE @@ -58,6 +59,7 @@ class QT3DRENDERSHARED_EXPORT QObjectPicker : public Qt3DCore::QComponent Q_PROPERTY(bool dragEnabled READ isDragEnabled WRITE setDragEnabled NOTIFY dragEnabledChanged) Q_PROPERTY(bool pressed READ isPressed NOTIFY pressedChanged) Q_PROPERTY(bool containsMouse READ containsMouse NOTIFY containsMouseChanged) + Q_PROPERTY(Qt3DRender::QEventForward *eventForward READ eventForward WRITE setEventForward NOTIFY eventForwardChanged) public: explicit QObjectPicker(QNode *parent = nullptr); @@ -69,9 +71,12 @@ public: bool containsMouse() const; bool isPressed() const; + QEventForward *eventForward() const; + public Q_SLOTS: void setHoverEnabled(bool hoverEnabled); void setDragEnabled(bool dragEnabled); + void setEventForward(QEventForward *eventForward); Q_SIGNALS: void pressed(Qt3DRender::QPickEvent *pick); @@ -84,6 +89,7 @@ Q_SIGNALS: void dragEnabledChanged(bool dragEnabled); void pressedChanged(bool pressed); void containsMouseChanged(bool containsMouse); + void eventForwardChanged(QEventForward *eventForward); protected: void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) Q_DECL_OVERRIDE; diff --git a/src/render/picking/qobjectpicker_p.h b/src/render/picking/qobjectpicker_p.h index 884e5673b..bddc213cc 100644 --- a/src/render/picking/qobjectpicker_p.h +++ b/src/render/picking/qobjectpicker_p.h @@ -68,6 +68,7 @@ public: , m_pressed(false) , m_containsMouse(false) , m_acceptedLastPressedEvent(true) + , m_eventForward(nullptr) { m_shareable = false; } @@ -78,6 +79,7 @@ public: bool m_pressed; bool m_containsMouse; bool m_acceptedLastPressedEvent; + QEventForward *m_eventForward; enum EventType { Pressed, @@ -101,6 +103,7 @@ struct QObjectPickerData { bool hoverEnabled; bool dragEnabled; + Qt3DCore::QNodeId eventForward; }; } // namespace Qt3DRender -- cgit v1.2.3 From 0c54f65af70b5aa5bf40864b7ea485c1a96a03b7 Mon Sep 17 00:00:00 2001 From: Paul Lemire Date: Fri, 16 Dec 2016 11:11:45 +0100 Subject: EntityLoader: add a status property And complete the documentation a bit Change-Id: I3d3520e09456d256ee258d14656e97a08f2727aa Task-number: QTBUG-57613 Reviewed-by: Sean Harmer --- src/quick3d/quick3d/items/quick3dentityloader.cpp | 52 +++++++++++++++++++++- src/quick3d/quick3d/items/quick3dentityloader_p.h | 12 +++++ .../quick3d/items/quick3dentityloader_p_p.h | 2 + 3 files changed, 64 insertions(+), 2 deletions(-) diff --git a/src/quick3d/quick3d/items/quick3dentityloader.cpp b/src/quick3d/quick3d/items/quick3dentityloader.cpp index 9c82db7ad..9bc9d9d28 100644 --- a/src/quick3d/quick3d/items/quick3dentityloader.cpp +++ b/src/quick3d/quick3d/items/quick3dentityloader.cpp @@ -71,6 +71,12 @@ protected: Q_ASSERT(priv->m_entity != nullptr); priv->m_entity->setParent(m_loader); emit m_loader->entityChanged(); + priv->setStatus(Quick3DEntityLoader::Ready); + break; + } + + case Loading: { + priv->setStatus(Quick3DEntityLoader::Loading); break; } @@ -78,6 +84,7 @@ protected: QQmlEnginePrivate::warning(qmlEngine(m_loader), errors()); priv->clear(); emit m_loader->entityChanged(); + priv->setStatus(Quick3DEntityLoader::Error); break; } @@ -95,13 +102,21 @@ private: \inqmlmodule Qt3D.Core \inherits Entity \since 5.5 - \brief Provides the facility to load entities from qml source + \brief Provides a way to dynamically load an Entity subtree An EntityLoader provides the facitily to load predefined set of entities from qml source file. EntityLoader itself is an entity and the loaded entity tree is set as a child of the loader. The loaded entity tree root can be accessed with EntityLoader::entity property. + + \badcode + EntityLoader { + id: loader + source: "./SphereEntity.qml" + } + \endcode */ + Quick3DEntityLoader::Quick3DEntityLoader(QNode *parent) : QEntity(*new Quick3DEntityLoaderPrivate, parent) { @@ -117,6 +132,10 @@ Quick3DEntityLoader::~Quick3DEntityLoader() \qmlproperty QtQml::QtObject EntityLoader::entity Holds the loaded entity tree root. \readonly + + This property allows access to the content of the loader. It references + either a valid Entity object if the status property equals + EntityLoader.Ready, it is equal to null otherwise. */ QObject *Quick3DEntityLoader::entity() const { @@ -147,12 +166,30 @@ void Quick3DEntityLoader::setSource(const QUrl &url) d->loadFromSource(); } +/*! + \qmlproperty Status Qt3DCore::EntityLoader::status + + Holds the status of the entity loader. + \list + \li EntityLoader.Null + \li EntityLoader.Loading + \li EntityLoader.Ready + \li EntityLoader.Error + \endlist + */ +Quick3DEntityLoader::Status Quick3DEntityLoader::status() const +{ + Q_D(const Quick3DEntityLoader); + return d->m_status; +} + Quick3DEntityLoaderPrivate::Quick3DEntityLoaderPrivate() : QEntityPrivate(), m_incubator(nullptr), m_context(nullptr), m_component(nullptr), - m_entity(nullptr) + m_entity(nullptr), + m_status(Quick3DEntityLoader::Null) { } @@ -234,6 +271,17 @@ void Quick3DEntityLoaderPrivate::_q_componentStatusChanged(QQmlComponent::Status m_component->create(*m_incubator, m_context); } +void Quick3DEntityLoaderPrivate::setStatus(Quick3DEntityLoader::Status status) +{ + Q_Q(Quick3DEntityLoader); + if (status != m_status) { + m_status = status; + const bool blocked = q->blockNotifications(true); + emit q->statusChanged(m_status); + q->blockNotifications(blocked); + } +} + } // namespace Quick } // namespace Qt3DCore diff --git a/src/quick3d/quick3d/items/quick3dentityloader_p.h b/src/quick3d/quick3d/items/quick3dentityloader_p.h index 5721af115..9cd0eff2e 100644 --- a/src/quick3d/quick3d/items/quick3dentityloader_p.h +++ b/src/quick3d/quick3d/items/quick3dentityloader_p.h @@ -74,7 +74,16 @@ class QT3DQUICKSHARED_PRIVATE_EXPORT Quick3DEntityLoader : public QEntity Q_OBJECT Q_PROPERTY(QObject *entity READ entity NOTIFY entityChanged) Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged) + Q_PROPERTY(Status status READ status NOTIFY statusChanged) public: + enum Status { + Null = 0, + Loading, + Ready, + Error + }; + Q_ENUM(Status) + explicit Quick3DEntityLoader(QNode *parent = 0); ~Quick3DEntityLoader(); @@ -83,9 +92,12 @@ public: QUrl source() const; void setSource(const QUrl &url); + Status status() const; + Q_SIGNALS: void entityChanged(); void sourceChanged(); + void statusChanged(Status status); private: Q_DECLARE_PRIVATE(Quick3DEntityLoader) diff --git a/src/quick3d/quick3d/items/quick3dentityloader_p_p.h b/src/quick3d/quick3d/items/quick3dentityloader_p_p.h index 235870933..1ff1459cb 100644 --- a/src/quick3d/quick3d/items/quick3dentityloader_p_p.h +++ b/src/quick3d/quick3d/items/quick3dentityloader_p_p.h @@ -82,6 +82,7 @@ public: void loadComponent(const QUrl &source); void _q_componentStatusChanged(QQmlComponent::Status status); + void setStatus(Quick3DEntityLoader::Status status); static inline Quick3DEntityLoaderPrivate *get(Quick3DEntityLoader *q) { return q->d_func(); } @@ -90,6 +91,7 @@ public: QQmlContext *m_context; QQmlComponent *m_component; QEntity *m_entity; + Quick3DEntityLoader::Status m_status; }; } // namespace Quick -- cgit v1.2.3 From 6a7e0e2822875e8e532e3cd58f2263d5b3c12da4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Mon, 24 Oct 2016 16:33:31 +0300 Subject: Register EventForward qml type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Ifb86ab26cf5da2ef540e607f2b13055c06165eea Reviewed-by: Tomi Korpipää Reviewed-by: Sean Harmer --- src/quick3d/imports/render/qt3dquick3drenderplugin.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/quick3d/imports/render/qt3dquick3drenderplugin.cpp b/src/quick3d/imports/render/qt3dquick3drenderplugin.cpp index 2e68893d6..51c029fc1 100644 --- a/src/quick3d/imports/render/qt3dquick3drenderplugin.cpp +++ b/src/quick3d/imports/render/qt3dquick3drenderplugin.cpp @@ -100,6 +100,7 @@ #include #include #include +#include #include #include #include @@ -197,6 +198,7 @@ void Qt3DQuick3DRenderPlugin::registerTypes(const char *uri) // Picking qmlRegisterType(uri, 2, 0, "ObjectPicker"); + qmlRegisterType(uri, 2, 2, "EventForward"); qmlRegisterUncreatableType(uri, 2, 0, "PickEvent", QStringLiteral("Events cannot be created")); // Compute Job -- cgit v1.2.3 From eecf5f7d7df3ec9fde757389d0ab18a63bcf09b0 Mon Sep 17 00:00:00 2001 From: Nico Vertriest Date: Wed, 25 Jan 2017 14:40:01 +0100 Subject: Doc: minor spelling mistake Change-Id: I7b2675400a7111bdb1f9817d52a96706942c2f1d Reviewed-by: Martin Smith --- src/input/frontend/qaxisaccumulator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/input/frontend/qaxisaccumulator.cpp b/src/input/frontend/qaxisaccumulator.cpp index 0785ad689..b13a18167 100644 --- a/src/input/frontend/qaxisaccumulator.cpp +++ b/src/input/frontend/qaxisaccumulator.cpp @@ -88,7 +88,7 @@ namespace Qt3DInput { */ /*! - \qmlproperty int Qt3D.Inpit::Axis::value + \qmlproperty int Qt3D.Input::Axis::value \readonly Holds the value accumulated from the sourceAxis. -- cgit v1.2.3 From 40f60c66ab538229f4f64ea8f56682ae33c5926c Mon Sep 17 00:00:00 2001 From: Nico Vertriest Date: Wed, 26 Oct 2016 13:20:40 +0200 Subject: Doc: corrected several qdoc errors qt3d qaxisaccumulator.cpp:182: warning: QML property documented multiple times: 'real Qt3D.Input::AxisAccumulator::value' Errors on \return Change-Id: Ibff02113e1a4ac3cfc79d23960812345cba513cb Reviewed-by: Martin Smith --- src/input/frontend/qaxisaccumulator.cpp | 14 ++++---------- src/render/picking/qpicktriangleevent.cpp | 2 +- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/src/input/frontend/qaxisaccumulator.cpp b/src/input/frontend/qaxisaccumulator.cpp index b13a18167..b9a5add35 100644 --- a/src/input/frontend/qaxisaccumulator.cpp +++ b/src/input/frontend/qaxisaccumulator.cpp @@ -183,11 +183,13 @@ QAxisAccumulator::SourceAxisType QAxisAccumulator::sourceAxisType() const /*! \qmlproperty real Qt3D.Input::AxisAccumulator::value - The accumulated (integrated) value. + The amount to scale the axis value by when accumulating. This can be + thought of as the maximum velocity or acceleration the axis can + control. */ /*! - \return the accumulated (integrated) value. + Returns the accumulated (integrated) value. */ float QAxisAccumulator::value() const { @@ -207,14 +209,6 @@ float QAxisAccumulator::velocity() const return d->m_velocity; } -/*! - \qmlproperty real Qt3D.Input::AxisAccumulator::value - - The amount to scale the axis value by when accumulating. This can be - thought of as the maximum velocity or acceleration the axis can - control. - */ - /*! The amount to scale the axis value by when accumulating. This can be thought of as the maximum velocity or acceleration the axis can diff --git a/src/render/picking/qpicktriangleevent.cpp b/src/render/picking/qpicktriangleevent.cpp index ae96d5d2b..a1da8b975 100644 --- a/src/render/picking/qpicktriangleevent.cpp +++ b/src/render/picking/qpicktriangleevent.cpp @@ -204,7 +204,7 @@ uint QPickTriangleEvent::vertex2Index() const */ /*! * \brief QPickTriangleEvent::vertex3Index - * \returns index of third point of picked triangle + * Returns index of third point of picked triangle */ uint QPickTriangleEvent::vertex3Index() const { -- cgit v1.2.3 From 514c2fe9f7e8cdd6b2ebd26d9501b851f7063cdb Mon Sep 17 00:00:00 2001 From: Paul Lemire Date: Fri, 16 Dec 2016 12:49:31 +0100 Subject: Shader sharing: perform introspection once per shared shader Change-Id: If726f3031cbd6311acdb13adb8abb191c362f386 Reviewed-by: Sean Harmer --- src/render/backend/renderer.cpp | 5 +-- src/render/graphicshelpers/graphicscontext.cpp | 46 +++++++++++++++++++------- src/render/graphicshelpers/graphicscontext_p.h | 4 ++- src/render/materialsystem/shader.cpp | 2 +- src/render/materialsystem/shader_p.h | 2 +- src/render/materialsystem/shadercache.cpp | 5 +++ src/render/materialsystem/shadercache_p.h | 1 + 7 files changed, 48 insertions(+), 17 deletions(-) diff --git a/src/render/backend/renderer.cpp b/src/render/backend/renderer.cpp index af73b1ae5..8a1ee548a 100644 --- a/src/render/backend/renderer.cpp +++ b/src/render/backend/renderer.cpp @@ -964,10 +964,11 @@ void Renderer::updateGLResources() { Profiling::GLTimeRecorder recorder(Profiling::ShaderUpload); const QVector dirtyShaderHandles = std::move(m_dirtyShaders); + ShaderManager *shaderManager = m_nodesManager->shaderManager(); for (HShader handle: dirtyShaderHandles) { - Shader *shader = m_nodesManager->shaderManager()->data(handle); + Shader *shader = shaderManager->data(handle); // Compile shader - m_graphicsContext->loadShader(shader); + m_graphicsContext->loadShader(shader, shaderManager); } } diff --git a/src/render/graphicshelpers/graphicscontext.cpp b/src/render/graphicshelpers/graphicscontext.cpp index 8701e3a16..05693f325 100644 --- a/src/render/graphicshelpers/graphicscontext.cpp +++ b/src/render/graphicshelpers/graphicscontext.cpp @@ -471,7 +471,9 @@ QOpenGLShaderProgram *GraphicsContext::createShaderProgram(Shader *shaderNode) // Since we are sharing shaders in the backend, we assume that if using custom // fragOutputs, they should all be the same for a given shader bindFragOutputs(shaderProgram->programId(), shaderNode->fragOutputs()); - if (!shaderProgram->link()) { + + const bool linkSucceeded = shaderProgram->link(); + if (!linkSucceeded) { qWarning().noquote() << "Failed to link shader program:" << shaderProgram->log(); return nullptr; } @@ -481,7 +483,17 @@ QOpenGLShaderProgram *GraphicsContext::createShaderProgram(Shader *shaderNode) } // That assumes that the shaderProgram in Shader stays the same -void GraphicsContext::loadShader(Shader *shader) +void GraphicsContext::introspectShaderInterface(Shader *shader, QOpenGLShaderProgram *shaderProgram) +{ + shader->initializeUniforms(m_glHelper->programUniformsAndLocations(shaderProgram->programId())); + shader->initializeAttributes(m_glHelper->programAttributesAndLocations(shaderProgram->programId())); + if (m_glHelper->supportsFeature(GraphicsHelperInterface::UniformBufferObject)) + shader->initializeUniformBlocks(m_glHelper->programUniformBlocks(shaderProgram->programId())); + if (m_glHelper->supportsFeature(GraphicsHelperInterface::ShaderStorageObject)) + shader->initializeShaderStorageBlocks(m_glHelper->programShaderStorageBlocks(shaderProgram->programId())); +} + +void GraphicsContext::loadShader(Shader *shader, ShaderManager *manager) { QOpenGLShaderProgram *shaderProgram = m_shaderCache.getShaderProgramAndAddRef(shader->dna(), shader->peerId()); if (!shaderProgram) { @@ -493,17 +505,27 @@ void GraphicsContext::loadShader(Shader *shader) } // Ensure the Shader node knows about the program interface - // TODO: Improve this so we only introspect once per actual OpenGL shader program - // rather than once per ShaderNode. Could cache the interface description along - // with the QOpenGLShaderProgram in the ShaderCache. if (Q_LIKELY(shaderProgram != nullptr) && !shader->isLoaded()) { - // Introspect and set up interface description on Shader backend node - shader->initializeUniforms(m_glHelper->programUniformsAndLocations(shaderProgram->programId())); - shader->initializeAttributes(m_glHelper->programAttributesAndLocations(shaderProgram->programId())); - if (m_glHelper->supportsFeature(GraphicsHelperInterface::UniformBufferObject)) - shader->initializeUniformBlocks(m_glHelper->programUniformBlocks(shaderProgram->programId())); - if (m_glHelper->supportsFeature(GraphicsHelperInterface::ShaderStorageObject)) - shader->initializeShaderStorageBlocks(m_glHelper->programShaderStorageBlocks(shaderProgram->programId())); + + // Find an already loaded shader that shares the same QOpenGLShaderProgram + Shader *refShader = nullptr; + const QVector sharedShaderIds = m_shaderCache.shaderIdsForProgram(shader->dna()); + for (const Qt3DCore::QNodeId sharedShaderId : sharedShaderIds) { + Shader *sharedShader = manager->lookupResource(sharedShaderId); + // Note: no need to check if shader->peerId != sharedShader->peerId + // as we are sure that this code path is executed only if !shared->isLoaded + if (sharedShader->isLoaded()) { + refShader = sharedShader; + break; + } + } + + // We only introspect once per actual OpenGL shader program + // rather than once per ShaderNode. + if (refShader != nullptr) + shader->initializeFromReference(*refShader); + else // Introspect and set up interface description on Shader backend node + introspectShaderInterface(shader, shaderProgram); shader->setGraphicsContext(this); shader->setLoaded(true); diff --git a/src/render/graphicshelpers/graphicscontext_p.h b/src/render/graphicshelpers/graphicscontext_p.h index 133c84b8c..02de636ff 100644 --- a/src/render/graphicshelpers/graphicscontext_p.h +++ b/src/render/graphicshelpers/graphicscontext_p.h @@ -91,6 +91,7 @@ class RenderTarget; class AttachmentPack; class Attribute; class Buffer; +class ShaderManager; enum TextureScope { @@ -130,9 +131,10 @@ public: bool isInitialized() const; QOpenGLShaderProgram *createShaderProgram(Shader *shaderNode); - void loadShader(Shader* shader); + void loadShader(Shader* shader, ShaderManager *manager); bool activateShader(ProgramDNA shaderDNA); void removeShaderProgramReference(Shader *shaderNode); + void introspectShaderInterface(Shader *shader, QOpenGLShaderProgram *shaderProgram); GLuint activeFBO() const { return m_activeFBO; } GLuint defaultFBO() const { return m_defaultFBO; } diff --git a/src/render/materialsystem/shader.cpp b/src/render/materialsystem/shader.cpp index bd0af0bed..6d1cfb92e 100644 --- a/src/render/materialsystem/shader.cpp +++ b/src/render/materialsystem/shader.cpp @@ -402,7 +402,7 @@ void Shader::initializeShaderStorageBlocks(const QVector &sh Initializes this Shader's state relating to attributes, global block uniforms and and named uniform blocks by copying these details from \a other. */ -void Shader::initialize(const Shader &other) +void Shader::initializeFromReference(const Shader &other) { Q_ASSERT(m_dna == other.m_dna); m_uniformsNamesIds = other.m_uniformsNamesIds; diff --git a/src/render/materialsystem/shader_p.h b/src/render/materialsystem/shader_p.h index ad68a3bd6..a09133a74 100644 --- a/src/render/materialsystem/shader_p.h +++ b/src/render/materialsystem/shader_p.h @@ -157,7 +157,7 @@ private: void initializeUniformBlocks(const QVector &uniformBlockDescription); void initializeShaderStorageBlocks(const QVector &shaderStorageBlockDescription); - void initialize(const Shader &other); + void initializeFromReference(const Shader &other); friend class GraphicsContext; }; diff --git a/src/render/materialsystem/shadercache.cpp b/src/render/materialsystem/shadercache.cpp index de3842386..4ddf26799 100644 --- a/src/render/materialsystem/shadercache.cpp +++ b/src/render/materialsystem/shadercache.cpp @@ -151,6 +151,11 @@ QOpenGLShaderProgram *ShaderCache::getShaderProgramForDNA(ProgramDNA dna) const return m_programHash.value(dna, nullptr); } +QVector ShaderCache::shaderIdsForProgram(ProgramDNA dna) const +{ + return m_programRefs.value(dna); +} + } // namespace Render } // namespace Qt3DRender diff --git a/src/render/materialsystem/shadercache_p.h b/src/render/materialsystem/shadercache_p.h index 3cbc6bd0c..24a55876e 100644 --- a/src/render/materialsystem/shadercache_p.h +++ b/src/render/materialsystem/shadercache_p.h @@ -79,6 +79,7 @@ public: // Only ever used from the OpenGL submission thread QOpenGLShaderProgram *getShaderProgramForDNA(ProgramDNA dna) const; + QVector shaderIdsForProgram(ProgramDNA dna) const; private: // Only ever used from the OpenGL submission thread -- cgit v1.2.3 From 571e1c4791ea356aa452a50d5793fb8e44b65bbe Mon Sep 17 00:00:00 2001 From: Paul Lemire Date: Fri, 16 Dec 2016 12:51:39 +0100 Subject: QShaderProgram: add log and status properties Change-Id: I8c54bbcff8099d188eac5dfc571246a9e05d5286 Task-number: QTBUG-57615 Reviewed-by: Paul Lemire --- src/render/materialsystem/qshaderprogram.cpp | 79 ++++++++++++++++++++++++++++ src/render/materialsystem/qshaderprogram.h | 15 ++++++ src/render/materialsystem/qshaderprogram_p.h | 8 ++- 3 files changed, 100 insertions(+), 2 deletions(-) diff --git a/src/render/materialsystem/qshaderprogram.cpp b/src/render/materialsystem/qshaderprogram.cpp index 522f021aa..35e8e25aa 100644 --- a/src/render/materialsystem/qshaderprogram.cpp +++ b/src/render/materialsystem/qshaderprogram.cpp @@ -80,15 +80,48 @@ \value Compute Compute shader */ +/*! + \enum QShaderProgram::ShaderStatus + + This enum identifies the status of shader used. + + \value NotReady The shader hasn't been compiled and linked yet + \value Ready The shader was successfully compiled + \value Error An error occurred while compiling the shader +*/ + QT_BEGIN_NAMESPACE namespace Qt3DRender { QShaderProgramPrivate::QShaderProgramPrivate() : QNodePrivate() + , m_status(QShaderProgram::NotReady) { } +void QShaderProgramPrivate::setLog(const QString &log) +{ + Q_Q(QShaderProgram); + if (log != m_log) { + m_log = log; + const bool blocked = q->blockNotifications(true); + emit q->logChanged(m_log); + q->blockNotifications(blocked); + } +} + +void QShaderProgramPrivate::setStatus(QShaderProgram::ShaderStatus status) +{ + Q_Q(QShaderProgram); + if (status != m_status) { + m_status = status; + const bool blocked = q->blockNotifications(true); + emit q->statusChanged(m_status); + q->blockNotifications(blocked); + } +} + QShaderProgram::QShaderProgram(QNode *parent) : QNode(*new QShaderProgramPrivate, parent) { @@ -104,6 +137,18 @@ QShaderProgram::QShaderProgram(QShaderProgramPrivate &dd, QNode *parent) { } +void QShaderProgram::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) +{ + Q_D(QShaderProgram); + if (change->type() == Qt3DCore::PropertyUpdated) { + const Qt3DCore::QPropertyUpdatedChangePtr e = qSharedPointerCast(change); + if (e->propertyName() == QByteArrayLiteral("log")) + d->setLog(e->value().toString()); + else if (e->propertyName() == QByteArrayLiteral("status")) + d->setStatus(static_cast(e->value().toInt())); + } +} + /*! \qmlproperty string ShaderProgram::vertexShaderCode @@ -308,6 +353,40 @@ QByteArray QShaderProgram::shaderCode(ShaderType type) const } } +/*! + \qmlproperty string ShaderProgram::log + + Holds the log of the current shader program. This is useful to diagnose a + compilation failure of the shader program. +*/ +/*! + \property QShaderProgram::log + + Holds the log of the current shader program. This is useful to diagnose a + compilation failure of the shader program. +*/ +QString QShaderProgram::log() const +{ + Q_D(const QShaderProgram); + return d->m_log; +} + +/*! + \qmlproperty string ShaderProgram::status + + Holds the status of the current shader program. +*/ +/*! + \property QShaderProgram::status + + Holds the status of the current shader program. +*/ +QShaderProgram::ShaderStatus QShaderProgram::status() const +{ + Q_D(const QShaderProgram); + return d->m_status; +} + static QByteArray deincludify(const QString &filePath) { QFile f(filePath); diff --git a/src/render/materialsystem/qshaderprogram.h b/src/render/materialsystem/qshaderprogram.h index 442a25b2e..dd90a7d07 100644 --- a/src/render/materialsystem/qshaderprogram.h +++ b/src/render/materialsystem/qshaderprogram.h @@ -58,6 +58,8 @@ class QT3DRENDERSHARED_EXPORT QShaderProgram : public Qt3DCore::QNode Q_PROPERTY(QByteArray geometryShaderCode READ geometryShaderCode WRITE setGeometryShaderCode NOTIFY geometryShaderCodeChanged) Q_PROPERTY(QByteArray fragmentShaderCode READ fragmentShaderCode WRITE setFragmentShaderCode NOTIFY fragmentShaderCodeChanged) Q_PROPERTY(QByteArray computeShaderCode READ computeShaderCode WRITE setComputeShaderCode NOTIFY computeShaderCodeChanged) + Q_PROPERTY(QString log READ log NOTIFY logChanged) + Q_PROPERTY(ShaderStatus status READ status NOTIFY statusChanged) public: explicit QShaderProgram(Qt3DCore::QNode *parent = nullptr); @@ -73,6 +75,13 @@ public: }; Q_ENUM(ShaderType) // LCOV_EXCL_LINE + enum ShaderStatus { + NotReady = 0, + Ready, + Error + }; + Q_ENUM(ShaderStatus) // LCOV_EXCL_LINE + // Source code in-line QByteArray vertexShaderCode() const; QByteArray tessellationControlShaderCode() const; @@ -84,6 +93,9 @@ public: void setShaderCode(ShaderType type, const QByteArray &shaderCode); QByteArray shaderCode(ShaderType type) const; + QString log() const; + ShaderStatus status() const; + Q_INVOKABLE static QByteArray loadSource(const QUrl &sourceUrl); public Q_SLOTS: @@ -101,9 +113,12 @@ Q_SIGNALS: void geometryShaderCodeChanged(const QByteArray &geometryShaderCode); void fragmentShaderCodeChanged(const QByteArray &fragmentShaderCode); void computeShaderCodeChanged(const QByteArray &computeShaderCode); + void logChanged(const QString &log); + void statusChanged(ShaderStatus status); protected: explicit QShaderProgram(QShaderProgramPrivate &dd, Qt3DCore::QNode *parent = nullptr); + void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) Q_DECL_OVERRIDE; private: Q_DECLARE_PRIVATE(QShaderProgram) diff --git a/src/render/materialsystem/qshaderprogram_p.h b/src/render/materialsystem/qshaderprogram_p.h index 5f695a279..171cd8724 100644 --- a/src/render/materialsystem/qshaderprogram_p.h +++ b/src/render/materialsystem/qshaderprogram_p.h @@ -52,13 +52,12 @@ // #include +#include QT_BEGIN_NAMESPACE namespace Qt3DRender { -class QShaderProgram; - class QShaderProgramPrivate : public Qt3DCore::QNodePrivate { public: @@ -77,6 +76,11 @@ public: QByteArray m_geometryShaderCode; QByteArray m_fragmentShaderCode; QByteArray m_computeShaderCode; + QString m_log; + QShaderProgram::ShaderStatus m_status; + + void setLog(const QString &log); + void setStatus(QShaderProgram::ShaderStatus status); }; struct QShaderProgramData -- cgit v1.2.3 From fe8ba714347091a61d0b335d3413b49f8094dfd8 Mon Sep 17 00:00:00 2001 From: Paul Lemire Date: Fri, 16 Dec 2016 15:10:16 +0100 Subject: Add unit test for QShaderProgram Change-Id: Icefb4f688143068334989fb9b64056f9fbe0dda3 Reviewed-by: Paul Lemire --- .../auto/render/qshaderprogram/qshaderprogram.pro | 12 + .../render/qshaderprogram/tst_qshaderprogram.cpp | 518 +++++++++++++++++++++ tests/auto/render/render.pro | 3 +- 3 files changed, 532 insertions(+), 1 deletion(-) create mode 100644 tests/auto/render/qshaderprogram/qshaderprogram.pro create mode 100644 tests/auto/render/qshaderprogram/tst_qshaderprogram.cpp diff --git a/tests/auto/render/qshaderprogram/qshaderprogram.pro b/tests/auto/render/qshaderprogram/qshaderprogram.pro new file mode 100644 index 000000000..6f40caee9 --- /dev/null +++ b/tests/auto/render/qshaderprogram/qshaderprogram.pro @@ -0,0 +1,12 @@ +TEMPLATE = app + +TARGET = tst_qshaderprogram + +QT += 3dcore 3dcore-private 3drender 3drender-private testlib + +CONFIG += testcase + +SOURCES += tst_qshaderprogram.cpp + +include(../../core/common/common.pri) +include(../commons/commons.pri) diff --git a/tests/auto/render/qshaderprogram/tst_qshaderprogram.cpp b/tests/auto/render/qshaderprogram/tst_qshaderprogram.cpp new file mode 100644 index 000000000..e5d001759 --- /dev/null +++ b/tests/auto/render/qshaderprogram/tst_qshaderprogram.cpp @@ -0,0 +1,518 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Paul Lemire +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $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 +#include +#include +#include +#include +#include +#include +#include +#include "testpostmanarbiter.h" + +// We need to call QShaderProgram::sceneChangeEvent +class tst_QShaderProgram : public Qt3DRender::QShaderProgram +{ + Q_OBJECT + +private Q_SLOTS: + + void checkDefaultConstruction() + { + // GIVEN + Qt3DRender::QShaderProgram shaderProgram; + + // THEN + QCOMPARE(shaderProgram.vertexShaderCode(), QByteArray()); + QCOMPARE(shaderProgram.tessellationControlShaderCode(), QByteArray()); + QCOMPARE(shaderProgram.tessellationEvaluationShaderCode(), QByteArray()); + QCOMPARE(shaderProgram.geometryShaderCode(), QByteArray()); + QCOMPARE(shaderProgram.fragmentShaderCode(), QByteArray()); + QCOMPARE(shaderProgram.computeShaderCode(), QByteArray()); + QCOMPARE(shaderProgram.log(), QString()); + QCOMPARE(shaderProgram.status(), Qt3DRender::QShaderProgram::NotReady); + } + + void checkPropertyChanges() + { + // GIVEN + Qt3DRender::QShaderProgram shaderProgram; + + { + // WHEN + QSignalSpy spy(&shaderProgram, SIGNAL(vertexShaderCodeChanged(QByteArray))); + const QByteArray newValue = "VERTEX"; + shaderProgram.setVertexShaderCode(newValue); + + // THEN + QVERIFY(spy.isValid()); + QCOMPARE(shaderProgram.vertexShaderCode(), newValue); + QCOMPARE(spy.count(), 1); + + // WHEN + spy.clear(); + shaderProgram.setVertexShaderCode(newValue); + + // THEN + QCOMPARE(shaderProgram.vertexShaderCode(), newValue); + QCOMPARE(spy.count(), 0); + } + { + // WHEN + QSignalSpy spy(&shaderProgram, SIGNAL(tessellationControlShaderCodeChanged(QByteArray))); + const QByteArray newValue = "TESSELATION_CONTROL"; + shaderProgram.setTessellationControlShaderCode(newValue); + + // THEN + QVERIFY(spy.isValid()); + QCOMPARE(shaderProgram.tessellationControlShaderCode(), newValue); + QCOMPARE(spy.count(), 1); + + // WHEN + spy.clear(); + shaderProgram.setTessellationControlShaderCode(newValue); + + // THEN + QCOMPARE(shaderProgram.tessellationControlShaderCode(), newValue); + QCOMPARE(spy.count(), 0); + } + { + // WHEN + QSignalSpy spy(&shaderProgram, SIGNAL(tessellationEvaluationShaderCodeChanged(QByteArray))); + const QByteArray newValue = "TESSELATION_EVALUTATION"; + shaderProgram.setTessellationEvaluationShaderCode(newValue); + + // THEN + QVERIFY(spy.isValid()); + QCOMPARE(shaderProgram.tessellationEvaluationShaderCode(), newValue); + QCOMPARE(spy.count(), 1); + + // WHEN + spy.clear(); + shaderProgram.setTessellationEvaluationShaderCode(newValue); + + // THEN + QCOMPARE(shaderProgram.tessellationEvaluationShaderCode(), newValue); + QCOMPARE(spy.count(), 0); + } + { + // WHEN + QSignalSpy spy(&shaderProgram, SIGNAL(geometryShaderCodeChanged(QByteArray))); + const QByteArray newValue = "GEOMETRY"; + shaderProgram.setGeometryShaderCode(newValue); + + // THEN + QVERIFY(spy.isValid()); + QCOMPARE(shaderProgram.geometryShaderCode(), newValue); + QCOMPARE(spy.count(), 1); + + // WHEN + spy.clear(); + shaderProgram.setGeometryShaderCode(newValue); + + // THEN + QCOMPARE(shaderProgram.geometryShaderCode(), newValue); + QCOMPARE(spy.count(), 0); + } + { + // WHEN + QSignalSpy spy(&shaderProgram, SIGNAL(fragmentShaderCodeChanged(QByteArray))); + const QByteArray newValue = "FRAGMENT"; + shaderProgram.setFragmentShaderCode(newValue); + + // THEN + QVERIFY(spy.isValid()); + QCOMPARE(shaderProgram.fragmentShaderCode(), newValue); + QCOMPARE(spy.count(), 1); + + // WHEN + spy.clear(); + shaderProgram.setFragmentShaderCode(newValue); + + // THEN + QCOMPARE(shaderProgram.fragmentShaderCode(), newValue); + QCOMPARE(spy.count(), 0); + } + { + // WHEN + QSignalSpy spy(&shaderProgram, SIGNAL(computeShaderCodeChanged(QByteArray))); + const QByteArray newValue = "COMPUTE"; + shaderProgram.setComputeShaderCode(newValue); + + // THEN + QVERIFY(spy.isValid()); + QCOMPARE(shaderProgram.computeShaderCode(), newValue); + QCOMPARE(spy.count(), 1); + + // WHEN + spy.clear(); + shaderProgram.setComputeShaderCode(newValue); + + // THEN + QCOMPARE(shaderProgram.computeShaderCode(), newValue); + QCOMPARE(spy.count(), 0); + } + } + + void checkCreationData() + { + // GIVEN + Qt3DRender::QShaderProgram shaderProgram; + + shaderProgram.setVertexShaderCode(QByteArrayLiteral("Vertex")); + shaderProgram.setTessellationControlShaderCode(QByteArrayLiteral("TesselControl")); + shaderProgram.setTessellationEvaluationShaderCode(QByteArrayLiteral("TesselEval")); + shaderProgram.setGeometryShaderCode(QByteArrayLiteral("Geometry")); + shaderProgram.setFragmentShaderCode(QByteArrayLiteral("Fragment")); + shaderProgram.setComputeShaderCode(QByteArrayLiteral("Compute")); + + // WHEN + QVector creationChanges; + + { + Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&shaderProgram); + creationChanges = creationChangeGenerator.creationChanges(); + } + + // THEN + { + QCOMPARE(creationChanges.size(), 1); + + const auto creationChangeData = qSharedPointerCast>(creationChanges.first()); + const Qt3DRender::QShaderProgramData cloneData = creationChangeData->data; + + QCOMPARE(shaderProgram.vertexShaderCode(), cloneData.vertexShaderCode); + QCOMPARE(shaderProgram.tessellationControlShaderCode(), cloneData.tessellationControlShaderCode); + QCOMPARE(shaderProgram.tessellationEvaluationShaderCode(), cloneData.tessellationEvaluationShaderCode); + QCOMPARE(shaderProgram.geometryShaderCode(), cloneData.geometryShaderCode); + QCOMPARE(shaderProgram.fragmentShaderCode(), cloneData.fragmentShaderCode); + QCOMPARE(shaderProgram.computeShaderCode(), cloneData.computeShaderCode); + QCOMPARE(shaderProgram.id(), creationChangeData->subjectId()); + QCOMPARE(shaderProgram.isEnabled(), true); + QCOMPARE(shaderProgram.isEnabled(), creationChangeData->isNodeEnabled()); + QCOMPARE(shaderProgram.metaObject(), creationChangeData->metaObject()); + } + + // WHEN + shaderProgram.setEnabled(false); + + { + Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&shaderProgram); + creationChanges = creationChangeGenerator.creationChanges(); + } + + // THEN + { + QCOMPARE(creationChanges.size(), 1); + + const auto creationChangeData = qSharedPointerCast>(creationChanges.first()); + const Qt3DRender::QShaderProgramData cloneData = creationChangeData->data; + + QCOMPARE(shaderProgram.vertexShaderCode(), cloneData.vertexShaderCode); + QCOMPARE(shaderProgram.tessellationControlShaderCode(), cloneData.tessellationControlShaderCode); + QCOMPARE(shaderProgram.tessellationEvaluationShaderCode(), cloneData.tessellationEvaluationShaderCode); + QCOMPARE(shaderProgram.geometryShaderCode(), cloneData.geometryShaderCode); + QCOMPARE(shaderProgram.fragmentShaderCode(), cloneData.fragmentShaderCode); + QCOMPARE(shaderProgram.computeShaderCode(), cloneData.computeShaderCode); + QCOMPARE(shaderProgram.id(), creationChangeData->subjectId()); + QCOMPARE(shaderProgram.isEnabled(), false); + QCOMPARE(shaderProgram.isEnabled(), creationChangeData->isNodeEnabled()); + QCOMPARE(shaderProgram.metaObject(), creationChangeData->metaObject()); + } + } + + void checkVertexShaderCodeUpdate() + { + // GIVEN + TestArbiter arbiter; + Qt3DRender::QShaderProgram shaderProgram; + arbiter.setArbiterOnNode(&shaderProgram); + + { + // WHEN + shaderProgram.setVertexShaderCode(QByteArrayLiteral("in vec3 toto;")); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 1); + auto change = arbiter.events.first().staticCast(); + QCOMPARE(change->propertyName(), "vertexShaderCode"); + QCOMPARE(change->value().value(), shaderProgram.vertexShaderCode()); + QCOMPARE(change->type(), Qt3DCore::PropertyUpdated); + + arbiter.events.clear(); + } + + { + // WHEN + shaderProgram.setVertexShaderCode(QByteArrayLiteral("in vec3 toto;")); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 0); + } + + } + + void checkTessellationControlShaderCodeUpdate() + { + // GIVEN + TestArbiter arbiter; + Qt3DRender::QShaderProgram shaderProgram; + arbiter.setArbiterOnNode(&shaderProgram); + + { + // WHEN + shaderProgram.setTessellationControlShaderCode(QByteArrayLiteral("in vec3 toto2;")); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 1); + auto change = arbiter.events.first().staticCast(); + QCOMPARE(change->propertyName(), "tessellationControlShaderCode"); + QCOMPARE(change->value().value(), shaderProgram.tessellationControlShaderCode()); + QCOMPARE(change->type(), Qt3DCore::PropertyUpdated); + + arbiter.events.clear(); + } + + { + // WHEN + shaderProgram.setTessellationControlShaderCode(QByteArrayLiteral("in vec3 toto2;")); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 0); + } + + } + + void checkTessellationEvaluationShaderCodeUpdate() + { + // GIVEN + TestArbiter arbiter; + Qt3DRender::QShaderProgram shaderProgram; + arbiter.setArbiterOnNode(&shaderProgram); + + { + // WHEN + shaderProgram.setTessellationEvaluationShaderCode(QByteArrayLiteral("in vec3 toto3;")); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 1); + auto change = arbiter.events.first().staticCast(); + QCOMPARE(change->propertyName(), "tessellationEvaluationShaderCode"); + QCOMPARE(change->value().value(), shaderProgram.tessellationEvaluationShaderCode()); + QCOMPARE(change->type(), Qt3DCore::PropertyUpdated); + + arbiter.events.clear(); + } + + { + // WHEN + shaderProgram.setTessellationEvaluationShaderCode(QByteArrayLiteral("in vec3 toto3;")); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 0); + } + + } + + void checkGeometryShaderCodeUpdate() + { + // GIVEN + TestArbiter arbiter; + Qt3DRender::QShaderProgram shaderProgram; + arbiter.setArbiterOnNode(&shaderProgram); + + { + // WHEN + shaderProgram.setGeometryShaderCode(QByteArrayLiteral("in vec3 toto4;")); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 1); + auto change = arbiter.events.first().staticCast(); + QCOMPARE(change->propertyName(), "geometryShaderCode"); + QCOMPARE(change->value().value(), shaderProgram.geometryShaderCode()); + QCOMPARE(change->type(), Qt3DCore::PropertyUpdated); + + arbiter.events.clear(); + } + + { + // WHEN + shaderProgram.setGeometryShaderCode(QByteArrayLiteral("in vec3 toto4;")); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 0); + } + + } + + void checkFragmentShaderCodeUpdate() + { + // GIVEN + TestArbiter arbiter; + Qt3DRender::QShaderProgram shaderProgram; + arbiter.setArbiterOnNode(&shaderProgram); + + { + // WHEN + shaderProgram.setFragmentShaderCode(QByteArrayLiteral("out vec4 fragColor;")); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 1); + auto change = arbiter.events.first().staticCast(); + QCOMPARE(change->propertyName(), "fragmentShaderCode"); + QCOMPARE(change->value().value(), shaderProgram.fragmentShaderCode()); + QCOMPARE(change->type(), Qt3DCore::PropertyUpdated); + + arbiter.events.clear(); + } + + { + // WHEN + shaderProgram.setFragmentShaderCode(QByteArrayLiteral("out vec4 fragColor;")); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 0); + } + + } + + void checkComputeShaderCodeUpdate() + { + // GIVEN + TestArbiter arbiter; + Qt3DRender::QShaderProgram shaderProgram; + arbiter.setArbiterOnNode(&shaderProgram); + + { + // WHEN + shaderProgram.setComputeShaderCode(QByteArrayLiteral("uniform vec3 temp;")); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 1); + auto change = arbiter.events.first().staticCast(); + QCOMPARE(change->propertyName(), "computeShaderCode"); + QCOMPARE(change->value().value(), shaderProgram.computeShaderCode()); + QCOMPARE(change->type(), Qt3DCore::PropertyUpdated); + + arbiter.events.clear(); + } + + { + // WHEN + shaderProgram.setComputeShaderCode(QByteArrayLiteral("uniform vec3 temp;")); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 0); + } + + } + + void checkLogPropertyUpdate() + { + // GIVEN + TestArbiter arbiter; + arbiter.setArbiterOnNode(this); + QSignalSpy spy(this, SIGNAL(logChanged(QString))); + const QString logValue = QStringLiteral("Some log..."); + + // THEN + QVERIFY(spy.isValid()); + + // WHEN + Qt3DCore::QPropertyUpdatedChangePtr valueChange(new Qt3DCore::QPropertyUpdatedChange(Qt3DCore::QNodeId())); + valueChange->setPropertyName("log"); + valueChange->setValue(QVariant::fromValue(logValue)); + sceneChangeEvent(valueChange); + + // THEN + QCOMPARE(spy.count(), 1); + QCOMPARE(arbiter.events.size(), 0); + QCOMPARE(log(), logValue); + + // WHEN + spy.clear(); + sceneChangeEvent(valueChange); + + // THEN + QCOMPARE(spy.count(), 0); + QCOMPARE(arbiter.events.size(), 0); + QCOMPARE(log(), logValue); + } + + void checkStatusPropertyUpdate() + { + // GIVEN + qRegisterMetaType("ShaderStatus"); + TestArbiter arbiter; + arbiter.setArbiterOnNode(this); + QSignalSpy spy(this, SIGNAL(statusChanged(ShaderStatus))); + const Qt3DRender::QShaderProgram::ShaderStatus newStatus = Qt3DRender::QShaderProgram::Error; + + // THEN + QVERIFY(spy.isValid()); + + // WHEN + Qt3DCore::QPropertyUpdatedChangePtr valueChange(new Qt3DCore::QPropertyUpdatedChange(Qt3DCore::QNodeId())); + valueChange->setPropertyName("status"); + valueChange->setValue(QVariant::fromValue(newStatus)); + sceneChangeEvent(valueChange); + + // THEN + QCOMPARE(spy.count(), 1); + QCOMPARE(arbiter.events.size(), 0); + QCOMPARE(status(), newStatus); + + // WHEN + spy.clear(); + sceneChangeEvent(valueChange); + + // THEN + QCOMPARE(spy.count(), 0); + QCOMPARE(arbiter.events.size(), 0); + QCOMPARE(status(), newStatus); + } + +}; + +QTEST_MAIN(tst_QShaderProgram) + +#include "tst_qshaderprogram.moc" diff --git a/tests/auto/render/render.pro b/tests/auto/render/render.pro index c1de2aff8..5c04c0fb8 100644 --- a/tests/auto/render/render.pro +++ b/tests/auto/render/render.pro @@ -100,7 +100,8 @@ qtConfig(private_tests) { rendercapture \ trianglevisitor \ qmemorybarrier \ - memorybarrier + memorybarrier \ + qshaderprogram !macos: SUBDIRS += graphicshelpergl4 } -- cgit v1.2.3 From 5578d5b89d06b502e05ef6b3e3c6ffa0c29a7aa7 Mon Sep 17 00:00:00 2001 From: Paul Lemire Date: Fri, 16 Dec 2016 16:09:17 +0100 Subject: ShaderProgram: store and send log and status to frontend Change-Id: I00b02f8b73ecf1194b4c4db7b60a95ee7cc3df22 Task-number: QTBUG-57615 Reviewed-by: Sean Harmer --- src/render/backend/renderer.cpp | 2 ++ src/render/graphicshelpers/graphicscontext.cpp | 17 +++++++---- src/render/materialsystem/shader.cpp | 42 ++++++++++++++++++++++++-- src/render/materialsystem/shader_p.h | 16 ++++++++-- tests/auto/render/shader/tst_shader.cpp | 2 ++ 5 files changed, 69 insertions(+), 10 deletions(-) diff --git a/src/render/backend/renderer.cpp b/src/render/backend/renderer.cpp index 8a1ee548a..bc9dde83e 100644 --- a/src/render/backend/renderer.cpp +++ b/src/render/backend/renderer.cpp @@ -935,6 +935,8 @@ void Renderer::lookForDirtyShaders() RenderPass *renderPass = m_nodesManager->renderPassManager()->lookupResource(passId); HShader shaderHandle = m_nodesManager->shaderManager()->lookupHandle(renderPass->shaderProgram()); Shader *shader = m_nodesManager->shaderManager()->data(shaderHandle); + if (Q_UNLIKELY(shader->hasPendingNotifications())) + shader->submitPendingNotifications(); if (shader != nullptr && !shader->isLoaded()) m_dirtyShaders.push_back(shaderHandle); } diff --git a/src/render/graphicshelpers/graphicscontext.cpp b/src/render/graphicshelpers/graphicscontext.cpp index 05693f325..8a2919a96 100644 --- a/src/render/graphicshelpers/graphicscontext.cpp +++ b/src/render/graphicshelpers/graphicscontext.cpp @@ -459,11 +459,14 @@ QOpenGLShaderProgram *GraphicsContext::createShaderProgram(Shader *shaderNode) // Compile shaders const auto shaderCode = shaderNode->shaderCode(); + QString logs; for (int i = QShaderProgram::Vertex; i <= QShaderProgram::Compute; ++i) { QShaderProgram::ShaderType type = static_cast(i); - if (!shaderCode.at(i).isEmpty() && - !shaderProgram->addShaderFromSourceCode(shaderType(type), shaderCode.at(i))) { - qWarning().noquote() << "Failed to compile shader:" << shaderProgram->log(); + if (!shaderCode.at(i).isEmpty()) { + // Note: logs only return the error but not all the shader code + // we could append it + if (!shaderProgram->addShaderFromSourceCode(shaderType(type), shaderCode.at(i))) + logs += shaderProgram->log(); } } @@ -473,10 +476,12 @@ QOpenGLShaderProgram *GraphicsContext::createShaderProgram(Shader *shaderNode) bindFragOutputs(shaderProgram->programId(), shaderNode->fragOutputs()); const bool linkSucceeded = shaderProgram->link(); - if (!linkSucceeded) { - qWarning().noquote() << "Failed to link shader program:" << shaderProgram->log(); + logs += shaderProgram->log(); + shaderNode->setLog(logs); + shaderNode->setStatus(linkSucceeded ? QShaderProgram::Ready : QShaderProgram::Error); + + if (!linkSucceeded) return nullptr; - } // take from scoped-pointer so it doesn't get deleted return shaderProgram.take(); diff --git a/src/render/materialsystem/shader.cpp b/src/render/materialsystem/shader.cpp index 6d1cfb92e..ae547836a 100644 --- a/src/render/materialsystem/shader.cpp +++ b/src/render/materialsystem/shader.cpp @@ -59,10 +59,11 @@ namespace Qt3DRender { namespace Render { Shader::Shader() - : BackendNode() + : BackendNode(ReadWrite) , m_isLoaded(false) , m_dna(0) , m_graphicsContext(nullptr) + , m_status(QShaderProgram::NotReady) { m_shaderCode.resize(static_cast(QShaderProgram::Compute) + 1); } @@ -96,6 +97,7 @@ void Shader::cleanup() m_uniforms.clear(); m_attributes.clear(); m_uniformBlocks.clear(); + m_status = QShaderProgram::NotReady; } void Shader::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) @@ -183,8 +185,10 @@ void Shader::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) m_shaderCode[QShaderProgram::Compute] = propertyValue.toByteArray(); m_isLoaded = false; } - if (!m_isLoaded) + if (!m_isLoaded) { + setStatus(QShaderProgram::NotReady); updateDNA(); + } markDirty(AbstractRenderer::AllDirty); } @@ -253,6 +257,14 @@ ShaderStorageBlock Shader::storageBlockForBlockName(const QString &blockName) return ShaderStorageBlock(); } +// To be called from a worker thread +void Shader::submitPendingNotifications() +{ + const QVector notifications = std::move(m_pendingNotifications); + for (const Qt3DCore::QPropertyUpdatedChangePtr ¬ification : notifications) + notifyObservers(notification); +} + void Shader::prepareUniforms(ShaderParameterPack &pack) { const PackUniformHash &values = pack.uniforms(); @@ -420,6 +432,32 @@ void Shader::initializeFromReference(const Shader &other) m_shaderStorageBlockNames = other.m_shaderStorageBlockNames; m_shaderStorageBlocks = other.m_shaderStorageBlocks; m_isLoaded = other.m_isLoaded; + setStatus(other.status()); + setLog(other.log()); +} + +void Shader::setLog(const QString &log) +{ + if (log != m_log) { + m_log = log; + Qt3DCore::QPropertyUpdatedChangePtr e = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId()); + e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll); + e->setPropertyName("log"); + e->setValue(QVariant::fromValue(m_log)); + m_pendingNotifications.push_back(e); + } +} + +void Shader::setStatus(QShaderProgram::ShaderStatus status) +{ + if (status != m_status) { + m_status = status; + Qt3DCore::QPropertyUpdatedChangePtr e = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId()); + e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll); + e->setPropertyName("status"); + e->setValue(QVariant::fromValue(m_status)); + m_pendingNotifications.push_back(e); + } } } // namespace Render diff --git a/src/render/materialsystem/shader_p.h b/src/render/materialsystem/shader_p.h index a09133a74..625abe847 100644 --- a/src/render/materialsystem/shader_p.h +++ b/src/render/materialsystem/shader_p.h @@ -54,6 +54,8 @@ #include #include #include +#include +#include #include #include @@ -63,8 +65,6 @@ class QOpenGLShaderProgram; namespace Qt3DRender { -class QShaderProgram; - namespace Render { class ShaderManager; @@ -118,6 +118,12 @@ public: ShaderStorageBlock storageBlockForBlockNameId(int blockNameId); ShaderStorageBlock storageBlockForBlockName(const QString &blockName); + inline QString log() const { return m_log; } + inline QShaderProgram::ShaderStatus status() const { return m_status; } + + void submitPendingNotifications(); + inline bool hasPendingNotifications() const { return !m_pendingNotifications.empty(); } + private: void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL; @@ -148,6 +154,10 @@ private: mutable QMutex m_mutex; GraphicsContext *m_graphicsContext; QMetaObject::Connection m_contextConnection; + QString m_log; + QShaderProgram::ShaderStatus m_status; + + QVector m_pendingNotifications; void updateDNA(); @@ -158,6 +168,8 @@ private: void initializeShaderStorageBlocks(const QVector &shaderStorageBlockDescription); void initializeFromReference(const Shader &other); + void setLog(const QString &log); + void setStatus(QShaderProgram::ShaderStatus status); friend class GraphicsContext; }; diff --git a/tests/auto/render/shader/tst_shader.cpp b/tests/auto/render/shader/tst_shader.cpp index 95576afe0..f6ed41a8b 100644 --- a/tests/auto/render/shader/tst_shader.cpp +++ b/tests/auto/render/shader/tst_shader.cpp @@ -81,6 +81,7 @@ void tst_RenderShader::hasCoherentInitialState() QVERIFY(shader->uniforms().isEmpty()); QVERIFY(shader->attributes().isEmpty()); QVERIFY(shader->uniformBlocks().isEmpty()); + QCOMPARE(shader->status(), Qt3DRender::QShaderProgram::NotReady); } void tst_RenderShader::matchesFrontendPeer() @@ -114,6 +115,7 @@ void tst_RenderShader::cleanupLeavesACoherentState() QVERIFY(shader->uniforms().isEmpty()); QVERIFY(shader->attributes().isEmpty()); QVERIFY(shader->uniformBlocks().isEmpty()); + QCOMPARE(shader->status(), Qt3DRender::QShaderProgram::NotReady); } QTEST_APPLESS_MAIN(tst_RenderShader) -- cgit v1.2.3 From dcd5756f3870d9aed7f73c338cc8715d5fe35297 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Wed, 2 Nov 2016 15:57:43 +0200 Subject: Update scene2d implementation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add inline qml support with QQuickItem as default property. Change output to QRenderTargetOutput. Change backend node to use resource accessor and implement own fbo creation. Add event support. Change-Id: Ieb82b986696b00ba026ac9ab08c8dcbe87e84b1c Reviewed-by: Tomi Korpipää Reviewed-by: Sean Harmer --- src/quick3d/quick3drender/scene2d/qscene2d.cpp | 178 ++++++++++++--------- src/quick3d/quick3drender/scene2d/qscene2d.h | 28 ++-- src/quick3d/quick3drender/scene2d/qscene2d_p.h | 31 ++-- src/quick3d/quick3drender/scene2d/scene2d.cpp | 213 ++++++++++++++----------- src/quick3d/quick3drender/scene2d/scene2d.pri | 5 + src/quick3d/quick3drender/scene2d/scene2d_p.h | 33 ++-- 6 files changed, 280 insertions(+), 208 deletions(-) diff --git a/src/quick3d/quick3drender/scene2d/qscene2d.cpp b/src/quick3d/quick3drender/scene2d/qscene2d.cpp index 5c20db184..2f4c12367 100644 --- a/src/quick3d/quick3drender/scene2d/qscene2d.cpp +++ b/src/quick3d/quick3drender/scene2d/qscene2d.cpp @@ -36,6 +36,7 @@ #include "qscene2d.h" #include "qscene2d_p.h" +#include "scene2d_p.h" #include @@ -75,8 +76,8 @@ namespace Quick { */ /*! - \qmlproperty Qt3DRender::QAbstractTexture Qt3D.Render::Scene2D::texture - Holds the texture being rendered to. + \qmlproperty RenderTargetOutput Qt3D.Render::Scene2D::output + Holds the RenderTargetOutput, which specifies where the Scene2D is rendering to. */ /*! @@ -227,32 +228,25 @@ Scene2DManager::Scene2DManager(QScene2DPrivate *priv) , m_qmlComponent(nullptr) , m_rootItem(nullptr) , m_source(nullptr) - , m_texture(nullptr) , m_requested(false) , m_initialized(false) , m_renderSyncRequested(false) , m_sharedObject(new Scene2DSharedObject(this)) , m_renderOnce(false) , m_backendInitialized(false) + , m_noSourceMode(false) + , m_item(nullptr) { - setFormat(QSurfaceFormat::defaultFormat()); - m_sharedObject->m_surface = new QOffscreenSurface; m_sharedObject->m_surface->setFormat(QSurfaceFormat::defaultFormat()); m_sharedObject->m_surface->create(); // Create render control - m_sharedObject->m_renderControl = new RenderControl(this); + m_sharedObject->m_renderControl = new RenderControl(nullptr); // Create window to render the QML with m_sharedObject->m_quickWindow = new QQuickWindow(m_sharedObject->m_renderControl); - m_sharedObject->m_quickWindow->setClearBeforeRendering(true); - m_sharedObject->m_quickWindow->setDefaultAlphaBuffer(true); - - // Create a QML engine. - m_qmlEngine = new QQmlEngine; - if (!m_qmlEngine->incubationController()) - m_qmlEngine->setIncubationController(m_sharedObject->m_quickWindow->incubationController()); + m_sharedObject->m_quickWindow->setClearBeforeRendering(false); connect(m_sharedObject->m_renderControl, &QQuickRenderControl::renderRequested, this, &Scene2DManager::requestRender); @@ -291,8 +285,14 @@ void Scene2DManager::requestRenderSync() void Scene2DManager::startIfInitialized() { - if (!m_initialized) { - if (m_backendInitialized && m_source.isValid()) { + if (!m_initialized && m_backendInitialized) { + if (m_source.isValid() && !m_noSourceMode) { + // Create a QML engine. + m_qmlEngine = new QQmlEngine; + if (!m_qmlEngine->incubationController()) + m_qmlEngine->setIncubationController(m_sharedObject->m_quickWindow->incubationController()); + + // create component m_qmlComponent = new QQmlComponent(m_qmlEngine, m_source); if (m_qmlComponent->isLoading()) { connect(m_qmlComponent, &QQmlComponent::statusChanged, @@ -300,6 +300,17 @@ void Scene2DManager::startIfInitialized() } else { run(); } + } else if (m_item != nullptr) { + m_rootItem = m_item; + + // Associate root item with the window. + m_rootItem->setParentItem(m_sharedObject->m_quickWindow->contentItem()); + + // Update window size. + updateSizes(); + + m_initialized = true; + m_sharedObject->setInitialized(); } } } @@ -364,19 +375,19 @@ void Scene2DManager::updateSizes() qWarning() << "QScene2D: Root item size not set."; return; } - resize(width, height); m_sharedObject->m_quickWindow->setGeometry(0, 0, width, height); } -void Scene2DManager::setTexture(QAbstractTexture *texture) +void Scene2DManager::setSource(const QUrl &url) { - m_texture = texture; + m_source = url; startIfInitialized(); } -void Scene2DManager::setSource(const QUrl &url) +void Scene2DManager::setItem(QQuickItem *item) { - m_source = url; + m_noSourceMode = true; + m_item = item; startIfInitialized(); } @@ -388,12 +399,6 @@ bool Scene2DManager::event(QEvent *e) // just render request, don't need to call sync in render thread QMutexLocker lock(&m_sharedObject->m_mutex); m_sharedObject->requestRender(false); - - Qt3DCore::QPropertyUpdatedChangePtr change(new Qt3DCore::QPropertyUpdatedChange(m_priv->m_id)); - change->setPropertyName("dirty"); - change->setValue(QVariant::fromValue(true)); - m_priv->notifyObservers(change); - m_requested = false; return true; } @@ -436,7 +441,34 @@ bool Scene2DManager::event(QEvent *e) default: break; } - return QWindow::event(e); + return QObject::event(e); +} + +bool Scene2DManager::forwardEvent(QEvent *event) +{ + switch (event->type()) { + + case QEvent::MouseMove: + case QEvent::MouseButtonDblClick: + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: { + QMouseEvent* me = static_cast(event); + QPointF pos = me->localPos(); + pos = QPointF(pos.x() * m_rootItem->width(), pos.y() * m_rootItem->height()); + QMouseEvent nme = QMouseEvent(me->type(), pos, pos, pos, me->button(), me->buttons(), + me->modifiers(), Qt::MouseEventSynthesizedByApplication); + QCoreApplication::sendEvent(m_sharedObject->m_quickWindow, &nme); + } break; + + case QEvent::KeyPress: + case QEvent::KeyRelease: { + QCoreApplication::sendEvent(m_sharedObject->m_quickWindow, event); + } break; + + default: + break; + } + return false; } void Scene2DManager::doRenderSync() @@ -446,12 +478,6 @@ void Scene2DManager::doRenderSync() m_sharedObject->requestRender(true); m_sharedObject->m_renderControl->polishItems(); - Qt3DCore::QPropertyUpdatedChangePtr change(new Qt3DCore::QPropertyUpdatedChange(m_priv->m_id)); - - change->setPropertyName("dirty"); - change->setValue(QVariant::fromValue(true)); - m_priv->notifyObservers(change); - // begin waiting render thread m_sharedObject->waitRender(); m_requested = false; @@ -464,7 +490,7 @@ void Scene2DManager::cleanup() QScene2DPrivate::QScene2DPrivate() - : QFrameGraphNodePrivate() + : Qt3DCore::QNodePrivate() , m_renderManager(new Scene2DManager(this)) { } @@ -476,26 +502,17 @@ QScene2DPrivate::~QScene2DPrivate() } -Scene2DSharedObject *QScene2DPrivate::getSharedObject(QScene2D *rqtt) -{ - return rqtt->d_func()->m_renderManager->m_sharedObject.data(); -} - - /*! - The constructor creates an instance with the specified \a parent. + The constructor creates a new QScene2D instance with the specified \a parent. */ QScene2D::QScene2D(Qt3DCore::QNode *parent) - : QFrameGraphNode(*new QScene2DPrivate, parent) + : Qt3DCore::QNode(*new QScene2DPrivate, parent) { Q_D(QScene2D); connect(d->m_renderManager, &Scene2DManager::onLoadedChanged, this, &QScene2D::sourceLoaded); } -/*! - Destructor. - */ QScene2D::~QScene2D() { } @@ -532,6 +549,23 @@ void QScene2D::setSource(const QUrl &url) emit sourceChanged(url); } +QQuickItem* QScene2D::item() const +{ + Q_D(const QScene2D); + return d->m_renderManager->m_rootItem; +} + +void QScene2D::setItem(QQuickItem *item) +{ + Q_D(QScene2D); + if (d->m_renderManager->m_initialized) { + qWarning() << "Unable to set item after initialization."; + return; + } + d->m_renderManager->setItem(item); + emit itemChanged(item); +} + /*! \property QScene2D::renderOnce \brief Property to specify if the texture will be rendered only once. @@ -557,58 +591,47 @@ void QScene2D::setRenderOnce(bool once) } /*! - \property QScene2D::texture - \brief The texture being rendered to. - - This property specifies the texture being rendered to. Once the texture has been - set and the rendering begins, the texture can not be changed anymore. + \property QScene2D::output + Holds the QRenderTargetOutput, which specifies where the QScene2D is + rendering to. */ -QAbstractTexture *QScene2D::texture() const +Qt3DRender::QRenderTargetOutput *QScene2D::output() const { Q_D(const QScene2D); - return d->m_renderManager->m_texture; + return d->m_output; } -void QScene2D::setTexture(QAbstractTexture *texture) +void QScene2D::setOutput(Qt3DRender::QRenderTargetOutput *output) { Q_D(QScene2D); - if (d->m_renderManager->m_initialized) { - qWarning() << "Unable to set texture after initialization."; - return; - } - if (d->m_renderManager->m_texture != texture) { - if (d->m_renderManager->m_texture) - QObject::disconnect(d->m_textureDestroyedConnection); - if (texture && !texture->parent()) - texture->setParent(this); - d->m_renderManager->setTexture(texture); - if (texture) - d->m_textureDestroyedConnection - = QObject::connect(texture, &QAbstractTexture::destroyed, - this, &QScene2D::textureDestroyed); - emit textureChanged(texture); + if (d->m_output != output) { + if (d->m_output) + d->unregisterDestructionHelper(d->m_output); + d->m_output = output; + if (output) + d->registerDestructionHelper(output, &QScene2D::setOutput, d->m_output); + emit outputChanged(output); } } -void QScene2D::textureDestroyed(QObject *object) -{ - Q_D(QScene2D); - Q_UNUSED(object); - d->m_renderManager->setTexture(nullptr); -} - Qt3DCore::QNodeCreatedChangeBasePtr QScene2D::createNodeCreationChange() const { auto creationChange = Qt3DCore::QNodeCreatedChangePtr::create(this); auto &data = creationChange->data; Q_D(const QScene2D); data.renderOnce = d->m_renderManager->m_renderOnce; - data.textureId = d->m_renderManager->m_texture - ? d->m_renderManager->m_texture->id() : Qt3DCore::QNodeId(); data.sharedObject = d->m_renderManager->m_sharedObject; + data.output = d->m_output ? d->m_output->id() : Qt3DCore::QNodeId(); return creationChange; } +bool QScene2D::event(QEvent *event) +{ + Q_D(QScene2D); + d->m_renderManager->forwardEvent(event); + return true; +} + /*! \internal */ @@ -618,7 +641,6 @@ void QScene2D::sourceLoaded() } } // namespace Quick - } // namespace Qt3DRender QT_END_NAMESPACE diff --git a/src/quick3d/quick3drender/scene2d/qscene2d.h b/src/quick3d/quick3drender/scene2d/qscene2d.h index a00e7b06b..67871f161 100644 --- a/src/quick3d/quick3drender/scene2d/qscene2d.h +++ b/src/quick3d/quick3drender/scene2d/qscene2d.h @@ -37,12 +37,15 @@ #ifndef QT3DRENDER_QUICK3DRENDER_QSCENE2D_H #define QT3DRENDER_QUICK3DRENDER_QSCENE2D_H +#include +#include + #include #include -#include -#include -#include +#include + +#include QT_BEGIN_NAMESPACE @@ -52,41 +55,46 @@ namespace Quick { class QScene2DPrivate; -class QT3DQUICKRENDERSHARED_EXPORT QScene2D : public Qt3DRender::QFrameGraphNode +class QT3DQUICKRENDERSHARED_EXPORT QScene2D : public Qt3DCore::QNode { Q_OBJECT - Q_PROPERTY(Qt3DRender::QAbstractTexture *texture READ texture WRITE setTexture NOTIFY textureChanged) + Q_PROPERTY(Qt3DRender::QRenderTargetOutput *output READ output WRITE setOutput NOTIFY outputChanged) Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged) Q_PROPERTY(bool renderOnce READ renderOnce WRITE setRenderOnce NOTIFY renderOnceChanged) Q_PROPERTY(bool loaded READ loaded NOTIFY loadedChanged) + Q_PROPERTY(QQuickItem *item READ item WRITE setItem NOTIFY itemChanged) + + Q_CLASSINFO("DefaultProperty", "item") public: explicit QScene2D(Qt3DCore::QNode *parent = nullptr); ~QScene2D(); + Qt3DRender::QRenderTargetOutput *output() const; QUrl source() const; - QAbstractTexture *texture() const; bool loaded() const; bool renderOnce() const; - + QQuickItem *item() const; + bool event(QEvent *event) Q_DECL_OVERRIDE; public Q_SLOTS: + void setOutput(Qt3DRender::QRenderTargetOutput *output); void setSource(const QUrl &url); - void setTexture(QAbstractTexture *texture); void setRenderOnce(bool once); + void setItem(QQuickItem *item); Q_SIGNALS: + void outputChanged(Qt3DRender::QRenderTargetOutput *output); void sourceChanged(const QUrl &url); - void textureChanged(QAbstractTexture *texture); void loadedChanged(bool loaded); void renderOnceChanged(bool once); + void itemChanged(QQuickItem *item); protected: Q_DECLARE_PRIVATE(QScene2D) private: Qt3DCore::QNodeCreatedChangeBasePtr createNodeCreationChange() const Q_DECL_OVERRIDE; - void textureDestroyed(QObject *object); void sourceLoaded(); }; diff --git a/src/quick3d/quick3drender/scene2d/qscene2d_p.h b/src/quick3d/quick3drender/scene2d/qscene2d_p.h index 165a54b72..4fa65fb1b 100644 --- a/src/quick3d/quick3drender/scene2d/qscene2d_p.h +++ b/src/quick3d/quick3drender/scene2d/qscene2d_p.h @@ -48,12 +48,6 @@ // We mean it. // -#include -#include - -#include -#include - #include #include #include @@ -64,6 +58,12 @@ #include #include +#include +#include + +#include +#include + QT_BEGIN_NAMESPACE namespace Qt3DRender { @@ -141,7 +141,7 @@ private: typedef QSharedPointer Scene2DSharedObjectPtr; -class Q_AUTOTEST_EXPORT QScene2DPrivate : public QFrameGraphNodePrivate +class Q_AUTOTEST_EXPORT QScene2DPrivate : public Qt3DCore::QNodePrivate { public: Q_DECLARE_PUBLIC(QScene2D) @@ -149,21 +149,19 @@ public: QScene2DPrivate(); ~QScene2DPrivate(); - static Scene2DSharedObject *getSharedObject(QScene2D *rqtt); - Scene2DManager *m_renderManager; QMetaObject::Connection m_textureDestroyedConnection; + Qt3DRender::QRenderTargetOutput *m_output; }; struct QScene2DData { bool renderOnce; - Qt3DCore::QNodeId textureId; Scene2DSharedObjectPtr sharedObject; + Qt3DCore::QNodeId output; }; - -class Scene2DManager : public QWindow +class Scene2DManager : public QObject { Q_OBJECT public: @@ -173,11 +171,11 @@ public: QQmlEngine *m_qmlEngine; QQmlComponent *m_qmlComponent; QQuickItem *m_rootItem; + QQuickItem *m_item; QScene2DPrivate *m_priv; QSharedPointer m_sharedObject; - QAbstractTexture *m_texture; QUrl m_source; Qt3DCore::QNodeId m_id; @@ -186,6 +184,7 @@ public: bool m_renderSyncRequested; bool m_renderOnce; bool m_backendInitialized; + bool m_noSourceMode; void requestRender(); void requestRenderSync(); @@ -195,10 +194,11 @@ public: void run(); void updateSizes(); - void setTexture(QAbstractTexture *texture); void setSource(const QUrl &url); + void setItem(QQuickItem *item); bool event(QEvent *e) Q_DECL_OVERRIDE; + bool forwardEvent(QEvent *event); Q_SIGNAL void onLoadedChanged(); @@ -206,9 +206,10 @@ public: }; } // namespace Quick - } // namespace Qt3DRender QT_END_NAMESPACE +Q_DECLARE_METATYPE(Qt3DRender::Quick::Scene2DSharedObjectPtr) + #endif // QT3DRENDER_QUICK3DRENDER_QSCENE2D_P_H diff --git a/src/quick3d/quick3drender/scene2d/scene2d.cpp b/src/quick3d/quick3drender/scene2d/scene2d.cpp index 210cc5f0f..0ccf38fc7 100644 --- a/src/quick3d/quick3drender/scene2d/scene2d.cpp +++ b/src/quick3d/quick3drender/scene2d/scene2d.cpp @@ -42,10 +42,15 @@ #include #include #include - +#include +#include QT_BEGIN_NAMESPACE +#ifndef GL_DEPTH24_STENCIL8 +#define GL_DEPTH24_STENCIL8 0x88F0 +#endif + using namespace Qt3DRender::Quick; namespace Qt3DRender { @@ -87,15 +92,15 @@ bool RenderQmlEventHandler::event(QEvent *e) } Scene2D::Scene2D() - : FrameGraphNode(FrameGraphNode::InvalidNodeType) - , m_context(nullptr) + : m_context(nullptr) + , m_shareContext(nullptr) , m_sharedObject(nullptr) , m_renderThread(nullptr) - , m_graphicsContext(nullptr) - , m_texture(nullptr) , m_initialized(false) , m_renderInitialized(false) , m_renderOnce(false) + , m_fbo(0) + , m_rbo(0) { } @@ -109,16 +114,14 @@ Scene2D::~Scene2D() } } -void Scene2D::setTexture(Qt3DCore::QNodeId textureId) +void Scene2D::setOutput(Qt3DCore::QNodeId outputId) { - m_textureId = textureId; - attach(); - checkInitialized(); + m_outputId = outputId; } -void Scene2D::checkInitialized() +void Scene2D::initializeSharedObject() { - if (!m_initialized && m_textureId != Qt3DCore::QNodeId()) { + if (!m_initialized) { // Create render thread m_renderThread = new QThread(); @@ -144,9 +147,11 @@ void Scene2D::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &chan { const auto typedChange = qSharedPointerCast>(change); const auto &data = typedChange->data; - m_renderOnce = m_renderOnce; + m_renderOnce = data.renderOnce; setSharedObject(data.sharedObject); - setTexture(data.textureId); + setOutput(data.output); + m_shareContext = renderer()->shareContext(); + m_accessor = resourceAccessor(); } void Scene2D::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) @@ -154,35 +159,31 @@ void Scene2D::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) if (e->type() == Qt3DCore::PropertyUpdated) { Qt3DCore::QPropertyUpdatedChangePtr propertyChange = qSharedPointerCast(e); - if (propertyChange->propertyName() == QByteArrayLiteral("enabled")) - setEnabled(propertyChange->value().toBool()); - else if (propertyChange->propertyName() == QByteArrayLiteral("dirty")) { - // sent to trigger backend update when the texture gets rendered - // so do nothing here - } - else if (propertyChange->propertyName() == QByteArrayLiteral("renderOnce")) + if (propertyChange->propertyName() == QByteArrayLiteral("renderOnce")) m_renderOnce = propertyChange->value().toBool(); - else if (propertyChange->propertyName() == QByteArrayLiteral("texture")) { - Qt3DCore::QNodeId textureId = propertyChange->value().value(); - setTexture(textureId); + else if (propertyChange->propertyName() == QByteArrayLiteral("output")) { + Qt3DCore::QNodeId outputId = propertyChange->value().value(); + setOutput(outputId); + } else if (propertyChange->propertyName() == QByteArrayLiteral("sharedObject")) { + const Scene2DSharedObjectPtr sharedObject + = propertyChange->value().value(); + setSharedObject(sharedObject); } - markDirty(AbstractRenderer::AllDirty); } - FrameGraphNode::sceneChangeEvent(e); } void Scene2D::setSharedObject(Qt3DRender::Quick::Scene2DSharedObjectPtr sharedObject) { m_sharedObject = sharedObject; + if (!m_initialized) + initializeSharedObject(); } void Scene2D::initializeRender() { if (!m_renderInitialized) { - Qt3DRender::Render::Renderer *renderer - = static_cast(this->renderer()); - if (!renderer) - return; + + Q_ASSERT(m_shareContext); QSurfaceFormat format; format.setDepthBufferSize(24); @@ -190,96 +191,124 @@ void Scene2D::initializeRender() m_context = new QOpenGLContext(); m_context->setFormat(format); - - m_context->setShareContext(renderer->shareContext()); + m_context->setShareContext(m_shareContext); m_context->create(); - m_graphicsContext = new GraphicsContext(); - m_graphicsContext->setOpenGLContext(m_context); - m_graphicsContext->setRenderer(renderer); - - m_graphicsContext->makeCurrent(m_sharedObject->m_surface); + m_context->makeCurrent(m_sharedObject->m_surface); m_sharedObject->m_renderControl->initialize(m_context); - m_graphicsContext->doneCurrent(); + m_context->doneCurrent(); QCoreApplication::postEvent(m_sharedObject->m_renderManager, new QEvent(PREPARE)); m_renderInitialized = true; } } -void Scene2D::attach() +bool Scene2D::updateFbo(QOpenGLTexture *texture) { - m_attachments = AttachmentPack(); - Attachment attach; - attach.m_mipLevel = 0; - attach.m_textureUuid = m_textureId; - attach.m_point = QRenderTargetOutput::AttachmentPoint::Color0; + QOpenGLFunctions *gl = m_context->functions(); + if (m_fbo == 0) { + gl->glGenFramebuffers(1, &m_fbo); + gl->glGenRenderbuffers(1, &m_rbo); + } + // TODO: Add another codepath when GL_DEPTH24_STENCIL8 is not supported + gl->glBindRenderbuffer(GL_RENDERBUFFER, m_rbo); + gl->glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, + m_textureSize.width(), m_textureSize.height()); + gl->glBindRenderbuffer(GL_RENDERBUFFER, 0); + + gl->glBindFramebuffer(GL_FRAMEBUFFER, m_fbo); + gl->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, texture->textureId(), 0); + gl->glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_rbo); + GLenum status = gl->glCheckFramebufferStatus(GL_FRAMEBUFFER); + gl->glBindFramebuffer(GL_FRAMEBUFFER, 0); + + if (status != GL_FRAMEBUFFER_COMPLETE) + return false; + return true; +} + +void Scene2D::syncRenderControl() +{ + if (m_sharedObject->isSyncRequested()) { -// m_attachments.addAttachment(attach); + m_sharedObject->clearSyncRequest(); + + m_sharedObject->m_renderControl->sync(); + + // gui thread can now continue + m_sharedObject->wakeWaiting(); + } } void Scene2D::render() { - if (m_initialized && m_sharedObject && this->isEnabled()) { + if (m_initialized && m_renderInitialized && m_sharedObject.data() != nullptr) { QMutexLocker lock(&m_sharedObject->m_mutex); - // Lookup backend texture - if (m_texture == nullptr) { - m_texture = renderer()->nodeManagers()->textureManager()->lookupResource(m_textureId); - if (!m_texture) { - qCDebug(Render::Framegraph) << Q_FUNC_INFO << "Texture not set"; + QOpenGLTexture *texture = nullptr; + const Qt3DRender::Render::Attachment *attachmentData = nullptr; + QMutex *textureLock = nullptr; + + m_context->makeCurrent(m_sharedObject->m_surface); + if (m_accessor->accessResource(m_outputId, (void**)&attachmentData, nullptr)) { + if (!m_accessor->accessResource(attachmentData->m_textureUuid, (void**)&texture, &textureLock)) { + // Need to call sync even if the texture is not in use + syncRenderControl(); + m_context->doneCurrent(); + // TODO: add logging category for scene2d + //qCWarning(Scene2D) << "Texture not in use."; return; } + textureLock->lock(); + const QSize textureSize = QSize(texture->width(), texture->height()); + if (m_attachmentData.m_textureUuid != attachmentData->m_textureUuid + || m_attachmentData.m_point != attachmentData->m_point + || m_attachmentData.m_face != attachmentData->m_face + || m_attachmentData.m_layer != attachmentData->m_layer + || m_attachmentData.m_mipLevel != attachmentData->m_mipLevel + || m_textureSize != textureSize) { + m_textureSize = textureSize; + m_attachmentData = *attachmentData; + if (!updateFbo(texture)) { + // Need to call sync even if the fbo is not usable + syncRenderControl(); + textureLock->unlock(); + m_context->doneCurrent(); + //qCWarning(Scene2D) << "Fbo not initialized."; + return; + } + } } - m_graphicsContext->makeCurrent(m_sharedObject->m_surface); - - // Don't create the OpenGL texture in this thread. - const bool canUseTexture = !m_texture->isTextureReset(); - - if (canUseTexture) { - // Activate fbo for the texture - QOpenGLTexture *glTex = m_texture->getOrCreateGLTexture(); - const QSize textureSize = QSize(glTex->width(), glTex->height()); + if (m_fbo != m_sharedObject->m_quickWindow->renderTargetId()) + m_sharedObject->m_quickWindow->setRenderTarget(m_fbo, m_textureSize); - GLuint fbo = 0; //m_graphicsContext->activateRenderTargetForQmlRender(this, m_attachments, 0); - - if (fbo != m_sharedObject->m_quickWindow->renderTargetId()) - m_sharedObject->m_quickWindow->setRenderTarget(fbo, textureSize); - - m_texture->textureLock()->lock(); - } // Call disallow rendering while mutex is locked - if (canUseTexture && m_renderOnce) + if (m_renderOnce) m_sharedObject->disallowRender(); - // Need to call sync even if the texture is not in use - if (m_sharedObject->isSyncRequested()) { + // Sync + syncRenderControl(); - m_sharedObject->clearSyncRequest(); + // The lock is not needed anymore so release it before the following + // time comsuming operations + lock.unlock(); - m_sharedObject->m_renderControl->sync(); + // Render + m_sharedObject->m_renderControl->render(); - // gui thread can now continue - m_sharedObject->wakeWaiting(); - lock.unlock(); - } + // Tell main thread we are done so it can begin cleanup if this is final frame + if (m_renderOnce) + QCoreApplication::postEvent(m_sharedObject->m_renderManager, new QEvent(RENDERED)); - if (canUseTexture) { - - // Render - m_sharedObject->m_renderControl->render(); - - // Tell main thread we are done so it can begin cleanup - if (m_renderOnce) - QCoreApplication::postEvent(m_sharedObject->m_renderManager, new QEvent(RENDERED)); - - m_sharedObject->m_quickWindow->resetOpenGLState(); - m_context->functions()->glFlush(); - m_texture->textureLock()->unlock(); - } - m_graphicsContext->doneCurrent(); + m_sharedObject->m_quickWindow->resetOpenGLState(); + m_context->functions()->glFlush(); + if (texture->isAutoMipMapGenerationEnabled()) + texture->generateMipMaps(); + textureLock->unlock(); + m_context->doneCurrent(); } } @@ -288,6 +317,8 @@ void Scene2D::cleanup() if (m_renderInitialized && m_initialized) { m_context->makeCurrent(m_sharedObject->m_surface); m_sharedObject->m_renderControl->invalidate(); + m_context->functions()->glDeleteFramebuffers(1, &m_fbo); + m_context->functions()->glDeleteRenderbuffers(1, &m_rbo); m_context->doneCurrent(); m_sharedObject->m_renderThread->quit(); delete m_sharedObject->m_renderObject; @@ -295,17 +326,13 @@ void Scene2D::cleanup() delete m_context; m_context = nullptr; m_sharedObject = nullptr; - delete m_graphicsContext; - m_graphicsContext = nullptr; m_renderInitialized = false; m_initialized = false; } } } // namespace Quick - } // namespace Render - } // namespace Qt3DRender QT_END_NAMESPACE diff --git a/src/quick3d/quick3drender/scene2d/scene2d.pri b/src/quick3d/quick3drender/scene2d/scene2d.pri index 05ab6b83f..4635c43e1 100644 --- a/src/quick3d/quick3drender/scene2d/scene2d.pri +++ b/src/quick3d/quick3drender/scene2d/scene2d.pri @@ -1,5 +1,10 @@ HEADERS += \ + $$PWD/qscene2d.h \ + $$PWD/qscene2d_p.h \ + $$PWD/scene2d_p.h SOURCES += \ + $$PWD/qscene2d.cpp \ + $$PWD/scene2d.cpp INCLUDEPATH += $$PWD diff --git a/src/quick3d/quick3drender/scene2d/scene2d_p.h b/src/quick3d/quick3drender/scene2d/scene2d_p.h index 950ddaa5b..769916fc9 100644 --- a/src/quick3d/quick3drender/scene2d/scene2d_p.h +++ b/src/quick3d/quick3drender/scene2d/scene2d_p.h @@ -50,12 +50,14 @@ #include -#include -#include - #include #include +#include +#include +#include +#include + QT_BEGIN_NAMESPACE namespace Qt3DRender { @@ -79,30 +81,37 @@ private: Scene2D *m_node; }; -class Q_AUTOTEST_EXPORT Scene2D : public FrameGraphNode +class Q_AUTOTEST_EXPORT Scene2D : public Qt3DRender::Render::BackendNode { public: Scene2D(); ~Scene2D(); - void attach(); void render(); void initializeRender(); void setSharedObject(Qt3DRender::Quick::Scene2DSharedObjectPtr sharedObject); void cleanup(); - void setTexture(Qt3DCore::QNodeId textureId); - void checkInitialized(); + void setOutput(Qt3DCore::QNodeId outputId); + void initializeSharedObject(); + void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_OVERRIDE; void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_OVERRIDE; - void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL; + + bool updateFbo(QOpenGLTexture *texture); + void syncRenderControl(); QOpenGLContext *m_context; - GraphicsContext *m_graphicsContext; + QOpenGLContext *m_shareContext; QThread *m_renderThread; - Qt3DCore::QNodeId m_textureId; + Qt3DCore::QNodeId m_outputId; QSharedPointer m_sharedObject; - AttachmentPack m_attachments; - Texture *m_texture; + Qt3DCore::QNodeId m_peerId; + QSharedPointer m_accessor; + Qt3DRender::Render::Attachment m_attachmentData; + + GLuint m_fbo; + GLuint m_rbo; + QSize m_textureSize; bool m_initialized; bool m_renderInitialized; -- cgit v1.2.3 From b25ff28d9bc30482a3bb95788a68cca124a290dc Mon Sep 17 00:00:00 2001 From: Wieland Hagen Date: Wed, 21 Dec 2016 21:51:59 +0700 Subject: Fix updating of texture generator Change-Id: I9cecfb7ec366b51f1a9c99f9d8297b41dda05ead Reviewed-by: Sean Harmer --- src/render/backend/renderer.cpp | 4 +++ src/render/texture/apitexturemanager_p.h | 15 +++++++++++ src/render/texture/gltexture.cpp | 45 ++++++++++++++++++++++---------- src/render/texture/gltexture_p.h | 5 +++- src/render/texture/texture.cpp | 4 +-- src/render/texture/texture_p.h | 3 ++- 6 files changed, 58 insertions(+), 18 deletions(-) diff --git a/src/render/backend/renderer.cpp b/src/render/backend/renderer.cpp index f169261d5..19529887a 100644 --- a/src/render/backend/renderer.cpp +++ b/src/render/backend/renderer.cpp @@ -995,6 +995,10 @@ void Renderer::updateTexture(Texture *texture) !glTextureManager->setImages(glTexture, texture->textureImages())) qWarning() << "[Qt3DRender::TextureNode] updateTexture: TextureImpl.setGenerators failed, should be non-shared"; + if (dirtyFlags.testFlag(Texture::DirtyDataGenerator) && + !glTextureManager->setGenerator(glTexture, texture->dataGenerator())) + qWarning() << "[Qt3DRender::TextureNode] updateTexture: TextureImpl.setGenerator failed, should be non-shared"; + // Unset the dirty flag on the texture texture->unsetDirty(); } diff --git a/src/render/texture/apitexturemanager_p.h b/src/render/texture/apitexturemanager_p.h index 2fd340e7e..c062f0971 100644 --- a/src/render/texture/apitexturemanager_p.h +++ b/src/render/texture/apitexturemanager_p.h @@ -237,6 +237,21 @@ public: return true; } + // Change the texture data generator for given texture, if it is a non-shared texture + // Return true, if it was changed successfully, false otherwise + bool setGenerator(APITexture *tex, const QTextureGeneratorPtr &generator) + { + Q_ASSERT(tex); + + if (isShared(tex)) + return false; + + tex->setGenerator(generator); + m_updatedTextures.push_back(tex); + + return true; + } + // Retrieves abandoned textures. This should be regularly called from the OpenGL thread // to make sure needed GL resources are de-allocated. QVector takeAbandonedTextures() diff --git a/src/render/texture/gltexture.cpp b/src/render/texture/gltexture.cpp index 0fc37891d..98af9b6f4 100644 --- a/src/render/texture/gltexture.cpp +++ b/src/render/texture/gltexture.cpp @@ -120,7 +120,7 @@ QOpenGLTexture* GLTexture::getOrCreateGLTexture() if (m_properties.target != QAbstractTexture::TargetAutomatic) qWarning() << "[Qt3DRender::GLTexture] When a texture provides a generator, it's target is expected to be TargetAutomatic"; - m_properties.target = m_textureData->target(); + m_actualTarget = m_textureData->target(); m_properties.width = m_textureData->width(); m_properties.height = m_textureData->height(); m_properties.depth = m_textureData->depth(); @@ -224,6 +224,7 @@ void GLTexture::setProperties(const TextureProperties &props) if (m_properties != props) { m_properties = props; QMutexLocker locker(&m_dirtyFlagMutex); + m_actualTarget = props.target; m_dirty |= Properties; } } @@ -278,6 +279,22 @@ void GLTexture::setImages(const QVector &images) } } +void GLTexture::setGenerator(const QTextureGeneratorPtr &generator) +{ + if (m_dataFunctor != generator) { + if (m_dataFunctor) + m_textureDataManager->releaseData(m_dataFunctor, this); + + m_textureData.reset(); + m_dataFunctor = generator; + + if (m_dataFunctor) { + m_textureDataManager->requestData(m_dataFunctor, this); + requestUpload(); + } + } +} + QOpenGLTexture *GLTexture::buildGLTexture() { QOpenGLContext *ctx = QOpenGLContext::currentContext(); @@ -286,12 +303,12 @@ QOpenGLTexture *GLTexture::buildGLTexture() return nullptr; } - if (m_properties.target == QAbstractTexture::TargetAutomatic) { + if (m_actualTarget == QAbstractTexture::TargetAutomatic) { qWarning() << Q_FUNC_INFO << "something went wrong, target shouldn't be automatic at this point"; return nullptr; } - QOpenGLTexture* glTex = new QOpenGLTexture(static_cast(m_properties.target)); + QOpenGLTexture* glTex = new QOpenGLTexture(static_cast(m_actualTarget)); // m_format may not be ES2 compatible. Now it's time to convert it, if necessary. QAbstractTexture::TextureFormat format = m_properties.format; @@ -329,16 +346,16 @@ QOpenGLTexture *GLTexture::buildGLTexture() static_cast(format)); glTex->setSize(m_properties.width, m_properties.height, m_properties.depth); // Set layers count if texture array - if (m_properties.target == QAbstractTexture::Target1DArray || - m_properties.target == QAbstractTexture::Target2DArray || - m_properties.target == QAbstractTexture::Target3D || - m_properties.target == QAbstractTexture::Target2DMultisampleArray || - m_properties.target == QAbstractTexture::TargetCubeMapArray) { + if (m_actualTarget == QAbstractTexture::Target1DArray || + m_actualTarget == QAbstractTexture::Target2DArray || + m_actualTarget == QAbstractTexture::Target3D || + m_actualTarget == QAbstractTexture::Target2DMultisampleArray || + m_actualTarget == QAbstractTexture::TargetCubeMapArray) { glTex->setLayers(m_properties.layers); } - if (m_properties.target == QAbstractTexture::Target2DMultisample || - m_properties.target == QAbstractTexture::Target2DMultisampleArray) { + if (m_actualTarget == QAbstractTexture::Target2DMultisample || + m_actualTarget == QAbstractTexture::Target2DMultisampleArray) { // Set samples count if multisampled texture // (multisampled textures don't have mipmaps) glTex->setSamples(m_properties.samples); @@ -410,11 +427,11 @@ void GLTexture::uploadGLTextureData() void GLTexture::updateGLTextureParameters() { m_gl->setWrapMode(QOpenGLTexture::DirectionS, static_cast(m_parameters.wrapModeX)); - if (m_properties.target != QAbstractTexture::Target1D && - m_properties.target != QAbstractTexture::Target1DArray && - m_properties.target != QAbstractTexture::TargetBuffer) + if (m_actualTarget != QAbstractTexture::Target1D && + m_actualTarget != QAbstractTexture::Target1DArray && + m_actualTarget != QAbstractTexture::TargetBuffer) m_gl->setWrapMode(QOpenGLTexture::DirectionT, static_cast(m_parameters.wrapModeY)); - if (m_properties.target == QAbstractTexture::Target3D) + if (m_actualTarget == QAbstractTexture::Target3D) m_gl->setWrapMode(QOpenGLTexture::DirectionR, static_cast(m_parameters.wrapModeZ)); m_gl->setMinMagFilters(static_cast(m_parameters.minificationFilter), static_cast(m_parameters.magnificationFilter)); diff --git a/src/render/texture/gltexture_p.h b/src/render/texture/gltexture_p.h index 424e77854..558a22f84 100644 --- a/src/render/texture/gltexture_p.h +++ b/src/render/texture/gltexture_p.h @@ -164,11 +164,12 @@ protected: void setParameters(const TextureParameters ¶ms); void setProperties(const TextureProperties &props); void setImages(const QVector &images); + void setGenerator(const QTextureGeneratorPtr &generator); private: enum DirtyFlag { - TextureData = 0x01, // one or more generators have been executed, data needs uploading to GPU + TextureData = 0x01, // one or more image generators have been executed, data needs uploading to GPU Properties = 0x02, // texture needs to be (re-)created Parameters = 0x04 // texture parameters need to be (re-)set @@ -188,6 +189,8 @@ private: TextureDataManager *m_textureDataManager; TextureImageDataManager *m_textureImageDataManager; + // target which is actually used for GL texture + QAbstractTexture::Target m_actualTarget; TextureProperties m_properties; TextureParameters m_parameters; diff --git a/src/render/texture/texture.cpp b/src/render/texture/texture.cpp index 863733523..b793462ca 100644 --- a/src/render/texture/texture.cpp +++ b/src/render/texture/texture.cpp @@ -61,7 +61,7 @@ namespace Render { Texture::Texture() // We need backend -> frontend notifications to update the status of the texture : BackendNode(ReadWrite) - , m_dirty(DirtyGenerators|DirtyProperties|DirtyParameters) + , m_dirty(DirtyGenerators|DirtyProperties|DirtyParameters|DirtyDataGenerator) , m_textureImageManager(nullptr) { } @@ -214,7 +214,7 @@ void Texture::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) dirty = DirtyProperties; } else if (propertyChange->propertyName() == QByteArrayLiteral("generator")) { m_dataFunctor = propertyChange->value().value(); - dirty = DirtyGenerators; + dirty = DirtyDataGenerator; } } break; diff --git a/src/render/texture/texture_p.h b/src/render/texture/texture_p.h index 8f5300552..1ce73b0fe 100644 --- a/src/render/texture/texture_p.h +++ b/src/render/texture/texture_p.h @@ -135,7 +135,8 @@ public: NotDirty = 0, DirtyProperties = 0x1, DirtyParameters = 0x2, - DirtyGenerators = 0x4 + DirtyGenerators = 0x4, + DirtyDataGenerator = 0x8 }; Q_DECLARE_FLAGS(DirtyFlags, DirtyFlag) -- cgit v1.2.3 From 8ec785d21c13ed0a8d375ff13bf06bea1deb11ae Mon Sep 17 00:00:00 2001 From: Wieland Hagen Date: Wed, 21 Dec 2016 23:07:44 +0700 Subject: Rename Texture::DirtyGenerators to DirtyImageGenerators To distinguish clearly from DirtyDataGenerator Change-Id: Ib170529c027f24bf848a25f99dd34352a1d1030e Reviewed-by: Sean Harmer --- src/render/backend/renderer.cpp | 2 +- src/render/texture/texture.cpp | 8 ++++---- src/render/texture/texture_p.h | 2 +- src/render/texture/textureimage.cpp | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/render/backend/renderer.cpp b/src/render/backend/renderer.cpp index 19529887a..c0b85c349 100644 --- a/src/render/backend/renderer.cpp +++ b/src/render/backend/renderer.cpp @@ -991,7 +991,7 @@ void Renderer::updateTexture(Texture *texture) !glTextureManager->setParameters(glTexture, texture->parameters())) qWarning() << "[Qt3DRender::TextureNode] updateTexture: TextureImpl.setParameters failed, should be non-shared"; - if (dirtyFlags.testFlag(Texture::DirtyGenerators) && + if (dirtyFlags.testFlag(Texture::DirtyImageGenerators) && !glTextureManager->setImages(glTexture, texture->textureImages())) qWarning() << "[Qt3DRender::TextureNode] updateTexture: TextureImpl.setGenerators failed, should be non-shared"; diff --git a/src/render/texture/texture.cpp b/src/render/texture/texture.cpp index b793462ca..8dd9ad229 100644 --- a/src/render/texture/texture.cpp +++ b/src/render/texture/texture.cpp @@ -61,7 +61,7 @@ namespace Render { Texture::Texture() // We need backend -> frontend notifications to update the status of the texture : BackendNode(ReadWrite) - , m_dirty(DirtyGenerators|DirtyProperties|DirtyParameters|DirtyDataGenerator) + , m_dirty(DirtyImageGenerators|DirtyProperties|DirtyParameters|DirtyDataGenerator) , m_textureImageManager(nullptr) { } @@ -101,7 +101,7 @@ void Texture::addTextureImage(Qt3DCore::QNodeId id) qWarning() << "[Qt3DRender::TextureNode] addTextureImage: image handle is NULL"; } else if (!m_textureImages.contains(handle)) { m_textureImages << handle; - addDirtyFlag(DirtyGenerators); + addDirtyFlag(DirtyImageGenerators); } } @@ -117,7 +117,7 @@ void Texture::removeTextureImage(Qt3DCore::QNodeId id) qWarning() << "[Qt3DRender::TextureNode] removeTextureImage: image handle is NULL"; } else { m_textureImages.removeAll(handle); - addDirtyFlag(DirtyGenerators); + addDirtyFlag(DirtyImageGenerators); } } @@ -269,7 +269,7 @@ void Texture::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &chan m_parameters.comparisonMode = data.comparisonMode; m_dataFunctor = data.dataFunctor; - addDirtyFlag(DirtyFlags(DirtyGenerators|DirtyProperties|DirtyParameters)); + addDirtyFlag(DirtyFlags(DirtyImageGenerators|DirtyProperties|DirtyParameters)); } diff --git a/src/render/texture/texture_p.h b/src/render/texture/texture_p.h index 1ce73b0fe..f99d1d38b 100644 --- a/src/render/texture/texture_p.h +++ b/src/render/texture/texture_p.h @@ -135,7 +135,7 @@ public: NotDirty = 0, DirtyProperties = 0x1, DirtyParameters = 0x2, - DirtyGenerators = 0x4, + DirtyImageGenerators = 0x4, DirtyDataGenerator = 0x8 }; Q_DECLARE_FLAGS(DirtyFlags, DirtyFlag) diff --git a/src/render/texture/textureimage.cpp b/src/render/texture/textureimage.cpp index f44a82649..b732be2d9 100644 --- a/src/render/texture/textureimage.cpp +++ b/src/render/texture/textureimage.cpp @@ -106,7 +106,7 @@ void TextureImage::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) // Notify the Texture that we were updated and request it to schedule an update job Texture *txt = m_textureManager->data(m_textureProvider); if (txt != nullptr) - txt->addDirtyFlag(Texture::DirtyGenerators); + txt->addDirtyFlag(Texture::DirtyImageGenerators); } markDirty(AbstractRenderer::AllDirty); -- cgit v1.2.3 From 5fb7611e5fac37739668d657642f5efd52797d96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Tue, 31 May 2016 15:22:15 +0300 Subject: Render QML to texture examples MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds tests for the RenderQmlToTexture. Task-number: QTBUG-51656 Change-Id: Ice18b308b85bc522ac5cdb37894d360438b8b3ac Reviewed-by: Tomi Korpipää Reviewed-by: Sean Harmer --- tests/manual/manual.pro | 4 +- .../render-qml-to-texture-qml/PlaneMaterial.qml | 117 ++++++++++++++++++ tests/manual/render-qml-to-texture-qml/main.cpp | 65 ++++++++++ tests/manual/render-qml-to-texture-qml/main.qml | 133 +++++++++++++++++++++ .../render-qml-to-texture-qml.pro | 21 ++++ .../render-qml-to-texture-qml.qrc | 6 + .../manual/render-qml-to-texture/OffscreenGui.qml | 131 ++++++++++++++++++++ .../manual/render-qml-to-texture/TextRectangle.qml | 86 +++++++++++++ tests/manual/render-qml-to-texture/main.cpp | 125 +++++++++++++++++++ .../manual/render-qml-to-texture/planematerial.cpp | 119 ++++++++++++++++++ tests/manual/render-qml-to-texture/planematerial.h | 59 +++++++++ .../render-qml-to-texture.pri | 8 ++ .../render-qml-to-texture.pro | 21 ++++ .../render-qml-to-texture.qrc | 10 ++ .../shaders/es2/texturing.frag | 16 +++ .../shaders/es2/texturing.vert | 26 ++++ .../shaders/gl3/texturing.frag | 16 +++ .../shaders/gl3/texturing.vert | 25 ++++ 18 files changed, 987 insertions(+), 1 deletion(-) create mode 100644 tests/manual/render-qml-to-texture-qml/PlaneMaterial.qml create mode 100644 tests/manual/render-qml-to-texture-qml/main.cpp create mode 100644 tests/manual/render-qml-to-texture-qml/main.qml create mode 100644 tests/manual/render-qml-to-texture-qml/render-qml-to-texture-qml.pro create mode 100644 tests/manual/render-qml-to-texture-qml/render-qml-to-texture-qml.qrc create mode 100644 tests/manual/render-qml-to-texture/OffscreenGui.qml create mode 100644 tests/manual/render-qml-to-texture/TextRectangle.qml create mode 100644 tests/manual/render-qml-to-texture/main.cpp create mode 100644 tests/manual/render-qml-to-texture/planematerial.cpp create mode 100644 tests/manual/render-qml-to-texture/planematerial.h create mode 100644 tests/manual/render-qml-to-texture/render-qml-to-texture.pri create mode 100644 tests/manual/render-qml-to-texture/render-qml-to-texture.pro create mode 100644 tests/manual/render-qml-to-texture/render-qml-to-texture.qrc create mode 100644 tests/manual/render-qml-to-texture/shaders/es2/texturing.frag create mode 100644 tests/manual/render-qml-to-texture/shaders/es2/texturing.vert create mode 100644 tests/manual/render-qml-to-texture/shaders/gl3/texturing.frag create mode 100644 tests/manual/render-qml-to-texture/shaders/gl3/texturing.vert diff --git a/tests/manual/manual.pro b/tests/manual/manual.pro index bfb95bfc2..9eedd74a6 100644 --- a/tests/manual/manual.pro +++ b/tests/manual/manual.pro @@ -34,7 +34,9 @@ SUBDIRS += \ transparency-qml-scene3d \ rendercapture-qml \ additional-attributes-qml \ - dynamic-model-loader-qml + dynamic-model-loader-qml \ + render-qml-to-texture \ + render-qml-to-texture-qml qtHaveModule(widgets): { SUBDIRS += \ diff --git a/tests/manual/render-qml-to-texture-qml/PlaneMaterial.qml b/tests/manual/render-qml-to-texture-qml/PlaneMaterial.qml new file mode 100644 index 000000000..6c65de9b3 --- /dev/null +++ b/tests/manual/render-qml-to-texture-qml/PlaneMaterial.qml @@ -0,0 +1,117 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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$ +** +****************************************************************************/ + +import QtQuick 2.0 +import Qt3D.Core 2.0 +import Qt3D.Render 2.0 + +Material { + + property Texture2D texture + property vector2d textureScale: Qt.vector2d(1,-1) + property vector2d textureBias: Qt.vector2d(0, 1) + + parameters: [ + Parameter { name: "surfaceTexture"; value: texture }, + Parameter { name: "texCoordScale"; value: textureScale }, + Parameter { name: "texCoordBias"; value: textureBias } + ] + + effect: Effect { + FilterKey { + id: forward + name: "renderingStyle" + value: "forward" + } + + ShaderProgram { + id: gl2Es2Shader + vertexShaderCode: loadSource("qrc:/shaders/es2/texturing.vert") + fragmentShaderCode: loadSource("qrc:/shaders/es2/texturing.frag") + } + + ShaderProgram { + id: gl3Shader + vertexShaderCode: loadSource("qrc:/shaders/gl3/texturing.vert") + fragmentShaderCode: loadSource("qrc:/shaders/gl3/texturing.frag") + } + techniques: [ + // OpenGL 3.1 + Technique { + filterKeys: [ forward ] + graphicsApiFilter { + api: GraphicsApiFilter.OpenGL + profile: GraphicsApiFilter.CoreProfile + majorVersion: 3 + minorVersion: 1 + } + + renderPasses: RenderPass { + shaderProgram: gl3Shader + } + }, + + // OpenGL 2.1 + Technique { + filterKeys: [ forward ] + graphicsApiFilter { + api: GraphicsApiFilter.OpenGL + profile: GraphicsApiFilter.NoProfile + majorVersion: 2 + minorVersion: 0 + } + + renderPasses: RenderPass { + shaderProgram: gl2Es2Shader + } + }, + + // OpenGL ES 2 + Technique { + filterKeys: [ forward ] + graphicsApiFilter { + api: GraphicsApiFilter.OpenGLES + profile: GraphicsApiFilter.NoProfile + majorVersion: 2 + minorVersion: 0 + } + renderPasses: RenderPass { + shaderProgram: gl2Es2Shader + } + } + ] + } +} diff --git a/tests/manual/render-qml-to-texture-qml/main.cpp b/tests/manual/render-qml-to-texture-qml/main.cpp new file mode 100644 index 000000000..ac85cbe46 --- /dev/null +++ b/tests/manual/render-qml-to-texture-qml/main.cpp @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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 + +#include +#include +#include +#include + +int main(int argc, char *argv[]) +{ + QGuiApplication app(argc, argv); + + QSurfaceFormat format; + if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGL) { + format.setVersion(3, 2); + format.setProfile(QSurfaceFormat::CoreProfile); + } + format.setDepthBufferSize(24); + format.setStencilBufferSize(8); + format.setSamples(4); + + QQuickView view; + view.setFormat(format); + view.setResizeMode(QQuickView::SizeRootObjectToView); + view.setSource(QUrl("qrc:/main.qml")); + view.setColor("#000000"); + view.show(); + + return app.exec(); +} diff --git a/tests/manual/render-qml-to-texture-qml/main.qml b/tests/manual/render-qml-to-texture-qml/main.qml new file mode 100644 index 000000000..1551065c8 --- /dev/null +++ b/tests/manual/render-qml-to-texture-qml/main.qml @@ -0,0 +1,133 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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$ +** +****************************************************************************/ + +import Qt3D.Core 2.0 +import Qt3D.Render 2.0 +import Qt3D.Input 2.0 +import QtQuick 2.0 as QQ2 +import QtQuick.Scene3D 2.0 +import QtQuick.Window 2.0 as QW2 +import Qt3D.Extras 2.0 + + +QQ2.Item { + width: 1024 + height: 768 + + Scene3D { + id: scene + anchors.fill: parent + + aspects: ["input"] + + Entity { + id: sceneRoot + + Camera { + id: camera + projectionType: CameraLens.PerspectiveProjection + fieldOfView: 45 + aspectRatio: scene.width / scene.height + nearPlane : 0.1 + farPlane : 1000.0 + position: Qt.vector3d( 0.0, 0.0, 6.0 ) + upVector: Qt.vector3d( 0.0, 1.0, 0.0 ) + viewCenter: Qt.vector3d( 0.0, 0.0, 0.0 ) + } + + Scene2D { + id: qmlTexture + source: "qrc:/OffscreenGui.qml" + renderOnce: false + output: RenderTargetOutput { + attachmentPoint: RenderTargetOutput.Color0 + texture: Texture2D { + id: offscreenTexture + width: 1024 + height: 1024 + format: Texture.RGBA8_UNorm + generateMipMaps: false + magnificationFilter: Texture.Linear + minificationFilter: Texture.Linear + wrapMode { + x: WrapMode.ClampToEdge + y: WrapMode.ClampToEdge + } + } + } + onLoadedChanged: { + console.log("qmlTexture loaded:" + loaded) + } + } + + FirstPersonCameraController { + camera: camera + } + + components: [ + RenderSettings { + activeFrameGraph: + ForwardRenderer { + camera: camera + } + }, + InputSettings {} + ] + + PlaneMesh { + id: planeMesh + width: 4 + height: 4 + } + + Entity { + id: plane1 + + property Transform transform: Transform { + scale: 1 + translation: Qt.vector3d(0,0,0) + rotation: fromAxisAndAngle(Qt.vector3d(1,0,0), 90) + } + + property Material material: PlaneMaterial { + texture: offscreenTexture + } + + components: [planeMesh, material, transform] + } + } + } +} diff --git a/tests/manual/render-qml-to-texture-qml/render-qml-to-texture-qml.pro b/tests/manual/render-qml-to-texture-qml/render-qml-to-texture-qml.pro new file mode 100644 index 000000000..402378f87 --- /dev/null +++ b/tests/manual/render-qml-to-texture-qml/render-qml-to-texture-qml.pro @@ -0,0 +1,21 @@ +!include( ../manual.pri ) { + error( "Couldn't find the manual.pri file!" ) +} + +!include ( ../render-qml-to-texture/render-qml-to-texture.pri ) { + error( "Couldn't find the render-qml-to-texture.pri file!") +} + +QT += 3dextras 3dcore 3drender 3dinput 3dquick qml quick 3dquickrender + +SOURCES += main.cpp + +RESOURCES += \ + render-qml-to-texture-qml.qrc + +OTHER_FILES += \ + main.qml + +DISTFILES += \ + PlaneMaterial.qml \ + diff --git a/tests/manual/render-qml-to-texture-qml/render-qml-to-texture-qml.qrc b/tests/manual/render-qml-to-texture-qml/render-qml-to-texture-qml.qrc new file mode 100644 index 000000000..6b2a1aef6 --- /dev/null +++ b/tests/manual/render-qml-to-texture-qml/render-qml-to-texture-qml.qrc @@ -0,0 +1,6 @@ + + + main.qml + PlaneMaterial.qml + + diff --git a/tests/manual/render-qml-to-texture/OffscreenGui.qml b/tests/manual/render-qml-to-texture/OffscreenGui.qml new file mode 100644 index 000000000..2e18a1e7a --- /dev/null +++ b/tests/manual/render-qml-to-texture/OffscreenGui.qml @@ -0,0 +1,131 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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$ +** +****************************************************************************/ + +import QtQuick 2.0 +import QtQuick.Controls 1.2 +import QtQuick.Controls.Styles 1.3 + +Item { + width: 1024 + height: 1024 + + TextRectangle { + id: textRect + } + + Rectangle { + id: rect + x: 0 + y: 0 + width: 200 + height: 200 + color: "red" + + ColorAnimation { + target: rect + loops: Animation.Infinite + property: "color" + from: "blue" + to: "green" + duration: 2000 + running: true + } + } + + Rectangle { + id: rect2 + width: 300 + height: 100 + anchors.right: parent.right + anchors.bottom: parent.bottom + color: "red" + + ColorAnimation { + target: rect2 + loops: Animation.Infinite + property: "color" + from: "red" + to: "white" + duration: 2000 + running: true + } + } + + Button { + id: button + width: 100 + height: 80 + anchors.top: rect.bottom + anchors.left: parent.left + text: "button" + scale: 2.0 + } + CheckBox { + id: checkbox + width: 200 + height: 180 + scale: 2.0 + text: "checkbox" + checked: true + anchors.top: parent.top + anchors.right: parent.right + + Timer { + interval: 1000 + repeat: true + running: true + onTriggered: { + checkbox.checked = !checkbox.checked; + } + } + } + Slider { + anchors.bottom: parent.bottom + anchors.left: parent.left + width: 400 + value: 0.0 + minimumValue: 0 + maximumValue: 1 + + PropertyAnimation on value { + loops: Animation.Infinite + duration: 3000 + from: 0.0 + to: 1.0 + running: true + } + } +} diff --git a/tests/manual/render-qml-to-texture/TextRectangle.qml b/tests/manual/render-qml-to-texture/TextRectangle.qml new file mode 100644 index 000000000..b47fa965b --- /dev/null +++ b/tests/manual/render-qml-to-texture/TextRectangle.qml @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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$ +** +****************************************************************************/ + +import QtQuick 2.0 + +Rectangle { + id: rectangle + property string myText: "The quick brown fox jumps over the lazy dog." + x: 352 + y: 272 + width: 320 + height: 480 + color: "steelblue" + + FontLoader { id: fixedFont; name: "Courier" } + + Column { + anchors { fill: parent; leftMargin: 10; rightMargin: 10; topMargin: 10 } + spacing: 15 + + Text { + text: rectangle.myText + color: "lightsteelblue" + width: parent.width + wrapMode: Text.WordWrap + font.family: "Times" + font.pixelSize: 20 + } + Text { + text: rectangle.myText + color: "lightsteelblue" + width: parent.width + wrapMode: Text.WordWrap + horizontalAlignment: Text.AlignHCenter + font { family: "Times"; pixelSize: 20; capitalization: Font.AllUppercase } + } + Text { + text: rectangle.myText + color: "lightsteelblue" + width: parent.width + horizontalAlignment: Text.AlignRight + wrapMode: Text.WordWrap + font { family: fixedFont.name; pixelSize: 20; weight: Font.Bold; capitalization: Font.AllLowercase } + } + Text { + text: rectangle.myText + color: "lightsteelblue" + width: parent.width + wrapMode: Text.WordWrap + font { family: fixedFont.name; pixelSize: 20; italic: true; capitalization: Font.SmallCaps } + } + } +} diff --git a/tests/manual/render-qml-to-texture/main.cpp b/tests/manual/render-qml-to-texture/main.cpp new file mode 100644 index 000000000..609da2ebe --- /dev/null +++ b/tests/manual/render-qml-to-texture/main.cpp @@ -0,0 +1,125 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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 +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "qt3dwindow.h" +#include "qfirstpersoncameracontroller.h" +#include "planematerial.h" + +int main(int argc, char *argv[]) +{ + QGuiApplication app(argc, argv); + + Qt3DExtras::Qt3DWindow view; + + // Scene Root + Qt3DCore::QEntity *sceneRoot = new Qt3DCore::QEntity(); + + // Scene Camera + Qt3DRender::QCamera *basicCamera = view.camera(); + basicCamera->setProjectionType(Qt3DRender::QCameraLens::PerspectiveProjection); + basicCamera->setAspectRatio(view.width() / view.height()); + basicCamera->setUpVector(QVector3D(0.0f, 1.0f, 0.0f)); + basicCamera->setPosition(QVector3D(0.0f, 0.0f, 6.0f)); + basicCamera->setViewCenter(QVector3D(0.0f, 0.0f, 0.0f)); + basicCamera->setNearPlane(0.1f); + basicCamera->setFarPlane(1000.0f); + basicCamera->setFieldOfView(45.0f); + + // For camera controls + Qt3DExtras::QFirstPersonCameraController *camController = new Qt3DExtras::QFirstPersonCameraController(sceneRoot); + camController->setCamera(basicCamera); + + Qt3DRender::QFrameGraphNode* frameGraphNode = view.activeFrameGraph(); + while (frameGraphNode->childNodes().size() > 0) + frameGraphNode = (Qt3DRender::QFrameGraphNode*)frameGraphNode->childNodes().at(0); + view.defaultFrameGraph()->setClearColor(QColor::fromRgbF(1.0f, 1.0f, 1.0f)); + Qt3DRender::Quick::QScene2D* qmlTextureRenderer = new Qt3DRender::Quick::QScene2D(frameGraphNode); + + Qt3DRender::QTexture2D* offscreenTexture = new Qt3DRender::QTexture2D(qmlTextureRenderer); + offscreenTexture->setSize(1024, 1024); + offscreenTexture->setFormat(Qt3DRender::QAbstractTexture::RGBA8_UNorm); + offscreenTexture->setGenerateMipMaps(true); + offscreenTexture->setMagnificationFilter(Qt3DRender::QAbstractTexture::Linear); + offscreenTexture->setMinificationFilter(Qt3DRender::QAbstractTexture::Linear); + offscreenTexture->setWrapMode(Qt3DRender::QTextureWrapMode(Qt3DRender::QTextureWrapMode::ClampToEdge, offscreenTexture)); + + Qt3DRender::QRenderTargetOutput *output = new Qt3DRender::QRenderTargetOutput(qmlTextureRenderer); + output->setAttachmentPoint(Qt3DRender::QRenderTargetOutput::Color0); + output->setTexture(offscreenTexture); + + qmlTextureRenderer->setOutput(output); + qmlTextureRenderer->setSource(QUrl(QStringLiteral("qrc:/OffscreenGui.qml"))); +// qmlTextureRenderer->setRenderOnce(true); + + Qt3DCore::QEntity* planeEntity = new Qt3DCore::QEntity(sceneRoot); + Qt3DExtras::QPlaneMesh* planeMesh = new Qt3DExtras::QPlaneMesh(planeEntity); + planeMesh->setWidth(4); + planeMesh->setHeight(4); + planeEntity->addComponent(planeMesh); + + PlaneMaterial* material = new PlaneMaterial(offscreenTexture, planeEntity); + planeEntity->addComponent(material); + + Qt3DCore::QTransform* transform = new Qt3DCore::QTransform(planeEntity); + transform->setRotation(QQuaternion::fromAxisAndAngle(1,0,0,90)); + planeEntity->addComponent(transform); + + view.setRootEntity(sceneRoot); + view.show(); + + return app.exec(); +} diff --git a/tests/manual/render-qml-to-texture/planematerial.cpp b/tests/manual/render-qml-to-texture/planematerial.cpp new file mode 100644 index 000000000..e3886a296 --- /dev/null +++ b/tests/manual/render-qml-to-texture/planematerial.cpp @@ -0,0 +1,119 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "planematerial.h" + +PlaneMaterial::PlaneMaterial(Qt3DRender::QAbstractTexture *texture, Qt3DCore::QNode *parent) + : QMaterial(parent) + , m_texture(texture) + , m_effect(new Qt3DRender::QEffect(this)) +{ + setEffect(m_effect); + + m_texCoordScaleParam = new Qt3DRender::QParameter(QStringLiteral("texCoordScale"), QVector2D(1.0f, -1.0f)); + m_texCoordBiasParam = new Qt3DRender::QParameter(QStringLiteral("texCoordBias"), QVector2D(0.0f, 1.0f)); + m_textureParam = new Qt3DRender::QParameter(QStringLiteral("surfaceTexture"), m_texture); + + m_effect->addParameter(m_texCoordScaleParam); + m_effect->addParameter(m_texCoordBiasParam); + m_effect->addParameter(m_textureParam); + + m_filter = new Qt3DRender::QFilterKey(this); + m_filter->setName(QStringLiteral("renderingStyle")); + m_filter->setValue(QStringLiteral("forward")); + + m_techniqueGLES = new Qt3DRender::QTechnique(m_effect); + m_techniqueGL3 = new Qt3DRender::QTechnique(m_effect); + m_techniqueGL2 = new Qt3DRender::QTechnique(m_effect); + + m_techniqueGLES->addFilterKey(m_filter); + m_techniqueGL3->addFilterKey(m_filter); + m_techniqueGL2->addFilterKey(m_filter); + + m_effect->addTechnique(m_techniqueGLES); + m_effect->addTechnique(m_techniqueGL3); + m_effect->addTechnique(m_techniqueGL2); + + m_programGLES = new Qt3DRender::QShaderProgram(m_effect); + m_programGLES->setVertexShaderCode(Qt3DRender::QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/es2/texturing.vert")))); + m_programGLES->setFragmentShaderCode(Qt3DRender::QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/es2/texturing.frag")))); + + m_programGL3 = new Qt3DRender::QShaderProgram(m_effect); + m_programGL3->setVertexShaderCode(Qt3DRender::QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/gl3/texturing.vert")))); + m_programGL3->setFragmentShaderCode(Qt3DRender::QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/gl3/texturing.frag")))); + + m_renderPassGLES = new Qt3DRender::QRenderPass(m_effect); + m_renderPassGL3 = new Qt3DRender::QRenderPass(m_effect); + m_renderPassGL2 = new Qt3DRender::QRenderPass(m_effect); + + m_renderPassGLES->setShaderProgram(m_programGLES); + m_renderPassGL3->setShaderProgram(m_programGL3); + m_renderPassGL2->setShaderProgram(m_programGL3); + + m_techniqueGL2->addRenderPass(m_renderPassGL2); + m_techniqueGLES->addRenderPass(m_renderPassGLES); + m_techniqueGL3->addRenderPass(m_renderPassGL3); + + m_techniqueGLES->graphicsApiFilter()->setApi(Qt3DRender::QGraphicsApiFilter::OpenGLES); + m_techniqueGLES->graphicsApiFilter()->setMajorVersion(2); + m_techniqueGLES->graphicsApiFilter()->setMinorVersion(0); + m_techniqueGLES->graphicsApiFilter()->setProfile(Qt3DRender::QGraphicsApiFilter::NoProfile); + + m_techniqueGL2->graphicsApiFilter()->setApi(Qt3DRender::QGraphicsApiFilter::OpenGL); + m_techniqueGL2->graphicsApiFilter()->setMajorVersion(2); + m_techniqueGL2->graphicsApiFilter()->setMinorVersion(0); + m_techniqueGL2->graphicsApiFilter()->setProfile(Qt3DRender::QGraphicsApiFilter::NoProfile); + + m_techniqueGL3->graphicsApiFilter()->setApi(Qt3DRender::QGraphicsApiFilter::OpenGL); + m_techniqueGL3->graphicsApiFilter()->setMajorVersion(3); + m_techniqueGL3->graphicsApiFilter()->setMinorVersion(1); + m_techniqueGL3->graphicsApiFilter()->setProfile(Qt3DRender::QGraphicsApiFilter::CoreProfile); +} + diff --git a/tests/manual/render-qml-to-texture/planematerial.h b/tests/manual/render-qml-to-texture/planematerial.h new file mode 100644 index 000000000..8de7a19c9 --- /dev/null +++ b/tests/manual/render-qml-to-texture/planematerial.h @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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$ +** +****************************************************************************/ + +#ifndef PLANEMATERIAL_H +#define PLANEMATERIAL_H + +#include +#include +#include +#include + +class PlaneMaterial : public Qt3DRender::QMaterial +{ +public: + explicit PlaneMaterial(Qt3DRender::QAbstractTexture *texture, Qt3DCore::QNode *parent = nullptr); +private: + Qt3DRender::QEffect *m_effect; + Qt3DRender::QAbstractTexture *m_texture; + Qt3DRender::QParameter *m_textureParam, *m_texCoordScaleParam, *m_texCoordBiasParam; + Qt3DRender::QFilterKey *m_filter; + Qt3DRender::QTechnique *m_techniqueGLES, *m_techniqueGL3, *m_techniqueGL2; + Qt3DRender::QShaderProgram *m_programGLES, *m_programGL3; + Qt3DRender::QRenderPass *m_renderPassGLES, *m_renderPassGL3, *m_renderPassGL2; +}; + +#endif // PLANEMATERIAL_H diff --git a/tests/manual/render-qml-to-texture/render-qml-to-texture.pri b/tests/manual/render-qml-to-texture/render-qml-to-texture.pri new file mode 100644 index 000000000..c0685debc --- /dev/null +++ b/tests/manual/render-qml-to-texture/render-qml-to-texture.pri @@ -0,0 +1,8 @@ +SOURCES += \ + ../render-qml-to-texture/keyframeanimation.cpp + +RESOURCES += \ + ../render-qml-to-texture/render-qml-to-texture.qrc + +HEADERS += \ + ../render-qml-to-texture/keyframeanimation.h diff --git a/tests/manual/render-qml-to-texture/render-qml-to-texture.pro b/tests/manual/render-qml-to-texture/render-qml-to-texture.pro new file mode 100644 index 000000000..e98e62654 --- /dev/null +++ b/tests/manual/render-qml-to-texture/render-qml-to-texture.pro @@ -0,0 +1,21 @@ +!include( ../manual.pri ) { + error( "Couldn't find the manual.pri file!" ) +} + +QT += 3dextras 3dcore 3drender 3dinput 3dquick qml quick 3dquickrender + +SOURCES += main.cpp \ + planematerial.cpp + +RESOURCES += \ + render-qml-to-texture.qrc + +OTHER_FILES += \ + main.qml + +DISTFILES += \ + OffscreenGui.qml \ + TextRectangle.qml + +HEADERS += \ + planematerial.h diff --git a/tests/manual/render-qml-to-texture/render-qml-to-texture.qrc b/tests/manual/render-qml-to-texture/render-qml-to-texture.qrc new file mode 100644 index 000000000..792a74b70 --- /dev/null +++ b/tests/manual/render-qml-to-texture/render-qml-to-texture.qrc @@ -0,0 +1,10 @@ + + + shaders/es2/texturing.frag + shaders/es2/texturing.vert + shaders/gl3/texturing.frag + shaders/gl3/texturing.vert + OffscreenGui.qml + TextRectangle.qml + + diff --git a/tests/manual/render-qml-to-texture/shaders/es2/texturing.frag b/tests/manual/render-qml-to-texture/shaders/es2/texturing.frag new file mode 100644 index 000000000..b651bd5ed --- /dev/null +++ b/tests/manual/render-qml-to-texture/shaders/es2/texturing.frag @@ -0,0 +1,16 @@ +#define FP highp + +uniform FP vec3 eyePosition; + +uniform sampler2D surfaceTexture; + +varying FP vec3 worldPosition; +varying FP vec3 worldNormal; +varying FP vec2 texCoord; + + + +void main() +{ + gl_FragColor = texture2D(surfaceTexture, texCoord); +} diff --git a/tests/manual/render-qml-to-texture/shaders/es2/texturing.vert b/tests/manual/render-qml-to-texture/shaders/es2/texturing.vert new file mode 100644 index 000000000..cfbd338d2 --- /dev/null +++ b/tests/manual/render-qml-to-texture/shaders/es2/texturing.vert @@ -0,0 +1,26 @@ + + +attribute vec3 vertexPosition; +attribute vec3 vertexNormal; +attribute vec2 vertexTexCoord; + +varying vec3 worldPosition; +varying vec3 worldNormal; +varying vec2 texCoord; + +uniform mat4 modelMatrix; +uniform mat3 modelNormalMatrix; +uniform mat4 mvp; + +uniform vec2 texCoordScale; +uniform vec2 texCoordBias; + +void main() +{ + texCoord = vertexTexCoord * texCoordScale + texCoordBias; + worldNormal = normalize(modelNormalMatrix * vertexNormal); + worldPosition = vec3(modelMatrix * vec4(vertexPosition, 1.0)); + + gl_Position = mvp * vec4(vertexPosition, 1.0); +} + diff --git a/tests/manual/render-qml-to-texture/shaders/gl3/texturing.frag b/tests/manual/render-qml-to-texture/shaders/gl3/texturing.frag new file mode 100644 index 000000000..b051dc254 --- /dev/null +++ b/tests/manual/render-qml-to-texture/shaders/gl3/texturing.frag @@ -0,0 +1,16 @@ +#version 150 core + +uniform vec3 eyePosition; + +uniform sampler2D surfaceTexture; + +in vec3 worldPosition; +in vec3 worldNormal; +in vec2 texCoord; + +out vec4 fragColor; + +void main() +{ + fragColor = texture(surfaceTexture, texCoord); +} diff --git a/tests/manual/render-qml-to-texture/shaders/gl3/texturing.vert b/tests/manual/render-qml-to-texture/shaders/gl3/texturing.vert new file mode 100644 index 000000000..2b8a08b0a --- /dev/null +++ b/tests/manual/render-qml-to-texture/shaders/gl3/texturing.vert @@ -0,0 +1,25 @@ +#version 150 core + +in vec3 vertexPosition; +in vec3 vertexNormal; +in vec2 vertexTexCoord; + +out vec3 worldPosition; +out vec3 worldNormal; +out vec2 texCoord; + +uniform mat4 modelMatrix; +uniform mat3 modelNormalMatrix; +uniform mat4 mvp; + +uniform vec2 texCoordScale; +uniform vec2 texCoordBias; + +void main() +{ + texCoord = vertexTexCoord * texCoordScale + texCoordBias; + worldNormal = normalize(modelNormalMatrix * vertexNormal); + worldPosition = vec3(modelMatrix * vec4(vertexPosition, 1.0)); + + gl_Position = mvp * vec4(vertexPosition, 1.0); +} -- cgit v1.2.3 From 57a25953d4cba3c3a5262edf8f6094d746d24748 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Mon, 31 Oct 2016 15:28:01 +0200 Subject: Update render-qml-to-texture test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use inline qml Change-Id: I3a4ceb82a9e8d4478bdbb71ca400bb81ab6ccad2 Reviewed-by: Tomi Korpipää Reviewed-by: Sean Harmer --- tests/manual/render-qml-to-texture-qml/main.qml | 9 +++++---- tests/manual/render-qml-to-texture/OffscreenGui.qml | 3 ++- tests/manual/render-qml-to-texture/render-qml-to-texture.pri | 6 ++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/manual/render-qml-to-texture-qml/main.qml b/tests/manual/render-qml-to-texture-qml/main.qml index 1551065c8..3c1ee61d8 100644 --- a/tests/manual/render-qml-to-texture-qml/main.qml +++ b/tests/manual/render-qml-to-texture-qml/main.qml @@ -49,9 +49,10 @@ QQ2.Item { Scene3D { id: scene + focus: true anchors.fill: parent - aspects: ["input"] + aspects: ["input", "logic"] Entity { id: sceneRoot @@ -70,7 +71,6 @@ QQ2.Item { Scene2D { id: qmlTexture - source: "qrc:/OffscreenGui.qml" renderOnce: false output: RenderTargetOutput { attachmentPoint: RenderTargetOutput.Color0 @@ -88,8 +88,9 @@ QQ2.Item { } } } - onLoadedChanged: { - console.log("qmlTexture loaded:" + loaded) + + OffscreenGui { + } } diff --git a/tests/manual/render-qml-to-texture/OffscreenGui.qml b/tests/manual/render-qml-to-texture/OffscreenGui.qml index 2e18a1e7a..20fb0937d 100644 --- a/tests/manual/render-qml-to-texture/OffscreenGui.qml +++ b/tests/manual/render-qml-to-texture/OffscreenGui.qml @@ -38,9 +38,10 @@ import QtQuick 2.0 import QtQuick.Controls 1.2 import QtQuick.Controls.Styles 1.3 -Item { +Rectangle { width: 1024 height: 1024 + color: "white" TextRectangle { id: textRect diff --git a/tests/manual/render-qml-to-texture/render-qml-to-texture.pri b/tests/manual/render-qml-to-texture/render-qml-to-texture.pri index c0685debc..b02c23840 100644 --- a/tests/manual/render-qml-to-texture/render-qml-to-texture.pri +++ b/tests/manual/render-qml-to-texture/render-qml-to-texture.pri @@ -1,8 +1,6 @@ -SOURCES += \ - ../render-qml-to-texture/keyframeanimation.cpp +SOURCES += RESOURCES += \ ../render-qml-to-texture/render-qml-to-texture.qrc -HEADERS += \ - ../render-qml-to-texture/keyframeanimation.h +HEADERS += -- cgit v1.2.3 From 313fc68719093f992c9e114420e72abfcc189c89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Fri, 28 Oct 2016 15:05:31 +0300 Subject: Add video texture example MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Ifaaaaf038f7b311c9c537bfb0b6ca2117296f1ce Reviewed-by: Tomi Korpipää Reviewed-by: Sean Harmer --- tests/manual/manual.pro | 3 +- tests/manual/video-texture-qml/PlaneMaterial.qml | 117 ++++++++++++++++ tests/manual/video-texture-qml/main.cpp | 53 ++++++++ tests/manual/video-texture-qml/main.qml | 147 +++++++++++++++++++++ .../manual/video-texture-qml/video-texture-qml.pro | 21 +++ .../manual/video-texture-qml/video-texture-qml.qrc | 6 + 6 files changed, 346 insertions(+), 1 deletion(-) create mode 100644 tests/manual/video-texture-qml/PlaneMaterial.qml create mode 100644 tests/manual/video-texture-qml/main.cpp create mode 100644 tests/manual/video-texture-qml/main.qml create mode 100644 tests/manual/video-texture-qml/video-texture-qml.pro create mode 100644 tests/manual/video-texture-qml/video-texture-qml.qrc diff --git a/tests/manual/manual.pro b/tests/manual/manual.pro index 9eedd74a6..a535e18f0 100644 --- a/tests/manual/manual.pro +++ b/tests/manual/manual.pro @@ -36,7 +36,8 @@ SUBDIRS += \ additional-attributes-qml \ dynamic-model-loader-qml \ render-qml-to-texture \ - render-qml-to-texture-qml + render-qml-to-texture-qml \ + video-texture-qml qtHaveModule(widgets): { SUBDIRS += \ diff --git a/tests/manual/video-texture-qml/PlaneMaterial.qml b/tests/manual/video-texture-qml/PlaneMaterial.qml new file mode 100644 index 000000000..6c65de9b3 --- /dev/null +++ b/tests/manual/video-texture-qml/PlaneMaterial.qml @@ -0,0 +1,117 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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$ +** +****************************************************************************/ + +import QtQuick 2.0 +import Qt3D.Core 2.0 +import Qt3D.Render 2.0 + +Material { + + property Texture2D texture + property vector2d textureScale: Qt.vector2d(1,-1) + property vector2d textureBias: Qt.vector2d(0, 1) + + parameters: [ + Parameter { name: "surfaceTexture"; value: texture }, + Parameter { name: "texCoordScale"; value: textureScale }, + Parameter { name: "texCoordBias"; value: textureBias } + ] + + effect: Effect { + FilterKey { + id: forward + name: "renderingStyle" + value: "forward" + } + + ShaderProgram { + id: gl2Es2Shader + vertexShaderCode: loadSource("qrc:/shaders/es2/texturing.vert") + fragmentShaderCode: loadSource("qrc:/shaders/es2/texturing.frag") + } + + ShaderProgram { + id: gl3Shader + vertexShaderCode: loadSource("qrc:/shaders/gl3/texturing.vert") + fragmentShaderCode: loadSource("qrc:/shaders/gl3/texturing.frag") + } + techniques: [ + // OpenGL 3.1 + Technique { + filterKeys: [ forward ] + graphicsApiFilter { + api: GraphicsApiFilter.OpenGL + profile: GraphicsApiFilter.CoreProfile + majorVersion: 3 + minorVersion: 1 + } + + renderPasses: RenderPass { + shaderProgram: gl3Shader + } + }, + + // OpenGL 2.1 + Technique { + filterKeys: [ forward ] + graphicsApiFilter { + api: GraphicsApiFilter.OpenGL + profile: GraphicsApiFilter.NoProfile + majorVersion: 2 + minorVersion: 0 + } + + renderPasses: RenderPass { + shaderProgram: gl2Es2Shader + } + }, + + // OpenGL ES 2 + Technique { + filterKeys: [ forward ] + graphicsApiFilter { + api: GraphicsApiFilter.OpenGLES + profile: GraphicsApiFilter.NoProfile + majorVersion: 2 + minorVersion: 0 + } + renderPasses: RenderPass { + shaderProgram: gl2Es2Shader + } + } + ] + } +} diff --git a/tests/manual/video-texture-qml/main.cpp b/tests/manual/video-texture-qml/main.cpp new file mode 100644 index 000000000..5146d5939 --- /dev/null +++ b/tests/manual/video-texture-qml/main.cpp @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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 +#include +#include +#include +#include + +int main(int argc, char* argv[]) +{ + QGuiApplication app(argc, argv); + Qt3DExtras::Quick::Qt3DQuickWindow view; + + view.engine()->qmlEngine()->rootContext()->setContextProperty("_window", &view); + view.setSource(QUrl("qrc:/main.qml")); + view.show(); + + return app.exec(); +} diff --git a/tests/manual/video-texture-qml/main.qml b/tests/manual/video-texture-qml/main.qml new file mode 100644 index 000000000..c7d0b47ec --- /dev/null +++ b/tests/manual/video-texture-qml/main.qml @@ -0,0 +1,147 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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$ +** +****************************************************************************/ + +import Qt3D.Core 2.0 +import Qt3D.Render 2.0 +import Qt3D.Input 2.0 +import QtQuick 2.2 as QQ2 +import QtQuick.Window 2.0 as QW2 +import Qt3D.Extras 2.0 +import QtMultimedia 5.6 as QMM +import QtQuick.Dialogs 1.0 + +Entity { + id: sceneRoot + + Camera { + id: camera + projectionType: CameraLens.PerspectiveProjection + fieldOfView: 45 + aspectRatio: _window.width / _window.height + nearPlane : 0.1 + farPlane : 1000.0 + position: Qt.vector3d( 0.0, 0.0, 3.0 ) + upVector: Qt.vector3d( 0.0, 1.0, 0.0 ) + viewCenter: Qt.vector3d( 0.0, 0.0, 0.0 ) + } + + Scene2D { + renderOnce: false + output: RenderTargetOutput { + attachmentPoint: RenderTargetOutput.Color0 + texture: Texture2D { + id: offscreenTexture + width: 1024 + height: 1024 + format: Texture.RGBA8_UNorm + generateMipMaps: false + magnificationFilter: Texture.Linear + minificationFilter: Texture.Linear + wrapMode { + x: WrapMode.ClampToEdge + y: WrapMode.ClampToEdge + } + } + } + QQ2.Rectangle { + width: 400 + height: 300 + color: "green" + + QMM.MediaPlayer { + id: player + autoPlay: false + loops: QMM.MediaPlayer.Infinite + } + + QMM.VideoOutput { + id: videoOutput + source: player + anchors.fill: parent + } + } + } + + FirstPersonCameraController { + camera: camera + } + + components: [ + RenderSettings { + activeFrameGraph: + ForwardRenderer { + camera: camera + } + }, + InputSettings {} + ] + + CuboidMesh { + id: mesh + } + + Entity { + id: entity + + property Transform transform: Transform { + scale: 1 + translation: Qt.vector3d(0,0,0) + } + + property Material material: PlaneMaterial { + texture: offscreenTexture + } + + components: [mesh, material, transform] + } + + FileDialog { + id: fileDialog + title: "Please choose a video" + folder: shortcuts.home + onAccepted: { + visible = false + player.source = fileDialog.fileUrl + player.play() + } + onRejected: { + Qt.quit() + } + QQ2.Component.onCompleted: { + visible = true + } + } +} diff --git a/tests/manual/video-texture-qml/video-texture-qml.pro b/tests/manual/video-texture-qml/video-texture-qml.pro new file mode 100644 index 000000000..713ef8cfe --- /dev/null +++ b/tests/manual/video-texture-qml/video-texture-qml.pro @@ -0,0 +1,21 @@ +!include( ../manual.pri ) { + error( "Couldn't find the manual.pri file!" ) +} + +!include ( ../render-qml-to-texture/render-qml-to-texture.pri ) { + error( "Couldn't find the render-qml-to-texture.pri file!") +} + +QT += 3dquickextras 3dcore 3drender 3dinput 3dquick qml quick 3dquickrender + +SOURCES += main.cpp + +RESOURCES += \ + video-texture-qml.qrc + +OTHER_FILES += \ + main.qml + +DISTFILES += \ + PlaneMaterial.qml + diff --git a/tests/manual/video-texture-qml/video-texture-qml.qrc b/tests/manual/video-texture-qml/video-texture-qml.qrc new file mode 100644 index 000000000..6b2a1aef6 --- /dev/null +++ b/tests/manual/video-texture-qml/video-texture-qml.qrc @@ -0,0 +1,6 @@ + + + main.qml + PlaneMaterial.qml + + -- cgit v1.2.3 From 421705544d8ba832c9e3ff67d048c57cc48b39b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Mon, 14 Nov 2016 11:37:23 +0200 Subject: Fix qscene2d autotests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I650f3b3b180ce9a5ed323060f303baaa670cf8be Reviewed-by: Tomi Korpipää Reviewed-by: Sean Harmer --- src/quick3d/quick3drender/scene2d/qscene2d.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/quick3d/quick3drender/scene2d/qscene2d.cpp b/src/quick3d/quick3drender/scene2d/qscene2d.cpp index 2f4c12367..c0028a6a0 100644 --- a/src/quick3d/quick3drender/scene2d/qscene2d.cpp +++ b/src/quick3d/quick3drender/scene2d/qscene2d.cpp @@ -492,6 +492,7 @@ void Scene2DManager::cleanup() QScene2DPrivate::QScene2DPrivate() : Qt3DCore::QNodePrivate() , m_renderManager(new Scene2DManager(this)) + , m_output(nullptr) { } @@ -545,14 +546,16 @@ void QScene2D::setSource(const QUrl &url) qWarning() << "Unable to set source after initialization."; return; } - d->m_renderManager->setSource(url); - emit sourceChanged(url); + if (d->m_renderManager->m_source != url) { + d->m_renderManager->setSource(url); + emit sourceChanged(url); + } } QQuickItem* QScene2D::item() const { Q_D(const QScene2D); - return d->m_renderManager->m_rootItem; + return d->m_renderManager->m_item; } void QScene2D::setItem(QQuickItem *item) @@ -562,8 +565,10 @@ void QScene2D::setItem(QQuickItem *item) qWarning() << "Unable to set item after initialization."; return; } - d->m_renderManager->setItem(item); - emit itemChanged(item); + if (d->m_renderManager->m_item != item) { + d->m_renderManager->setItem(item); + emit itemChanged(item); + } } /*! -- cgit v1.2.3 From c7be0f914e58aca8442b19d0f8df86f59dcc0858 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Mon, 14 Nov 2016 14:10:27 +0200 Subject: Fix scene2d unit tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Id3caa548ad906647488a343cf0c68f176270f319 Reviewed-by: Tomi Korpipää Reviewed-by: Sean Harmer --- src/quick3d/quick3drender/scene2d/scene2d.cpp | 19 +++++++++++-------- src/quick3d/quick3drender/scene2d/scene2d_p.h | 1 - 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/quick3d/quick3drender/scene2d/scene2d.cpp b/src/quick3d/quick3drender/scene2d/scene2d.cpp index 0ccf38fc7..309899066 100644 --- a/src/quick3d/quick3drender/scene2d/scene2d.cpp +++ b/src/quick3d/quick3drender/scene2d/scene2d.cpp @@ -134,7 +134,8 @@ void Scene2D::initializeSharedObject() m_sharedObject->m_renderThread->start(); // Notify main thread we have been initialized - QCoreApplication::postEvent(m_sharedObject->m_renderManager, new QEvent(INITIALIZED)); + if (m_sharedObject->m_renderManager) + QCoreApplication::postEvent(m_sharedObject->m_renderManager, new QEvent(INITIALIZED)); // Initialize render thread QCoreApplication::postEvent(m_sharedObject->m_renderObject, new QEvent(INITIALIZE)); @@ -151,7 +152,6 @@ void Scene2D::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &chan setSharedObject(data.sharedObject); setOutput(data.output); m_shareContext = renderer()->shareContext(); - m_accessor = resourceAccessor(); } void Scene2D::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) @@ -170,6 +170,7 @@ void Scene2D::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) setSharedObject(sharedObject); } } + BackendNode::sceneChangeEvent(e); } void Scene2D::setSharedObject(Qt3DRender::Quick::Scene2DSharedObjectPtr sharedObject) @@ -181,9 +182,7 @@ void Scene2D::setSharedObject(Qt3DRender::Quick::Scene2DSharedObjectPtr sharedOb void Scene2D::initializeRender() { - if (!m_renderInitialized) { - - Q_ASSERT(m_shareContext); + if (!m_renderInitialized && m_sharedObject.data() != nullptr) { QSurfaceFormat format; format.setDepthBufferSize(24); @@ -252,8 +251,10 @@ void Scene2D::render() QMutex *textureLock = nullptr; m_context->makeCurrent(m_sharedObject->m_surface); - if (m_accessor->accessResource(m_outputId, (void**)&attachmentData, nullptr)) { - if (!m_accessor->accessResource(attachmentData->m_textureUuid, (void**)&texture, &textureLock)) { + + if (resourceAccessor()->accessResource(m_outputId, (void**)&attachmentData, nullptr)) { + if (!resourceAccessor()->accessResource(attachmentData->m_textureUuid, + (void**)&texture, &textureLock)) { // Need to call sync even if the texture is not in use syncRenderControl(); m_context->doneCurrent(); @@ -320,13 +321,15 @@ void Scene2D::cleanup() m_context->functions()->glDeleteFramebuffers(1, &m_fbo); m_context->functions()->glDeleteRenderbuffers(1, &m_rbo); m_context->doneCurrent(); + m_renderInitialized = false; + } + if (m_initialized) { m_sharedObject->m_renderThread->quit(); delete m_sharedObject->m_renderObject; m_sharedObject->m_renderObject = nullptr; delete m_context; m_context = nullptr; m_sharedObject = nullptr; - m_renderInitialized = false; m_initialized = false; } } diff --git a/src/quick3d/quick3drender/scene2d/scene2d_p.h b/src/quick3d/quick3drender/scene2d/scene2d_p.h index 769916fc9..cfe8035bf 100644 --- a/src/quick3d/quick3drender/scene2d/scene2d_p.h +++ b/src/quick3d/quick3drender/scene2d/scene2d_p.h @@ -106,7 +106,6 @@ public: Qt3DCore::QNodeId m_outputId; QSharedPointer m_sharedObject; Qt3DCore::QNodeId m_peerId; - QSharedPointer m_accessor; Qt3DRender::Render::Attachment m_attachmentData; GLuint m_fbo; -- cgit v1.2.3 From 1cb4a185b85c2d8a3559e080ba61708607ca47d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Thu, 17 Nov 2016 15:07:18 +0200 Subject: Add Scene2D logging category MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Ie327f139095e71b30accca212509be5f655e2ebf Reviewed-by: Tomi Korpipää Reviewed-by: Sean Harmer --- .../quick3drender/qt3dquickrender_logging.cpp | 49 ++++++++++++++++ .../quick3drender/qt3dquickrender_logging_p.h | 65 ++++++++++++++++++++++ src/quick3d/quick3drender/quick3drender.pro | 6 +- src/quick3d/quick3drender/scene2d/scene2d.cpp | 6 +- 4 files changed, 121 insertions(+), 5 deletions(-) create mode 100644 src/quick3d/quick3drender/qt3dquickrender_logging.cpp create mode 100644 src/quick3d/quick3drender/qt3dquickrender_logging_p.h diff --git a/src/quick3d/quick3drender/qt3dquickrender_logging.cpp b/src/quick3d/quick3drender/qt3dquickrender_logging.cpp new file mode 100644 index 000000000..b9e5d2e08 --- /dev/null +++ b/src/quick3d/quick3drender/qt3dquickrender_logging.cpp @@ -0,0 +1,49 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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 "qt3dquickrender_logging_p.h" + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { +namespace Quick { + +Q_LOGGING_CATEGORY(Scene2D, "Qt3D.Scene2D") + +} // Quick +} // Qt3DRender + +QT_END_NAMESPACE diff --git a/src/quick3d/quick3drender/qt3dquickrender_logging_p.h b/src/quick3d/quick3drender/qt3dquickrender_logging_p.h new file mode 100644 index 000000000..c34abfdd3 --- /dev/null +++ b/src/quick3d/quick3drender/qt3dquickrender_logging_p.h @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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$ +** +****************************************************************************/ + +#ifndef QT3DQUICKRENDER_LOGGING_P_H +#define QT3DQUICKRENDER_LOGGING_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { +namespace Quick { + +Q_DECLARE_LOGGING_CATEGORY(Scene2D) + +} // Quick +} // Qt3DRender + +QT_END_NAMESPACE + +#endif // QT3DQUICKRENDER_LOGGING_P_H diff --git a/src/quick3d/quick3drender/quick3drender.pro b/src/quick3d/quick3drender/quick3drender.pro index 989f5615b..b1b904e12 100644 --- a/src/quick3d/quick3drender/quick3drender.pro +++ b/src/quick3d/quick3drender/quick3drender.pro @@ -14,12 +14,14 @@ gcov { SOURCES += \ qt3dquickrender_global.cpp \ - qt3dquickrendernodefactory.cpp + qt3dquickrendernodefactory.cpp \ + qt3dquickrender_logging.cpp HEADERS += \ qt3dquickrendernodefactory_p.h \ qt3dquickrender_global_p.h \ - qt3dquickrender_global.h + qt3dquickrender_global.h \ + qt3dquickrender_logging_p.h # otherwise mingw headers do not declare common functions like ::strcasecmp win32-g++*:QMAKE_CXXFLAGS_CXX11 = -std=gnu++0x diff --git a/src/quick3d/quick3drender/scene2d/scene2d.cpp b/src/quick3d/quick3drender/scene2d/scene2d.cpp index 309899066..10bb9a3fe 100644 --- a/src/quick3d/quick3drender/scene2d/scene2d.cpp +++ b/src/quick3d/quick3drender/scene2d/scene2d.cpp @@ -44,6 +44,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE @@ -258,8 +259,7 @@ void Scene2D::render() // Need to call sync even if the texture is not in use syncRenderControl(); m_context->doneCurrent(); - // TODO: add logging category for scene2d - //qCWarning(Scene2D) << "Texture not in use."; + qCWarning(Qt3DRender::Quick::Scene2D) << Q_FUNC_INFO << "Texture not in use."; return; } textureLock->lock(); @@ -277,7 +277,7 @@ void Scene2D::render() syncRenderControl(); textureLock->unlock(); m_context->doneCurrent(); - //qCWarning(Scene2D) << "Fbo not initialized."; + qCWarning(Qt3DRender::Quick::Scene2D) << Q_FUNC_INFO << "Fbo not initialized."; return; } } -- cgit v1.2.3 From caf99904a91cb015b681b3ef5a9d8e13fd8323bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Tue, 22 Nov 2016 12:08:12 +0200 Subject: Resend render event when texture is not in use MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This ensures that it gets rendered when there is no animation Change-Id: Ib72808bedaa4a2847932e496980a7fc17fea7bba Reviewed-by: Tomi Korpipää Reviewed-by: Sean Harmer --- src/quick3d/quick3drender/scene2d/scene2d.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/quick3d/quick3drender/scene2d/scene2d.cpp b/src/quick3d/quick3drender/scene2d/scene2d.cpp index 10bb9a3fe..51ddfaea0 100644 --- a/src/quick3d/quick3drender/scene2d/scene2d.cpp +++ b/src/quick3d/quick3drender/scene2d/scene2d.cpp @@ -260,6 +260,7 @@ void Scene2D::render() syncRenderControl(); m_context->doneCurrent(); qCWarning(Qt3DRender::Quick::Scene2D) << Q_FUNC_INFO << "Texture not in use."; + QCoreApplication::postEvent(m_sharedObject->m_renderObject, new QEvent(RENDER)); return; } textureLock->lock(); -- cgit v1.2.3 From 28c0ea55ea77747c0a396537b40a0078f94c95df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Fri, 28 Oct 2016 13:53:45 +0300 Subject: Register scene2d qml type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I12e90f027653ca4bed230d3c0839786d03c2de16 Reviewed-by: Tomi Korpipää Reviewed-by: Sean Harmer --- src/quick3d/imports/render/qt3dquick3drenderplugin.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/quick3d/imports/render/qt3dquick3drenderplugin.cpp b/src/quick3d/imports/render/qt3dquick3drenderplugin.cpp index 51c029fc1..a5a6df040 100644 --- a/src/quick3d/imports/render/qt3dquick3drenderplugin.cpp +++ b/src/quick3d/imports/render/qt3dquick3drenderplugin.cpp @@ -102,6 +102,8 @@ #include #include #include + +#include #include #include #include @@ -262,6 +264,9 @@ void Qt3DQuick3DRenderPlugin::registerTypes(const char *uri) qmlRegisterType(uri, 2, 0, "SeamlessCubemap"); qmlRegisterType(uri, 2, 0, "StencilOperation"); qmlRegisterType(uri, 2, 0, "StencilMask"); + + // Scene2D + Qt3DRender::Quick::registerType("QScene2D", "Qt3D.Render/Scene2D", uri, 2, 0, "Scene2D"); } QT_END_NAMESPACE -- cgit v1.2.3 From 09364817fa76d9aee92bbc24d93e3e523cd2f853 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Tue, 22 Nov 2016 16:50:45 +0200 Subject: Enable mouse events for the render-qml-to-texture-qml test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This makes the rendered Quick controls interactive. Change-Id: I887ca9dd779c8333491e04430717e9b86ba74eda Reviewed-by: Tomi Korpipää Reviewed-by: Sean Harmer --- .../render-qml-to-texture-qml/InteractiveGui.qml | 97 ++++++++++++++++++++++ tests/manual/render-qml-to-texture-qml/main.qml | 32 +++++-- .../render-qml-to-texture-qml.pro | 4 +- .../render-qml-to-texture-qml.qrc | 1 + 4 files changed, 125 insertions(+), 9 deletions(-) create mode 100644 tests/manual/render-qml-to-texture-qml/InteractiveGui.qml diff --git a/tests/manual/render-qml-to-texture-qml/InteractiveGui.qml b/tests/manual/render-qml-to-texture-qml/InteractiveGui.qml new file mode 100644 index 000000000..65e5f27de --- /dev/null +++ b/tests/manual/render-qml-to-texture-qml/InteractiveGui.qml @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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$ +** +****************************************************************************/ + +import QtQuick 2.0 +import QtQuick.Controls 1.2 +import QtQuick.Controls.Styles 1.3 + +Rectangle { + width: 1024 + height: 1024 + color: "white" + focus: true + + Rectangle { + id: rect + x: 0 + y: 0 + width: 200 + height: 200 + color: "red" + } + + Rectangle { + id: rect2 + width: 300 + height: 100 + anchors.right: parent.right + anchors.bottom: parent.bottom + color: "blue" + } + + Button { + id: button + width: 100 + height: 80 + anchors.top: rect.bottom + anchors.left: parent.left + text: "button" + scale: 2.0 + } + CheckBox { + id: checkbox + width: 200 + height: 180 + scale: 2.0 + text: "checkbox" + checked: true + anchors.top: parent.top + anchors.right: parent.right + } + Slider { + anchors.bottom: parent.bottom + anchors.left: parent.left + width: 400 + value: 1 + minimumValue: 0 + maximumValue: 1 + + onValueChanged: { + rect.color = Qt.rgba(value, 0, 0, 1) + rect2.color = Qt.rgba(0, 0, value, 1) + } + } +} diff --git a/tests/manual/render-qml-to-texture-qml/main.qml b/tests/manual/render-qml-to-texture-qml/main.qml index 3c1ee61d8..23ff823e1 100644 --- a/tests/manual/render-qml-to-texture-qml/main.qml +++ b/tests/manual/render-qml-to-texture-qml/main.qml @@ -35,7 +35,7 @@ ****************************************************************************/ import Qt3D.Core 2.0 -import Qt3D.Render 2.0 +import Qt3D.Render 2.2 import Qt3D.Input 2.0 import QtQuick 2.0 as QQ2 import QtQuick.Scene3D 2.0 @@ -79,31 +79,33 @@ QQ2.Item { width: 1024 height: 1024 format: Texture.RGBA8_UNorm - generateMipMaps: false + generateMipMaps: true magnificationFilter: Texture.Linear - minificationFilter: Texture.Linear + minificationFilter: Texture.LinearMipMapLinear wrapMode { x: WrapMode.ClampToEdge y: WrapMode.ClampToEdge } } - } - OffscreenGui { + } + InteractiveGui { } } FirstPersonCameraController { + id: controller camera: camera } components: [ RenderSettings { + pickingSettings.pickMethod: PickingSettings.TrianglePicking activeFrameGraph: ForwardRenderer { camera: camera - } + } }, InputSettings {} ] @@ -127,7 +129,23 @@ QQ2.Item { texture: offscreenTexture } - components: [planeMesh, material, transform] + property ObjectPicker picker: ObjectPicker { + hoverEnabled: true + dragEnabled: true + eventForward: EventForward { + id: eventForward + target: qmlTexture + focus: true + } + onPressed: { + controller.enabled = false + } + onReleased: { + controller.enabled = true + } + } + + components: [planeMesh, material, transform, picker] } } } diff --git a/tests/manual/render-qml-to-texture-qml/render-qml-to-texture-qml.pro b/tests/manual/render-qml-to-texture-qml/render-qml-to-texture-qml.pro index 402378f87..8155840d3 100644 --- a/tests/manual/render-qml-to-texture-qml/render-qml-to-texture-qml.pro +++ b/tests/manual/render-qml-to-texture-qml/render-qml-to-texture-qml.pro @@ -16,6 +16,6 @@ RESOURCES += \ OTHER_FILES += \ main.qml -DISTFILES += \ - PlaneMaterial.qml \ +HEADERS += + diff --git a/tests/manual/render-qml-to-texture-qml/render-qml-to-texture-qml.qrc b/tests/manual/render-qml-to-texture-qml/render-qml-to-texture-qml.qrc index 6b2a1aef6..51ec4790c 100644 --- a/tests/manual/render-qml-to-texture-qml/render-qml-to-texture-qml.qrc +++ b/tests/manual/render-qml-to-texture-qml/render-qml-to-texture-qml.qrc @@ -2,5 +2,6 @@ main.qml PlaneMaterial.qml + InteractiveGui.qml -- cgit v1.2.3 From 4c8bdacc8521e52cc655e6eddcc19d73ebcb6678 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Tue, 13 Dec 2016 15:04:30 +0200 Subject: Use only one thread in the scene2d renderer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make all scene2d backend renderers use shared thread Change-Id: I019f463023198aa73f1f64a8d1f9d7b63b962d0c Reviewed-by: Tomi Korpipää Reviewed-by: Sean Harmer --- src/quick3d/quick3drender/scene2d/qscene2d.cpp | 8 ++-- src/quick3d/quick3drender/scene2d/qscene2d_p.h | 4 +- src/quick3d/quick3drender/scene2d/scene2d.cpp | 53 ++++++++++++++++++-------- src/quick3d/quick3drender/scene2d/scene2d_p.h | 2 +- 4 files changed, 44 insertions(+), 23 deletions(-) diff --git a/src/quick3d/quick3drender/scene2d/qscene2d.cpp b/src/quick3d/quick3drender/scene2d/qscene2d.cpp index c0028a6a0..a1f84a929 100644 --- a/src/quick3d/quick3drender/scene2d/qscene2d.cpp +++ b/src/quick3d/quick3drender/scene2d/qscene2d.cpp @@ -203,12 +203,12 @@ void Scene2DSharedObject::requestRender(bool sync) QCoreApplication::postEvent(m_renderObject, new QEvent(RENDER)); } -void Scene2DSharedObject::waitRender() +void Scene2DSharedObject::wait() { m_cond.wait(&m_mutex); } -void Scene2DSharedObject::wakeWaiting() +void Scene2DSharedObject::wake() { m_cond.wakeOne(); } @@ -320,7 +320,7 @@ void Scene2DManager::stopAndClean() if (m_sharedObject->isInitialized()) { QMutexLocker lock(&m_sharedObject->m_mutex); m_sharedObject->requestQuit(); - m_sharedObject->m_renderThread->wait(); + m_sharedObject->wait(); m_sharedObject->cleanup(); delete m_qmlEngine; delete m_qmlComponent; @@ -479,7 +479,7 @@ void Scene2DManager::doRenderSync() m_sharedObject->m_renderControl->polishItems(); // begin waiting render thread - m_sharedObject->waitRender(); + m_sharedObject->wait(); m_requested = false; } diff --git a/src/quick3d/quick3drender/scene2d/qscene2d_p.h b/src/quick3d/quick3drender/scene2d/qscene2d_p.h index 4fa65fb1b..fbc19a42f 100644 --- a/src/quick3d/quick3drender/scene2d/qscene2d_p.h +++ b/src/quick3d/quick3drender/scene2d/qscene2d_p.h @@ -118,8 +118,8 @@ public: bool isSyncRequested() const; void clearSyncRequest(); - void waitRender(); - void wakeWaiting(); + void wait(); + void wake(); bool isPrepared() const; void setPrepared(); diff --git a/src/quick3d/quick3drender/scene2d/scene2d.cpp b/src/quick3d/quick3drender/scene2d/scene2d.cpp index 51ddfaea0..35c791000 100644 --- a/src/quick3d/quick3drender/scene2d/scene2d.cpp +++ b/src/quick3d/quick3drender/scene2d/scene2d.cpp @@ -37,6 +37,9 @@ #include #include +#include +#include + #include #include #include @@ -60,6 +63,13 @@ namespace Render { namespace Quick { +Q_GLOBAL_STATIC(QThread, renderThread) +Q_GLOBAL_STATIC(QAtomicInt, renderThreadClientCount) + +#ifndef GL_DEPTH24_STENCIL8 +#define GL_DEPTH24_STENCIL8 0x88F0 +#endif + RenderQmlEventHandler::RenderQmlEventHandler(Scene2D *node) : QObject() , m_node(node) @@ -103,16 +113,17 @@ Scene2D::Scene2D() , m_fbo(0) , m_rbo(0) { - + renderThreadClientCount->fetchAndAddAcquire(1); } Scene2D::~Scene2D() { // this gets called from aspect thread. Wait for the render thread then delete it. - if (m_renderThread) { - m_renderThread->wait(1000); - delete m_renderThread; - } + // TODO: render thread deletion +// if (m_renderThread) { +// m_renderThread->wait(1000); +// delete m_renderThread; +// } } void Scene2D::setOutput(Qt3DCore::QNodeId outputId) @@ -124,15 +135,15 @@ void Scene2D::initializeSharedObject() { if (!m_initialized) { - // Create render thread - m_renderThread = new QThread(); - m_renderThread->setObjectName(QStringLiteral("Scene2D::renderThread")); + renderThread->setObjectName(QStringLiteral("Scene2D::renderThread")); + m_renderThread = renderThread; m_sharedObject->m_renderThread = m_renderThread; // Create event handler for the render thread m_sharedObject->m_renderObject = new RenderQmlEventHandler(this); m_sharedObject->m_renderObject->moveToThread(m_sharedObject->m_renderThread); - m_sharedObject->m_renderThread->start(); + if (!m_sharedObject->m_renderThread->isRunning()) + m_sharedObject->m_renderThread->start(); // Notify main thread we have been initialized if (m_sharedObject->m_renderManager) @@ -237,7 +248,7 @@ void Scene2D::syncRenderControl() m_sharedObject->m_renderControl->sync(); // gui thread can now continue - m_sharedObject->wakeWaiting(); + m_sharedObject->wake(); } } @@ -292,11 +303,12 @@ void Scene2D::render() m_sharedObject->disallowRender(); // Sync - syncRenderControl(); + if (m_sharedObject->isSyncRequested()) { + + m_sharedObject->clearSyncRequest(); - // The lock is not needed anymore so release it before the following - // time comsuming operations - lock.unlock(); + m_sharedObject->m_renderControl->sync(); + } // Render m_sharedObject->m_renderControl->render(); @@ -311,9 +323,13 @@ void Scene2D::render() texture->generateMipMaps(); textureLock->unlock(); m_context->doneCurrent(); + + // gui thread can now continue + m_sharedObject->wake(); } } +// this function gets called while the main thread is waiting void Scene2D::cleanup() { if (m_renderInitialized && m_initialized) { @@ -325,14 +341,19 @@ void Scene2D::cleanup() m_renderInitialized = false; } if (m_initialized) { - m_sharedObject->m_renderThread->quit(); delete m_sharedObject->m_renderObject; m_sharedObject->m_renderObject = nullptr; delete m_context; m_context = nullptr; - m_sharedObject = nullptr; m_initialized = false; } + // wake up the main thread + m_sharedObject->wake(); + m_sharedObject = nullptr; + + renderThreadClientCount->fetchAndSubAcquire(1); + if (renderThreadClientCount->load() == 0) + renderThread->quit(); } } // namespace Quick diff --git a/src/quick3d/quick3drender/scene2d/scene2d_p.h b/src/quick3d/quick3drender/scene2d/scene2d_p.h index cfe8035bf..fdb4ff1d2 100644 --- a/src/quick3d/quick3drender/scene2d/scene2d_p.h +++ b/src/quick3d/quick3drender/scene2d/scene2d_p.h @@ -81,7 +81,7 @@ private: Scene2D *m_node; }; -class Q_AUTOTEST_EXPORT Scene2D : public Qt3DRender::Render::BackendNode +class QT3DQUICKRENDERSHARED_EXPORT Scene2D : public Qt3DRender::Render::BackendNode { public: Scene2D(); -- cgit v1.2.3 From 7d4968bf04bdd86e5651763979c5e91699ca06a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Wed, 2 Nov 2016 11:50:43 +0200 Subject: Add render plugin MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I083b029a9bde4a3c6d81cfd06dfc509ba4f60a2d Reviewed-by: Tomi Korpipää Reviewed-by: Sean Harmer --- src/render/frontend/qrenderplugin_p.h | 89 +++++++++++++++++++++++ src/render/frontend/qrenderpluginfactory.cpp | 99 ++++++++++++++++++++++++++ src/render/frontend/qrenderpluginfactory_p.h | 75 +++++++++++++++++++ src/render/frontend/qrenderpluginfactoryif.cpp | 65 +++++++++++++++++ src/render/frontend/qrenderpluginfactoryif_p.h | 82 +++++++++++++++++++++ src/render/frontend/render-frontend.pri | 9 ++- src/render/render.pro | 3 +- 7 files changed, 419 insertions(+), 3 deletions(-) create mode 100644 src/render/frontend/qrenderplugin_p.h create mode 100644 src/render/frontend/qrenderpluginfactory.cpp create mode 100644 src/render/frontend/qrenderpluginfactory_p.h create mode 100644 src/render/frontend/qrenderpluginfactoryif.cpp create mode 100644 src/render/frontend/qrenderpluginfactoryif_p.h diff --git a/src/render/frontend/qrenderplugin_p.h b/src/render/frontend/qrenderplugin_p.h new file mode 100644 index 000000000..5144448c1 --- /dev/null +++ b/src/render/frontend/qrenderplugin_p.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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$ +** +****************************************************************************/ + +#ifndef QT3DRENDER_RENDER_QRENDERPLUGIN_P_H +#define QT3DRENDER_RENDER_QRENDERPLUGIN_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +#include +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +namespace Render { + +class AbstractRenderer; + +class QT3DRENDERSHARED_PRIVATE_EXPORT QRenderPlugin +{ +public: + virtual bool registerBackendTypes(QRenderAspect *aspect, AbstractRenderer *renderer) = 0; + virtual bool unregisterBackendTypes(QRenderAspect *aspect) = 0; + +protected: + void registerBackendType(QRenderAspect *aspect, const QMetaObject &obj, const Qt3DCore::QBackendNodeMapperPtr &functor) + { + aspect->registerBackendType(obj, functor); + } + void unregisterBackendType(QRenderAspect *aspect, const QMetaObject &obj) + { + aspect->unregisterBackendType(obj); + } +}; + +} // namespace Render +} // namespace Qt3DRender + +QT_END_NAMESPACE + +#endif // QT3DRENDER_RENDER_QRENDERPLUGIN_P_H diff --git a/src/render/frontend/qrenderpluginfactory.cpp b/src/render/frontend/qrenderpluginfactory.cpp new file mode 100644 index 000000000..51fa068c6 --- /dev/null +++ b/src/render/frontend/qrenderpluginfactory.cpp @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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 "qrenderpluginfactory_p.h" +#include "qrenderpluginfactoryif_p.h" +#include "qrenderplugin_p.h" + +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { +namespace Render { + +#ifndef QT_NO_LIBRARY +Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader, (QRenderPluginFactoryInterface_iid, QLatin1String("/renderplugins"), Qt::CaseInsensitive)) +Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, directLoader, (QRenderPluginFactoryInterface_iid, QLatin1String(""), Qt::CaseInsensitive)) +#endif + +QStringList QRenderPluginFactory::keys(const QString &pluginPath) +{ +#ifndef QT_NO_LIBRARY + QStringList list; + if (!pluginPath.isEmpty()) { + QCoreApplication::addLibraryPath(pluginPath); + list = directLoader()->keyMap().values(); + if (!list.isEmpty()) { + const QString postFix = QLatin1String(" (from ") + + QDir::toNativeSeparators(pluginPath) + + QLatin1Char(')'); + const QStringList::iterator end = list.end(); + for (QStringList::iterator it = list.begin(); it != end; ++it) + (*it).append(postFix); + } + } + list.append(loader()->keyMap().values()); + return list; +#else + return QStringList(); +#endif +} + +QRenderPlugin *QRenderPluginFactory::create(const QString &name, const QStringList &args, + const QString &pluginPath) +{ +#ifndef QT_NO_LIBRARY + if (!pluginPath.isEmpty()) { + QCoreApplication::addLibraryPath(pluginPath); + if (QRenderPlugin *ret + = qLoadPlugin(directLoader(), name, args)) { + return ret; + } + } + if (QRenderPlugin *ret = qLoadPlugin(loader(), name, args)) + return ret; +#endif + return nullptr; +} + +} // namespace Render +} // namespace Qt3DRender + +QT_END_NAMESPACE diff --git a/src/render/frontend/qrenderpluginfactory_p.h b/src/render/frontend/qrenderpluginfactory_p.h new file mode 100644 index 000000000..9cffd500a --- /dev/null +++ b/src/render/frontend/qrenderpluginfactory_p.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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$ +** +****************************************************************************/ + +#ifndef QT3DRENDER_RENDER_QRENDERPLUGINFACTORY_P_H +#define QT3DRENDER_RENDER_QRENDERPLUGINFACTORY_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { +namespace Render { + +class QRenderPlugin; + +class QT3DRENDERSHARED_PRIVATE_EXPORT QRenderPluginFactory +{ +public: + static QStringList keys(const QString &pluginPath = QString()); + static QRenderPlugin *create(const QString &name, const QStringList &args, + const QString &pluginPath = QString()); +}; + +} // namespace Render +} // namespace Qt3DRender + +QT_END_NAMESPACE + +#endif // QT3DRENDER_RENDER_QRENDERPLUGINFACTORY_P_H diff --git a/src/render/frontend/qrenderpluginfactoryif.cpp b/src/render/frontend/qrenderpluginfactoryif.cpp new file mode 100644 index 000000000..af567084c --- /dev/null +++ b/src/render/frontend/qrenderpluginfactoryif.cpp @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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 "qrenderpluginfactoryif_p.h" + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { +namespace Render { + +QRenderPluginFactoryIf::QRenderPluginFactoryIf(QObject *parent) + : QObject(parent) +{ + +} + +QRenderPluginFactoryIf::~QRenderPluginFactoryIf() +{ + +} + +QRenderPlugin *QRenderPluginFactoryIf::create(const QString &key, const QStringList ¶mList) +{ + Q_UNUSED(key) + Q_UNUSED(paramList) + return nullptr; +} + +} // namespace Render +} // namespace Qt3DRender + +QT_END_NAMESPACE diff --git a/src/render/frontend/qrenderpluginfactoryif_p.h b/src/render/frontend/qrenderpluginfactoryif_p.h new file mode 100644 index 000000000..d5f0008d2 --- /dev/null +++ b/src/render/frontend/qrenderpluginfactoryif_p.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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$ +** +****************************************************************************/ + +#ifndef QT3DRENDER_RENDER_QRENDERPLUGINFACTORYIF_P_H +#define QT3DRENDER_RENDER_QRENDERPLUGINFACTORYIF_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include + +#include + + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { +namespace Render { + +#define QRenderPluginFactoryInterface_iid "org.qt-project.Qt3DRender.QRenderPluginFactoryInterface 5.9" + +class QRenderPlugin; + +class QT3DRENDERSHARED_PRIVATE_EXPORT QRenderPluginFactoryIf : public QObject +{ + Q_OBJECT +public: + explicit QRenderPluginFactoryIf(QObject *parent = nullptr); + ~QRenderPluginFactoryIf(); + + virtual QRenderPlugin *create(const QString &key, const QStringList ¶mList); +}; + +} // namespace Render +} // namespace Qt3DRender + +QT_END_NAMESPACE + +#endif // QT3DRENDER_QRENDERPLUGINFACTORYIF_P_H diff --git a/src/render/frontend/render-frontend.pri b/src/render/frontend/render-frontend.pri index 829e3d756..d42f33b87 100644 --- a/src/render/frontend/render-frontend.pri +++ b/src/render/frontend/render-frontend.pri @@ -21,7 +21,10 @@ HEADERS += \ $$PWD/qpickingsettings.h \ $$PWD/qpickingsettings_p.h \ $$PWD/qcomputecommand_p.h \ - $$PWD/qcomputecommand.h + $$PWD/qcomputecommand.h \ + $$PWD/qrenderplugin_p.h \ + $$PWD/qrenderpluginfactory_p.h \ + $$PWD/qrenderpluginfactoryif_p.h SOURCES += \ $$PWD/qabstractfunctor.cpp \ @@ -35,5 +38,7 @@ SOURCES += \ $$PWD/qrendersettings.cpp \ $$PWD/qpickingsettings.cpp \ $$PWD/qrendertargetoutput.cpp \ - $$PWD/qcomputecommand.cpp + $$PWD/qcomputecommand.cpp \ + $$PWD/qrenderpluginfactory.cpp \ + $$PWD/qrenderpluginfactoryif.cpp diff --git a/src/render/render.pro b/src/render/render.pro index bcfcadd97..84970c2bf 100644 --- a/src/render/render.pro +++ b/src/render/render.pro @@ -40,5 +40,6 @@ SOURCES += \ renderlogging.cpp MODULE_PLUGIN_TYPES = \ - sceneparsers + sceneparsers \ + renderplugins load(qt_module) -- cgit v1.2.3 From 01a3d94f2c96b67215bf376d6260c06f6dd84160 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Wed, 2 Nov 2016 12:02:22 +0200 Subject: Load render plugins MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I035a4d1fa41988514551425917d6fd735a790b05 Reviewed-by: Tomi Korpipää Reviewed-by: Sean Harmer --- src/core/aspects/qabstractaspect.cpp | 6 ++++++ src/core/aspects/qabstractaspect.h | 9 +++++++++ src/render/frontend/qrenderaspect.cpp | 16 +++++++++++++++- src/render/frontend/qrenderaspect.h | 2 ++ src/render/frontend/qrenderaspect_p.h | 5 +++++ 5 files changed, 37 insertions(+), 1 deletion(-) diff --git a/src/core/aspects/qabstractaspect.cpp b/src/core/aspects/qabstractaspect.cpp index c049d3503..8f1afb30e 100644 --- a/src/core/aspects/qabstractaspect.cpp +++ b/src/core/aspects/qabstractaspect.cpp @@ -157,6 +157,12 @@ void QAbstractAspect::registerBackendType(const QMetaObject &obj, const QBackend d->m_backendCreatorFunctors.insert(&obj, functor); } +void QAbstractAspect::unregisterBackendType(const QMetaObject &obj) +{ + Q_D(QAbstractAspect); + d->m_backendCreatorFunctors.remove(&obj); +} + void QAbstractAspectPrivate::sceneNodeAdded(QSceneChangePtr &change) { QNodeCreatedChangeBasePtr creationChange = qSharedPointerCast(change); diff --git a/src/core/aspects/qabstractaspect.h b/src/core/aspects/qabstractaspect.h index 86938d2d2..a4ad68c1d 100644 --- a/src/core/aspects/qabstractaspect.h +++ b/src/core/aspects/qabstractaspect.h @@ -76,6 +76,9 @@ protected: template void registerBackendType(const QBackendNodeMapperPtr &functor); void registerBackendType(const QMetaObject &, const QBackendNodeMapperPtr &functor); + template + void unregisterBackendType(); + void unregisterBackendType(const QMetaObject &); private: virtual QVariant executeCommand(const QStringList &args); @@ -99,6 +102,12 @@ void QAbstractAspect::registerBackendType(const QBackendNodeMapperPtr &functor) registerBackendType(Frontend::staticMetaObject, functor); } +template +void QAbstractAspect::unregisterBackendType() +{ + unregisterBackendType(Frontend::staticMetaObject); +} + } // namespace Qt3DCore QT_END_NAMESPACE diff --git a/src/render/frontend/qrenderaspect.cpp b/src/render/frontend/qrenderaspect.cpp index e0a2e1469..3ab68dc0a 100644 --- a/src/render/frontend/qrenderaspect.cpp +++ b/src/render/frontend/qrenderaspect.cpp @@ -124,6 +124,9 @@ #include #include +#include +#include + #include #include @@ -158,8 +161,8 @@ QRenderAspectPrivate::QRenderAspectPrivate(QRenderAspect::RenderType type) , m_renderType(type) , m_offscreenHelper(nullptr) { - // Load the scene parsers loadSceneParsers(); + loadRenderPlugins(); } /*! \internal */ @@ -240,6 +243,7 @@ void QRenderAspectPrivate::registerBackendTypes() /*! \internal */ void QRenderAspectPrivate::unregisterBackendTypes() { + Q_Q(QRenderAspect); unregisterBackendType(); unregisterBackendType(); @@ -525,6 +529,16 @@ void QRenderAspectPrivate::loadSceneParsers() } } +void QRenderAspectPrivate::loadRenderPlugins() +{ + const QStringList keys = Render::QRenderPluginFactory::keys(); + for (const QString &key : keys) { + Render::QRenderPlugin *plugin = Render::QRenderPluginFactory::create(key, QStringList()); + if (plugin != nullptr) + m_renderPlugins.append(plugin); + } +} + } // namespace Qt3DRender QT_END_NAMESPACE diff --git a/src/render/frontend/qrenderaspect.h b/src/render/frontend/qrenderaspect.h index 72e8e4bdb..48ef5b164 100644 --- a/src/render/frontend/qrenderaspect.h +++ b/src/render/frontend/qrenderaspect.h @@ -56,6 +56,7 @@ class TestAspect; namespace Render { class Renderer; +class QRenderPlugin; } class QRenderAspectPrivate; @@ -92,6 +93,7 @@ private: void onEngineStartup() Q_DECL_OVERRIDE; friend class Render::Renderer; + friend class Render::QRenderPlugin; #if defined(QT_BUILD_INTERNAL) friend class QRenderAspectTester; friend class TestAspect; diff --git a/src/render/frontend/qrenderaspect_p.h b/src/render/frontend/qrenderaspect_p.h index 72183ef87..1fa0b26df 100644 --- a/src/render/frontend/qrenderaspect_p.h +++ b/src/render/frontend/qrenderaspect_p.h @@ -62,9 +62,11 @@ class QSurface; namespace Qt3DRender { class QSceneImporter; + namespace Render { class AbstractRenderer; class NodeManagers; +class QRenderPlugin; } namespace Render { @@ -82,9 +84,11 @@ public: void registerBackendTypes(); void unregisterBackendTypes(); void loadSceneParsers(); + void loadRenderPlugins(); void renderInitialize(QOpenGLContext *context); void renderSynchronous(); void renderShutdown(); + void registerBackendType(const QMetaObject &, const Qt3DCore::QBackendNodeMapperPtr &functor); QVector createGeometryRendererJobs(); Render::NodeManagers *m_nodeManagers; @@ -92,6 +96,7 @@ public: bool m_initialized; QList m_sceneImporter; + QVector m_renderPlugins; QRenderAspect::RenderType m_renderType; Render::OffscreenSurfaceHelper *m_offscreenHelper; }; -- cgit v1.2.3 From 2395b1fa9b9c5f66fd9c3b175d5eb8635cda6582 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Wed, 2 Nov 2016 12:04:14 +0200 Subject: Add scene2dplugin MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I4875c1a8c319d03e002d591f406379a636f07d8d Reviewed-by: Tomi Korpipää Reviewed-by: Sean Harmer --- src/plugins/renderplugins/renderplugins.pro | 2 + src/plugins/renderplugins/scene2d/main.cpp | 63 ++++++++++++ src/plugins/renderplugins/scene2d/scene2d.pro | 21 ++++ .../renderplugins/scene2d/scene2dplugin.cpp | 111 +++++++++++++++++++++ src/plugins/renderplugins/scene2d/scene2dplugin.h | 92 +++++++++++++++++ .../renderplugins/scene2d/scene2dplugin.json | 3 + src/src.pro | 5 + 7 files changed, 297 insertions(+) create mode 100644 src/plugins/renderplugins/renderplugins.pro create mode 100644 src/plugins/renderplugins/scene2d/main.cpp create mode 100644 src/plugins/renderplugins/scene2d/scene2d.pro create mode 100644 src/plugins/renderplugins/scene2d/scene2dplugin.cpp create mode 100644 src/plugins/renderplugins/scene2d/scene2dplugin.h create mode 100644 src/plugins/renderplugins/scene2d/scene2dplugin.json diff --git a/src/plugins/renderplugins/renderplugins.pro b/src/plugins/renderplugins/renderplugins.pro new file mode 100644 index 000000000..1bc2f6c6c --- /dev/null +++ b/src/plugins/renderplugins/renderplugins.pro @@ -0,0 +1,2 @@ +TEMPLATE = subdirs +SUBDIRS += scene2d diff --git a/src/plugins/renderplugins/scene2d/main.cpp b/src/plugins/renderplugins/scene2d/main.cpp new file mode 100644 index 000000000..00a3db734 --- /dev/null +++ b/src/plugins/renderplugins/scene2d/main.cpp @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd and/or its subsidiary(-ies). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "scene2dplugin.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +class Scene2DPlugin : public Qt3DRender::Render::QRenderPluginFactoryIf +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID QRenderPluginFactoryInterface_iid FILE "scene2dplugin.json") + + Qt3DRender::Render::QRenderPlugin *create(const QString &key, + const QStringList ¶mList) Q_DECL_OVERRIDE + { + Q_UNUSED(key) + Q_UNUSED(paramList) + return new Qt3DRender::Render::Scene2DPlugin(); + } +}; + +QT_END_NAMESPACE + +#include "main.moc" diff --git a/src/plugins/renderplugins/scene2d/scene2d.pro b/src/plugins/renderplugins/scene2d/scene2d.pro new file mode 100644 index 000000000..dbf9c3e36 --- /dev/null +++ b/src/plugins/renderplugins/scene2d/scene2d.pro @@ -0,0 +1,21 @@ +TARGET = scene2d +QT += core-private 3dcore 3dcore-private 3drender 3drender-private 3dextras 3dquickrender 3dquickrender-private + +# Qt3D is free of Q_FOREACH - make sure it stays that way: +DEFINES += QT_NO_FOREACH + +HEADERS += \ + scene2dplugin.h +# scene2dnode_p.h + +SOURCES += \ + main.cpp \ + scene2dplugin.cpp +# scene2dnode.cpp + +DISTFILES += \ + scene2dplugin.json + +PLUGIN_TYPE = renderplugins +PLUGIN_CLASS_NAME = Scene2DPlugin +load(qt_plugin) diff --git a/src/plugins/renderplugins/scene2d/scene2dplugin.cpp b/src/plugins/renderplugins/scene2d/scene2dplugin.cpp new file mode 100644 index 000000000..5621858ea --- /dev/null +++ b/src/plugins/renderplugins/scene2d/scene2dplugin.cpp @@ -0,0 +1,111 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd and/or its subsidiary(-ies). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "scene2dplugin.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { +namespace Render { + +template +class Scene2DBackendNodeMapper : public Qt3DCore::QBackendNodeMapper +{ +public: + explicit Scene2DBackendNodeMapper(Render::AbstractRenderer *renderer, + Render::Scene2DNodeManager *manager) + : m_manager(manager) + , m_renderer(renderer) + { + } + + Qt3DCore::QBackendNode *create(const Qt3DCore::QNodeCreatedChangeBasePtr &change) const Q_DECL_FINAL + { + Backend *backend = m_manager->getOrCreateResource(change->subjectId()); + backend->setRenderer(m_renderer); + return backend; + } + + Qt3DCore::QBackendNode *get(Qt3DCore::QNodeId id) const Q_DECL_FINAL + { + return m_manager->lookupResource(id); + } + + void destroy(Qt3DCore::QNodeId id) const Q_DECL_FINAL + { + m_manager->releaseResource(id); + } + +private: + Render::Scene2DNodeManager *m_manager; + Render::AbstractRenderer *m_renderer; +}; + +Scene2DPlugin::Scene2DPlugin() + : m_scene2dNodeManager(new Render::Scene2DNodeManager()) +{ + +} + +Scene2DPlugin::~Scene2DPlugin() +{ + delete m_scene2dNodeManager; +} + +bool Scene2DPlugin::registerBackendTypes(QRenderAspect *aspect, + AbstractRenderer *renderer) +{ + registerBackendType(aspect, Qt3DRender::Quick::QScene2D::staticMetaObject, + QSharedPointer > + ::create(renderer, m_scene2dNodeManager)); + return true; +} +bool Scene2DPlugin::unregisterBackendTypes(QRenderAspect *aspect) +{ + unregisterBackendType(aspect, Qt3DRender::Quick::QScene2D::staticMetaObject); + return true; +} + +} // namespace Render +} // namespace Qt3DRender + +QT_END_NAMESPACE diff --git a/src/plugins/renderplugins/scene2d/scene2dplugin.h b/src/plugins/renderplugins/scene2d/scene2dplugin.h new file mode 100644 index 000000000..f19093c7e --- /dev/null +++ b/src/plugins/renderplugins/scene2d/scene2dplugin.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd and/or its subsidiary(-ies). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3DRENDER_SCENE2DPLUGIN_H +#define QT3DRENDER_SCENE2DPLUGIN_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { +namespace Render { + +class Scene2DNode; + +class Scene2DNodeManager : public Qt3DCore::QResourceManager< + Render::Quick::Scene2D, + Qt3DCore::QNodeId, + 16, + Qt3DCore::ArrayAllocatingPolicy, + Qt3DCore::ObjectLevelLockingPolicy> +{ +}; + +class Scene2DPlugin : public QRenderPlugin +{ +public: + Scene2DPlugin(); + ~Scene2DPlugin(); + bool registerBackendTypes(QRenderAspect *aspect, AbstractRenderer *renderer) Q_DECL_OVERRIDE; + bool unregisterBackendTypes(QRenderAspect *aspect) Q_DECL_OVERRIDE; +private: + Render::Scene2DNodeManager *m_scene2dNodeManager; +}; + +} // Render +} // namespace Qt3DRender + +QT_END_NAMESPACE + +#endif // QT3DRENDER_SCENE2DPLUGIN_H diff --git a/src/plugins/renderplugins/scene2d/scene2dplugin.json b/src/plugins/renderplugins/scene2d/scene2dplugin.json new file mode 100644 index 000000000..2eece1046 --- /dev/null +++ b/src/plugins/renderplugins/scene2d/scene2dplugin.json @@ -0,0 +1,3 @@ +{ + "Keys": ["scene2d"] +} diff --git a/src/src.pro b/src/src.pro index 61ceeb5f9..eb41669c8 100644 --- a/src/src.pro +++ b/src/src.pro @@ -66,6 +66,10 @@ src_plugins_sceneparsers.file = $$PWD/plugins/sceneparsers/sceneparsers.pro src_plugins_sceneparsers.target = sub-plugins-sceneparsers src_plugins_sceneparsers.depends = src_render src_extras +src_plugins_render.file = $$PWD/plugins/renderplugins/renderplugins.pro +src_plugins_render.target = sub-plugins-render +src_plugins_render.depends = src_render src_extras src_quick3d_render + SUBDIRS += \ src_core \ src_render \ @@ -83,6 +87,7 @@ SUBDIRS += \ src_quick3d_imports_logic \ src_quick3d_imports_extras \ src_plugins_sceneparsers \ + src_plugins_render \ doc -- cgit v1.2.3 From 29807dbcd23b47940311e45bbb789f1be1b8f66d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Tue, 25 Oct 2016 13:14:52 +0300 Subject: Add focus to EventForward MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I6e8d2c65bfbc3ba0373a119b6c244eb2a634be28 Reviewed-by: Tomi Korpipää Reviewed-by: Sean Harmer --- src/render/picking/eventforward.cpp | 15 +++++++++++++++ src/render/picking/eventforward_p.h | 3 +++ src/render/picking/qeventforward.cpp | 27 +++++++++++++++++++++++++++ src/render/picking/qeventforward.h | 4 ++++ src/render/picking/qeventforward_p.h | 3 +++ 5 files changed, 52 insertions(+) diff --git a/src/render/picking/eventforward.cpp b/src/render/picking/eventforward.cpp index 7e24557ab..132e022ce 100644 --- a/src/render/picking/eventforward.cpp +++ b/src/render/picking/eventforward.cpp @@ -54,6 +54,7 @@ EventForward::EventForward() : m_target(nullptr) , m_forwardMouseEvents(false) , m_forwardKeyboardEvents(false) + , m_focus(false) { } @@ -71,6 +72,7 @@ void EventForward::cleanup() m_coordinateTransform.setToIdentity(); m_forwardMouseEvents = false; m_forwardKeyboardEvents = false; + m_focus = false; } QObject *EventForward::target() const @@ -98,6 +100,11 @@ bool EventForward::forwardKeyboardEvents() const return m_forwardKeyboardEvents; } +bool EventForward::focus() const +{ + return m_focus; +} + void EventForward::setTarget(QObject *target) { m_target = target; @@ -123,6 +130,11 @@ void EventForward::setForwardKeyboardEvents(bool enabled) m_forwardKeyboardEvents = enabled; } +void EventForward::setFocus(bool focus) +{ + m_focus = focus; +} + void EventForward::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) { const auto typedChange = qSharedPointerCast>(change); @@ -132,6 +144,7 @@ void EventForward::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr setCoordinateTransform(data.coordinateTransform); setForwardMouseEvents(data.forwardMouseEvents); setForwardKeyboardEvents(data.forwardKeyboardEvents); + setFocus(data.focus); } void EventForward::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) @@ -150,6 +163,8 @@ void EventForward::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) setForwardMouseEvents(propertyChange->value().toBool()); else if (propertyChange->propertyName() == QByteArrayLiteral("forwardKeyboardEvents")) setForwardKeyboardEvents(propertyChange->value().toBool()); + else if (propertyChange->propertyName() == QByteArrayLiteral("focus")) + setFocus(propertyChange->value().toBool()); } BackendNode::sceneChangeEvent(e); diff --git a/src/render/picking/eventforward_p.h b/src/render/picking/eventforward_p.h index 1fc56ead2..e090ba5e4 100644 --- a/src/render/picking/eventforward_p.h +++ b/src/render/picking/eventforward_p.h @@ -74,12 +74,14 @@ public: QMatrix4x4 coordinateTransform() const; bool forwardMouseEvents() const; bool forwardKeyboardEvents() const; + bool focus() const; void setTarget(QObject *target); void setCoordinateTransform(const QMatrix4x4 &transform); void setCoordinateAttribute(const QString &attribute); void setForwardMouseEvents(bool enabled); void setForwardKeyboardEvents(bool enabled); + void setFocus(bool focus); void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_FINAL; @@ -94,6 +96,7 @@ private: QMatrix4x4 m_coordinateTransform; bool m_forwardMouseEvents; bool m_forwardKeyboardEvents; + bool m_focus; }; } // Render diff --git a/src/render/picking/qeventforward.cpp b/src/render/picking/qeventforward.cpp index 74b52989e..8aa22e276 100644 --- a/src/render/picking/qeventforward.cpp +++ b/src/render/picking/qeventforward.cpp @@ -99,6 +99,10 @@ namespace Qt3DRender { \qmlproperty string Qt3D.Render::EventForward::coordinateAttribute Holds the name of the coordinate attribute the mouse coordinates are calculated from. */ +/*! + \qmlproperty bool Qt3D.Render::EventForward::focus + Holds whether the QObjectPicker has focus. +*/ /*! \property QEventForward::target @@ -120,7 +124,14 @@ namespace Qt3DRender { \property QEventForward::coordinateAttribute Holds the name of the coordinate attribute the mouse coordinates are calculated from. */ +/*! + \property QEventForward::focus + Holds whether the ObjectPicker has focus. + */ +/*! + + */ QEventForward::QEventForward(Qt3DCore::QNode *parent) : Qt3DCore::QNode(*new QEventForwardPrivate(), parent) { @@ -206,6 +217,21 @@ void QEventForward::setForwardKeyboardEvents(bool forward) } } +bool QEventForward::focus() const +{ + Q_D(const QEventForward); + return d->m_focus; +} + +void QEventForward::setFocus(bool focus) +{ + Q_D(QEventForward); + if (d->m_focus != focus) { + d->m_focus = focus; + emit focusChanged(focus); + } +} + /*! \internal */ @@ -219,6 +245,7 @@ Qt3DCore::QNodeCreatedChangeBasePtr QEventForward::createNodeCreationChange() co data.coordinateAttribute = d->m_attribute; data.forwardMouseEvents = d->m_forwardMouseEvents; data.forwardKeyboardEvents = d->m_forwardKeyboardEvents; + data.focus = d->m_focus; return creationChange; } diff --git a/src/render/picking/qeventforward.h b/src/render/picking/qeventforward.h index 694ad0d2d..28659606b 100644 --- a/src/render/picking/qeventforward.h +++ b/src/render/picking/qeventforward.h @@ -58,6 +58,7 @@ class QT3DRENDERSHARED_EXPORT QEventForward : public Qt3DCore::QNode Q_PROPERTY(bool forwardKeyboardEvents READ forwardKeyboardEvents WRITE setForwardKeyboardEvents NOTIFY forwardKeyboardEventsChanged) Q_PROPERTY(QMatrix4x4 coordinateTransform READ coordinateTransform WRITE setCoordinateTransform NOTIFY coordinateTransformChanged) Q_PROPERTY(QString coordinateAttribute READ coordinateAttribute WRITE setCoordinateAttribute NOTIFY coordinateAttributeChanged) + Q_PROPERTY(bool focus READ focus WRITE setFocus NOTIFY focusChanged) public: explicit QEventForward(Qt3DCore::QNode *parent = nullptr); @@ -68,6 +69,7 @@ public: QString coordinateAttribute() const; bool forwardMouseEvents() const; bool forwardKeyboardEvents() const; + bool focus() const; public Q_SLOTS: void setTarget(QObject *target); @@ -75,6 +77,7 @@ public Q_SLOTS: void setCoordinateAttribute(const QString &coordinateAttribute); void setForwardMouseEvents(bool forward); void setForwardKeyboardEvents(bool forward); + void setFocus(bool focus); Q_SIGNALS: void targetChanged(QObject *target); @@ -82,6 +85,7 @@ Q_SIGNALS: void coordinateAttributeChanged(const QString &coordinateAttribute); void forwardMouseEventsChanged(bool forward); void forwardKeyboardEventsChanged(bool forward); + void focusChanged(bool focus); private: Q_DECLARE_PRIVATE(QEventForward) diff --git a/src/render/picking/qeventforward_p.h b/src/render/picking/qeventforward_p.h index be2e832d8..4aa6834df 100644 --- a/src/render/picking/qeventforward_p.h +++ b/src/render/picking/qeventforward_p.h @@ -68,6 +68,7 @@ public: , m_attribute("default") , m_forwardMouseEvents(true) , m_forwardKeyboardEvents(false) + , m_focus(false) { } @@ -79,6 +80,7 @@ public: QString m_attribute; bool m_forwardMouseEvents; bool m_forwardKeyboardEvents; + bool m_focus; }; struct QEventForwardData @@ -88,6 +90,7 @@ struct QEventForwardData QString coordinateAttribute; bool forwardMouseEvents; bool forwardKeyboardEvents; + bool focus; }; } // namespace Qt3DRender -- cgit v1.2.3 From 7d1ba2e0676241634f38d907b10ae6e2bd2c6f0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Mon, 28 Nov 2016 16:37:53 +0200 Subject: Add QmlEngine contructor parameter to Scene2D MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I841f4f8e516d6b3656ed2dbc9ee694d25b4be78f Reviewed-by: Tomi Korpipää Reviewed-by: Sean Harmer --- src/quick3d/quick3drender/scene2d/qscene2d.cpp | 52 ++++++++++++++++++++++++-- src/quick3d/quick3drender/scene2d/qscene2d.h | 3 ++ src/quick3d/quick3drender/scene2d/qscene2d_p.h | 4 ++ 3 files changed, 55 insertions(+), 4 deletions(-) diff --git a/src/quick3d/quick3drender/scene2d/qscene2d.cpp b/src/quick3d/quick3drender/scene2d/qscene2d.cpp index a1f84a929..f83cd3e4f 100644 --- a/src/quick3d/quick3drender/scene2d/qscene2d.cpp +++ b/src/quick3d/quick3drender/scene2d/qscene2d.cpp @@ -236,6 +236,7 @@ Scene2DManager::Scene2DManager(QScene2DPrivate *priv) , m_backendInitialized(false) , m_noSourceMode(false) , m_item(nullptr) + , m_ownEngine(false) { m_sharedObject->m_surface = new QOffscreenSurface; m_sharedObject->m_surface->setFormat(QSurfaceFormat::defaultFormat()); @@ -288,11 +289,16 @@ void Scene2DManager::startIfInitialized() if (!m_initialized && m_backendInitialized) { if (m_source.isValid() && !m_noSourceMode) { // Create a QML engine. - m_qmlEngine = new QQmlEngine; - if (!m_qmlEngine->incubationController()) - m_qmlEngine->setIncubationController(m_sharedObject->m_quickWindow->incubationController()); + if (!m_qmlEngine) { + m_qmlEngine = new QQmlEngine; + if (!m_qmlEngine->incubationController()) { + m_qmlEngine->setIncubationController(m_sharedObject->m_quickWindow + ->incubationController()); + } + } // create component + m_ownEngine = true; m_qmlComponent = new QQmlComponent(m_qmlEngine, m_source); if (m_qmlComponent->isLoading()) { connect(m_qmlComponent, &QQmlComponent::statusChanged, @@ -322,7 +328,10 @@ void Scene2DManager::stopAndClean() m_sharedObject->requestQuit(); m_sharedObject->wait(); m_sharedObject->cleanup(); - delete m_qmlEngine; + if (m_ownEngine) { + QObject::disconnect(m_connection); + delete m_qmlEngine; + } delete m_qmlComponent; m_qmlEngine = nullptr; m_qmlComponent = nullptr; @@ -488,6 +497,23 @@ void Scene2DManager::cleanup() stopAndClean(); } +void Scene2DManager::setEngine(QQmlEngine *engine) +{ + m_qmlEngine = engine; + m_ownEngine = false; + if (engine) { + m_connection = QObject::connect(engine, &QObject::destroyed, + this, &Scene2DManager::engineDestroyed); + } +} + +void Scene2DManager::engineDestroyed() +{ + QObject::disconnect(m_connection); + m_qmlEngine = nullptr; + m_ownEngine = false; +} + QScene2DPrivate::QScene2DPrivate() : Qt3DCore::QNodePrivate() @@ -514,6 +540,15 @@ QScene2D::QScene2D(Qt3DCore::QNode *parent) this, &QScene2D::sourceLoaded); } +QScene2D::QScene2D(QQmlEngine *engine, Qt3DCore::QNode *parent) + : Qt3DCore::QNode(*new QScene2DPrivate, parent) +{ + Q_D(QScene2D); + connect(d->m_renderManager, &Scene2DManager::onLoadedChanged, + this, &QScene2D::sourceLoaded); + d->m_renderManager->setEngine(engine); +} + QScene2D::~QScene2D() { } @@ -637,6 +672,15 @@ bool QScene2D::event(QEvent *event) return true; } +/*! + Returns the qml engine used by the QScene2D. + */ +QQmlEngine *QScene2D::engine() const +{ + Q_D(const QScene2D); + return d->m_renderManager->m_qmlEngine; +} + /*! \internal */ diff --git a/src/quick3d/quick3drender/scene2d/qscene2d.h b/src/quick3d/quick3drender/scene2d/qscene2d.h index 67871f161..77ad6ea86 100644 --- a/src/quick3d/quick3drender/scene2d/qscene2d.h +++ b/src/quick3d/quick3drender/scene2d/qscene2d.h @@ -69,6 +69,7 @@ class QT3DQUICKRENDERSHARED_EXPORT QScene2D : public Qt3DCore::QNode public: explicit QScene2D(Qt3DCore::QNode *parent = nullptr); + QScene2D(QQmlEngine *engine, Qt3DCore::QNode *parent = nullptr); ~QScene2D(); Qt3DRender::QRenderTargetOutput *output() const; @@ -76,7 +77,9 @@ public: bool loaded() const; bool renderOnce() const; QQuickItem *item() const; + QQmlEngine *engine() const; bool event(QEvent *event) Q_DECL_OVERRIDE; + public Q_SLOTS: void setOutput(Qt3DRender::QRenderTargetOutput *output); void setSource(const QUrl &url); diff --git a/src/quick3d/quick3drender/scene2d/qscene2d_p.h b/src/quick3d/quick3drender/scene2d/qscene2d_p.h index fbc19a42f..95f32f7c9 100644 --- a/src/quick3d/quick3drender/scene2d/qscene2d_p.h +++ b/src/quick3d/quick3drender/scene2d/qscene2d_p.h @@ -178,6 +178,7 @@ public: QUrl m_source; Qt3DCore::QNodeId m_id; + QMetaObject::Connection m_connection; bool m_requested; bool m_initialized; @@ -185,6 +186,7 @@ public: bool m_renderOnce; bool m_backendInitialized; bool m_noSourceMode; + bool m_ownEngine; void requestRender(); void requestRenderSync(); @@ -203,6 +205,8 @@ public: Q_SIGNAL void onLoadedChanged(); void cleanup(); + void setEngine(QQmlEngine *engine); + void engineDestroyed(); }; } // namespace Quick -- cgit v1.2.3 From 1e04bb374fafe4a00d0fd4b8d5a0c5588781f888 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Tue, 22 Nov 2016 13:45:45 +0200 Subject: Move event forwarding to frontend MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the event forwarding to frontend so that the target object destruction can be handled properly. Change-Id: I6bdee731760cee69334aad7ca39f0dd16c44a471 Reviewed-by: Tomi Korpipää Reviewed-by: Sean Harmer --- src/render/picking/eventforward.cpp | 41 ++++++++------- src/render/picking/eventforward_p.h | 4 +- src/render/picking/picking.pri | 6 ++- src/render/picking/posteventstofrontend.cpp | 74 ++++++++++++++++++++++++++ src/render/picking/posteventstofrontend_p.h | 81 +++++++++++++++++++++++++++++ src/render/picking/qeventforward.cpp | 31 +++++++++++ src/render/picking/qeventforward.h | 4 ++ src/render/picking/qeventforward_p.h | 1 + 8 files changed, 217 insertions(+), 25 deletions(-) create mode 100644 src/render/picking/posteventstofrontend.cpp create mode 100644 src/render/picking/posteventstofrontend_p.h diff --git a/src/render/picking/eventforward.cpp b/src/render/picking/eventforward.cpp index 132e022ce..0216542bd 100644 --- a/src/render/picking/eventforward.cpp +++ b/src/render/picking/eventforward.cpp @@ -40,6 +40,7 @@ #include #include +#include #include #include @@ -51,7 +52,7 @@ namespace Qt3DRender { namespace Render { EventForward::EventForward() - : m_target(nullptr) + : BackendNode(QBackendNode::ReadWrite) , m_forwardMouseEvents(false) , m_forwardKeyboardEvents(false) , m_focus(false) @@ -67,7 +68,6 @@ EventForward::~EventForward() void EventForward::cleanup() { setEnabled(false); - m_target = nullptr; m_coordinateAttribute = ""; m_coordinateTransform.setToIdentity(); m_forwardMouseEvents = false; @@ -75,11 +75,6 @@ void EventForward::cleanup() m_focus = false; } -QObject *EventForward::target() const -{ - return m_target; -} - QString EventForward::coordinateAttribute() const { return m_coordinateAttribute; @@ -105,11 +100,6 @@ bool EventForward::focus() const return m_focus; } -void EventForward::setTarget(QObject *target) -{ - m_target = target; -} - void EventForward::setCoordinateTransform(const QMatrix4x4 &transform) { m_coordinateTransform = transform; @@ -139,7 +129,6 @@ void EventForward::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr { const auto typedChange = qSharedPointerCast>(change); const auto &data = typedChange->data; - setTarget(data.target); setCoordinateAttribute(data.coordinateAttribute); setCoordinateTransform(data.coordinateTransform); setForwardMouseEvents(data.forwardMouseEvents); @@ -153,9 +142,7 @@ void EventForward::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) const Qt3DCore::QPropertyUpdatedChangePtr propertyChange = qSharedPointerCast(e); - if (propertyChange->propertyName() == QByteArrayLiteral("target")) - setTarget(propertyChange->value().value()); - else if (propertyChange->propertyName() == QByteArrayLiteral("coordinateTransform")) + if (propertyChange->propertyName() == QByteArrayLiteral("coordinateTransform")) setCoordinateTransform(propertyChange->value().value()); else if (propertyChange->propertyName() == QByteArrayLiteral("coordinateAttribute")) setCoordinateAttribute(propertyChange->value().toString()); @@ -177,16 +164,30 @@ void EventForward::forward(const QMouseEvent &event, const QVector4D &coordinate QMouseEvent *mouseEvent = new QMouseEvent(event.type(), local, local, local, event.button(), event.buttons(), event.modifiers(), Qt::MouseEventSynthesizedByApplication); - QCoreApplication::postEvent(m_target, mouseEvent); + + PostEventsToFrontendPtr events = PostEventsToFrontendPtr::create(mouseEvent); + + auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId()); + e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll); + e->setPropertyName("events"); + e->setValue(QVariant::fromValue(events)); + notifyObservers(e); } -void EventForward::forward(const QList &events) +void EventForward::forward(const QList &keyEvents) { - for (const QKeyEvent &e : events) { + QVector eventsToSend; + for (const QKeyEvent &e : keyEvents) { QKeyEvent *keyEvent = new QKeyEvent(e.type(), e.key(), e.modifiers(), e.nativeScanCode(), e.nativeVirtualKey(), e.nativeModifiers()); - QCoreApplication::postEvent(m_target, keyEvent); + eventsToSend.append(keyEvent); } + PostEventsToFrontendPtr events = PostEventsToFrontendPtr::create(eventsToSend); + auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId()); + e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll); + e->setPropertyName("events"); + e->setValue(QVariant::fromValue(events)); + notifyObservers(e); } } // Render diff --git a/src/render/picking/eventforward_p.h b/src/render/picking/eventforward_p.h index e090ba5e4..663298e40 100644 --- a/src/render/picking/eventforward_p.h +++ b/src/render/picking/eventforward_p.h @@ -69,7 +69,6 @@ public: void cleanup(); - QObject *target() const; QString coordinateAttribute() const; QMatrix4x4 coordinateTransform() const; bool forwardMouseEvents() const; @@ -86,12 +85,11 @@ public: void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_FINAL; void forward(const QMouseEvent &event, const QVector4D &coordinate); - void forward(const QList &events); + void forward(const QList &keyEvents); private: void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL; - QObject *m_target; QString m_coordinateAttribute; QMatrix4x4 m_coordinateTransform; bool m_forwardMouseEvents; diff --git a/src/render/picking/picking.pri b/src/render/picking/picking.pri index e581a8f8a..c2eb8f50b 100644 --- a/src/render/picking/picking.pri +++ b/src/render/picking/picking.pri @@ -10,7 +10,8 @@ HEADERS += \ $$PWD/qobjectpicker_p.h \ $$PWD/qeventforward.h \ $$PWD/qeventforward_p.h \ - $$PWD/eventforward_p.h + $$PWD/eventforward_p.h \ + $$PWD/posteventstofrontend_p.h SOURCES += \ $$PWD/qobjectpicker.cpp \ @@ -19,4 +20,5 @@ SOURCES += \ $$PWD/objectpicker.cpp \ $$PWD/pickeventfilter.cpp \ $$PWD/qeventforward.cpp \ - $$PWD/eventforward.cpp + $$PWD/eventforward.cpp \ + $$PWD/posteventstofrontend.cpp diff --git a/src/render/picking/posteventstofrontend.cpp b/src/render/picking/posteventstofrontend.cpp new file mode 100644 index 000000000..51f986902 --- /dev/null +++ b/src/render/picking/posteventstofrontend.cpp @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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 "posteventstofrontend_p.h" + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +PostEventsToFrontend::PostEventsToFrontend() + : QObject() +{ + +} + +PostEventsToFrontend::PostEventsToFrontend(QEvent *event) + : QObject() +{ + m_events.append(event); +} + +PostEventsToFrontend::PostEventsToFrontend(const QVector &events) + : QObject() +{ + m_events = events; +} + +PostEventsToFrontend::~PostEventsToFrontend() +{ + for (QEvent *e : m_events) + delete e; +} + +QVector &PostEventsToFrontend::events() +{ + return m_events; +} + +} + +QT_END_NAMESPACE diff --git a/src/render/picking/posteventstofrontend_p.h b/src/render/picking/posteventstofrontend_p.h new file mode 100644 index 000000000..5dd29b047 --- /dev/null +++ b/src/render/picking/posteventstofrontend_p.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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$ +** +****************************************************************************/ + +#ifndef QT3DRENDER_POSTEVENTSTOFRONTEND_P_H +#define QT3DRENDER_POSTEVENTSTOFRONTEND_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +class Q_AUTOTEST_EXPORT PostEventsToFrontend : public QObject +{ + Q_OBJECT +public: + PostEventsToFrontend(); + PostEventsToFrontend(QEvent *event); + PostEventsToFrontend(const QVector &events); + ~PostEventsToFrontend(); + + QVector &events(); +private: + QVector m_events; +}; + +typedef QSharedPointer PostEventsToFrontendPtr; + +} // Qt3DRender + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(Qt3DRender::PostEventsToFrontend*) + +#endif // QT3DRENDER_POSTEVENTSTOFRONTEND_P_H diff --git a/src/render/picking/qeventforward.cpp b/src/render/picking/qeventforward.cpp index 8aa22e276..08546fabd 100644 --- a/src/render/picking/qeventforward.cpp +++ b/src/render/picking/qeventforward.cpp @@ -36,8 +36,12 @@ #include "qeventforward.h" #include "qeventforward_p.h" +#include "posteventstofrontend_p.h" #include +#include + +#include QT_BEGIN_NAMESPACE @@ -148,11 +152,24 @@ QObject *QEventForward::target() const return d->m_target; } +void QEventForward::targetDestroyed(QObject *target) +{ + Q_D(QEventForward); + Q_ASSERT(target == d->m_target); + setTarget(nullptr); +} + void QEventForward::setTarget(QObject *target) { Q_D(QEventForward); if (target != d->m_target) { + if (d->m_target != nullptr) + QObject::disconnect(d->m_destructionConnection); d->m_target = target; + if (d->m_target) { + d->m_destructionConnection = QObject::connect(target, &QObject::destroyed, + this, &QEventForward::targetDestroyed); + } emit targetChanged(target); } } @@ -249,6 +266,20 @@ Qt3DCore::QNodeCreatedChangeBasePtr QEventForward::createNodeCreationChange() co return creationChange; } +void QEventForward::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) +{ + Q_D(QEventForward); + Qt3DCore::QPropertyUpdatedChangePtr e + = qSharedPointerCast(change); + if (e->type() == Qt3DCore::PropertyUpdated && d->m_target != nullptr) { + if (e->propertyName() == QByteArrayLiteral("events")) { + PostEventsToFrontendPtr postedEvents = e->value().value(); + for (QEvent *event : postedEvents->events()) + QCoreApplication::sendEvent(d->m_target, event); + } + } +} + } // Qt3DRender QT_END_NAMESPACE diff --git a/src/render/picking/qeventforward.h b/src/render/picking/qeventforward.h index 28659606b..ee8100318 100644 --- a/src/render/picking/qeventforward.h +++ b/src/render/picking/qeventforward.h @@ -87,9 +87,13 @@ Q_SIGNALS: void forwardKeyboardEventsChanged(bool forward); void focusChanged(bool focus); +protected: + void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) Q_DECL_OVERRIDE; + private: Q_DECLARE_PRIVATE(QEventForward) Qt3DCore::QNodeCreatedChangeBasePtr createNodeCreationChange() const Q_DECL_OVERRIDE; + void targetDestroyed(QObject *target); }; } // Qt3DRender diff --git a/src/render/picking/qeventforward_p.h b/src/render/picking/qeventforward_p.h index 4aa6834df..c087bc8f5 100644 --- a/src/render/picking/qeventforward_p.h +++ b/src/render/picking/qeventforward_p.h @@ -81,6 +81,7 @@ public: bool m_forwardMouseEvents; bool m_forwardKeyboardEvents; bool m_focus; + QMetaObject::Connection m_destructionConnection; }; struct QEventForwardData -- cgit v1.2.3 From 61a7a44b4f2ea88ee4451dbc0faedbd5efd11558 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Tue, 25 Oct 2016 13:51:37 +0300 Subject: Update pickboundingvolumejob with event forwarding MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I6d14d4ad1bf78bf3e6d6e8b2415137a94d833c9e Reviewed-by: Tomi Korpipää Reviewed-by: Sean Harmer --- src/render/backend/renderer.cpp | 7 ++- src/render/backend/renderer_p.h | 2 +- src/render/jobs/pickboundingvolumejob.cpp | 77 +++++++++++++++++++++++++++++-- src/render/jobs/pickboundingvolumejob_p.h | 6 ++- src/render/picking/pickeventfilter.cpp | 21 +++++++-- src/render/picking/pickeventfilter_p.h | 7 ++- 6 files changed, 107 insertions(+), 13 deletions(-) diff --git a/src/render/backend/renderer.cpp b/src/render/backend/renderer.cpp index 191e70392..c82ae7ec6 100644 --- a/src/render/backend/renderer.cpp +++ b/src/render/backend/renderer.cpp @@ -1576,7 +1576,12 @@ void Renderer::cleanGraphicsResources() QList Renderer::pendingPickingEvents() const { - return m_pickEventFilter->pendingEvents(); + return m_pickEventFilter->pendingMouseEvents(); +} + +QList Renderer::pendingKeyEvents() const +{ + return m_pickEventFilter->pendingKeyEvents(); } const GraphicsApiFilterData *Renderer::contextInfo() const diff --git a/src/render/backend/renderer_p.h b/src/render/backend/renderer_p.h index 344565173..690ce8584 100644 --- a/src/render/backend/renderer_p.h +++ b/src/render/backend/renderer_p.h @@ -227,8 +227,8 @@ public: inline RenderStateSet *defaultRenderState() const { return m_defaultRenderStateSet; } - QList pendingPickingEvents() const; + QList pendingKeyEvents() const; void addRenderCaptureSendRequest(Qt3DCore::QNodeId nodeId); const QVector takePendingRenderCaptureSendRequests(); diff --git a/src/render/jobs/pickboundingvolumejob.cpp b/src/render/jobs/pickboundingvolumejob.cpp index 2ce6eb92e..a7df5270f 100644 --- a/src/render/jobs/pickboundingvolumejob.cpp +++ b/src/render/jobs/pickboundingvolumejob.cpp @@ -58,6 +58,8 @@ namespace Render { namespace { +typedef PickingUtils::AbstractCollisionGathererFunctor::result_type HitList; + void setEventButtonAndModifiers(const QMouseEvent &event, QPickEvent::Buttons &eventButton, int &eventButtons, int &eventModifiers) { switch (event.button()) { @@ -118,6 +120,11 @@ void PickBoundingVolumeJob::setMouseEvents(const QList &pendingEven m_pendingMouseEvents = pendingEvents; } +void PickBoundingVolumeJob::setKeyEvents(const QList &pendingEvents) +{ + m_pendingKeyEvents = pendingEvents; +} + void PickBoundingVolumeJob::setFrameGraphRoot(FrameGraphNode *frameGraphRoot) { m_frameGraphRoot = frameGraphRoot; @@ -145,9 +152,10 @@ bool PickBoundingVolumeJob::runHelper() // Move to clear the events so that we don't process them several times // if run is called several times const auto mouseEvents = std::move(m_pendingMouseEvents); + const auto keyEvents = std::move(m_pendingKeyEvents); // If we have no events return early - if (mouseEvents.empty()) + if (mouseEvents.empty() && keyEvents.empty()) return false; // bail out early if no picker is enabled @@ -178,6 +186,23 @@ bool PickBoundingVolumeJob::runHelper() // that the tree structure has changed PickingUtils::EntityGatherer entitiesGatherer(m_node); + // Forward keyboard events + if (keyEvents.size() > 0) { + for (Entity *e : entitiesGatherer.entities()) { + ObjectPicker *picker = e->renderComponent(); + if (picker != nullptr) { + if (picker->isEventForwardingEnabled()) { + EventForward *eventForward + = m_manager->eventForwardManager()->lookupResource(picker->eventForward()); + if (eventForward->focus() && eventForward->forwardKeyboardEvents()) { + eventForward->forward(keyEvents); + break; + } + } + } + } + } + // Store the reducer function which varies depending on the picking settings set on the renderer using ReducerFunction = PickingUtils::CollisionVisitor::HitList (*)(PickingUtils::CollisionVisitor::HitList &results, const PickingUtils::CollisionVisitor::HitList &intermediate); @@ -203,7 +228,6 @@ bool PickBoundingVolumeJob::runHelper() // For each triplet of Viewport / Camera and Area for (const PickingUtils::ViewportCameraAreaTriplet &vca : vcaTriplets) { - typedef PickingUtils::AbstractCollisionGathererFunctor::result_type HitList; HitList sphereHits; QRay3D ray = rayForViewportAndCamera(vca.area, event.pos(), vca.viewport, vca.cameraId); if (trianglePickingRequested) { @@ -221,7 +245,8 @@ bool PickBoundingVolumeJob::runHelper() } // Dispatch events based on hit results - dispatchPickEvents(event, sphereHits, eventButton, eventButtons, eventModifiers, trianglePickingRequested); + dispatchPickEvents(event, sphereHits, eventButton, eventButtons, + eventModifiers, trianglePickingRequested, ray); } } @@ -249,7 +274,8 @@ void PickBoundingVolumeJob::dispatchPickEvents(const QMouseEvent &event, QPickEvent::Buttons eventButton, int eventButtons, int eventModifiers, - bool trianglePickingRequested) + bool trianglePickingRequested, + const QRay3D &ray) { ObjectPicker *lastCurrentPicker = m_manager->objectPickerManager()->data(m_currentPicker); // If we have hits @@ -337,6 +363,49 @@ void PickBoundingVolumeJob::dispatchPickEvents(const QMouseEvent &event, default: break; } + if (objectPicker->isEventForwardingEnabled()) { + EventForward *eventForward + = m_manager->eventForwardManager()->lookupResource(objectPicker->eventForward()); + QCollisionQueryResult::Hit triangleHit = hit; + bool valid = true; + if (eventForward->isEnabled() && eventForward->forwardMouseEvents()) { + if (!trianglePickingRequested) { + // Triangle picking is not enables so the triangle is not already in the + // query results. We need to redo the picking to get the triangle. + Qt3DRender::QRayCastingService rayCasting; + PickingUtils::TriangleCollisionGathererFunctor gathererFunctor; + const bool frontFaceRequested = + m_renderSettings->faceOrientationPickingMode() != QPickingSettings::BackFace; + const bool backFaceRequested = + m_renderSettings->faceOrientationPickingMode() != QPickingSettings::FrontFace; + gathererFunctor.m_frontFaceRequested = frontFaceRequested; + gathererFunctor.m_backFaceRequested = backFaceRequested; + gathererFunctor.m_manager = m_manager; + gathererFunctor.m_ray = ray; + + // The bounding method is inaccurate so the triangle picking doesn't + // necessarely produce any results + HitList hitlist = gathererFunctor.pick(&rayCasting, entity); + if (hitlist.size() > 0) + triangleHit = hitlist.at(0); + else + valid = false; + } + if (valid) { + CoordinateReader reader(m_manager); + if (reader.setGeometry(entity->renderComponent(), + eventForward->coordinateAttribute())) { + QVector4D c0 = reader.getCoordinate(triangleHit.m_vertexIndex[0]); + QVector4D c1 = reader.getCoordinate(triangleHit.m_vertexIndex[1]); + QVector4D c2 = reader.getCoordinate(triangleHit.m_vertexIndex[2]); + QVector4D ci = c2 * triangleHit.m_uvw.x() + + c1 * triangleHit.m_uvw.y() + c0 * triangleHit.m_uvw.z(); + ci.setW(1.0f); + eventForward->forward(event, ci); + } + } + } + } } // The ObjectPicker was hit -> it is still being hovered diff --git a/src/render/jobs/pickboundingvolumejob_p.h b/src/render/jobs/pickboundingvolumejob_p.h index 913a5ace0..90a0bdbda 100644 --- a/src/render/jobs/pickboundingvolumejob_p.h +++ b/src/render/jobs/pickboundingvolumejob_p.h @@ -59,6 +59,7 @@ #include #include #include +#include #include QT_BEGIN_NAMESPACE @@ -85,6 +86,7 @@ public: void setRoot(Entity *root); void setMouseEvents(const QList &pendingEvents); + void setKeyEvents(const QList &pendingEvents); void setFrameGraphRoot(FrameGraphNode *frameGraphRoot); void setRenderSettings(RenderSettings *settings); void setManagers(NodeManagers *manager); @@ -104,7 +106,8 @@ protected: void dispatchPickEvents(const QMouseEvent &event, const PickingUtils::CollisionVisitor::HitList &sphereHits, QPickEvent::Buttons eventButton, int eventButtons, - int eventModifiers, bool trianglePickingRequested); + int eventModifiers, bool trianglePickingRequested, + const QRay3D &ray); private: NodeManagers *m_manager; @@ -112,6 +115,7 @@ private: FrameGraphNode *m_frameGraphRoot; RenderSettings *m_renderSettings; QList m_pendingMouseEvents; + QList m_pendingKeyEvents; void viewMatrixForCamera(Qt3DCore::QNodeId cameraId, QMatrix4x4 &viewMatrix, diff --git a/src/render/picking/pickeventfilter.cpp b/src/render/picking/pickeventfilter.cpp index a1ae52068..19d3b6b6e 100644 --- a/src/render/picking/pickeventfilter.cpp +++ b/src/render/picking/pickeventfilter.cpp @@ -61,11 +61,19 @@ PickEventFilter::~PickEventFilter() Called from a worker thread in the thread pool so be sure to mutex protect the data. */ -QList PickEventFilter::pendingEvents() +QList PickEventFilter::pendingMouseEvents() { QMutexLocker locker(&m_mutex); - QList pendingEvents(m_pendingEvents); - m_pendingEvents.clear(); + QList pendingEvents(m_pendingMouseEvents); + m_pendingMouseEvents.clear(); + return pendingEvents; +} + +QList PickEventFilter::pendingKeyEvents() +{ + QMutexLocker locker(&m_mutex); + QList pendingEvents(m_pendingKeyEvents); + m_pendingKeyEvents.clear(); return pendingEvents; } @@ -82,7 +90,12 @@ bool PickEventFilter::eventFilter(QObject *obj, QEvent *e) case QEvent::MouseMove: case QEvent::HoverMove: { QMutexLocker locker(&m_mutex); - m_pendingEvents.push_back(QMouseEvent(*static_cast(e))); + m_pendingMouseEvents.push_back(QMouseEvent(*static_cast(e))); + } break; + case QEvent::KeyPress: + case QEvent::KeyRelease: { + QMutexLocker locker(&m_mutex); + m_pendingKeyEvents.push_back(QKeyEvent(*static_cast(e))); } default: break; diff --git a/src/render/picking/pickeventfilter_p.h b/src/render/picking/pickeventfilter_p.h index df94a3085..fc4b00ddc 100644 --- a/src/render/picking/pickeventfilter_p.h +++ b/src/render/picking/pickeventfilter_p.h @@ -53,6 +53,7 @@ #include #include +#include #include QT_BEGIN_NAMESPACE @@ -68,13 +69,15 @@ public: explicit PickEventFilter(QObject *parent = nullptr); ~PickEventFilter(); - QList pendingEvents(); + QList pendingMouseEvents(); + QList pendingKeyEvents(); protected: bool eventFilter(QObject *obj, QEvent *e) Q_DECL_FINAL; private: - QList m_pendingEvents; + QList m_pendingMouseEvents; + QList m_pendingKeyEvents; QMutex m_mutex; }; -- cgit v1.2.3 From c2da124e676c3e1b599210d1ee50a09b3fff9ffa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Tue, 25 Oct 2016 13:10:23 +0300 Subject: Update ObjectPicker unit tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I648e0b49e06c68779631870f9d31e3671eb5e691 Reviewed-by: Tomi Korpipää Reviewed-by: Sean Harmer --- tests/auto/render/objectpicker/tst_objectpicker.cpp | 17 +++++++++++++++++ tests/auto/render/qobjectpicker/tst_qobjectpicker.cpp | 14 ++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/tests/auto/render/objectpicker/tst_objectpicker.cpp b/tests/auto/render/objectpicker/tst_objectpicker.cpp index c42ec60c9..96ee76827 100644 --- a/tests/auto/render/objectpicker/tst_objectpicker.cpp +++ b/tests/auto/render/objectpicker/tst_objectpicker.cpp @@ -46,7 +46,9 @@ private Q_SLOTS: // GIVEN Qt3DRender::Render::ObjectPicker objectPicker; Qt3DRender::QObjectPicker picker; + Qt3DRender::QEventForward eventForward; picker.setHoverEnabled(true); + picker.setEventForward(&eventForward); // WHEN simulateInitialization(&picker, &objectPicker); @@ -55,6 +57,7 @@ private Q_SLOTS: QVERIFY(!objectPicker.peerId().isNull()); QCOMPARE(objectPicker.isHoverEnabled(), true); QCOMPARE(objectPicker.isDirty(), true); + QCOMPARE(objectPicker.eventForward(), eventForward.id()); } void checkInitialAndCleanedUpState() @@ -66,6 +69,8 @@ private Q_SLOTS: QVERIFY(objectPicker.peerId().isNull()); QCOMPARE(objectPicker.isHoverEnabled(), false); QCOMPARE(objectPicker.isDirty(), false); + QCOMPARE(objectPicker.isEventForwardingEnabled(), false); + QCOMPARE(objectPicker.eventForward(), Qt3DCore::QNodeId()); // GIVEN Qt3DRender::QObjectPicker picker; @@ -78,12 +83,15 @@ private Q_SLOTS: // THEN QCOMPARE(objectPicker.isHoverEnabled(), false); QCOMPARE(objectPicker.isDirty(), false); + QCOMPARE(objectPicker.isEventForwardingEnabled(), false); + QCOMPARE(objectPicker.eventForward(), Qt3DCore::QNodeId()); } void checkPropertyChanges() { // GIVEN Qt3DRender::Render::ObjectPicker objectPicker; + Qt3DRender::QEventForward eventForward; TestRenderer renderer; objectPicker.setRenderer(&renderer); @@ -102,6 +110,15 @@ private Q_SLOTS: objectPicker.unsetDirty(); QVERIFY(!objectPicker.isDirty()); + + // WHEN + updateChange->setValue(QVariant::fromValue(eventForward.id())); + updateChange->setPropertyName("eventForward"); + objectPicker.sceneChangeEvent(updateChange); + + // THEN + QCOMPARE(objectPicker.isEventForwardingEnabled(), true); + QCOMPARE(objectPicker.eventForward(), eventForward.id()); } void checkBackendPropertyNotifications() diff --git a/tests/auto/render/qobjectpicker/tst_qobjectpicker.cpp b/tests/auto/render/qobjectpicker/tst_qobjectpicker.cpp index 4397954ec..8cc87ce14 100644 --- a/tests/auto/render/qobjectpicker/tst_qobjectpicker.cpp +++ b/tests/auto/render/qobjectpicker/tst_qobjectpicker.cpp @@ -105,6 +105,7 @@ private Q_SLOTS: // GIVEN TestArbiter arbiter; QScopedPointer objectPicker(new Qt3DRender::QObjectPicker()); + QScopedPointer eventForward(new Qt3DRender::QEventForward()); arbiter.setArbiterOnNode(objectPicker.data()); // WHEN @@ -119,6 +120,19 @@ private Q_SLOTS: QCOMPARE(change->type(), Qt3DCore::PropertyUpdated); arbiter.events.clear(); + + // WHEN + objectPicker->setEventForward(eventForward.data()); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 1); + change = arbiter.events.last().staticCast(); + QCOMPARE(change->propertyName(), "eventForward"); + QCOMPARE(change->value().value(), eventForward->id()); + QCOMPARE(change->type(), Qt3DCore::PropertyUpdated); + + arbiter.events.clear(); } void checkBackendUpdates_data() -- cgit v1.2.3 From b11edfb98c14d91d8a59352b05b5e902e8d2231b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Tue, 25 Oct 2016 13:43:59 +0300 Subject: Update EventForward autotests with focus MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I7bc92c46f9ebb8fddc30207635cb5252944dfbca Reviewed-by: Tomi Korpipää Reviewed-by: Sean Harmer --- .../auto/render/eventforward/tst_eventforward.cpp | 17 +++++++ .../render/qeventforward/tst_qeventforward.cpp | 56 ++++++++++++++++++++++ 2 files changed, 73 insertions(+) diff --git a/tests/auto/render/eventforward/tst_eventforward.cpp b/tests/auto/render/eventforward/tst_eventforward.cpp index 9a87fc40f..5352853a1 100644 --- a/tests/auto/render/eventforward/tst_eventforward.cpp +++ b/tests/auto/render/eventforward/tst_eventforward.cpp @@ -53,6 +53,7 @@ private Q_SLOTS: QCOMPARE(backendEventForward.coordinateTransform(), QMatrix4x4()); QCOMPARE(backendEventForward.forwardMouseEvents(), false); QCOMPARE(backendEventForward.forwardKeyboardEvents(), false); + QCOMPARE(backendEventForward.focus(), false); } void checkCleanupState() @@ -70,6 +71,7 @@ private Q_SLOTS: backendEventForward.setCoordinateTransform(transform); backendEventForward.setForwardMouseEvents(true); backendEventForward.setForwardKeyboardEvents(true); + backendEventForward.setFocus(true); backendEventForward.cleanup(); @@ -80,6 +82,7 @@ private Q_SLOTS: QCOMPARE(backendEventForward.coordinateTransform(), QMatrix4x4()); QCOMPARE(backendEventForward.forwardMouseEvents(), false); QCOMPARE(backendEventForward.forwardKeyboardEvents(), false); + QCOMPARE(backendEventForward.focus(), false); } void checkInitializeFromPeer() @@ -100,16 +103,19 @@ private Q_SLOTS: QCOMPARE(backendEventForward.coordinateTransform(), QMatrix4x4()); QCOMPARE(backendEventForward.forwardMouseEvents(), true); QCOMPARE(backendEventForward.forwardKeyboardEvents(), false); + QCOMPARE(backendEventForward.focus(), false); } { // WHEN Qt3DRender::Render::EventForward backendEventForward; eventForward.setEnabled(false); + eventForward.setFocus(true); simulateInitialization(&eventForward, &backendEventForward); // THEN QCOMPARE(backendEventForward.peerId(), eventForward.id()); QCOMPARE(backendEventForward.isEnabled(), false); + QCOMPARE(backendEventForward.focus(), true); } } @@ -188,6 +194,17 @@ private Q_SLOTS: // THEN QCOMPARE(backendEventForward.forwardKeyboardEvents(), newValue); } + { + // WHEN + const bool newValue = true; + const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId()); + change->setPropertyName("focus"); + change->setValue(QVariant::fromValue(newValue)); + backendEventForward.sceneChangeEvent(change); + + // THEN + QCOMPARE(backendEventForward.focus(), newValue); + } } }; diff --git a/tests/auto/render/qeventforward/tst_qeventforward.cpp b/tests/auto/render/qeventforward/tst_qeventforward.cpp index 87ba114f2..aa525d4a2 100644 --- a/tests/auto/render/qeventforward/tst_qeventforward.cpp +++ b/tests/auto/render/qeventforward/tst_qeventforward.cpp @@ -54,6 +54,7 @@ private Q_SLOTS: QCOMPARE(eventForward.forwardKeyboardEvents(), false); QCOMPARE(eventForward.coordinateTransform(), QMatrix4x4()); QCOMPARE(eventForward.coordinateAttribute(), QStringLiteral("default")); + QCOMPARE(eventForward.focus(), false); } void checkPropertyChanges() @@ -158,6 +159,25 @@ private Q_SLOTS: QCOMPARE(eventForward.coordinateAttribute(), newValue); QCOMPARE(spy.count(), 0); } + { + // WHEN + QSignalSpy spy(&eventForward, SIGNAL(focusChanged(bool))); + const bool newValue = true; + eventForward.setFocus(newValue); + + // THEN + QVERIFY(spy.isValid()); + QCOMPARE(eventForward.focus(), newValue); + QCOMPARE(spy.count(), 1); + + // WHEN + spy.clear(); + eventForward.setFocus(newValue); + + // THEN + QCOMPARE(eventForward.focus(), newValue); + QCOMPARE(spy.count(), 0); + } } void checkCreationData() @@ -173,6 +193,7 @@ private Q_SLOTS: eventForward.setForwardKeyboardEvents(true); eventForward.setCoordinateTransform(transform); eventForward.setCoordinateAttribute(QStringLiteral("position")); + eventForward.setFocus(true); // WHEN QVector creationChanges; @@ -196,6 +217,7 @@ private Q_SLOTS: QCOMPARE(eventForward.forwardKeyboardEvents(), cloneData.forwardKeyboardEvents); QCOMPARE(eventForward.coordinateTransform(), cloneData.coordinateTransform); QCOMPARE(eventForward.coordinateAttribute(), cloneData.coordinateAttribute); + QCOMPARE(eventForward.focus(), cloneData.focus); QCOMPARE(eventForward.id(), creationChangeData->subjectId()); QCOMPARE(eventForward.isEnabled(), true); QCOMPARE(eventForward.isEnabled(), creationChangeData->isNodeEnabled()); @@ -224,6 +246,7 @@ private Q_SLOTS: QCOMPARE(eventForward.forwardKeyboardEvents(), cloneData.forwardKeyboardEvents); QCOMPARE(eventForward.coordinateTransform(), cloneData.coordinateTransform); QCOMPARE(eventForward.coordinateAttribute(), cloneData.coordinateAttribute); + QCOMPARE(eventForward.focus(), cloneData.focus); QCOMPARE(eventForward.id(), creationChangeData->subjectId()); QCOMPARE(eventForward.isEnabled(), false); QCOMPARE(eventForward.isEnabled(), creationChangeData->isNodeEnabled()); @@ -399,6 +422,39 @@ private Q_SLOTS: } + void checkFocusUpdate() + { + // GIVEN + TestArbiter arbiter; + Qt3DRender::QEventForward eventForward; + arbiter.setArbiterOnNode(&eventForward); + + { + // WHEN + eventForward.setFocus(true); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 1); + auto change = arbiter.events.first().staticCast(); + QCOMPARE(change->propertyName(), "focus"); + QCOMPARE(change->value().toBool(), eventForward.focus()); + QCOMPARE(change->type(), Qt3DCore::PropertyUpdated); + + arbiter.events.clear(); + } + + { + // WHEN + eventForward.setFocus(true); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 0); + } + + } + }; QTEST_MAIN(tst_QEventForward) -- cgit v1.2.3 From de5283370e08979c43c934538f5fa604a9bdb507 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Tue, 25 Oct 2016 08:49:20 +0300 Subject: Register EventForward backend type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I568ea403e408104bd39c2b24942a84df766c671c Reviewed-by: Tomi Korpipää Reviewed-by: Sean Harmer --- src/render/frontend/qrenderaspect.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/render/frontend/qrenderaspect.cpp b/src/render/frontend/qrenderaspect.cpp index 3ab68dc0a..6e67a79ce 100644 --- a/src/render/frontend/qrenderaspect.cpp +++ b/src/render/frontend/qrenderaspect.cpp @@ -78,6 +78,8 @@ #include #include #include +#include + #include #include #include @@ -123,6 +125,7 @@ #include #include #include +#include #include #include @@ -238,6 +241,11 @@ void QRenderAspectPrivate::registerBackendTypes() // Picking q->registerBackendType(QSharedPointer >::create(m_renderer)); + q->registerBackendType(QSharedPointer >::create(m_renderer)); + + // Plugins + for (Render::QRenderPlugin *plugin : m_renderPlugins) + plugin->registerBackendTypes(q, m_renderer); } /*! \internal */ @@ -295,6 +303,18 @@ void QRenderAspectPrivate::unregisterBackendTypes() // Picking unregisterBackendType(); + unregisterBackendType(); + + // Plugins + for (Render::QRenderPlugin *plugin : m_renderPlugins) + plugin->unregisterBackendTypes(q); +} + +void QRenderAspectPrivate::registerBackendType(const QMetaObject &obj, + const QBackendNodeMapperPtr &functor) +{ + Q_Q(QRenderAspect); + q->registerBackendType(obj, functor); } /*! -- cgit v1.2.3 From de0270437c18d37a2cad6f6705ce73e2f3a8f76f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Mon, 28 Nov 2016 15:32:23 +0200 Subject: Update eventForward unit tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Id0898fde106ac9a4407033867a13e46f7ce4b86e Reviewed-by: Tomi Korpipää Reviewed-by: Sean Harmer --- .../auto/render/eventforward/tst_eventforward.cpp | 100 +++++++++++++--- .../render/qeventforward/tst_qeventforward.cpp | 128 ++++++++++++++++++++- 2 files changed, 207 insertions(+), 21 deletions(-) diff --git a/tests/auto/render/eventforward/tst_eventforward.cpp b/tests/auto/render/eventforward/tst_eventforward.cpp index 5352853a1..de86b8ef3 100644 --- a/tests/auto/render/eventforward/tst_eventforward.cpp +++ b/tests/auto/render/eventforward/tst_eventforward.cpp @@ -28,11 +28,15 @@ #include #include -#include -#include +#include +#include +#include +#include #include #include "qbackendnodetester.h" #include "testrenderer.h" +#include "testpostmanarbiter.h" + class tst_EventForward : public Qt3DCore::QBackendNodeTester { @@ -48,7 +52,6 @@ private Q_SLOTS: // THEN QCOMPARE(backendEventForward.isEnabled(), false); QVERIFY(backendEventForward.peerId().isNull()); - QCOMPARE(backendEventForward.target(), nullptr); QCOMPARE(backendEventForward.coordinateAttribute(), QStringLiteral("")); QCOMPARE(backendEventForward.coordinateTransform(), QMatrix4x4()); QCOMPARE(backendEventForward.forwardMouseEvents(), false); @@ -66,7 +69,6 @@ private Q_SLOTS: // WHEN backendEventForward.setEnabled(true); - backendEventForward.setTarget(obj.data()); backendEventForward.setCoordinateAttribute(QStringLiteral("default")); backendEventForward.setCoordinateTransform(transform); backendEventForward.setForwardMouseEvents(true); @@ -77,7 +79,6 @@ private Q_SLOTS: // THEN QCOMPARE(backendEventForward.isEnabled(), false); - QCOMPARE(backendEventForward.target(), nullptr); QCOMPARE(backendEventForward.coordinateAttribute(), QStringLiteral("")); QCOMPARE(backendEventForward.coordinateTransform(), QMatrix4x4()); QCOMPARE(backendEventForward.forwardMouseEvents(), false); @@ -98,7 +99,6 @@ private Q_SLOTS: // THEN QCOMPARE(backendEventForward.isEnabled(), true); QCOMPARE(backendEventForward.peerId(), eventForward.id()); - QCOMPARE(backendEventForward.target(), nullptr); QCOMPARE(backendEventForward.coordinateAttribute(), QStringLiteral("default")); QCOMPARE(backendEventForward.coordinateTransform(), QMatrix4x4()); QCOMPARE(backendEventForward.forwardMouseEvents(), true); @@ -137,18 +137,6 @@ private Q_SLOTS: // THEN QCOMPARE(backendEventForward.isEnabled(), newValue); } - { - // WHEN - QScopedPointer obj(new Qt3DRender::QEventForward()); - Qt3DRender::QEventForward * newValue = obj.data(); - const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId()); - change->setPropertyName("target"); - change->setValue(QVariant::fromValue(newValue)); - backendEventForward.sceneChangeEvent(change); - - // THEN - QCOMPARE(backendEventForward.target(), newValue); - } { // WHEN const QString newValue = QStringLiteral("position"); @@ -206,7 +194,83 @@ private Q_SLOTS: QCOMPARE(backendEventForward.focus(), newValue); } } + void checkEventForwarding() + { + Qt3DRender::Render::EventForward backendEventForward; + TestRenderer renderer; + TestArbiter arbiter; + backendEventForward.setRenderer(&renderer); + Qt3DCore::QBackendNodePrivate::get(&backendEventForward)->setArbiter(&arbiter); + + { + // WHEN + const QPointF localPos; + QMouseEvent event = QMouseEvent(QEvent::MouseButtonPress, localPos, + Qt::LeftButton, Qt::LeftButton, 0); + + const QVector4D coordinate; + backendEventForward.forward(event, coordinate); + QCoreApplication::processEvents(); + + // THEN + QVERIFY(arbiter.events.size() == 1); + Qt3DCore::QPropertyUpdatedChangePtr change + = arbiter.events.first().staticCast(); + QCOMPARE(change->propertyName(), "events"); + + Qt3DRender::PostEventsToFrontendPtr postedEvents + = change->value().value(); + QVERIFY(postedEvents->events().size() == 1); + + QEvent *receivedEvent = postedEvents->events().first(); + QCOMPARE(receivedEvent->type(), QEvent::MouseButtonPress); + + QMouseEvent *me = static_cast(receivedEvent); + QCOMPARE(me->localPos(), localPos); + QCOMPARE(me->button(), Qt::LeftButton); + QCOMPARE(me->buttons(), Qt::LeftButton); + QCOMPARE(me->modifiers(), 0); + + arbiter.events.clear(); + } + + { + // WHEN + QKeyEvent event1 = QKeyEvent(QEvent::KeyPress, 48, 0); + QKeyEvent event2 = QKeyEvent(QEvent::KeyRelease, 48, 0); + QList eventList; + eventList.push_back(event1); + eventList.push_back(event2); + backendEventForward.forward(eventList); + QCoreApplication::processEvents(); + + // THEN + QVERIFY(arbiter.events.size() == 1); + Qt3DCore::QPropertyUpdatedChangePtr change + = arbiter.events.first().staticCast(); + QCOMPARE(change->propertyName(), "events"); + + Qt3DRender::PostEventsToFrontendPtr postedEvents + = change->value().value(); + QVERIFY(postedEvents->events().size() == 2); + + QEvent *receivedEvent1 = postedEvents->events().first(); + QCOMPARE(receivedEvent1->type(), QEvent::KeyPress); + + QEvent *receivedEvent2 = postedEvents->events().at(1); + QCOMPARE(receivedEvent2->type(), QEvent::KeyRelease); + + QKeyEvent *ke1 = static_cast(receivedEvent1); + QKeyEvent *ke2 = static_cast(receivedEvent2); + QCOMPARE(ke1->key(), 48); + QCOMPARE(ke1->modifiers(), 0); + QCOMPARE(ke2->key(), 48); + QCOMPARE(ke2->modifiers(), 0); + + arbiter.events.clear(); + } + } }; QTEST_MAIN(tst_EventForward) diff --git a/tests/auto/render/qeventforward/tst_qeventforward.cpp b/tests/auto/render/qeventforward/tst_qeventforward.cpp index aa525d4a2..eeca5b3ea 100644 --- a/tests/auto/render/qeventforward/tst_qeventforward.cpp +++ b/tests/auto/render/qeventforward/tst_qeventforward.cpp @@ -29,14 +29,73 @@ #include #include #include -#include +#include #include #include #include -#include +#include +#include #include #include "testpostmanarbiter.h" + +class EventReceiver : public QObject +{ +public: + EventReceiver() + : QObject() + { + + } + + ~EventReceiver() + { + + } + + int eventCount() + { + return m_events.size(); + } + + QEvent *eventAt(int index) const + { + return m_events.at(index); + } + bool event(QEvent *event) Q_DECL_OVERRIDE + { + m_events.push_back(event); + return true; + } + + void clearEvents() + { + m_events.clear(); + } + +private: + QVector m_events; +}; + +class TestEventForward : public Qt3DRender::QEventForward +{ + Q_OBJECT +public: + TestEventForward(Qt3DCore::QNode *parent = nullptr) + : Qt3DRender::QEventForward(parent) + {} + + void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) Q_DECL_FINAL + { + Qt3DRender::QEventForward::sceneChangeEvent(change); + } + +private: + friend class tst_QEventForward; + +}; + + class tst_QEventForward : public QObject { Q_OBJECT @@ -452,9 +511,72 @@ private Q_SLOTS: // THEN QCOMPARE(arbiter.events.size(), 0); } - } + void checkReceiveEvents() + { + EventReceiver receiver; + TestEventForward eventForward; + eventForward.setTarget(&receiver); + eventForward.setForwardKeyboardEvents(true); + eventForward.setForwardMouseEvents(true); + + { + // WHEN + const QPointF local = QPointF(); + QMouseEvent* mouseEvent + = new QMouseEvent(QEvent::MouseButtonPress, local, local, local, + Qt::LeftButton,0,0, Qt::MouseEventSynthesizedByApplication); + Qt3DRender::PostEventsToFrontendPtr events + = Qt3DRender::PostEventsToFrontendPtr::create(mouseEvent); + + auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId()); + e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll); + e->setPropertyName("events"); + e->setValue(QVariant::fromValue(events)); + + eventForward.sceneChangeEvent(e); + + // THEN + QVERIFY(receiver.eventCount() == 1); + QEvent *event = receiver.eventAt(0); + QCOMPARE(event->type(), QEvent::MouseButtonPress); + + QMouseEvent *me = static_cast(receiver.eventAt(0)); + QCOMPARE(me->localPos(), local); + QCOMPARE(me->button(), Qt::LeftButton); + + receiver.clearEvents(); + } + + { + // WHEN + QKeyEvent *event1 = new QKeyEvent(QEvent::KeyPress, 48, 0); + QKeyEvent *event2 = new QKeyEvent(QEvent::KeyRelease, 48, 0); + QVector eventList; + eventList.push_back(event1); + eventList.push_back(event2); + Qt3DRender::PostEventsToFrontendPtr events + = Qt3DRender::PostEventsToFrontendPtr::create(eventList); + + auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId()); + e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll); + e->setPropertyName("events"); + e->setValue(QVariant::fromValue(events)); + + eventForward.sceneChangeEvent(e); + + // THEN + QVERIFY(receiver.eventCount() == 2); + QEvent *event = receiver.eventAt(0); + QCOMPARE(event->type(), QEvent::KeyPress); + QCOMPARE(static_cast(event)->key(), 48); + + event = receiver.eventAt(1); + QCOMPARE(event->type(), QEvent::KeyRelease); + QCOMPARE(static_cast(event)->key(), 48); + } + } }; QTEST_MAIN(tst_QEventForward) -- cgit v1.2.3 From 0888e3db4d390406a434036a5cf06ef662c40b10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Tue, 17 Jan 2017 17:40:43 +0200 Subject: Change renderOnce to RenderPolicy enum Change-Id: Ie37085ec884034c0f080c782ec44505f046c50bd Reviewed-by: Sean Harmer --- src/quick3d/quick3drender/scene2d/qscene2d.cpp | 40 +++++++++++++------------ src/quick3d/quick3drender/scene2d/qscene2d.h | 15 +++++++--- src/quick3d/quick3drender/scene2d/qscene2d_p.h | 4 +-- src/quick3d/quick3drender/scene2d/scene2d.cpp | 14 ++++----- src/quick3d/quick3drender/scene2d/scene2d_p.h | 3 +- tests/manual/render-qml-to-texture-qml/main.qml | 1 - tests/manual/render-qml-to-texture/main.cpp | 1 - 7 files changed, 43 insertions(+), 35 deletions(-) diff --git a/src/quick3d/quick3drender/scene2d/qscene2d.cpp b/src/quick3d/quick3drender/scene2d/qscene2d.cpp index f83cd3e4f..fa46cd3d2 100644 --- a/src/quick3d/quick3drender/scene2d/qscene2d.cpp +++ b/src/quick3d/quick3drender/scene2d/qscene2d.cpp @@ -72,9 +72,17 @@ namespace Quick { \ingroup \instantiates Qt3DRender::QScene2D \brief Scene2D - * */ +/*! + \enum QScene2D::RenderPolicy + + This enum type describes types of render policies available. + \value Continuous The Scene2D is rendering continuously. This is the default render policy. + \value SingleShot The Scene2D renders to the texture only once after which the resources + allocated for rendering are released. +*/ + /*! \qmlproperty RenderTargetOutput Qt3D.Render::Scene2D::output Holds the RenderTargetOutput, which specifies where the Scene2D is rendering to. @@ -86,10 +94,8 @@ namespace Quick { */ /*! - \qmlproperty bool Qt3D.Render::Scene2D::renderOnce - Holds whether the first rendered image to the texture is also the last, after which the - renderer releases resources needed for the rendering and the rendering is no longer possible - with this Scene2D object. + \qmlproperty enumeration Qt3D.Render::Scene2D::renderPolicy + Holds the render policy of this Scene2D. */ /*! @@ -232,7 +238,7 @@ Scene2DManager::Scene2DManager(QScene2DPrivate *priv) , m_initialized(false) , m_renderSyncRequested(false) , m_sharedObject(new Scene2DSharedObject(this)) - , m_renderOnce(false) + , m_renderPolicy(QScene2D::Continuous) , m_backendInitialized(false) , m_noSourceMode(false) , m_item(nullptr) @@ -607,26 +613,22 @@ void QScene2D::setItem(QQuickItem *item) } /*! - \property QScene2D::renderOnce - \brief Property to specify if the texture will be rendered only once. + \property QScene2D::renderPolicy - This property specifies that the texture will be rendered only one time. - Once the rendering has been done, resources reserved for rendering will be - released and the QScene2D will become unusable. - If set to false, which is the default, the rendering is continuous. + Holds the render policy of this Scene2D. */ -bool QScene2D::renderOnce() const +QScene2D::RenderPolicy QScene2D::renderPolicy() const { Q_D(const QScene2D); - return d->m_renderManager->m_renderOnce; + return d->m_renderManager->m_renderPolicy; } -void QScene2D::setRenderOnce(bool once) +void QScene2D::setRenderPolicy(QScene2D::RenderPolicy renderPolicy) { Q_D(const QScene2D); - if (d->m_renderManager->m_renderOnce != once) { - d->m_renderManager->m_renderOnce = once; - emit renderOnceChanged(once); + if (d->m_renderManager->m_renderPolicy != renderPolicy) { + d->m_renderManager->m_renderPolicy = renderPolicy; + emit renderPolicyChanged(renderPolicy); } } @@ -659,7 +661,7 @@ Qt3DCore::QNodeCreatedChangeBasePtr QScene2D::createNodeCreationChange() const auto creationChange = Qt3DCore::QNodeCreatedChangePtr::create(this); auto &data = creationChange->data; Q_D(const QScene2D); - data.renderOnce = d->m_renderManager->m_renderOnce; + data.renderPolicy = d->m_renderManager->m_renderPolicy; data.sharedObject = d->m_renderManager->m_sharedObject; data.output = d->m_output ? d->m_output->id() : Qt3DCore::QNodeId(); return creationChange; diff --git a/src/quick3d/quick3drender/scene2d/qscene2d.h b/src/quick3d/quick3drender/scene2d/qscene2d.h index 77ad6ea86..0a7e943d6 100644 --- a/src/quick3d/quick3drender/scene2d/qscene2d.h +++ b/src/quick3d/quick3drender/scene2d/qscene2d.h @@ -61,13 +61,20 @@ class QT3DQUICKRENDERSHARED_EXPORT QScene2D : public Qt3DCore::QNode Q_PROPERTY(Qt3DRender::QRenderTargetOutput *output READ output WRITE setOutput NOTIFY outputChanged) Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged) - Q_PROPERTY(bool renderOnce READ renderOnce WRITE setRenderOnce NOTIFY renderOnceChanged) + Q_PROPERTY(QScene2D::RenderPolicy renderPolicy READ renderPolicy WRITE setRenderPolicy NOTIFY renderPolicyChanged) Q_PROPERTY(bool loaded READ loaded NOTIFY loadedChanged) Q_PROPERTY(QQuickItem *item READ item WRITE setItem NOTIFY itemChanged) Q_CLASSINFO("DefaultProperty", "item") public: + + enum RenderPolicy { + Continuous, + SingleShot + }; + Q_ENUM(RenderPolicy) + explicit QScene2D(Qt3DCore::QNode *parent = nullptr); QScene2D(QQmlEngine *engine, Qt3DCore::QNode *parent = nullptr); ~QScene2D(); @@ -75,7 +82,7 @@ public: Qt3DRender::QRenderTargetOutput *output() const; QUrl source() const; bool loaded() const; - bool renderOnce() const; + QScene2D::RenderPolicy renderPolicy() const; QQuickItem *item() const; QQmlEngine *engine() const; bool event(QEvent *event) Q_DECL_OVERRIDE; @@ -83,14 +90,14 @@ public: public Q_SLOTS: void setOutput(Qt3DRender::QRenderTargetOutput *output); void setSource(const QUrl &url); - void setRenderOnce(bool once); + void setRenderPolicy(QScene2D::RenderPolicy policy); void setItem(QQuickItem *item); Q_SIGNALS: void outputChanged(Qt3DRender::QRenderTargetOutput *output); void sourceChanged(const QUrl &url); void loadedChanged(bool loaded); - void renderOnceChanged(bool once); + void renderPolicyChanged(QScene2D::RenderPolicy policy); void itemChanged(QQuickItem *item); protected: diff --git a/src/quick3d/quick3drender/scene2d/qscene2d_p.h b/src/quick3d/quick3drender/scene2d/qscene2d_p.h index 95f32f7c9..34b54b231 100644 --- a/src/quick3d/quick3drender/scene2d/qscene2d_p.h +++ b/src/quick3d/quick3drender/scene2d/qscene2d_p.h @@ -156,7 +156,7 @@ public: struct QScene2DData { - bool renderOnce; + QScene2D::RenderPolicy renderPolicy; Scene2DSharedObjectPtr sharedObject; Qt3DCore::QNodeId output; }; @@ -179,11 +179,11 @@ public: QUrl m_source; Qt3DCore::QNodeId m_id; QMetaObject::Connection m_connection; + QScene2D::RenderPolicy m_renderPolicy; bool m_requested; bool m_initialized; bool m_renderSyncRequested; - bool m_renderOnce; bool m_backendInitialized; bool m_noSourceMode; bool m_ownEngine; diff --git a/src/quick3d/quick3drender/scene2d/scene2d.cpp b/src/quick3d/quick3drender/scene2d/scene2d.cpp index 35c791000..227829f3e 100644 --- a/src/quick3d/quick3drender/scene2d/scene2d.cpp +++ b/src/quick3d/quick3drender/scene2d/scene2d.cpp @@ -109,7 +109,7 @@ Scene2D::Scene2D() , m_renderThread(nullptr) , m_initialized(false) , m_renderInitialized(false) - , m_renderOnce(false) + , m_renderPolicy(Qt3DRender::Quick::QScene2D::Continuous) , m_fbo(0) , m_rbo(0) { @@ -160,7 +160,7 @@ void Scene2D::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &chan { const auto typedChange = qSharedPointerCast>(change); const auto &data = typedChange->data; - m_renderOnce = data.renderOnce; + m_renderPolicy = data.renderPolicy; setSharedObject(data.sharedObject); setOutput(data.output); m_shareContext = renderer()->shareContext(); @@ -171,9 +171,9 @@ void Scene2D::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) if (e->type() == Qt3DCore::PropertyUpdated) { Qt3DCore::QPropertyUpdatedChangePtr propertyChange = qSharedPointerCast(e); - if (propertyChange->propertyName() == QByteArrayLiteral("renderOnce")) - m_renderOnce = propertyChange->value().toBool(); - else if (propertyChange->propertyName() == QByteArrayLiteral("output")) { + if (propertyChange->propertyName() == QByteArrayLiteral("renderPolicy")) { + m_renderPolicy = propertyChange->value().value(); + } else if (propertyChange->propertyName() == QByteArrayLiteral("output")) { Qt3DCore::QNodeId outputId = propertyChange->value().value(); setOutput(outputId); } else if (propertyChange->propertyName() == QByteArrayLiteral("sharedObject")) { @@ -299,7 +299,7 @@ void Scene2D::render() m_sharedObject->m_quickWindow->setRenderTarget(m_fbo, m_textureSize); // Call disallow rendering while mutex is locked - if (m_renderOnce) + if (m_renderPolicy == QScene2D::SingleShot) m_sharedObject->disallowRender(); // Sync @@ -314,7 +314,7 @@ void Scene2D::render() m_sharedObject->m_renderControl->render(); // Tell main thread we are done so it can begin cleanup if this is final frame - if (m_renderOnce) + if (m_renderPolicy == QScene2D::SingleShot) QCoreApplication::postEvent(m_sharedObject->m_renderManager, new QEvent(RENDERED)); m_sharedObject->m_quickWindow->resetOpenGLState(); diff --git a/src/quick3d/quick3drender/scene2d/scene2d_p.h b/src/quick3d/quick3drender/scene2d/scene2d_p.h index fdb4ff1d2..3a8ccf531 100644 --- a/src/quick3d/quick3drender/scene2d/scene2d_p.h +++ b/src/quick3d/quick3drender/scene2d/scene2d_p.h @@ -49,6 +49,7 @@ // #include +#include #include #include @@ -114,7 +115,7 @@ public: bool m_initialized; bool m_renderInitialized; - bool m_renderOnce; + Qt3DRender::Quick::QScene2D::RenderPolicy m_renderPolicy; }; } // Quick diff --git a/tests/manual/render-qml-to-texture-qml/main.qml b/tests/manual/render-qml-to-texture-qml/main.qml index 23ff823e1..32c919af7 100644 --- a/tests/manual/render-qml-to-texture-qml/main.qml +++ b/tests/manual/render-qml-to-texture-qml/main.qml @@ -71,7 +71,6 @@ QQ2.Item { Scene2D { id: qmlTexture - renderOnce: false output: RenderTargetOutput { attachmentPoint: RenderTargetOutput.Color0 texture: Texture2D { diff --git a/tests/manual/render-qml-to-texture/main.cpp b/tests/manual/render-qml-to-texture/main.cpp index 609da2ebe..79c0dbca2 100644 --- a/tests/manual/render-qml-to-texture/main.cpp +++ b/tests/manual/render-qml-to-texture/main.cpp @@ -103,7 +103,6 @@ int main(int argc, char *argv[]) qmlTextureRenderer->setOutput(output); qmlTextureRenderer->setSource(QUrl(QStringLiteral("qrc:/OffscreenGui.qml"))); -// qmlTextureRenderer->setRenderOnce(true); Qt3DCore::QEntity* planeEntity = new Qt3DCore::QEntity(sceneRoot); Qt3DExtras::QPlaneMesh* planeMesh = new Qt3DExtras::QPlaneMesh(planeEntity); -- cgit v1.2.3 From d5c5a12cf45d9b0e72f9cfe78223813485b929ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Fri, 13 Jan 2017 14:40:34 +0200 Subject: Fix qml registration version Change-Id: Id1943002a0acd255b3175670851e8cac218f4cdc Reviewed-by: Sean Harmer --- src/quick3d/imports/render/qt3dquick3drenderplugin.cpp | 2 +- tests/manual/video-texture-qml/main.qml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/quick3d/imports/render/qt3dquick3drenderplugin.cpp b/src/quick3d/imports/render/qt3dquick3drenderplugin.cpp index a5a6df040..8ac9bdb0a 100644 --- a/src/quick3d/imports/render/qt3dquick3drenderplugin.cpp +++ b/src/quick3d/imports/render/qt3dquick3drenderplugin.cpp @@ -266,7 +266,7 @@ void Qt3DQuick3DRenderPlugin::registerTypes(const char *uri) qmlRegisterType(uri, 2, 0, "StencilMask"); // Scene2D - Qt3DRender::Quick::registerType("QScene2D", "Qt3D.Render/Scene2D", uri, 2, 0, "Scene2D"); + Qt3DRender::Quick::registerType("QScene2D", "Qt3D.Render/Scene2D", uri, 2, 2, "Scene2D"); } QT_END_NAMESPACE diff --git a/tests/manual/video-texture-qml/main.qml b/tests/manual/video-texture-qml/main.qml index c7d0b47ec..55b2329eb 100644 --- a/tests/manual/video-texture-qml/main.qml +++ b/tests/manual/video-texture-qml/main.qml @@ -35,7 +35,7 @@ ****************************************************************************/ import Qt3D.Core 2.0 -import Qt3D.Render 2.0 +import Qt3D.Render 2.2 import Qt3D.Input 2.0 import QtQuick 2.2 as QQ2 import QtQuick.Window 2.0 as QW2 -- cgit v1.2.3 From 2f44f4ecb3b0c9eb3f00c9a08e30ba7dd11785ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Mon, 14 Nov 2016 11:33:14 +0200 Subject: Rename and update qrenderqmltotexture unit tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Ib80c7ade344a83c2ee900f87f69a8f7c4bf8cc2e Reviewed-by: Tomi Korpipää Reviewed-by: Sean Harmer --- .../qrenderqmltotexture/qrenderqmltotexture.pro | 11 - .../tst_qrenderqmltotexture.cpp | 284 ------------------ tests/auto/render/qscene2d/qscene2d.pro | 12 + tests/auto/render/qscene2d/tst_qscene2d.cpp | 316 +++++++++++++++++++++ tests/auto/render/render.pro | 3 +- 5 files changed, 330 insertions(+), 296 deletions(-) delete mode 100644 tests/auto/render/qrenderqmltotexture/qrenderqmltotexture.pro delete mode 100644 tests/auto/render/qrenderqmltotexture/tst_qrenderqmltotexture.cpp create mode 100644 tests/auto/render/qscene2d/qscene2d.pro create mode 100644 tests/auto/render/qscene2d/tst_qscene2d.cpp diff --git a/tests/auto/render/qrenderqmltotexture/qrenderqmltotexture.pro b/tests/auto/render/qrenderqmltotexture/qrenderqmltotexture.pro deleted file mode 100644 index 8b2840929..000000000 --- a/tests/auto/render/qrenderqmltotexture/qrenderqmltotexture.pro +++ /dev/null @@ -1,11 +0,0 @@ -TEMPLATE = app - -TARGET = qrenderqmltotexture - -QT += 3dcore 3dcore-private 3drender 3drender-private testlib - -CONFIG += testcase - -SOURCES += tst_qrenderqmltotexture.cpp - -include(../commons/commons.pri) diff --git a/tests/auto/render/qrenderqmltotexture/tst_qrenderqmltotexture.cpp b/tests/auto/render/qrenderqmltotexture/tst_qrenderqmltotexture.cpp deleted file mode 100644 index b337306be..000000000 --- a/tests/auto/render/qrenderqmltotexture/tst_qrenderqmltotexture.cpp +++ /dev/null @@ -1,284 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt3D module of the Qt Toolkit. -** -** $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 -#include -#include -#include -#include -#include -#include -#include -#include -#include "testpostmanarbiter.h" - -class tst_QRenderQmlToTexture : public QObject -{ - Q_OBJECT - -private Q_SLOTS: - - void checkDefaultConstruction() - { - // GIVEN - Qt3DRender::QRenderQmlToTexture renderQmlToTexture; - - // THEN - QCOMPARE(renderQmlToTexture.texture(), nullptr); - QCOMPARE(renderQmlToTexture.source(), QUrl(QStringLiteral(""))); - QCOMPARE(renderQmlToTexture.renderOnce(), false); - QCOMPARE(renderQmlToTexture.loaded(), false); - } - - void checkPropertyChanges() - { - // GIVEN - Qt3DRender::QRenderQmlToTexture renderQmlToTexture; - QScopedPointer texture(new Qt3DRender::QTexture2D()); - - { - // WHEN - QSignalSpy spy(&renderQmlToTexture, SIGNAL(textureChanged(Qt3DRender::QAbstractTexture *))); - Qt3DRender::QAbstractTexture * newValue = texture.data(); - renderQmlToTexture.setTexture(newValue); - - // THEN - QVERIFY(spy.isValid()); - QCOMPARE(renderQmlToTexture.texture(), newValue); - QCOMPARE(spy.count(), 1); - - // WHEN - spy.clear(); - renderQmlToTexture.setTexture(newValue); - - // THEN - QCOMPARE(renderQmlToTexture.texture(), newValue); - QCOMPARE(spy.count(), 0); - } - { - // WHEN - QSignalSpy spy(&renderQmlToTexture, SIGNAL(sourceChanged(QUrl))); - const QUrl newValue = QUrl(QStringLiteral("qrc://source.qml")); - renderQmlToTexture.setSource(newValue); - - // THEN - QVERIFY(spy.isValid()); - QCOMPARE(renderQmlToTexture.source(), newValue); - QCOMPARE(spy.count(), 1); - - // WHEN - spy.clear(); - renderQmlToTexture.setSource(newValue); - - // THEN - QCOMPARE(renderQmlToTexture.source(), newValue); - QCOMPARE(spy.count(), 0); - } - { - // WHEN - QSignalSpy spy(&renderQmlToTexture, SIGNAL(renderOnceChanged(bool))); - const bool newValue = true; - renderQmlToTexture.setRenderOnce(newValue); - - // THEN - QVERIFY(spy.isValid()); - QCOMPARE(renderQmlToTexture.renderOnce(), newValue); - QCOMPARE(spy.count(), 1); - - // WHEN - spy.clear(); - renderQmlToTexture.setRenderOnce(newValue); - - // THEN - QCOMPARE(renderQmlToTexture.renderOnce(), newValue); - QCOMPARE(spy.count(), 0); - } - } - - void checkCreationData() - { - // GIVEN - Qt3DRender::QRenderQmlToTexture renderQmlToTexture; - QScopedPointer texture(new Qt3DRender::QTexture2D()); - - renderQmlToTexture.setTexture(texture.data()); - renderQmlToTexture.setSource(QUrl(QStringLiteral("qrc://source.qml"))); - renderQmlToTexture.setRenderOnce(true); - - // WHEN - QVector creationChanges; - - { - Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&renderQmlToTexture); - creationChanges = creationChangeGenerator.creationChanges(); - } - - // THEN - { - QCOMPARE(creationChanges.size(), 1); - - const auto creationChangeData = qSharedPointerCast>(creationChanges.first()); - const Qt3DRender::QRenderQmlToTextureData cloneData = creationChangeData->data; - - QCOMPARE(renderQmlToTexture.texture()->id(), cloneData.textureId); - QCOMPARE(renderQmlToTexture.renderOnce(), cloneData.renderOnce); - QCOMPARE(renderQmlToTexture.id(), creationChangeData->subjectId()); - QCOMPARE(renderQmlToTexture.isEnabled(), true); - QCOMPARE(renderQmlToTexture.isEnabled(), creationChangeData->isNodeEnabled()); - QCOMPARE(renderQmlToTexture.metaObject(), creationChangeData->metaObject()); - } - - // WHEN - renderQmlToTexture.setEnabled(false); - - { - Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&renderQmlToTexture); - creationChanges = creationChangeGenerator.creationChanges(); - } - - // THEN - { - QCOMPARE(creationChanges.size(), 1); - - const auto creationChangeData = qSharedPointerCast>(creationChanges.first()); - const Qt3DRender::QRenderQmlToTextureData cloneData = creationChangeData->data; - - QCOMPARE(renderQmlToTexture.texture()->id(), cloneData.textureId); - QCOMPARE(renderQmlToTexture.renderOnce(), cloneData.renderOnce); - QCOMPARE(renderQmlToTexture.id(), creationChangeData->subjectId()); - QCOMPARE(renderQmlToTexture.isEnabled(), false); - QCOMPARE(renderQmlToTexture.isEnabled(), creationChangeData->isNodeEnabled()); - QCOMPARE(renderQmlToTexture.metaObject(), creationChangeData->metaObject()); - } - } - - void checkTextureUpdate() - { - // GIVEN - TestArbiter arbiter; - Qt3DRender::QRenderQmlToTexture renderQmlToTexture; - arbiter.setArbiterOnNode(&renderQmlToTexture); - QScopedPointer texture(new Qt3DRender::QTexture2D()); - - { - // WHEN - renderQmlToTexture.setTexture(texture.data()); - QCoreApplication::processEvents(); - - // THEN - QCOMPARE(arbiter.events.size(), 1); - auto change = arbiter.events.first().staticCast(); - QCOMPARE(change->propertyName(), "texture"); - QCOMPARE(change->value().value(), renderQmlToTexture.texture()); - QCOMPARE(change->type(), Qt3DCore::PropertyUpdated); - - arbiter.events.clear(); - } - - { - // WHEN - renderQmlToTexture.setTexture(texture.data()); - QCoreApplication::processEvents(); - - // THEN - QCOMPARE(arbiter.events.size(), 0); - } - - } - - void checkSourceUpdate() - { - // GIVEN - TestArbiter arbiter; - Qt3DRender::QRenderQmlToTexture renderQmlToTexture; - arbiter.setArbiterOnNode(&renderQmlToTexture); - - { - // WHEN - renderQmlToTexture.setSource(QUrl(QStringLiteral("qrc://source.qml"))); - QCoreApplication::processEvents(); - - // THEN - QCOMPARE(arbiter.events.size(), 1); - auto change = arbiter.events.first().staticCast(); - QCOMPARE(change->propertyName(), "source"); - QCOMPARE(change->value().value(), renderQmlToTexture.source()); - QCOMPARE(change->type(), Qt3DCore::PropertyUpdated); - - arbiter.events.clear(); - } - - { - // WHEN - renderQmlToTexture.setSource(QUrl(QStringLiteral("qrc://source.qml"))); - QCoreApplication::processEvents(); - - // THEN - QCOMPARE(arbiter.events.size(), 0); - } - - } - - void checkRenderOnceUpdate() - { - // GIVEN - TestArbiter arbiter; - Qt3DRender::QRenderQmlToTexture renderQmlToTexture; - arbiter.setArbiterOnNode(&renderQmlToTexture); - - { - // WHEN - renderQmlToTexture.setRenderOnce(true); - QCoreApplication::processEvents(); - - // THEN - QCOMPARE(arbiter.events.size(), 1); - auto change = arbiter.events.first().staticCast(); - QCOMPARE(change->propertyName(), "renderOnce"); - QCOMPARE(change->value().value(), renderQmlToTexture.renderOnce()); - QCOMPARE(change->type(), Qt3DCore::PropertyUpdated); - - arbiter.events.clear(); - } - - { - // WHEN - renderQmlToTexture.setRenderOnce(true); - QCoreApplication::processEvents(); - - // THEN - QCOMPARE(arbiter.events.size(), 0); - } - - } - -}; - -QTEST_MAIN(tst_QRenderQmlToTexture) - -#include "tst_qrenderqmltotexture.moc" diff --git a/tests/auto/render/qscene2d/qscene2d.pro b/tests/auto/render/qscene2d/qscene2d.pro new file mode 100644 index 000000000..b7458d1c2 --- /dev/null +++ b/tests/auto/render/qscene2d/qscene2d.pro @@ -0,0 +1,12 @@ +TEMPLATE = app + +TARGET = qscene2d + +QT += 3dcore 3dcore-private 3drender 3drender-private testlib 3dquickrender 3dquickrender-private + +CONFIG += testcase + +SOURCES += tst_qscene2d.cpp + +include(../../core/common/common.pri) +include(../commons/commons.pri) diff --git a/tests/auto/render/qscene2d/tst_qscene2d.cpp b/tests/auto/render/qscene2d/tst_qscene2d.cpp new file mode 100644 index 000000000..8d27945e4 --- /dev/null +++ b/tests/auto/render/qscene2d/tst_qscene2d.cpp @@ -0,0 +1,316 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $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 +#include +#include +#include +#include +#include +#include +#include +#include +#include "testpostmanarbiter.h" + +using namespace Qt3DRender::Quick; + +class tst_QScene2D : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + + void initTestCase() + { + qRegisterMetaType( + "QScene2D::RenderPolicy"); + } + + void checkDefaultConstruction() + { + // GIVEN + Qt3DRender::Quick::QScene2D scene2d; + + // THEN + QCOMPARE(scene2d.output(), nullptr); + QCOMPARE(scene2d.source(), QUrl(QStringLiteral(""))); + QCOMPARE(scene2d.renderPolicy(), QScene2D::Continuous); + QCOMPARE(scene2d.loaded(), false); + QCOMPARE(scene2d.item(), nullptr); + } + + void checkPropertyChanges() + { + // GIVEN + Qt3DRender::Quick::QScene2D scene2d; + QScopedPointer output(new Qt3DRender::QRenderTargetOutput()); + QScopedPointer item(new QQuickItem()); + + { + // WHEN + QSignalSpy spy(&scene2d, SIGNAL(outputChanged(Qt3DRender::QRenderTargetOutput*))); + Qt3DRender::QRenderTargetOutput *newValue = output.data(); + scene2d.setOutput(newValue); + + // THEN + QVERIFY(spy.isValid()); + QCOMPARE(scene2d.output(), newValue); + QCOMPARE(spy.count(), 1); + + // WHEN + spy.clear(); + scene2d.setOutput(newValue); + + // THEN + QCOMPARE(scene2d.output(), newValue); + QCOMPARE(spy.count(), 0); + } + { + // WHEN + QSignalSpy spy(&scene2d, SIGNAL(sourceChanged(QUrl))); + const QUrl newValue = QUrl(QStringLiteral("qrc://source.qml")); + scene2d.setSource(newValue); + + // THEN + QVERIFY(spy.isValid()); + QCOMPARE(scene2d.source(), newValue); + QCOMPARE(spy.count(), 1); + + // WHEN + spy.clear(); + scene2d.setSource(newValue); + + // THEN + QCOMPARE(scene2d.source(), newValue); + QCOMPARE(spy.count(), 0); + } + { + // WHEN + QSignalSpy spy(&scene2d, SIGNAL(renderPolicyChanged(QScene2D::RenderPolicy))); + const QScene2D::RenderPolicy newValue = QScene2D::SingleShot; + scene2d.setRenderPolicy(newValue); + + // THEN + QVERIFY(spy.isValid()); + QCOMPARE(scene2d.renderPolicy(), newValue); + QCOMPARE(spy.count(), 1); + + // WHEN + spy.clear(); + scene2d.setRenderPolicy(newValue); + + // THEN + QCOMPARE(scene2d.renderPolicy(), newValue); + QCOMPARE(spy.count(), 0); + } + { + // WHEN + QSignalSpy spy(&scene2d, SIGNAL(itemChanged(QQuickItem*))); + QQuickItem *newValue = item.data(); + scene2d.setItem(newValue); + + // THEN + QVERIFY(spy.isValid()); + QCOMPARE(scene2d.item(), newValue); + QCOMPARE(spy.count(), 1); + + // WHEN + spy.clear(); + scene2d.setItem(newValue); + + // THEN + QCOMPARE(scene2d.item(), newValue); + QCOMPARE(spy.count(), 0); + } + } + + void checkCreationData() + { + // GIVEN + Qt3DRender::Quick::QScene2D scene2d; + QScopedPointer output(new Qt3DRender::QRenderTargetOutput()); + + scene2d.setOutput(output.data()); + scene2d.setSource(QUrl(QStringLiteral("qrc://source.qml"))); + scene2d.setRenderPolicy(QScene2D::SingleShot); + + // WHEN + QVector creationChanges; + + { + Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&scene2d); + creationChanges = creationChangeGenerator.creationChanges(); + } + + // THEN + { + QCOMPARE(creationChanges.size(), 1); + + const auto creationChangeData = qSharedPointerCast>(creationChanges.first()); + const Qt3DRender::Quick::QScene2DData cloneData = creationChangeData->data; + + QCOMPARE(scene2d.output()->id(), cloneData.output); + QCOMPARE(scene2d.renderPolicy(), cloneData.renderPolicy); + QCOMPARE(scene2d.id(), creationChangeData->subjectId()); + QCOMPARE(scene2d.isEnabled(), true); + QCOMPARE(scene2d.isEnabled(), creationChangeData->isNodeEnabled()); + QCOMPARE(scene2d.metaObject(), creationChangeData->metaObject()); + } + + // WHEN + scene2d.setEnabled(false); + + { + Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&scene2d); + creationChanges = creationChangeGenerator.creationChanges(); + } + + // THEN + { + QCOMPARE(creationChanges.size(), 1); + + const auto creationChangeData = qSharedPointerCast>(creationChanges.first()); + const Qt3DRender::Quick::QScene2DData cloneData = creationChangeData->data; + + QCOMPARE(scene2d.output()->id(), cloneData.output); + QCOMPARE(scene2d.renderPolicy(), cloneData.renderPolicy); + QCOMPARE(scene2d.id(), creationChangeData->subjectId()); + QCOMPARE(scene2d.isEnabled(), false); + QCOMPARE(scene2d.isEnabled(), creationChangeData->isNodeEnabled()); + QCOMPARE(scene2d.metaObject(), creationChangeData->metaObject()); + } + } + + void checkOutputUpdate() + { + // GIVEN + TestArbiter arbiter; + Qt3DRender::Quick::QScene2D scene2d; + arbiter.setArbiterOnNode(&scene2d); + QScopedPointer output(new Qt3DRender::QRenderTargetOutput()); + + { + // WHEN + scene2d.setOutput(output.data()); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 1); + auto change = arbiter.events.first().staticCast(); + QCOMPARE(change->propertyName(), "output"); + QCOMPARE(change->value().value(), scene2d.output()->id()); + QCOMPARE(change->type(), Qt3DCore::PropertyUpdated); + + arbiter.events.clear(); + } + + { + // WHEN + scene2d.setOutput(output.data()); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 0); + } + + } + + void checkSourceUpdate() + { + // GIVEN + TestArbiter arbiter; + Qt3DRender::Quick::QScene2D scene2d; + arbiter.setArbiterOnNode(&scene2d); + + { + // WHEN + scene2d.setSource(QUrl(QStringLiteral("qrc://source.qml"))); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 1); + auto change = arbiter.events.first().staticCast(); + QCOMPARE(change->propertyName(), "source"); + QCOMPARE(change->value().value(), scene2d.source()); + QCOMPARE(change->type(), Qt3DCore::PropertyUpdated); + + arbiter.events.clear(); + } + + { + // WHEN + scene2d.setSource(QUrl(QStringLiteral("qrc://source.qml"))); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 0); + } + + } + + void checkRenderPolicyUpdate() + { + // GIVEN + TestArbiter arbiter; + Qt3DRender::Quick::QScene2D scene2d; + arbiter.setArbiterOnNode(&scene2d); + + { + // WHEN + scene2d.setRenderPolicy(QScene2D::SingleShot); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 1); + auto change = arbiter.events.first().staticCast(); + QCOMPARE(change->propertyName(), "renderPolicy"); + QCOMPARE(change->value().value(), + scene2d.renderPolicy()); + QCOMPARE(change->type(), Qt3DCore::PropertyUpdated); + + arbiter.events.clear(); + } + + { + // WHEN + scene2d.setRenderPolicy(QScene2D::SingleShot); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 0); + } + + } + +}; + +QTEST_MAIN(tst_QScene2D) + +#include "tst_qscene2d.moc" diff --git a/tests/auto/render/render.pro b/tests/auto/render/render.pro index 34c07f7dc..c89299095 100644 --- a/tests/auto/render/render.pro +++ b/tests/auto/render/render.pro @@ -98,7 +98,8 @@ qtConfig(private_tests) { trianglevisitor \ qmemorybarrier \ qeventforward \ - eventforward + eventforward \ + qscene2d !macos: SUBDIRS += graphicshelpergl4 } -- cgit v1.2.3 From 3acea3a81c216c28aa0067e20b7ce5f17b4f5ffd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Mon, 14 Nov 2016 14:09:43 +0200 Subject: Rename and update renderqmltotexture unit tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I461db1324ca068a9f0f1ef2cf2c28bdeb2bee1b3 Reviewed-by: Tomi Korpipää Reviewed-by: Sean Harmer --- tests/auto/render/render.pro | 3 +- .../renderqmltotexture/renderqmltotexture.pro | 12 -- .../renderqmltotexture/tst_renderqmltotexture.cpp | 150 ------------------- tests/auto/render/scene2d/scene2d.pro | 12 ++ tests/auto/render/scene2d/tst_scene2d.cpp | 160 +++++++++++++++++++++ 5 files changed, 174 insertions(+), 163 deletions(-) delete mode 100644 tests/auto/render/renderqmltotexture/renderqmltotexture.pro delete mode 100644 tests/auto/render/renderqmltotexture/tst_renderqmltotexture.cpp create mode 100644 tests/auto/render/scene2d/scene2d.pro create mode 100644 tests/auto/render/scene2d/tst_scene2d.cpp diff --git a/tests/auto/render/render.pro b/tests/auto/render/render.pro index c89299095..e03c07d41 100644 --- a/tests/auto/render/render.pro +++ b/tests/auto/render/render.pro @@ -99,7 +99,8 @@ qtConfig(private_tests) { qmemorybarrier \ qeventforward \ eventforward \ - qscene2d + qscene2d \ + scene2d !macos: SUBDIRS += graphicshelpergl4 } diff --git a/tests/auto/render/renderqmltotexture/renderqmltotexture.pro b/tests/auto/render/renderqmltotexture/renderqmltotexture.pro deleted file mode 100644 index 2c0f56391..000000000 --- a/tests/auto/render/renderqmltotexture/renderqmltotexture.pro +++ /dev/null @@ -1,12 +0,0 @@ -TEMPLATE = app - -TARGET = tst_renderqmltotexture - -QT += 3dcore 3dcore-private 3drender 3drender-private testlib - -CONFIG += testcase - -SOURCES += tst_renderqmltotexture.cpp - -include(../../core/common/common.pri) -include(../commons/commons.pri) diff --git a/tests/auto/render/renderqmltotexture/tst_renderqmltotexture.cpp b/tests/auto/render/renderqmltotexture/tst_renderqmltotexture.cpp deleted file mode 100644 index b6148c514..000000000 --- a/tests/auto/render/renderqmltotexture/tst_renderqmltotexture.cpp +++ /dev/null @@ -1,150 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt3D module of the Qt Toolkit. -** -** $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 -#include -#include -#include -#include -#include -#include "testrenderer.h" - -class tst_RenderQmlToTexture : public Qt3DCore::QBackendNodeTester -{ - Q_OBJECT - -private Q_SLOTS: - - void checkInitialState() - { - // GIVEN - Qt3DRender::Render::RenderQmlToTexture backendRenderQmlToTexture; - - // THEN - QCOMPARE(backendRenderQmlToTexture.isEnabled(), false); - QVERIFY(backendRenderQmlToTexture.peerId().isNull()); - QCOMPARE(backendRenderQmlToTexture.m_context, nullptr); - QCOMPARE(backendRenderQmlToTexture.m_graphicsContext, nullptr); - QCOMPARE(backendRenderQmlToTexture.m_renderThread, nullptr); - QCOMPARE(backendRenderQmlToTexture.m_textureId, Qt3DCore::QNodeId()); - QCOMPARE(backendRenderQmlToTexture.m_texture, nullptr); - QCOMPARE(backendRenderQmlToTexture.m_initialized, false); - QCOMPARE(backendRenderQmlToTexture.m_renderInitialized, false); - QCOMPARE(backendRenderQmlToTexture.m_renderOnce, false); - } - - void checkInitializeFromPeer() - { - // GIVEN - Qt3DRender::QRenderQmlToTexture renderQmlToTexture; - - { - // WHEN - Qt3DRender::Render::RenderQmlToTexture backendRenderQmlToTexture; - simulateInitialization(&renderQmlToTexture, &backendRenderQmlToTexture); - - // THEN - QCOMPARE(backendRenderQmlToTexture.isEnabled(), true); - QCOMPARE(backendRenderQmlToTexture.peerId(), renderQmlToTexture.id()); - QCOMPARE(backendRenderQmlToTexture.m_textureId, Qt3DCore::QNodeId()); - QCOMPARE(backendRenderQmlToTexture.m_sharedObject.data(), nullptr); - QCOMPARE(backendRenderQmlToTexture.m_renderOnce, false); - } - { - // WHEN - Qt3DRender::Render::RenderQmlToTexture backendRenderQmlToTexture; - renderQmlToTexture.setEnabled(false); - simulateInitialization(&renderQmlToTexture, &backendRenderQmlToTexture); - - // THEN - QCOMPARE(backendRenderQmlToTexture.peerId(), renderQmlToTexture.id()); - QCOMPARE(backendRenderQmlToTexture.isEnabled(), false); - } - } - - void checkSceneChangeEvents() - { - // GIVEN - Qt3DRender::Render::RenderQmlToTexture backendRenderQmlToTexture; - TestRenderer renderer; - QScopedPointer texture(new Qt3DRender::QTexture2D()); - backendRenderQmlToTexture.setRenderer(&renderer); - - { - // WHEN - const bool newValue = false; - const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId()); - change->setPropertyName("enabled"); - change->setValue(newValue); - backendRenderQmlToTexture.sceneChangeEvent(change); - - // THEN - QCOMPARE(backendRenderQmlToTexture.isEnabled(), newValue); - } - { - // WHEN - const Qt3DCore::QNodeId newValue = texture.data()->id(); - const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId()); - change->setPropertyName("textureId"); - change->setValue(QVariant::fromValue(newValue)); - backendRenderQmlToTexture.sceneChangeEvent(change); - - // THEN - QCOMPARE(backendRenderQmlToTexture.m_textureId, newValue); - } - { - // WHEN - const QSharedPointer newValue - = QSharedPointer(new Qt3DRender::RenderQmlToTextureSharedObject(nullptr)); - const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId()); - change->setPropertyName("sharedObject"); - change->setValue(QVariant::fromValue(newValue)); - backendRenderQmlToTexture.sceneChangeEvent(change); - - // THEN - QCOMPARE(backendRenderQmlToTexture.m_sharedObject, newValue); - QCOMPARE(backendRenderQmlToTexture.m_sharedObject.data(), newValue.data()); - } - { - // WHEN - const bool newValue = true; - const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId()); - change->setPropertyName("renderOnce"); - change->setValue(QVariant::fromValue(newValue)); - backendRenderQmlToTexture.sceneChangeEvent(change); - - // THEN - QCOMPARE(backendRenderQmlToTexture.m_renderOnce, newValue); - } - } - -}; - -QTEST_MAIN(tst_RenderQmlToTexture) - -#include "tst_renderqmltotexture.moc" diff --git a/tests/auto/render/scene2d/scene2d.pro b/tests/auto/render/scene2d/scene2d.pro new file mode 100644 index 000000000..8685b0b5b --- /dev/null +++ b/tests/auto/render/scene2d/scene2d.pro @@ -0,0 +1,12 @@ +TEMPLATE = app + +TARGET = tst_scene2d + +QT += 3dcore 3dcore-private 3drender 3drender-private testlib 3dquickrender 3dquickrender-private + +CONFIG += testcase + +SOURCES += tst_scene2d.cpp + +include(../../core/common/common.pri) +include(../commons/commons.pri) diff --git a/tests/auto/render/scene2d/tst_scene2d.cpp b/tests/auto/render/scene2d/tst_scene2d.cpp new file mode 100644 index 000000000..f07a35b19 --- /dev/null +++ b/tests/auto/render/scene2d/tst_scene2d.cpp @@ -0,0 +1,160 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $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 +#include +#include +#include +#include +#include +#include "testrenderer.h" + +using namespace Qt3DRender::Quick; +using namespace Qt3DRender::Render::Quick; + +class tst_Scene2D : public Qt3DCore::QBackendNodeTester +{ + Q_OBJECT + +private Q_SLOTS: + + void checkInitialState() + { + // GIVEN + Scene2D backendScene2d; + + // THEN + QCOMPARE(backendScene2d.isEnabled(), false); + QVERIFY(backendScene2d.peerId().isNull()); + QCOMPARE(backendScene2d.m_context, nullptr); + QCOMPARE(backendScene2d.m_shareContext, nullptr); + QCOMPARE(backendScene2d.m_renderThread, nullptr); + QCOMPARE(backendScene2d.m_outputId, Qt3DCore::QNodeId()); + QCOMPARE(backendScene2d.m_initialized, false); + QCOMPARE(backendScene2d.m_renderInitialized, false); + QCOMPARE(backendScene2d.m_renderPolicy, QScene2D::Continuous); + } + + void checkInitializeFromPeer() + { + // GIVEN + Qt3DRender::Quick::QScene2D frontend; + TestRenderer renderer; + + { + // WHEN + QScopedPointer backendScene2d(new Scene2D()); + backendScene2d->setRenderer(&renderer); + simulateInitialization(&frontend, backendScene2d.data()); + + // THEN + QCOMPARE(backendScene2d->isEnabled(), true); + QCOMPARE(backendScene2d->peerId(), frontend.id()); + QCOMPARE(backendScene2d->m_outputId, Qt3DCore::QNodeId()); + QVERIFY(backendScene2d->m_sharedObject.data() != nullptr); + QCOMPARE(backendScene2d->m_renderPolicy, QScene2D::Continuous); + backendScene2d->cleanup(); + } + { + // WHEN + QScopedPointer backendScene2d(new Scene2D()); + frontend.setEnabled(false); + backendScene2d->setRenderer(&renderer); + simulateInitialization(&frontend, backendScene2d.data()); + + // THEN + QCOMPARE(backendScene2d->peerId(), frontend.id()); + QCOMPARE(backendScene2d->isEnabled(), false); + backendScene2d->cleanup(); + } + } + + void checkSceneChangeEvents() + { + // GIVEN + QScopedPointer backendScene2d(new Scene2D()); + TestRenderer renderer; + QScopedPointer output(new Qt3DRender::QRenderTargetOutput()); + backendScene2d->setRenderer(&renderer); + + { + // WHEN + const bool newValue = false; + const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId()); + change->setPropertyName("enabled"); + change->setValue(newValue); + backendScene2d->sceneChangeEvent(change); + + // THEN + QCOMPARE(backendScene2d->isEnabled(), newValue); + } + { + // WHEN + const Qt3DCore::QNodeId newValue = output.data()->id(); + const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId()); + change->setPropertyName("output"); + change->setValue(QVariant::fromValue(newValue)); + backendScene2d->sceneChangeEvent(change); + + // THEN + QCOMPARE(backendScene2d->m_outputId, newValue); + } + { + // WHEN + const QSharedPointer newValue + = QSharedPointer( + new Qt3DRender::Quick::Scene2DSharedObject(nullptr)); + const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId()); + change->setPropertyName("sharedObject"); + change->setValue(QVariant::fromValue(newValue)); + backendScene2d->sceneChangeEvent(change); + + // THEN + QCOMPARE(backendScene2d->m_sharedObject, newValue); + QCOMPARE(backendScene2d->m_sharedObject.data(), newValue.data()); + } + { + // WHEN + const QScene2D::RenderPolicy newValue = QScene2D::SingleShot; + const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId()); + change->setPropertyName("renderPolicy"); + change->setValue(QVariant::fromValue(newValue)); + backendScene2d->sceneChangeEvent(change); + + // THEN + QCOMPARE(backendScene2d->m_renderPolicy, newValue); + } + + backendScene2d->cleanup(); + } + +}; + +QTEST_MAIN(tst_Scene2D) + +#include "tst_scene2d.moc" -- cgit v1.2.3 From 2f3cfb7f19911f29e6ea7c0528b26f9263d38121 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Thu, 17 Nov 2016 09:44:15 +0200 Subject: Add unit tests for coordinate reader MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Id2645f3ecf1d36b4b4fbbfd1457f45106ca608ed Reviewed-by: Tomi Korpipää Reviewed-by: Sean Harmer --- .../render/coordinatereader/coordinatereader.pro | 12 + .../coordinatereader/tst_coordinatereader.cpp | 491 +++++++++++++++++++++ tests/auto/render/render.pro | 3 +- 3 files changed, 505 insertions(+), 1 deletion(-) create mode 100644 tests/auto/render/coordinatereader/coordinatereader.pro create mode 100644 tests/auto/render/coordinatereader/tst_coordinatereader.cpp diff --git a/tests/auto/render/coordinatereader/coordinatereader.pro b/tests/auto/render/coordinatereader/coordinatereader.pro new file mode 100644 index 000000000..036898c2b --- /dev/null +++ b/tests/auto/render/coordinatereader/coordinatereader.pro @@ -0,0 +1,12 @@ +TEMPLATE = app + +TARGET = coordinatereader + +QT += 3dcore 3dcore-private 3drender 3drender-private testlib + +CONFIG += testcase + +SOURCES += tst_coordinatereader.cpp + +include(../../core/common/common.pri) +include(../commons/commons.pri) diff --git a/tests/auto/render/coordinatereader/tst_coordinatereader.cpp b/tests/auto/render/coordinatereader/tst_coordinatereader.cpp new file mode 100644 index 000000000..7dfe3ceba --- /dev/null +++ b/tests/auto/render/coordinatereader/tst_coordinatereader.cpp @@ -0,0 +1,491 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "testrenderer.h" + +using namespace Qt3DRender::Render; + +class TestReader : public CoordinateReader +{ +public: + TestReader(NodeManagers *manager) + : CoordinateReader(manager) + { + + } + NodeManagers *manager() const + { + return m_manager; + } + + Attribute *attribute() const + { + return m_attribute; + } + + Buffer *buffer() const + { + return m_buffer; + } + + BufferInfo bufferInfo() const + { + return m_bufferInfo; + } + bool verifyCoordinate(uint index, QVector4D value) + { + return qFuzzyCompare(getCoordinate(index), value); + } +}; + +class tst_CoordinateReader : public Qt3DCore::QBackendNodeTester +{ + Q_OBJECT + +private Q_SLOTS: + + void checkInitialize() + { + // WHEN + QScopedPointer nodeManagers(new NodeManagers()); + TestReader reader(nodeManagers.data()); + + // THEN + QCOMPARE(reader.manager(), nodeManagers.data()); + } + + void checkSetEmptyGeometry() + { + QScopedPointer nodeManagers(new NodeManagers()); + QScopedPointer geometryRenderer( + new Qt3DRender::QGeometryRenderer()); + TestReader reader(nodeManagers.data()); + TestRenderer renderer; + + GeometryRenderer *backendRenderer = nodeManagers->geometryRendererManager() + ->getOrCreateResource(geometryRenderer->id()); + backendRenderer->setRenderer(&renderer); + backendRenderer->setManager(nodeManagers->geometryRendererManager()); + simulateInitialization(geometryRenderer.data(), backendRenderer); + + // WHEN + bool ret = reader.setGeometry(backendRenderer, QString("")); + + // THEN + QCOMPARE(ret, false); + QCOMPARE(reader.attribute(), nullptr); + QCOMPARE(reader.buffer(), nullptr); + } + + void checkSetGeometry() + { + QScopedPointer nodeManagers(new NodeManagers()); + Qt3DRender::QGeometry *geometry = new Qt3DRender::QGeometry(); + QScopedPointer geometryRenderer( + new Qt3DRender::QGeometryRenderer()); + QScopedPointer positionAttribute(new Qt3DRender::QAttribute()); + QScopedPointer dataBuffer(new Qt3DRender::QBuffer()); + TestReader reader(nodeManagers.data()); + TestRenderer renderer; + + QByteArray data; + data.resize(sizeof(float) * 3 * 3 * 2); + float *dataPtr = reinterpret_cast(data.data()); + dataPtr[0] = 0; + dataPtr[1] = 0; + dataPtr[2] = 1.0f; + dataPtr[3] = 1.0f; + dataPtr[4] = 0; + dataPtr[5] = 0; + dataPtr[6] = 0; + dataPtr[7] = 1.0f; + dataPtr[8] = 0; + + dataPtr[9] = 0; + dataPtr[10] = 0; + dataPtr[11] = 1.0f; + dataPtr[12] = 1.0f; + dataPtr[13] = 0; + dataPtr[14] = 0; + dataPtr[15] = 0; + dataPtr[16] = 1.0f; + dataPtr[17] = 0; + dataBuffer->setData(data); + Buffer *backendBuffer = nodeManagers->bufferManager()->getOrCreateResource(dataBuffer->id()); + backendBuffer->setRenderer(&renderer); + backendBuffer->setManager(nodeManagers->bufferManager()); + simulateInitialization(dataBuffer.data(), backendBuffer); + + positionAttribute->setBuffer(dataBuffer.data()); + positionAttribute->setName(Qt3DRender::QAttribute::defaultPositionAttributeName()); + positionAttribute->setVertexBaseType(Qt3DRender::QAttribute::Float); + positionAttribute->setVertexSize(3); + positionAttribute->setCount(6); + positionAttribute->setByteStride(3 * 4); + positionAttribute->setByteOffset(0); + positionAttribute->setAttributeType(Qt3DRender::QAttribute::VertexAttribute); + geometry->addAttribute(positionAttribute.data()); + + geometryRenderer->setGeometry(geometry); + geometryRenderer->setPrimitiveType(Qt3DRender::QGeometryRenderer::Triangles); + + Attribute *backendAttribute = nodeManagers->attributeManager() + ->getOrCreateResource(positionAttribute->id()); + backendAttribute->setRenderer(&renderer); + simulateInitialization(positionAttribute.data(), backendAttribute); + + Geometry *backendGeometry = nodeManagers->geometryManager() + ->getOrCreateResource(geometry->id()); + backendGeometry->setRenderer(&renderer); + simulateInitialization(geometry, backendGeometry); + + GeometryRenderer *backendRenderer = nodeManagers->geometryRendererManager() + ->getOrCreateResource(geometryRenderer->id()); + backendRenderer->setRenderer(&renderer); + backendRenderer->setManager(nodeManagers->geometryRendererManager()); + simulateInitialization(geometryRenderer.data(), backendRenderer); + + // WHEN + bool ret = reader.setGeometry(backendRenderer, + Qt3DRender::QAttribute::defaultPositionAttributeName()); + + // THEN + QCOMPARE(ret, true); + QCOMPARE(reader.attribute(), backendAttribute); + QCOMPARE(reader.buffer(), backendBuffer); + QCOMPARE(reader.bufferInfo().type, Qt3DRender::QAttribute::Float); + QCOMPARE(reader.bufferInfo().dataSize, 3u); + QCOMPARE(reader.bufferInfo().count, 6u); + QCOMPARE(reader.bufferInfo().byteStride, 12u); + QCOMPARE(reader.bufferInfo().byteOffset, 0u); + } + + void testReadCoordinate() + { + QScopedPointer nodeManagers(new NodeManagers()); + Qt3DRender::QGeometry *geometry = new Qt3DRender::QGeometry(); + QScopedPointer geometryRenderer( + new Qt3DRender::QGeometryRenderer()); + QScopedPointer positionAttribute(new Qt3DRender::QAttribute()); + QScopedPointer dataBuffer(new Qt3DRender::QBuffer()); + TestReader reader(nodeManagers.data()); + TestRenderer renderer; + + QByteArray data; + data.resize(sizeof(float) * 3 * 3 * 2); + float *dataPtr = reinterpret_cast(data.data()); + dataPtr[0] = 0; + dataPtr[1] = 0; + dataPtr[2] = 1.0f; + dataPtr[3] = 1.0f; + dataPtr[4] = 0; + dataPtr[5] = 0; + dataPtr[6] = 0; + dataPtr[7] = 1.0f; + dataPtr[8] = 0; + + dataPtr[9] = 0; + dataPtr[10] = 0; + dataPtr[11] = 1.0f; + dataPtr[12] = 1.0f; + dataPtr[13] = 0; + dataPtr[14] = 0; + dataPtr[15] = 0; + dataPtr[16] = 1.0f; + dataPtr[17] = 0; + dataBuffer->setData(data); + Buffer *backendBuffer = nodeManagers->bufferManager()->getOrCreateResource(dataBuffer->id()); + backendBuffer->setRenderer(&renderer); + backendBuffer->setManager(nodeManagers->bufferManager()); + simulateInitialization(dataBuffer.data(), backendBuffer); + + positionAttribute->setBuffer(dataBuffer.data()); + positionAttribute->setName(Qt3DRender::QAttribute::defaultPositionAttributeName()); + positionAttribute->setVertexBaseType(Qt3DRender::QAttribute::Float); + positionAttribute->setVertexSize(3); + positionAttribute->setCount(6); + positionAttribute->setByteStride(3 * 4); + positionAttribute->setByteOffset(0); + positionAttribute->setAttributeType(Qt3DRender::QAttribute::VertexAttribute); + geometry->addAttribute(positionAttribute.data()); + + geometryRenderer->setGeometry(geometry); + geometryRenderer->setPrimitiveType(Qt3DRender::QGeometryRenderer::Triangles); + + Attribute *backendAttribute = nodeManagers->attributeManager() + ->getOrCreateResource(positionAttribute->id()); + backendAttribute->setRenderer(&renderer); + simulateInitialization(positionAttribute.data(), backendAttribute); + + Geometry *backendGeometry = nodeManagers->geometryManager() + ->getOrCreateResource(geometry->id()); + backendGeometry->setRenderer(&renderer); + simulateInitialization(geometry, backendGeometry); + + GeometryRenderer *backendRenderer = nodeManagers->geometryRendererManager() + ->getOrCreateResource(geometryRenderer->id()); + backendRenderer->setRenderer(&renderer); + backendRenderer->setManager(nodeManagers->geometryRendererManager()); + simulateInitialization(geometryRenderer.data(), backendRenderer); + + // WHEN + bool ret = reader.setGeometry(backendRenderer, + Qt3DRender::QAttribute::defaultPositionAttributeName()); + + // THEN + QCOMPARE(ret, true); + + QVERIFY(reader.verifyCoordinate(0, QVector4D(0, 0, 1, 1))); + QVERIFY(reader.verifyCoordinate(1, QVector4D(1, 0, 0, 1))); + QVERIFY(reader.verifyCoordinate(2, QVector4D(0, 1, 0, 1))); + QVERIFY(reader.verifyCoordinate(3, QVector4D(0, 0, 1, 1))); + QVERIFY(reader.verifyCoordinate(4, QVector4D(1, 0, 0, 1))); + QVERIFY(reader.verifyCoordinate(5, QVector4D(0, 1, 0, 1))); + } + + void testReadCoordinateVec4() + { + QScopedPointer nodeManagers(new NodeManagers()); + Qt3DRender::QGeometry *geometry = new Qt3DRender::QGeometry(); + QScopedPointer geometryRenderer( + new Qt3DRender::QGeometryRenderer()); + QScopedPointer positionAttribute(new Qt3DRender::QAttribute()); + QScopedPointer dataBuffer(new Qt3DRender::QBuffer()); + TestReader reader(nodeManagers.data()); + TestRenderer renderer; + + QByteArray data; + data.resize(sizeof(float) * 4 * 3 * 2); + float *dataPtr = reinterpret_cast(data.data()); + dataPtr[0] = 0; + dataPtr[1] = 0; + dataPtr[2] = 1.0f; + dataPtr[3] = 1.0f; + + dataPtr[4] = 1.0f; + dataPtr[5] = 0; + dataPtr[6] = 0; + dataPtr[7] = 1.0f; + + dataPtr[8] = 0; + dataPtr[9] = 1.0f; + dataPtr[10] = 0; + dataPtr[11] = 0; + + dataPtr[12] = 0; + dataPtr[13] = 0; + dataPtr[14] = 1.0f; + dataPtr[15] = 0; + + dataPtr[16] = 1.0f; + dataPtr[17] = 0; + dataPtr[18] = 0; + dataPtr[19] = 0; + + dataPtr[20] = 0; + dataPtr[21] = 1.0f; + dataPtr[22] = 0; + dataPtr[23] = 1.0f; + + dataBuffer->setData(data); + Buffer *backendBuffer = nodeManagers->bufferManager()->getOrCreateResource(dataBuffer->id()); + backendBuffer->setRenderer(&renderer); + backendBuffer->setManager(nodeManagers->bufferManager()); + simulateInitialization(dataBuffer.data(), backendBuffer); + + positionAttribute->setBuffer(dataBuffer.data()); + positionAttribute->setName(Qt3DRender::QAttribute::defaultPositionAttributeName()); + positionAttribute->setVertexBaseType(Qt3DRender::QAttribute::Float); + positionAttribute->setVertexSize(4); + positionAttribute->setCount(6); + positionAttribute->setByteStride(4 * 4); + positionAttribute->setByteOffset(0); + positionAttribute->setAttributeType(Qt3DRender::QAttribute::VertexAttribute); + geometry->addAttribute(positionAttribute.data()); + + geometryRenderer->setGeometry(geometry); + geometryRenderer->setPrimitiveType(Qt3DRender::QGeometryRenderer::Triangles); + + Attribute *backendAttribute = nodeManagers->attributeManager() + ->getOrCreateResource(positionAttribute->id()); + backendAttribute->setRenderer(&renderer); + simulateInitialization(positionAttribute.data(), backendAttribute); + + Geometry *backendGeometry = nodeManagers->geometryManager() + ->getOrCreateResource(geometry->id()); + backendGeometry->setRenderer(&renderer); + simulateInitialization(geometry, backendGeometry); + + GeometryRenderer *backendRenderer = nodeManagers->geometryRendererManager() + ->getOrCreateResource(geometryRenderer->id()); + backendRenderer->setRenderer(&renderer); + backendRenderer->setManager(nodeManagers->geometryRendererManager()); + simulateInitialization(geometryRenderer.data(), backendRenderer); + + // WHEN + bool ret = reader.setGeometry(backendRenderer, + Qt3DRender::QAttribute::defaultPositionAttributeName()); + + // THEN + QCOMPARE(ret, true); + + QVERIFY(reader.verifyCoordinate(0, QVector4D(0, 0, 1, 1))); + QVERIFY(reader.verifyCoordinate(1, QVector4D(1, 0, 0, 1))); + QVERIFY(reader.verifyCoordinate(2, QVector4D(0, 1, 0, 0))); + QVERIFY(reader.verifyCoordinate(3, QVector4D(0, 0, 1, 0))); + QVERIFY(reader.verifyCoordinate(4, QVector4D(1, 0, 0, 0))); + QVERIFY(reader.verifyCoordinate(5, QVector4D(0, 1, 0, 1))); + } + + void testReadCoordinateFromAttribute() + { + QScopedPointer nodeManagers(new NodeManagers()); + Qt3DRender::QGeometry *geometry = new Qt3DRender::QGeometry(); + QScopedPointer geometryRenderer( + new Qt3DRender::QGeometryRenderer()); + QScopedPointer positionAttribute(new Qt3DRender::QAttribute()); + QScopedPointer texcoordAttribute(new Qt3DRender::QAttribute()); + QScopedPointer dataBuffer(new Qt3DRender::QBuffer()); + TestReader reader(nodeManagers.data()); + TestRenderer renderer; + + QByteArray data; + data.resize(sizeof(float) * 3 * 3 * 2); + float *dataPtr = reinterpret_cast(data.data()); + dataPtr[0] = 0; + dataPtr[1] = 0; + dataPtr[2] = 1.0f; + + dataPtr[3] = 1.0f; + dataPtr[4] = 0; + dataPtr[5] = 0; + + dataPtr[6] = 0; + dataPtr[7] = 1.0f; + dataPtr[8] = 0; + + dataPtr[9] = 0; + dataPtr[10] = 0; + dataPtr[11] = 1.0f; + + dataPtr[12] = 1.0f; + dataPtr[13] = 0; + dataPtr[14] = 0; + + dataPtr[15] = 0; + dataPtr[16] = 1.0f; + dataPtr[17] = 0; + + dataBuffer->setData(data); + Buffer *backendBuffer = nodeManagers->bufferManager()->getOrCreateResource(dataBuffer->id()); + backendBuffer->setRenderer(&renderer); + backendBuffer->setManager(nodeManagers->bufferManager()); + simulateInitialization(dataBuffer.data(), backendBuffer); + + positionAttribute->setBuffer(dataBuffer.data()); + positionAttribute->setName(Qt3DRender::QAttribute::defaultPositionAttributeName()); + positionAttribute->setVertexBaseType(Qt3DRender::QAttribute::Float); + positionAttribute->setVertexSize(3); + positionAttribute->setCount(3); + positionAttribute->setByteStride(3 * 4 * 2); + positionAttribute->setByteOffset(0); + positionAttribute->setAttributeType(Qt3DRender::QAttribute::VertexAttribute); + geometry->addAttribute(positionAttribute.data()); + + texcoordAttribute->setBuffer(dataBuffer.data()); + texcoordAttribute->setName(Qt3DRender::QAttribute::defaultTextureCoordinateAttributeName()); + texcoordAttribute->setVertexBaseType(Qt3DRender::QAttribute::Float); + texcoordAttribute->setVertexSize(3); + texcoordAttribute->setCount(6); + texcoordAttribute->setByteStride(3 * 4 * 2); + texcoordAttribute->setByteOffset(3 * 4); + texcoordAttribute->setAttributeType(Qt3DRender::QAttribute::VertexAttribute); + geometry->addAttribute(texcoordAttribute.data()); + + geometryRenderer->setGeometry(geometry); + geometryRenderer->setPrimitiveType(Qt3DRender::QGeometryRenderer::Triangles); + + Attribute *backendAttribute = nodeManagers->attributeManager()->getOrCreateResource( + positionAttribute->id()); + backendAttribute->setRenderer(&renderer); + simulateInitialization(positionAttribute.data(), backendAttribute); + + Attribute *backendTexcoordAttribute = nodeManagers->attributeManager() + ->getOrCreateResource(texcoordAttribute->id()); + backendTexcoordAttribute->setRenderer(&renderer); + simulateInitialization(texcoordAttribute.data(), backendTexcoordAttribute); + + Geometry *backendGeometry = nodeManagers->geometryManager() + ->getOrCreateResource(geometry->id()); + backendGeometry->setRenderer(&renderer); + simulateInitialization(geometry, backendGeometry); + + GeometryRenderer *backendRenderer = nodeManagers->geometryRendererManager() + ->getOrCreateResource(geometryRenderer->id()); + backendRenderer->setRenderer(&renderer); + backendRenderer->setManager(nodeManagers->geometryRendererManager()); + simulateInitialization(geometryRenderer.data(), backendRenderer); + + // WHEN + bool ret = reader.setGeometry(backendRenderer, + Qt3DRender::QAttribute::defaultPositionAttributeName()); + + // THEN + QCOMPARE(ret, true); + + QVERIFY(reader.verifyCoordinate(0, QVector4D(0, 0, 1, 1))); + QVERIFY(reader.verifyCoordinate(1, QVector4D(0, 1, 0, 1))); + QVERIFY(reader.verifyCoordinate(2, QVector4D(1, 0, 0, 1))); + + // WHEN + ret = reader.setGeometry(backendRenderer, + Qt3DRender::QAttribute::defaultTextureCoordinateAttributeName()); + + // THEN + QCOMPARE(ret, true); + + QVERIFY(reader.verifyCoordinate(0, QVector4D(1, 0, 0, 1))); + QVERIFY(reader.verifyCoordinate(1, QVector4D(0, 0, 1, 1))); + QVERIFY(reader.verifyCoordinate(2, QVector4D(0, 1, 0, 1))); + } + +}; + +QTEST_MAIN(tst_CoordinateReader) + +#include "tst_coordinatereader.moc" diff --git a/tests/auto/render/render.pro b/tests/auto/render/render.pro index e03c07d41..abaac7d05 100644 --- a/tests/auto/render/render.pro +++ b/tests/auto/render/render.pro @@ -100,7 +100,8 @@ qtConfig(private_tests) { qeventforward \ eventforward \ qscene2d \ - scene2d + scene2d \ + coordinatereader !macos: SUBDIRS += graphicshelpergl4 } -- cgit v1.2.3 From 946e78eada359f651d337309b25d51d4204289b0 Mon Sep 17 00:00:00 2001 From: Kevin Ottens Date: Tue, 24 Jan 2017 16:41:53 +0100 Subject: Change QTextureLoader defaults We realized that for rich formats the defaults are ignored by QTextureLoader. At the same time for simpler formats the defaults coming from QAbstractTexture are a bit subpar for quality. So change QTextureLoader defaults to be better in that regard to make QTextureLoader a nice way to load a texture from file in one line. Change-Id: Iefe1b07d14f362ef619e4a86d6599370534041ff Reviewed-by: Sean Harmer --- src/render/texture/qtexture.cpp | 15 +++++++++++++++ tests/auto/render/qtextureloader/tst_qtextureloader.cpp | 7 +++++++ 2 files changed, 22 insertions(+) diff --git a/src/render/texture/qtexture.cpp b/src/render/texture/qtexture.cpp index 7dc071833..b5e9a147b 100644 --- a/src/render/texture/qtexture.cpp +++ b/src/render/texture/qtexture.cpp @@ -900,10 +900,25 @@ QTextureBuffer::~QTextureBuffer() /*! * Constructs a new Qt3DRender::QTextureLoader instance with \a parent as parent. + * + * Note that by default, if not contradicted by the file metadata, the loaded texture + * will have the following properties set: + * - wrapMode set to Repeat + * - minificationFilter set to LinearMipMapLinear + * - magnificationFilter set to Linear + * - generateMipMaps set to true + * - maximumAnisotropy set to 16.0f + * - target set to TargetAutomatic */ QTextureLoader::QTextureLoader(QNode *parent) : QAbstractTexture(*new QTextureLoaderPrivate, parent) { + d_func()->m_wrapMode.setX(QTextureWrapMode::Repeat); + d_func()->m_wrapMode.setY(QTextureWrapMode::Repeat); + d_func()->m_minFilter = LinearMipMapLinear; + d_func()->m_magFilter = Linear; + d_func()->m_autoMipMap = true; + d_func()->m_maximumAnisotropy = 16.0f; d_func()->m_target = TargetAutomatic; } diff --git a/tests/auto/render/qtextureloader/tst_qtextureloader.cpp b/tests/auto/render/qtextureloader/tst_qtextureloader.cpp index 252bc85af..56ad55adf 100644 --- a/tests/auto/render/qtextureloader/tst_qtextureloader.cpp +++ b/tests/auto/render/qtextureloader/tst_qtextureloader.cpp @@ -51,6 +51,13 @@ private Q_SLOTS: // THEN QCOMPARE(textureLoader.source(), QUrl()); QCOMPARE(textureLoader.isMirrored(), true); + QCOMPARE(textureLoader.target(), Qt3DRender::QTextureLoader::TargetAutomatic); + QCOMPARE(textureLoader.wrapMode()->x(), Qt3DRender::QTextureWrapMode::Repeat); + QCOMPARE(textureLoader.wrapMode()->y(), Qt3DRender::QTextureWrapMode::Repeat); + QCOMPARE(textureLoader.magnificationFilter(), Qt3DRender::QTextureLoader::Linear); + QCOMPARE(textureLoader.minificationFilter(), Qt3DRender::QTextureLoader::LinearMipMapLinear); + QCOMPARE(textureLoader.generateMipMaps(), true); + QCOMPARE(textureLoader.maximumAnisotropy(), 16.0f); } void checkPropertyChanges() -- cgit v1.2.3 From f5b66ed6706c129754a8fc0c0541eab1f9ed4181 Mon Sep 17 00:00:00 2001 From: Kevin Ottens Date: Wed, 25 Jan 2017 12:10:33 +0100 Subject: Consolidate QML/C++ materials in extras We remove the qml implementation of materials in extras that were also implemented in C++. Note this is an API change for the materials having texture properties. The QML ones had mistakenly a string property instead of a texture one. This move also fixes this API issue on the QML end. Change-Id: Ibed14288cd7b8c5ab9615b74b949c6a73ac29329 Reviewed-by: Sean Harmer --- examples/qt3d/audio-visualizer-qml/Visualizer.qml | 8 +- examples/qt3d/lights/main.qml | 4 +- examples/qt3d/materials/Barrel.qml | 12 +-- examples/qt3d/materials/Chest.qml | 2 +- examples/qt3d/materials/HousePlant.qml | 12 +-- examples/qt3d/materials/main.qml | 6 +- src/quick3d/imports/extras/defaults/defaults.pri | 9 -- .../extras/defaults/qml/DiffuseMapMaterial.qml | 81 --------------- .../defaults/qml/DiffuseSpecularMapMaterial.qml | 93 ----------------- .../imports/extras/defaults/qml/GoochMaterial.qml | 71 ------------- .../defaults/qml/NormalDiffuseMapAlphaMaterial.qml | 92 ----------------- .../defaults/qml/NormalDiffuseMapMaterial.qml | 97 ------------------ .../qml/NormalDiffuseSpecularMapMaterial.qml | 110 --------------------- .../extras/defaults/qml/PerVertexColorMaterial.qml | 53 ---------- .../extras/defaults/qml/PhongAlphaMaterial.qml | 68 ------------- .../imports/extras/defaults/qml/PhongMaterial.qml | 59 ----------- .../imports/extras/qt3dquick3dextrasplugin.cpp | 29 ++++-- 17 files changed, 41 insertions(+), 765 deletions(-) delete mode 100644 src/quick3d/imports/extras/defaults/qml/DiffuseMapMaterial.qml delete mode 100644 src/quick3d/imports/extras/defaults/qml/DiffuseSpecularMapMaterial.qml delete mode 100644 src/quick3d/imports/extras/defaults/qml/GoochMaterial.qml delete mode 100644 src/quick3d/imports/extras/defaults/qml/NormalDiffuseMapAlphaMaterial.qml delete mode 100644 src/quick3d/imports/extras/defaults/qml/NormalDiffuseMapMaterial.qml delete mode 100644 src/quick3d/imports/extras/defaults/qml/NormalDiffuseSpecularMapMaterial.qml delete mode 100644 src/quick3d/imports/extras/defaults/qml/PerVertexColorMaterial.qml delete mode 100644 src/quick3d/imports/extras/defaults/qml/PhongAlphaMaterial.qml delete mode 100644 src/quick3d/imports/extras/defaults/qml/PhongMaterial.qml diff --git a/examples/qt3d/audio-visualizer-qml/Visualizer.qml b/examples/qt3d/audio-visualizer-qml/Visualizer.qml index 562d8c184..ce32dd3ee 100644 --- a/examples/qt3d/audio-visualizer-qml/Visualizer.qml +++ b/examples/qt3d/audio-visualizer-qml/Visualizer.qml @@ -189,8 +189,8 @@ Entity { NormalDiffuseMapAlphaMaterial { id: titlePlaneMaterial - diffuse: "qrc:/images/demotitle.png" - normal: "qrc:/images/normalmap.png" + diffuse: TextureLoader { source: "qrc:/images/demotitle.png" } + normal: TextureLoader { source: "qrc:/images/normalmap.png" } shininess: 1.0 } @@ -215,8 +215,8 @@ Entity { } property Material songPlaneMaterial: NormalDiffuseMapAlphaMaterial { - diffuse: "qrc:/images/songtitle.png" - normal: "qrc:/images/normalmap.png" + diffuse: TextureLoader { source: "qrc:/images/songtitle.png" } + normal: TextureLoader { source: "qrc:/images/normalmap.png" } shininess: 1.0 } diff --git a/examples/qt3d/lights/main.qml b/examples/qt3d/lights/main.qml index 8f1c603cf..69250da13 100644 --- a/examples/qt3d/lights/main.qml +++ b/examples/qt3d/lights/main.qml @@ -183,8 +183,8 @@ Entity material: NormalDiffuseMapMaterial { ambient: Qt.rgba( 0.2, 0.2, 0.2, 1.0 ) - diffuse: "assets/textures/pattern_09/diffuse.webp" - normal: "assets/textures/pattern_09/normal.webp" + diffuse: TextureLoader { source: "assets/textures/pattern_09/diffuse.webp" } + normal: TextureLoader { source: "assets/textures/pattern_09/normal.webp" } textureScale: 10 shininess: 10 } diff --git a/examples/qt3d/materials/Barrel.qml b/examples/qt3d/materials/Barrel.qml index c68cab657..31abd329f 100644 --- a/examples/qt3d/materials/Barrel.qml +++ b/examples/qt3d/materials/Barrel.qml @@ -74,13 +74,11 @@ Entity { material: NormalDiffuseSpecularMapMaterial { id: material ambient: "black" - diffuse: "assets/metalbarrel/diffus_" + root.diffuseColor + ".webp" - normal: "assets/metalbarrel/normal_" + root.bump + ".webp" - specular: { - if (root.specular !== "" ) - return "assets/metalbarrel/specular_" + root.specular + ".webp" - else - return "assets/metalbarrel/specular.webp" + diffuse: TextureLoader { source: "assets/metalbarrel/diffus_" + root.diffuseColor + ".webp" } //TextureLoader { source: ("assets/metalbarrel/diffus_" + root.diffuseColor + ".webp") } + normal: TextureLoader { source: "assets/metalbarrel/normal_" + root.bump + ".webp" } + specular: TextureLoader { + source: root.specular !== "" ? "assets/metalbarrel/specular_" + root.specular + ".webp" + : "assets/metalbarrel/specular.webp" } shininess: 5.0 diff --git a/examples/qt3d/materials/Chest.qml b/examples/qt3d/materials/Chest.qml index 879ebb26f..227e32864 100644 --- a/examples/qt3d/materials/Chest.qml +++ b/examples/qt3d/materials/Chest.qml @@ -68,7 +68,7 @@ Entity { material: DiffuseMapMaterial { id: material - diffuse: "assets/chest/diffuse.webp" + diffuse: TextureLoader { source: "assets/chest/diffuse.webp" } specular: Qt.rgba( 0.2, 0.2, 0.2, 1.0 ) shininess: 2.0 } diff --git a/examples/qt3d/materials/HousePlant.qml b/examples/qt3d/materials/HousePlant.qml index 6505ab171..7ee810d7f 100644 --- a/examples/qt3d/materials/HousePlant.qml +++ b/examples/qt3d/materials/HousePlant.qml @@ -70,8 +70,8 @@ Entity { position: Qt.vector3d(root.x, root.y, root.z) material: NormalDiffuseMapMaterial { - diffuse: "assets/houseplants/pot.webp" - normal: "assets/houseplants/pot_normal.webp" + diffuse: TextureLoader { source: "assets/houseplants/pot.webp" } + normal: TextureLoader { source: "assets/houseplants/pot_normal.webp" } specular: Qt.rgba( 0.75, 0.75, 0.75, 1.0 ) shininess: 5.0 } @@ -79,8 +79,8 @@ Entity { RenderableEntity { source: "assets/houseplants/" + root.potShape + "-" + root.plantType + ".obj" material: NormalDiffuseMapAlphaMaterial { - diffuse: "assets/houseplants/" + root.plantType + ".webp" - normal: "assets/houseplants/" + root.plantType + "_normal.webp" + diffuse: TextureLoader { source: "assets/houseplants/" + root.plantType + ".webp" } + normal: TextureLoader { source: "assets/houseplants/" + root.plantType + "_normal.webp" } shininess: 10.0 } } @@ -88,8 +88,8 @@ Entity { RenderableEntity { source: "assets/houseplants/" + root.potShape + "-pot-cover.obj" material: NormalDiffuseMapMaterial { - diffuse: "assets/houseplants/cover.webp" - normal: "assets/houseplants/cover_normal.webp" + diffuse: TextureLoader { source: "assets/houseplants/cover.webp" } + normal: TextureLoader { source: "assets/houseplants/cover_normal.webp" } specular: Qt.rgba( 0.05, 0.05, 0.05, 1.0 ) shininess: 5.0 } diff --git a/examples/qt3d/materials/main.qml b/examples/qt3d/materials/main.qml index 9ed9bd219..c09454065 100644 --- a/examples/qt3d/materials/main.qml +++ b/examples/qt3d/materials/main.qml @@ -96,9 +96,9 @@ Entity { material: NormalDiffuseSpecularMapMaterial { ambient: Qt.rgba( 0.05, 0.05, 0.05, 1.0 ) - diffuse: "assets/textures/pattern_09/diffuse.webp" - specular: "assets/textures/pattern_09/specular.webp" - normal: "assets/textures/pattern_09/normal.webp" + diffuse: TextureLoader { source: "assets/textures/pattern_09/diffuse.webp" } + specular: TextureLoader { source: "assets/textures/pattern_09/specular.webp" } + normal: TextureLoader { source: "assets/textures/pattern_09/normal.webp" } textureScale: 10.0 shininess: 10.0 } diff --git a/src/quick3d/imports/extras/defaults/defaults.pri b/src/quick3d/imports/extras/defaults/defaults.pri index 98f542fd6..7872837a7 100644 --- a/src/quick3d/imports/extras/defaults/defaults.pri +++ b/src/quick3d/imports/extras/defaults/defaults.pri @@ -8,17 +8,8 @@ QML_FILES = \ $$PWD/qml/DefaultEffect.qml \ $$PWD/qml/DefaultAlphaEffect.qml \ - $$PWD/qml/PhongMaterial.qml \ - $$PWD/qml/DiffuseMapMaterial.qml \ - $$PWD/qml/DiffuseSpecularMapMaterial.qml \ - $$PWD/qml/NormalDiffuseMapMaterial.qml \ - $$PWD/qml/NormalDiffuseMapAlphaMaterial.qml \ - $$PWD/qml/NormalDiffuseSpecularMapMaterial.qml \ $$PWD/qml/ForwardRenderer.qml \ - $$PWD/qml/PerVertexColorMaterial.qml \ $$PWD/qml/SkyboxEntity.qml \ - $$PWD/qml/GoochMaterial.qml \ - $$PWD/qml/PhongAlphaMaterial.qml \ $$PWD/qml/TextureMaterial.qml \ $$PWD/qml/OrbitCameraController.qml \ $$PWD/qml/FirstPersonCameraController.qml \ diff --git a/src/quick3d/imports/extras/defaults/qml/DiffuseMapMaterial.qml b/src/quick3d/imports/extras/defaults/qml/DiffuseMapMaterial.qml deleted file mode 100644 index 4b49d76de..000000000 --- a/src/quick3d/imports/extras/defaults/qml/DiffuseMapMaterial.qml +++ /dev/null @@ -1,81 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt3D module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** 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-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import Qt3D.Core 2.0 -import Qt3D.Render 2.0 - -Material { - id: root - - property color ambient: Qt.rgba( 0.05, 0.05, 0.05, 1.0 ) - property alias diffuse: diffuseTextureImage.source - property color specular: Qt.rgba( 0.01, 0.01, 0.01, 1.0 ) - property real shininess: 150.0 - property real textureScale: 1.0 - - parameters: [ - Parameter { name: "ka"; value: Qt.vector3d(root.ambient.r, root.ambient.g, root.ambient.b) }, - Parameter { - name: "diffuseTexture" - value: Texture2D { - id: diffuseTexture - minificationFilter: Texture.LinearMipMapLinear - magnificationFilter: Texture.Linear - wrapMode { - x: WrapMode.Repeat - y: WrapMode.Repeat - } - generateMipMaps: true - maximumAnisotropy: 16.0 - TextureImage { id: diffuseTextureImage; } - } - }, - Parameter { name: "ks"; value: Qt.vector3d(root.specular.r, root.specular.g, root.specular.b) }, - Parameter { name: "shininess"; value: root.shininess }, - Parameter { name: "texCoordScale"; value: textureScale } - ] - - effect: DefaultEffect { - vertexES: "qrc:/shaders/es2/diffusemap.vert" - fragmentES: "qrc:/shaders/es2/diffusemap.frag" - vertex: "qrc:/shaders/gl3/diffusemap.vert" - fragment: "qrc:/shaders/gl3/diffusemap.frag" - } -} - diff --git a/src/quick3d/imports/extras/defaults/qml/DiffuseSpecularMapMaterial.qml b/src/quick3d/imports/extras/defaults/qml/DiffuseSpecularMapMaterial.qml deleted file mode 100644 index 629cb6d11..000000000 --- a/src/quick3d/imports/extras/defaults/qml/DiffuseSpecularMapMaterial.qml +++ /dev/null @@ -1,93 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt3D module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** 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-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import Qt3D.Core 2.0 -import Qt3D.Render 2.0 - -Material { - id: root - - property color ambient: Qt.rgba( 0.05, 0.05, 0.05, 1.0 ) - property alias diffuse: diffuseTextureImage.source - property alias specular: specularTextureImage.source - property real shininess: 150.0 - property real textureScale: 1.0 - - parameters: [ - Parameter { name: "ka"; value: Qt.vector3d(root.ambient.r, root.ambient.g, root.ambient.b) }, - Parameter { - name: "diffuseTexture" - value: Texture2D { - id: diffuseTexture - minificationFilter: Texture.LinearMipMapLinear - magnificationFilter: Texture.Linear - wrapMode { - x: WrapMode.Repeat - y: WrapMode.Repeat - } - generateMipMaps: true - maximumAnisotropy: 16.0 - TextureImage { id: diffuseTextureImage; } - } - }, - Parameter { name: "specularTexture"; - value: Texture2D { - id: specularTexture - minificationFilter: Texture.LinearMipMapLinear - magnificationFilter: Texture.Linear - wrapMode { - x: WrapMode.Repeat - y: WrapMode.Repeat - } - generateMipMaps: true - maximumAnisotropy: 16.0 - TextureImage { id: specularTextureImage; } - } - }, - Parameter { name: "shininess"; value: root.shininess }, - Parameter { name: "texCoordScale"; value: textureScale } - ] - - effect: DefaultEffect { - vertexES: "qrc:/shaders/es2/diffusemap.vert" - fragmentES: "qrc:/shaders/es2/diffusespecularmap.frag" - vertex: "qrc:/shaders/gl3/diffusemap.vert" - fragment: "qrc:/shaders/gl3/diffusespecularmap.frag" - } -} diff --git a/src/quick3d/imports/extras/defaults/qml/GoochMaterial.qml b/src/quick3d/imports/extras/defaults/qml/GoochMaterial.qml deleted file mode 100644 index fffa2284d..000000000 --- a/src/quick3d/imports/extras/defaults/qml/GoochMaterial.qml +++ /dev/null @@ -1,71 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 Klaralvdalens Datakonsult AB (KDAB). -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt3D module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** 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-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import Qt3D.Core 2.0 -import Qt3D.Render 2.0 - -Material { - id: root - - property color diffuse: Qt.rgba( 0.0, 0.0, 0.0, 1.0 ) - property color specular: Qt.rgba( 0.0, 0.0, 0.0, 1.0 ) - property color coolColor: Qt.rgba( 0.0, 0.0, 0.4, 1.0 ) - property color warmColor: Qt.rgba( 0.4, 0.4, 0.0, 1.0 ) - property real alpha: 0.25 - property real beta: 0.5 - property real shininess: 100.0 - - parameters: [ - Parameter { name: "kd"; value: root.diffuse }, - Parameter { name: "ks"; value: root.specular }, - Parameter { name: "kblue"; value: root.coolColor }, - Parameter { name: "kyellow"; value: root.warmColor }, - Parameter { name: "alpha"; value: root.alpha }, - Parameter { name: "beta"; value: root.beta }, - Parameter { name: "shininess"; value: root.shininess } - ] - - effect: DefaultEffect { - vertexES: "qrc:/shaders/es2/gooch.vert" - fragmentES: "qrc:/shaders/es2/gooch.frag" - vertex: "qrc:/shaders/gl3/gooch.vert" - fragment: "qrc:/shaders/gl3/gooch.frag" - } -} - diff --git a/src/quick3d/imports/extras/defaults/qml/NormalDiffuseMapAlphaMaterial.qml b/src/quick3d/imports/extras/defaults/qml/NormalDiffuseMapAlphaMaterial.qml deleted file mode 100644 index 421cc3aa9..000000000 --- a/src/quick3d/imports/extras/defaults/qml/NormalDiffuseMapAlphaMaterial.qml +++ /dev/null @@ -1,92 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt3D module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** 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-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import Qt3D.Core 2.0 -import Qt3D.Render 2.0 - -Material { - id: root - - property color ambient: Qt.rgba( 0.05, 0.05, 0.05, 1.0 ) - property alias diffuse: diffuseTextureImage.source - property color specular: Qt.rgba( 0.01, 0.01, 0.01, 1.0 ) - property alias normal: normalTextureImage.source - property real shininess: 150.0 - property real textureScale: 1.0 - - parameters: [ - Parameter { name: "ka"; value: Qt.vector3d(root.ambient.r, root.ambient.g, root.ambient.b) }, - Parameter { - name: "diffuseTexture" - value: Texture2D { - id: diffuseTexture - minificationFilter: Texture.LinearMipMapLinear - magnificationFilter: Texture.Linear - wrapMode { - x: WrapMode.Repeat - y: WrapMode.Repeat - } - generateMipMaps: true - maximumAnisotropy: 16.0 - TextureImage { id: diffuseTextureImage; } - } - }, - Parameter { - name: "normalTexture" - value: Texture2D { - id: normalTexture - minificationFilter: Texture.LinearMipMapLinear - magnificationFilter: Texture.Linear - wrapMode { - x: WrapMode.Repeat - y: WrapMode.Repeat - } - generateMipMaps: true - maximumAnisotropy: 16.0 - TextureImage { id: normalTextureImage; } - } - }, - Parameter { name: "ks"; value: Qt.vector3d(root.specular.r, root.specular.g, root.specular.b) }, - Parameter { name: "shininess"; value: root.shininess }, - Parameter { name: "texCoordScale"; value: textureScale } - ] - - effect: NormalDiffuseMapAlphaEffect { } -} - diff --git a/src/quick3d/imports/extras/defaults/qml/NormalDiffuseMapMaterial.qml b/src/quick3d/imports/extras/defaults/qml/NormalDiffuseMapMaterial.qml deleted file mode 100644 index 0724cf597..000000000 --- a/src/quick3d/imports/extras/defaults/qml/NormalDiffuseMapMaterial.qml +++ /dev/null @@ -1,97 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt3D module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** 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-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import Qt3D.Core 2.0 -import Qt3D.Render 2.0 - -Material { - id: root - - property color ambient: Qt.rgba( 0.05, 0.05, 0.05, 1.0 ) - property alias diffuse: diffuseTextureImage.source - property color specular: Qt.rgba( 0.01, 0.01, 0.01, 1.0 ) - property alias normal: normalTextureImage.source - property real shininess: 150.0 - property real textureScale: 1.0 - - parameters: [ - Parameter { name: "ka"; value: Qt.vector3d(root.ambient.r, root.ambient.g, root.ambient.b) }, - Parameter { - name: "diffuseTexture" - value: Texture2D { - id: diffuseTexture - minificationFilter: Texture.LinearMipMapLinear - magnificationFilter: Texture.Linear - wrapMode { - x: WrapMode.Repeat - y: WrapMode.Repeat - } - generateMipMaps: true - maximumAnisotropy: 16.0 - TextureImage { id: diffuseTextureImage; } - } - }, - Parameter { - name: "normalTexture" - value: Texture2D { - id: normalTexture - minificationFilter: Texture.LinearMipMapLinear - magnificationFilter: Texture.Linear - wrapMode { - x: WrapMode.Repeat - y: WrapMode.Repeat - } - generateMipMaps: true - maximumAnisotropy: 16.0 - TextureImage { id: normalTextureImage; } - } - }, - Parameter { name: "ks"; value: Qt.vector3d(root.specular.r, root.specular.g, root.specular.b) }, - Parameter { name: "shininess"; value: root.shininess }, - Parameter { name: "texCoordScale"; value: textureScale } - ] - - effect: DefaultEffect { - vertexES: "qrc:/shaders/es2/normaldiffusemap.vert" - fragmentES: "qrc:/shaders/es2/normaldiffusemap.frag" - vertex: "qrc:/shaders/gl3/normaldiffusemap.vert" - fragment: "qrc:/shaders/gl3/normaldiffusemap.frag" - } -} - diff --git a/src/quick3d/imports/extras/defaults/qml/NormalDiffuseSpecularMapMaterial.qml b/src/quick3d/imports/extras/defaults/qml/NormalDiffuseSpecularMapMaterial.qml deleted file mode 100644 index 497209c32..000000000 --- a/src/quick3d/imports/extras/defaults/qml/NormalDiffuseSpecularMapMaterial.qml +++ /dev/null @@ -1,110 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt3D module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** 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-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import Qt3D.Core 2.0 -import Qt3D.Render 2.0 - -Material { - id: root - - property color ambient: Qt.rgba( 0.05, 0.05, 0.05, 1.0 ) - property alias diffuse: diffuseTextureImage.source - property alias specular: specularTextureImage.source - property alias normal: normalTextureImage.source - property real shininess: 150.0 - property real textureScale: 1.0 - - parameters: [ - Parameter { name: "ka"; value: Qt.vector3d(root.ambient.r, root.ambient.g, root.ambient.b) }, - Parameter { - name: "diffuseTexture" - value: Texture2D { - id: diffuseTexture - minificationFilter: Texture.LinearMipMapLinear - magnificationFilter: Texture.Linear - wrapMode { - x: WrapMode.Repeat - y: WrapMode.Repeat - } - generateMipMaps: true - maximumAnisotropy: 16.0 - TextureImage { id: diffuseTextureImage; } - } - }, - Parameter { name: "specularTexture"; - value: Texture2D { - id: specularTexture - minificationFilter: Texture.LinearMipMapLinear - magnificationFilter: Texture.Linear - wrapMode { - x: WrapMode.Repeat - y: WrapMode.Repeat - } - generateMipMaps: true - maximumAnisotropy: 16.0 - TextureImage { id: specularTextureImage; } - } - }, - Parameter { - name: "normalTexture" - value: Texture2D { - id: normalTexture - minificationFilter: Texture.LinearMipMapLinear - magnificationFilter: Texture.Linear - wrapMode { - x: WrapMode.Repeat - y: WrapMode.Repeat - } - generateMipMaps: true - maximumAnisotropy: 16.0 - TextureImage { id: normalTextureImage; } - } - }, - Parameter { name: "shininess"; value: root.shininess }, - Parameter { name: "texCoordScale"; value: textureScale } - ] - - effect: DefaultEffect { - vertexES: "qrc:/shaders/es2/normaldiffusemap.vert" - fragmentES: "qrc:/shaders/es2/normaldiffusespecularmap.frag" - vertex: "qrc:/shaders/gl3/normaldiffusemap.vert" - fragment: "qrc:/shaders/gl3/normaldiffusespecularmap.frag" - } -} - diff --git a/src/quick3d/imports/extras/defaults/qml/PerVertexColorMaterial.qml b/src/quick3d/imports/extras/defaults/qml/PerVertexColorMaterial.qml deleted file mode 100644 index 70c461edd..000000000 --- a/src/quick3d/imports/extras/defaults/qml/PerVertexColorMaterial.qml +++ /dev/null @@ -1,53 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 Lorenz Esch (TU Ilmenau). -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt3D module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** 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-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import Qt3D.Core 2.0 -import Qt3D.Render 2.0 - -Material { - id: root - - effect: DefaultEffect { - vertexES: "qrc:/shaders/es2/pervertexcolor.vert" - fragmentES: "qrc:/shaders/es2/pervertexcolor.frag" - vertex: "qrc:/shaders/gl3/pervertexcolor.vert" - fragment: "qrc:/shaders/gl3/pervertexcolor.frag" - } -} - diff --git a/src/quick3d/imports/extras/defaults/qml/PhongAlphaMaterial.qml b/src/quick3d/imports/extras/defaults/qml/PhongAlphaMaterial.qml deleted file mode 100644 index 87373242d..000000000 --- a/src/quick3d/imports/extras/defaults/qml/PhongAlphaMaterial.qml +++ /dev/null @@ -1,68 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 Paul Lemire -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt3D module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** 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-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import Qt3D.Core 2.0 -import Qt3D.Render 2.0 - -Material { - id: root - - property color ambient: Qt.rgba( 0.05, 0.05, 0.05, 1.0 ) - property color diffuse: Qt.rgba( 0.7, 0.7, 0.7, 1.0 ) - property color specular: Qt.rgba( 0.01, 0.01, 0.01, 1.0 ) - property real shininess: 150.0 - property real alpha: 0.5 - - property alias sourceRgbArg: alphaEffect.sourceRgbArg - property alias destinationRgbArg: alphaEffect.destinationRgbArg - property alias sourceAlphaArg: alphaEffect.sourceAlphaArg - property alias destinationAlphaArg: alphaEffect.destinationAlphaArg - property alias blendFunctionArg: alphaEffect.blendFunctionArg - - parameters: [ - Parameter { name: "alpha"; value: root.alpha }, - Parameter { name: "ka"; value: Qt.vector3d(root.ambient.r, root.ambient.g, root.ambient.b) }, - Parameter { name: "kd"; value: Qt.vector3d(root.diffuse.r, root.diffuse.g, root.diffuse.b) }, - Parameter { name: "ks"; value: Qt.vector3d(root.specular.r, root.specular.g, root.specular.b) }, - Parameter { name: "shininess"; value: root.shininess } - ] - - effect: DefaultAlphaEffect { id: alphaEffect } -} - diff --git a/src/quick3d/imports/extras/defaults/qml/PhongMaterial.qml b/src/quick3d/imports/extras/defaults/qml/PhongMaterial.qml deleted file mode 100644 index 5b770a56d..000000000 --- a/src/quick3d/imports/extras/defaults/qml/PhongMaterial.qml +++ /dev/null @@ -1,59 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt3D module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** 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-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import Qt3D.Core 2.0 -import Qt3D.Render 2.0 - -Material { - id:root - property color ambient: Qt.rgba( 0.05, 0.05, 0.05, 1.0 ) - property color diffuse: Qt.rgba( 0.7, 0.7, 0.7, 1.0 ) - property color specular: Qt.rgba( 0.01, 0.01, 0.01, 1.0 ) - property real shininess: 150.0 - - parameters: [ - Parameter { name: "ka"; value: Qt.vector3d(root.ambient.r, root.ambient.g, root.ambient.b) }, - Parameter { name: "kd"; value: Qt.vector3d(root.diffuse.r, root.diffuse.g, root.diffuse.b) }, - Parameter { name: "ks"; value: Qt.vector3d(root.specular.r, root.specular.g, root.specular.b) }, - Parameter { name: "shininess"; value: root.shininess } - ] - - effect: DefaultEffect {} -} - diff --git a/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp b/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp index 7d695ea5b..38cc77503 100644 --- a/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp +++ b/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp @@ -41,6 +41,15 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include @@ -61,15 +70,6 @@ static const struct { int major, minor; } qmldir [] = { // Materials - { "PhongMaterial", 2, 0 }, - { "PhongAlphaMaterial", 2, 0 }, - { "DiffuseMapMaterial", 2, 0 }, - { "DiffuseSpecularMapMaterial", 2, 0 }, - { "NormalDiffuseMapAlphaMaterial", 2, 0 }, - { "NormalDiffuseMapMaterial", 2, 0 }, - { "NormalDiffuseSpecularMapMaterial", 2, 0 }, - { "PerVertexColorMaterial", 2, 0 }, - { "GoochMaterial", 2, 0 }, { "TextureMaterial", 2, 0 }, // Effects { "DefaultEffect", 2, 0 }, @@ -88,6 +88,17 @@ static const struct { void Qt3DQuick3DExtrasPlugin::registerTypes(const char *uri) { + // Materials + qmlRegisterType(uri, 2, 0, "PhongMaterial"); + qmlRegisterType(uri, 2, 0, "PhongAlphaMaterial"); + qmlRegisterType(uri, 2, 0, "DiffuseMapMaterial"); + qmlRegisterType(uri, 2, 0, "DiffuseSpecularMapMaterial"); + qmlRegisterType(uri, 2, 0, "NormalDiffuseMapAlphaMaterial"); + qmlRegisterType(uri, 2, 0, "NormalDiffuseMapMaterial"); + qmlRegisterType(uri, 2, 0, "NormalDiffuseSpecularMapMaterial"); + qmlRegisterType(uri, 2, 0, "PerVertexColorMaterial"); + qmlRegisterType(uri, 2, 0, "GoochMaterial"); + // Meshes qmlRegisterType(uri, 2, 0, "ConeMesh"); qmlRegisterType(uri, 2, 0, "ConeGeometry"); -- cgit v1.2.3 From 435ae33f177a889aad0e2e30ff1d03d687900c62 Mon Sep 17 00:00:00 2001 From: Kevin Ottens Date: Wed, 25 Jan 2017 13:04:37 +0100 Subject: Introduce QTextureMaterial This is a straight port from TextureMaterial.qml which is now obsoleted and removed. Change-Id: Icd5f1e362dc5ece1db1842dfa82f54353ac7974a Reviewed-by: Sean Harmer --- src/extras/defaults/defaults.pri | 7 +- src/extras/defaults/qtexturematerial.cpp | 209 +++++++++++++++++++++ src/extras/defaults/qtexturematerial.h | 87 +++++++++ src/extras/defaults/qtexturematerial_p.h | 104 ++++++++++ src/quick3d/imports/extras/defaults/defaults.pri | 1 - .../extras/defaults/qml/TextureMaterial.qml | 68 ------- .../imports/extras/qt3dquick3dextrasplugin.cpp | 4 +- 7 files changed, 407 insertions(+), 73 deletions(-) create mode 100644 src/extras/defaults/qtexturematerial.cpp create mode 100644 src/extras/defaults/qtexturematerial.h create mode 100644 src/extras/defaults/qtexturematerial_p.h delete mode 100644 src/quick3d/imports/extras/defaults/qml/TextureMaterial.qml diff --git a/src/extras/defaults/defaults.pri b/src/extras/defaults/defaults.pri index 04cd87246..8e6a5861a 100644 --- a/src/extras/defaults/defaults.pri +++ b/src/extras/defaults/defaults.pri @@ -27,7 +27,9 @@ HEADERS += \ $$PWD/qfirstpersoncameracontroller.h \ $$PWD/qfirstpersoncameracontroller_p.h \ $$PWD/qorbitcameracontroller.h \ - $$PWD/qorbitcameracontroller_p.h + $$PWD/qorbitcameracontroller_p.h \ + $$PWD/qtexturematerial.h \ + $$PWD/qtexturematerial_p.h SOURCES += \ $$PWD/qphongmaterial.cpp \ @@ -43,5 +45,6 @@ SOURCES += \ $$PWD/qphongalphamaterial.cpp \ $$PWD/qt3dwindow.cpp \ $$PWD/qfirstpersoncameracontroller.cpp \ - $$PWD/qorbitcameracontroller.cpp + $$PWD/qorbitcameracontroller.cpp \ + $$PWD/qtexturematerial.cpp diff --git a/src/extras/defaults/qtexturematerial.cpp b/src/extras/defaults/qtexturematerial.cpp new file mode 100644 index 000000000..15a01f828 --- /dev/null +++ b/src/extras/defaults/qtexturematerial.cpp @@ -0,0 +1,209 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtexturematerial.h" +#include "qtexturematerial_p.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +using namespace Qt3DRender; + +namespace Qt3DExtras { + +QTextureMaterialPrivate::QTextureMaterialPrivate() + : QMaterialPrivate() + , m_textureEffect(new QEffect) + , m_textureParameter(new QParameter(QStringLiteral("diffuseTexture"), new QTexture2D)) + , m_textureOffsetParameter(new QParameter(QStringLiteral("texCoordOffset"), QVector2D(0.0f, 0.0f))) + , m_textureGL3Technique(new QTechnique) + , m_textureGL2Technique(new QTechnique) + , m_textureES2Technique(new QTechnique) + , m_textureGL3RenderPass(new QRenderPass) + , m_textureGL2RenderPass(new QRenderPass) + , m_textureES2RenderPass(new QRenderPass) + , m_textureGL3Shader(new QShaderProgram) + , m_textureGL2ES2Shader(new QShaderProgram) + , m_filterKey(new QFilterKey) +{ +} + +void QTextureMaterialPrivate::init() +{ + connect(m_textureParameter, &Qt3DRender::QParameter::valueChanged, + this, &QTextureMaterialPrivate::handleTextureChanged); + connect(m_textureOffsetParameter, &Qt3DRender::QParameter::valueChanged, + this, &QTextureMaterialPrivate::handleTextureOffsetChanged); + + m_textureGL3Shader->setVertexShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/gl3/unlittexture.vert")))); + m_textureGL3Shader->setFragmentShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/gl3/unlittexture.frag")))); + m_textureGL2ES2Shader->setVertexShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/es2/unlittexture.vert")))); + m_textureGL2ES2Shader->setFragmentShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/es2/unlittexture.frag")))); + + m_textureGL3Technique->graphicsApiFilter()->setApi(QGraphicsApiFilter::OpenGL); + m_textureGL3Technique->graphicsApiFilter()->setMajorVersion(3); + m_textureGL3Technique->graphicsApiFilter()->setMinorVersion(1); + m_textureGL3Technique->graphicsApiFilter()->setProfile(QGraphicsApiFilter::CoreProfile); + + m_textureGL2Technique->graphicsApiFilter()->setApi(QGraphicsApiFilter::OpenGL); + m_textureGL2Technique->graphicsApiFilter()->setMajorVersion(2); + m_textureGL2Technique->graphicsApiFilter()->setMinorVersion(0); + m_textureGL2Technique->graphicsApiFilter()->setProfile(QGraphicsApiFilter::NoProfile); + + m_textureES2Technique->graphicsApiFilter()->setApi(QGraphicsApiFilter::OpenGLES); + m_textureES2Technique->graphicsApiFilter()->setMajorVersion(2); + m_textureES2Technique->graphicsApiFilter()->setMinorVersion(0); + m_textureES2Technique->graphicsApiFilter()->setProfile(QGraphicsApiFilter::NoProfile); + + Q_Q(QTextureMaterial); + m_filterKey->setParent(q); + m_filterKey->setName(QStringLiteral("renderingStyle")); + m_filterKey->setValue(QStringLiteral("forward")); + + m_textureGL3Technique->addFilterKey(m_filterKey); + m_textureGL2Technique->addFilterKey(m_filterKey); + m_textureES2Technique->addFilterKey(m_filterKey); + + m_textureGL3RenderPass->setShaderProgram(m_textureGL3Shader); + m_textureGL2RenderPass->setShaderProgram(m_textureGL2ES2Shader); + m_textureES2RenderPass->setShaderProgram(m_textureGL2ES2Shader); + + m_textureGL3Technique->addRenderPass(m_textureGL3RenderPass); + m_textureGL2Technique->addRenderPass(m_textureGL2RenderPass); + m_textureES2Technique->addRenderPass(m_textureES2RenderPass); + + m_textureEffect->addTechnique(m_textureGL3Technique); + m_textureEffect->addTechnique(m_textureGL2Technique); + m_textureEffect->addTechnique(m_textureES2Technique); + + m_textureEffect->addParameter(m_textureParameter); + m_textureEffect->addParameter(m_textureOffsetParameter); + + q->setEffect(m_textureEffect); +} + +void QTextureMaterialPrivate::handleTextureChanged(const QVariant &var) +{ + Q_Q(QTextureMaterial); + emit q->textureChanged(var.value()); +} + +void QTextureMaterialPrivate::handleTextureOffsetChanged(const QVariant &var) +{ + Q_Q(QTextureMaterial); + emit q->textureOffsetChanged(var.value()); +} + +/*! + \class Qt3DExtras::QTextureMaterial + \brief The QTextureMaterial provides a default implementation of a simple unlit + texture material. + \inmodule Qt3DExtras + \since 5.9 + \inherits Qt3DRender::QMaterial + + This material uses an effect with a single render pass approach. Techniques are provided + for OpenGL 2, OpenGL 3 or above as well as OpenGL ES 2. +*/ + +/*! + Constructs a new QTextureMaterial instance with parent object \a parent. + */ +QTextureMaterial::QTextureMaterial(QNode *parent) + : QMaterial(*new QTextureMaterialPrivate, parent) +{ + Q_D(QTextureMaterial); + d->init(); +} + +/*! + Destroys the QTextureMaterial instance. +*/ +QTextureMaterial::~QTextureMaterial() +{ +} + +/*! + \property QTextureMaterial::texture + + Holds the current texture used by the material. +*/ +QAbstractTexture *QTextureMaterial::texture() const +{ + Q_D(const QTextureMaterial); + return d->m_textureParameter->value().value(); +} + +/*! + \property QTextureMaterial::textureOffset + + Holds the current texture offset. It is applied to texture + coordinates at render time. Defaults to (0.0, 0.0). + +*/ +QVector2D QTextureMaterial::textureOffset() const +{ + Q_D(const QTextureMaterial); + return d->m_textureOffsetParameter->value().value(); +} + +void QTextureMaterial::setTexture(QAbstractTexture *texture) +{ + Q_D(QTextureMaterial); + d->m_textureParameter->setValue(QVariant::fromValue(texture)); +} + +void QTextureMaterial::setTextureOffset(const QVector2D &textureOffset) +{ + Q_D(QTextureMaterial); + d->m_textureOffsetParameter->setValue(QVariant::fromValue(textureOffset)); +} + +} // namespace Qt3DExtras + +QT_END_NAMESPACE diff --git a/src/extras/defaults/qtexturematerial.h b/src/extras/defaults/qtexturematerial.h new file mode 100644 index 000000000..46e618418 --- /dev/null +++ b/src/extras/defaults/qtexturematerial.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3DEXTRAS_QTEXTUREMATERIAL_H +#define QT3DEXTRAS_QTEXTUREMATERIAL_H + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +class QAbstractTexture; + +} // namespace Qt3DRender + +namespace Qt3DExtras { + +class QTextureMaterialPrivate; + +class QT3DEXTRASSHARED_EXPORT QTextureMaterial : public Qt3DRender::QMaterial +{ + Q_OBJECT + Q_PROPERTY(Qt3DRender::QAbstractTexture *texture READ texture WRITE setTexture NOTIFY textureChanged) + Q_PROPERTY(QVector2D textureOffset READ textureOffset WRITE setTextureOffset NOTIFY textureOffsetChanged) +public: + explicit QTextureMaterial(Qt3DCore::QNode *parent = nullptr); + ~QTextureMaterial(); + + Qt3DRender::QAbstractTexture *texture() const; + QVector2D textureOffset() const; + +public Q_SLOTS: + void setTexture(Qt3DRender::QAbstractTexture *texture); + void setTextureOffset(const QVector2D &textureOffset); + +Q_SIGNALS: + void textureChanged(Qt3DRender::QAbstractTexture *texture); + void textureOffsetChanged(const QVector2D &textureOffset); + +private: + Q_DECLARE_PRIVATE(QTextureMaterial) +}; + +} // Qt3DExtras + +QT_END_NAMESPACE + +#endif // QT3DEXTRAS_QTEXTUREMATERIAL_H diff --git a/src/extras/defaults/qtexturematerial_p.h b/src/extras/defaults/qtexturematerial_p.h new file mode 100644 index 000000000..5a8e78154 --- /dev/null +++ b/src/extras/defaults/qtexturematerial_p.h @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3DEXTRAS_QTEXTUREMATERIAL_P_H +#define QT3DEXTRAS_QTEXTUREMATERIAL_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +class QFilterKey; +class QEffect; +class QAbstractTexture; +class QTechnique; +class QParameter; +class QShaderProgram; +class QRenderPass; + +} // namespace Qt3DRender + +namespace Qt3DExtras { + +class QTextureMaterial; + +class QTextureMaterialPrivate : public Qt3DRender::QMaterialPrivate +{ + QTextureMaterialPrivate(); + + void init(); + + void handleTextureChanged(const QVariant &var); + void handleTextureOffsetChanged(const QVariant &var); + + Qt3DRender::QEffect *m_textureEffect; + Qt3DRender::QParameter *m_textureParameter; + Qt3DRender::QParameter *m_textureOffsetParameter; + Qt3DRender::QTechnique *m_textureGL3Technique; + Qt3DRender::QTechnique *m_textureGL2Technique; + Qt3DRender::QTechnique *m_textureES2Technique; + Qt3DRender::QRenderPass *m_textureGL3RenderPass; + Qt3DRender::QRenderPass *m_textureGL2RenderPass; + Qt3DRender::QRenderPass *m_textureES2RenderPass; + Qt3DRender::QShaderProgram *m_textureGL3Shader; + Qt3DRender::QShaderProgram *m_textureGL2ES2Shader; + Qt3DRender::QFilterKey *m_filterKey; + + Q_DECLARE_PUBLIC(QTextureMaterial) +}; + +} // Qt3DExtras + +QT_END_NAMESPACE + +#endif // QT3DEXTRAS_QTEXTUREMATERIAL_P_H + diff --git a/src/quick3d/imports/extras/defaults/defaults.pri b/src/quick3d/imports/extras/defaults/defaults.pri index 7872837a7..aa3b7c998 100644 --- a/src/quick3d/imports/extras/defaults/defaults.pri +++ b/src/quick3d/imports/extras/defaults/defaults.pri @@ -10,7 +10,6 @@ QML_FILES = \ $$PWD/qml/DefaultAlphaEffect.qml \ $$PWD/qml/ForwardRenderer.qml \ $$PWD/qml/SkyboxEntity.qml \ - $$PWD/qml/TextureMaterial.qml \ $$PWD/qml/OrbitCameraController.qml \ $$PWD/qml/FirstPersonCameraController.qml \ $$PWD/qml/NormalDiffuseMapAlphaEffect.qml \ diff --git a/src/quick3d/imports/extras/defaults/qml/TextureMaterial.qml b/src/quick3d/imports/extras/defaults/qml/TextureMaterial.qml deleted file mode 100644 index 387d8d4aa..000000000 --- a/src/quick3d/imports/extras/defaults/qml/TextureMaterial.qml +++ /dev/null @@ -1,68 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 Klaralvdalens Datakonsult AB (KDAB). -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt3D module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** 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-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import Qt3D.Core 2.0 -import Qt3D.Render 2.0 - -Material { - id: root - - property Texture2D texture: Texture2D {} - property alias textureOffset: texCoordOffset.offset - - parameters: [ - Parameter { - name: "diffuseTexture" - value: root.texture - }, - Parameter { - id: texCoordOffset - property vector2d offset: Qt.vector2d(0, 0) - name: "texCoordOffset" - value: offset - } - ] - - effect: DefaultEffect { - vertexES: "qrc:/shaders/es2/unlittexture.vert" - fragmentES: "qrc:/shaders/es2/unlittexture.frag" - vertex: "qrc:/shaders/gl3/unlittexture.vert" - fragment: "qrc:/shaders/gl3/unlittexture.frag" - } -} diff --git a/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp b/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp index 38cc77503..506235c3e 100644 --- a/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp +++ b/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp @@ -52,6 +52,7 @@ #include #include #include +#include #include #include #include @@ -69,8 +70,6 @@ static const struct { const char *type; int major, minor; } qmldir [] = { - // Materials - { "TextureMaterial", 2, 0 }, // Effects { "DefaultEffect", 2, 0 }, { "DefaultAlphaEffect", 2, 0 }, @@ -98,6 +97,7 @@ void Qt3DQuick3DExtrasPlugin::registerTypes(const char *uri) qmlRegisterType(uri, 2, 0, "NormalDiffuseSpecularMapMaterial"); qmlRegisterType(uri, 2, 0, "PerVertexColorMaterial"); qmlRegisterType(uri, 2, 0, "GoochMaterial"); + qmlRegisterType(uri, 2, 0, "TextureMaterial"); // Meshes qmlRegisterType(uri, 2, 0, "ConeMesh"); -- cgit v1.2.3 From 0b031ca3c828e83772aaf5605722a5cc54a5683e Mon Sep 17 00:00:00 2001 From: Kevin Ottens Date: Wed, 25 Jan 2017 13:05:19 +0100 Subject: Remove the QML based default Effects With the removal of the materials to move them on the C++ end, those are now unused. Change-Id: Idc1d78c8118834832a264cfc52bd01303350c70c Reviewed-by: Sean Harmer --- src/quick3d/imports/extras/defaults/defaults.pri | 3 - .../extras/defaults/qml/DefaultAlphaEffect.qml | 148 --------------------- .../imports/extras/defaults/qml/DefaultEffect.qml | 104 --------------- .../defaults/qml/NormalDiffuseMapAlphaEffect.qml | 115 ---------------- .../imports/extras/qt3dquick3dextrasplugin.cpp | 4 - 5 files changed, 374 deletions(-) delete mode 100644 src/quick3d/imports/extras/defaults/qml/DefaultAlphaEffect.qml delete mode 100644 src/quick3d/imports/extras/defaults/qml/DefaultEffect.qml delete mode 100644 src/quick3d/imports/extras/defaults/qml/NormalDiffuseMapAlphaEffect.qml diff --git a/src/quick3d/imports/extras/defaults/defaults.pri b/src/quick3d/imports/extras/defaults/defaults.pri index aa3b7c998..69a1fd209 100644 --- a/src/quick3d/imports/extras/defaults/defaults.pri +++ b/src/quick3d/imports/extras/defaults/defaults.pri @@ -6,11 +6,8 @@ # To have the plugin register them as types, add an entries to the # qmldir array in qt3dquick3dextrasplugin.cpp QML_FILES = \ - $$PWD/qml/DefaultEffect.qml \ - $$PWD/qml/DefaultAlphaEffect.qml \ $$PWD/qml/ForwardRenderer.qml \ $$PWD/qml/SkyboxEntity.qml \ $$PWD/qml/OrbitCameraController.qml \ $$PWD/qml/FirstPersonCameraController.qml \ - $$PWD/qml/NormalDiffuseMapAlphaEffect.qml \ $$PWD/qml/LevelOfDetailLoader.qml diff --git a/src/quick3d/imports/extras/defaults/qml/DefaultAlphaEffect.qml b/src/quick3d/imports/extras/defaults/qml/DefaultAlphaEffect.qml deleted file mode 100644 index c28fda4d1..000000000 --- a/src/quick3d/imports/extras/defaults/qml/DefaultAlphaEffect.qml +++ /dev/null @@ -1,148 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt3D module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** 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-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import Qt3D.Core 2.0 -import Qt3D.Render 2.0 - -Effect { - property string vertexES: "qrc:/shaders/es2/phong.vert" - property string fragmentES: "qrc:/shaders/es2/phongalpha.frag" - property string vertex: "qrc:/shaders/gl3/phong.vert" - property string fragment: "qrc:/shaders/gl3/phongalpha.frag" - property int sourceRgbArg: BlendEquationArguments.SourceAlpha - property int destinationRgbArg: BlendEquationArguments.OneMinusSourceAlpha - property int sourceAlphaArg: BlendEquationArguments.One - property int destinationAlphaArg: BlendEquationArguments.Zero - property int blendFunctionArg: BlendEquation.Add - - FilterKey { - id: forward - name: "renderingStyle" - value: "forward" - } - - ShaderProgram { - id: gl2Es2Shader - vertexShaderCode: loadSource(vertexES) - fragmentShaderCode: loadSource(fragmentES) - } - - ShaderProgram { - id: gl3Shader - vertexShaderCode: loadSource(vertex) - fragmentShaderCode: loadSource(fragment) - } - - techniques: [ - // OpenGL 3.1 - Technique { - filterKeys: [ forward ] - graphicsApiFilter { - api: GraphicsApiFilter.OpenGL - profile: GraphicsApiFilter.CoreProfile - majorVersion: 3 - minorVersion: 1 - } - renderPasses: RenderPass { - shaderProgram: gl3Shader - renderStates: [ - BlendEquationArguments { - sourceRgb: sourceRgbArg - destinationRgb: destinationRgbArg - sourceAlpha: sourceAlphaArg - destinationAlpha: destinationAlphaArg - }, - BlendEquation { - blendFunction: blendFunctionArg - } - ] - } - }, - - // OpenGL 2.1 - Technique { - filterKeys: [ forward ] - graphicsApiFilter { - api: GraphicsApiFilter.OpenGL - profile: GraphicsApiFilter.NoProfile - majorVersion: 2 - minorVersion: 0 - } - renderPasses: RenderPass { - shaderProgram: gl2Es2Shader - renderStates: [ - BlendEquationArguments { - sourceRgb: sourceRgbArg - destinationRgb: destinationRgbArg - sourceAlpha: sourceAlphaArg - destinationAlpha: destinationAlphaArg - }, - BlendEquation { - blendFunction: blendFunctionArg - } - ] - } - }, - - // OpenGL ES 2 - Technique { - filterKeys: [ forward ] - graphicsApiFilter { - api: GraphicsApiFilter.OpenGLES - profile: GraphicsApiFilter.NoProfile - majorVersion: 2 - minorVersion: 0 - } - renderPasses: RenderPass { - shaderProgram: gl2Es2Shader - renderStates: [ - BlendEquationArguments { - sourceRgb: sourceRgbArg - destinationRgb: destinationRgbArg - sourceAlpha: sourceAlphaArg - destinationAlpha: destinationAlphaArg - }, - BlendEquation { - blendFunction: blendFunctionArg - } - ] - } - } - ] -} diff --git a/src/quick3d/imports/extras/defaults/qml/DefaultEffect.qml b/src/quick3d/imports/extras/defaults/qml/DefaultEffect.qml deleted file mode 100644 index fed87c94d..000000000 --- a/src/quick3d/imports/extras/defaults/qml/DefaultEffect.qml +++ /dev/null @@ -1,104 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt3D module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** 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-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import Qt3D.Core 2.0 -import Qt3D.Render 2.0 - -Effect { - property string vertexES: "qrc:/shaders/es2/phong.vert" - property string fragmentES: "qrc:/shaders/es2/phong.frag" - property string vertex: "qrc:/shaders/gl3/phong.vert" - property string fragment: "qrc:/shaders/gl3/phong.frag" - - FilterKey { - id: forward - name: "renderingStyle" - value: "forward" - } - - ShaderProgram { - id: gl2Es2Shader - vertexShaderCode: loadSource(vertexES) - fragmentShaderCode: loadSource(fragmentES) - } - - ShaderProgram { - id: gl3Shader - vertexShaderCode: loadSource(vertex) - fragmentShaderCode: loadSource(fragment) - } - - techniques: [ - // OpenGL 3.1 - Technique { - filterKeys: [ forward ] - graphicsApiFilter { - api: GraphicsApiFilter.OpenGL - profile: GraphicsApiFilter.CoreProfile - majorVersion: 3 - minorVersion: 1 - } - renderPasses: RenderPass { shaderProgram: gl3Shader } - }, - - // OpenGL 2.1 - Technique { - filterKeys: [ forward ] - graphicsApiFilter { - api: GraphicsApiFilter.OpenGL - profile: GraphicsApiFilter.NoProfile - majorVersion: 2 - minorVersion: 0 - } - renderPasses: RenderPass { shaderProgram: gl2Es2Shader } - }, - - // OpenGL ES 2 - Technique { - filterKeys: [ forward ] - graphicsApiFilter { - api: GraphicsApiFilter.OpenGLES - profile: GraphicsApiFilter.NoProfile - majorVersion: 2 - minorVersion: 0 - } - renderPasses: RenderPass { shaderProgram: gl2Es2Shader } - } - ] -} diff --git a/src/quick3d/imports/extras/defaults/qml/NormalDiffuseMapAlphaEffect.qml b/src/quick3d/imports/extras/defaults/qml/NormalDiffuseMapAlphaEffect.qml deleted file mode 100644 index e4f038642..000000000 --- a/src/quick3d/imports/extras/defaults/qml/NormalDiffuseMapAlphaEffect.qml +++ /dev/null @@ -1,115 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB). -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt3D module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** 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-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import Qt3D.Core 2.0 -import Qt3D.Render 2.0 - -Effect { - property string vertexES: "qrc:/shaders/es2/normaldiffusemap.vert" - property string fragmentES: "qrc:/shaders/es2/normaldiffusemapalpha.frag" - property string vertex: "qrc:/shaders/gl3/normaldiffusemap.vert" - property string fragment: "qrc:/shaders/gl3/normaldiffusemapalpha.frag" - - FilterKey { - id: forward - name: "renderingStyle" - value: "forward" - } - - ShaderProgram { - id: gl2Es2Shader - vertexShaderCode: loadSource(vertexES) - fragmentShaderCode: loadSource(fragmentES) - } - - ShaderProgram { - id: gl3Shader - vertexShaderCode: loadSource(vertex) - fragmentShaderCode: loadSource(fragment) - } - - AlphaCoverage { id: alphaCoverage } - - techniques: [ - // OpenGL 3.1 - Technique { - filterKeys: [ forward ] - graphicsApiFilter { - api: GraphicsApiFilter.OpenGL - profile: GraphicsApiFilter.CoreProfile - majorVersion: 3 - minorVersion: 1 - } - renderPasses: RenderPass { - shaderProgram: gl3Shader - renderStates: [ alphaCoverage ] - } - }, - - // OpenGL 2.1 - Technique { - filterKeys: [ forward ] - graphicsApiFilter { - api: GraphicsApiFilter.OpenGL - profile: GraphicsApiFilter.NoProfile - majorVersion: 2 - minorVersion: 0 - } - renderPasses: RenderPass { - shaderProgram: gl2Es2Shader - renderStates: [ alphaCoverage ] - } - }, - - // OpenGL ES 2 - Technique { - filterKeys: [ forward ] - graphicsApiFilter { - api: GraphicsApiFilter.OpenGLES - profile: GraphicsApiFilter.NoProfile - majorVersion: 2 - minorVersion: 0 - } - renderPasses: RenderPass { - shaderProgram: gl2Es2Shader - renderStates: [ alphaCoverage ] - } - } - ] -} diff --git a/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp b/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp index 506235c3e..d5a2e9c40 100644 --- a/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp +++ b/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp @@ -70,10 +70,6 @@ static const struct { const char *type; int major, minor; } qmldir [] = { - // Effects - { "DefaultEffect", 2, 0 }, - { "DefaultAlphaEffect", 2, 0 }, - { "NormalDiffuseMapAlphaEffect", 2, 0 }, // Scene Graph { "LevelOfDetailLoader", 2, 2 }, // FrameGraphs -- cgit v1.2.3 From c5768dd2c04ebdb3a411e88bfa8af2767aa33368 Mon Sep 17 00:00:00 2001 From: Kevin Ottens Date: Wed, 25 Jan 2017 13:22:46 +0100 Subject: Align QForwardRenderer API with its QML counterpart The QML based ForwardRenderer was slightly different: * window property instead of surface, so we provide an alias window name for surface in QForwardRenderer * frustumCulling property to control the corresponding node, also added here. Change-Id: I7ec51ee27e97c612ba09b73a43cf4d1baba343bf Reviewed-by: Sean Harmer --- src/extras/defaults/qforwardrenderer.cpp | 38 ++++++++++++++++++++++ src/extras/defaults/qforwardrenderer.h | 5 +++ .../qforwardrenderer/tst_qforwardrenderer.cpp | 26 +++++++++++++++ 3 files changed, 69 insertions(+) diff --git a/src/extras/defaults/qforwardrenderer.cpp b/src/extras/defaults/qforwardrenderer.cpp index d556b58d3..7790313e3 100644 --- a/src/extras/defaults/qforwardrenderer.cpp +++ b/src/extras/defaults/qforwardrenderer.cpp @@ -134,6 +134,7 @@ QForwardRenderer::QForwardRenderer(QNode *parent) QObject::connect(d->m_cameraSelector, &QCameraSelector::cameraChanged, this, &QForwardRenderer::cameraChanged); QObject::connect(d->m_surfaceSelector, &QRenderSurfaceSelector::surfaceChanged, this, &QForwardRenderer::surfaceChanged); QObject::connect(d->m_surfaceSelector, &QRenderSurfaceSelector::externalRenderTargetSizeChanged, this, &QForwardRenderer::externalRenderTargetSizeChanged); + QObject::connect(d->m_frustumCulling, &QFrustumCulling::enabledChanged, this, &QForwardRenderer::frustumCullingEnabledChanged); d->init(); } @@ -171,6 +172,12 @@ void QForwardRenderer::setExternalRenderTargetSize(const QSize &size) d->m_surfaceSelector->setExternalRenderTargetSize(size); } +void QForwardRenderer::setFrustumCullingEnabled(bool enabled) +{ + Q_D(QForwardRenderer); + d->m_frustumCulling->setEnabled(enabled); +} + /*! \qmlproperty rect ForwardRenderer::viewportRect @@ -225,6 +232,21 @@ Qt3DCore::QEntity *QForwardRenderer::camera() const return d->m_cameraSelector->camera(); } +/*! + \qmlproperty Object ForwardRenderer::window + + Holds the current render surface. + + \deprecated +*/ +/*! + \property QForwardRenderer::window + + Holds the current render surface. + + \deprecated +*/ + /*! \qmlproperty Object ForwardRenderer::surface @@ -247,6 +269,22 @@ QSize QForwardRenderer::externalRenderTargetSize() const return d->m_surfaceSelector->externalRenderTargetSize(); } +/*! + \qmlproperty color ForwardRenderer::frustumCulling + + Indicates if the renderer applies frustum culling to the scene. +*/ +/*! + \property QForwardRenderer::frustumCulling + + Indicates if the renderer applies frustum culling to the scene. +*/ +bool QForwardRenderer::isFrustumCullingEnabled() const +{ + Q_D(const QForwardRenderer); + return d->m_frustumCulling->isEnabled(); +} + } // namespace Qt3DExtras QT_END_NAMESPACE diff --git a/src/extras/defaults/qforwardrenderer.h b/src/extras/defaults/qforwardrenderer.h index 01f50f452..6a2773029 100644 --- a/src/extras/defaults/qforwardrenderer.h +++ b/src/extras/defaults/qforwardrenderer.h @@ -57,10 +57,12 @@ class QT3DEXTRASSHARED_EXPORT QForwardRenderer : public Qt3DRender::QTechniqueFi { Q_OBJECT Q_PROPERTY(QObject *surface READ surface WRITE setSurface NOTIFY surfaceChanged) + Q_PROPERTY(QObject *window READ surface WRITE setSurface NOTIFY surfaceChanged) Q_PROPERTY(QRectF viewportRect READ viewportRect WRITE setViewportRect NOTIFY viewportRectChanged) Q_PROPERTY(QColor clearColor READ clearColor WRITE setClearColor NOTIFY clearColorChanged) Q_PROPERTY(Qt3DCore::QEntity *camera READ camera WRITE setCamera NOTIFY cameraChanged) Q_PROPERTY(QSize externalRenderTargetSize READ externalRenderTargetSize WRITE setExternalRenderTargetSize NOTIFY externalRenderTargetSizeChanged) + Q_PROPERTY(bool frustumCulling READ isFrustumCullingEnabled WRITE setFrustumCullingEnabled NOTIFY frustumCullingEnabledChanged) public: explicit QForwardRenderer(Qt3DCore::QNode *parent = nullptr); ~QForwardRenderer(); @@ -70,6 +72,7 @@ public: Qt3DCore::QEntity *camera() const; QObject *surface() const; QSize externalRenderTargetSize() const; + bool isFrustumCullingEnabled() const; public Q_SLOTS: void setViewportRect(const QRectF &viewportRect); @@ -77,6 +80,7 @@ public Q_SLOTS: void setCamera(Qt3DCore::QEntity *camera); void setSurface(QObject * surface); void setExternalRenderTargetSize(const QSize &size); + void setFrustumCullingEnabled(bool enabled); Q_SIGNALS: void viewportRectChanged(const QRectF &viewportRect); @@ -84,6 +88,7 @@ Q_SIGNALS: void cameraChanged(Qt3DCore::QEntity *camera); void surfaceChanged(QObject *surface); void externalRenderTargetSizeChanged(const QSize &size); + void frustumCullingEnabledChanged(bool enabled); private: Q_DECLARE_PRIVATE(QForwardRenderer) diff --git a/tests/auto/extras/qforwardrenderer/tst_qforwardrenderer.cpp b/tests/auto/extras/qforwardrenderer/tst_qforwardrenderer.cpp index 122aed520..0d80f0e35 100644 --- a/tests/auto/extras/qforwardrenderer/tst_qforwardrenderer.cpp +++ b/tests/auto/extras/qforwardrenderer/tst_qforwardrenderer.cpp @@ -55,6 +55,7 @@ private Q_SLOTS: QCOMPARE(forwardRenderer.clearColor(), QColor(Qt::white)); QVERIFY(forwardRenderer.camera() == nullptr); QCOMPARE(forwardRenderer.externalRenderTargetSize(), QSize()); + QVERIFY(forwardRenderer.isFrustumCullingEnabled()); } void checkPropertyChanges() @@ -163,6 +164,31 @@ private Q_SLOTS: QCOMPARE(spy.count(), 0); } + { + // WHEN + QSignalSpy spy(&forwardRenderer, SIGNAL(frustumCullingEnabledChanged(bool))); + forwardRenderer.setFrustumCullingEnabled(false); + + // THEN + QVERIFY(!forwardRenderer.isFrustumCullingEnabled()); + QCOMPARE(spy.count(), 1); + QVERIFY(!spy.takeFirst().takeFirst().toBool()); + + // WHEN + forwardRenderer.setFrustumCullingEnabled(false); + + // THEN + QVERIFY(!forwardRenderer.isFrustumCullingEnabled()); + QCOMPARE(spy.count(), 0); + + // WHEN + forwardRenderer.setFrustumCullingEnabled(true); + + // THEN + QVERIFY(forwardRenderer.isFrustumCullingEnabled()); + QCOMPARE(spy.count(), 1); + QVERIFY(spy.takeFirst().takeFirst().toBool()); + } } }; -- cgit v1.2.3 From 713373a9264e8d5e265e44ea8ec2172906263537 Mon Sep 17 00:00:00 2001 From: Kevin Ottens Date: Wed, 25 Jan 2017 13:30:10 +0100 Subject: Remove ForwardRenderer.qml, QForwardRenderer is enough Change-Id: I54449c642a8ac81e57b533be0a7ecb255a18e588 Reviewed-by: Sean Harmer --- src/quick3d/imports/extras/defaults/defaults.pri | 1 - .../extras/defaults/qml/ForwardRenderer.qml | 77 ---------------------- .../imports/extras/qt3dquick3dextrasplugin.cpp | 6 +- 3 files changed, 4 insertions(+), 80 deletions(-) delete mode 100644 src/quick3d/imports/extras/defaults/qml/ForwardRenderer.qml diff --git a/src/quick3d/imports/extras/defaults/defaults.pri b/src/quick3d/imports/extras/defaults/defaults.pri index 69a1fd209..7179db854 100644 --- a/src/quick3d/imports/extras/defaults/defaults.pri +++ b/src/quick3d/imports/extras/defaults/defaults.pri @@ -6,7 +6,6 @@ # To have the plugin register them as types, add an entries to the # qmldir array in qt3dquick3dextrasplugin.cpp QML_FILES = \ - $$PWD/qml/ForwardRenderer.qml \ $$PWD/qml/SkyboxEntity.qml \ $$PWD/qml/OrbitCameraController.qml \ $$PWD/qml/FirstPersonCameraController.qml \ diff --git a/src/quick3d/imports/extras/defaults/qml/ForwardRenderer.qml b/src/quick3d/imports/extras/defaults/qml/ForwardRenderer.qml deleted file mode 100644 index b7ad3188c..000000000 --- a/src/quick3d/imports/extras/defaults/qml/ForwardRenderer.qml +++ /dev/null @@ -1,77 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 Klaralvdalens Datakonsult AB (KDAB). -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt3D module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** 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-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import Qt3D.Core 2.0 -import Qt3D.Render 2.0 - -TechniqueFilter { - // Expose camera to allow user to choose which camera to use for rendering - property alias camera: cameraSelector.camera - property alias clearColor: clearBuffer.clearColor - property alias viewportRect: viewport.normalizedRect - property alias window: surfaceSelector.surface - property alias externalRenderTargetSize: surfaceSelector.externalRenderTargetSize - property alias frustumCulling: frustumCulling.enabled - - // Select the forward rendering Technique of any used Effect - matchAll: [ FilterKey { name: "renderingStyle"; value: "forward" } ] - - RenderSurfaceSelector { - id: surfaceSelector - - // Use the whole viewport - Viewport { - id: viewport - normalizedRect: Qt.rect(0.0, 0.0, 1.0, 1.0) - - // Use the specified camera - CameraSelector { - id : cameraSelector - FrustumCulling { - id: frustumCulling - ClearBuffers { - id: clearBuffer - clearColor: "white" - buffers : ClearBuffers.ColorDepthBuffer - } - } - } - } - } -} diff --git a/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp b/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp index d5a2e9c40..00e090e5a 100644 --- a/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp +++ b/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -72,8 +73,6 @@ static const struct { } qmldir [] = { // Scene Graph { "LevelOfDetailLoader", 2, 2 }, - // FrameGraphs - { "ForwardRenderer", 2, 0 }, // Entities { "SkyboxEntity", 2, 0 }, // Camera Controllers @@ -83,6 +82,9 @@ static const struct { void Qt3DQuick3DExtrasPlugin::registerTypes(const char *uri) { + // Framegraphs + qmlRegisterType(uri, 2, 0, "ForwardRenderer"); + // Materials qmlRegisterType(uri, 2, 0, "PhongMaterial"); qmlRegisterType(uri, 2, 0, "PhongAlphaMaterial"); -- cgit v1.2.3 From 4cea17da05a811215fd23dba8e11adcd00016a8f Mon Sep 17 00:00:00 2001 From: Kevin Ottens Date: Wed, 25 Jan 2017 15:05:19 +0100 Subject: Add missing properties to QSkyboxEntity Also adjust the signal name for baseName, looked like a missed API change. Change-Id: Ifc6074bfec79ec147bd3549f458f806865d93494 Reviewed-by: Sean Harmer --- src/extras/defaults/qskyboxentity.cpp | 2 +- src/extras/defaults/qskyboxentity.h | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/extras/defaults/qskyboxentity.cpp b/src/extras/defaults/qskyboxentity.cpp index 32e68e6fc..92c540189 100644 --- a/src/extras/defaults/qskyboxentity.cpp +++ b/src/extras/defaults/qskyboxentity.cpp @@ -232,7 +232,7 @@ void QSkyboxEntity::setBaseName(const QString &baseName) Q_D(QSkyboxEntity); if (baseName != d->m_baseName) { d->m_baseName = baseName; - emit sourceDirectoryChanged(baseName); + emit baseNameChanged(baseName); d->reloadTexture(); } } diff --git a/src/extras/defaults/qskyboxentity.h b/src/extras/defaults/qskyboxentity.h index a11d2f0a0..ca5cab6f2 100644 --- a/src/extras/defaults/qskyboxentity.h +++ b/src/extras/defaults/qskyboxentity.h @@ -52,6 +52,8 @@ class QSkyboxEntityPrivate; class QT3DEXTRASSHARED_EXPORT QSkyboxEntity : public Qt3DCore::QEntity { Q_OBJECT + Q_PROPERTY(QString baseName READ baseName WRITE setBaseName NOTIFY baseNameChanged) + Q_PROPERTY(QString extension READ extension WRITE setExtension NOTIFY extensionChanged) public: explicit QSkyboxEntity(Qt3DCore::QNode *parent = nullptr); ~QSkyboxEntity(); @@ -63,7 +65,7 @@ public: QString extension() const; Q_SIGNALS: - void sourceDirectoryChanged(const QString &path); + void baseNameChanged(const QString &path); void extensionChanged(const QString &extension); private: -- cgit v1.2.3 From 1ec4f98f8f0ef301220c01732a0cec268b4ecf29 Mon Sep 17 00:00:00 2001 From: Kevin Ottens Date: Wed, 25 Jan 2017 15:13:06 +0100 Subject: QSkyboxEntity: fix cubemap loading The mirroring needs to be disabled to have the same convention than the QML variant. Change-Id: I3ed933aa31fc235205507326ff667c8e0c348e10 Reviewed-by: Sean Harmer --- src/extras/defaults/qskyboxentity.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/extras/defaults/qskyboxentity.cpp b/src/extras/defaults/qskyboxentity.cpp index 92c540189..46c1a4743 100644 --- a/src/extras/defaults/qskyboxentity.cpp +++ b/src/extras/defaults/qskyboxentity.cpp @@ -151,11 +151,17 @@ void QSkyboxEntityPrivate::init() m_mesh->setYZMeshResolution(QSize(2, 2)); m_posXImage->setFace(QTextureCubeMap::CubeMapPositiveX); + m_posXImage->setMirrored(false); m_posYImage->setFace(QTextureCubeMap::CubeMapPositiveY); + m_posYImage->setMirrored(false); m_posZImage->setFace(QTextureCubeMap::CubeMapPositiveZ); + m_posZImage->setMirrored(false); m_negXImage->setFace(QTextureCubeMap::CubeMapNegativeX); + m_negXImage->setMirrored(false); m_negYImage->setFace(QTextureCubeMap::CubeMapNegativeY); + m_negYImage->setMirrored(false); m_negZImage->setFace(QTextureCubeMap::CubeMapNegativeZ); + m_negZImage->setMirrored(false); m_skyboxTexture->setMagnificationFilter(QTextureCubeMap::Linear); m_skyboxTexture->setMinificationFilter(QTextureCubeMap::Linear); -- cgit v1.2.3 From fbb3c3f59fdb7a60fdbf9590baf953920585957e Mon Sep 17 00:00:00 2001 From: Kevin Ottens Date: Wed, 25 Jan 2017 15:14:55 +0100 Subject: Replace SkyboxEntity.qml with QSkyboxEntity Now that they are the same, no need to keep the QML version Change-Id: I2d1fe32128397c604c62585fc043e6ac4aa82daf Reviewed-by: Sean Harmer --- src/quick3d/imports/extras/defaults/defaults.pri | 1 - .../imports/extras/defaults/qml/SkyboxEntity.qml | 151 --------------------- .../imports/extras/qt3dquick3dextrasplugin.cpp | 6 +- 3 files changed, 4 insertions(+), 154 deletions(-) delete mode 100644 src/quick3d/imports/extras/defaults/qml/SkyboxEntity.qml diff --git a/src/quick3d/imports/extras/defaults/defaults.pri b/src/quick3d/imports/extras/defaults/defaults.pri index 7179db854..57ef15f08 100644 --- a/src/quick3d/imports/extras/defaults/defaults.pri +++ b/src/quick3d/imports/extras/defaults/defaults.pri @@ -6,7 +6,6 @@ # To have the plugin register them as types, add an entries to the # qmldir array in qt3dquick3dextrasplugin.cpp QML_FILES = \ - $$PWD/qml/SkyboxEntity.qml \ $$PWD/qml/OrbitCameraController.qml \ $$PWD/qml/FirstPersonCameraController.qml \ $$PWD/qml/LevelOfDetailLoader.qml diff --git a/src/quick3d/imports/extras/defaults/qml/SkyboxEntity.qml b/src/quick3d/imports/extras/defaults/qml/SkyboxEntity.qml deleted file mode 100644 index 00bff6f10..000000000 --- a/src/quick3d/imports/extras/defaults/qml/SkyboxEntity.qml +++ /dev/null @@ -1,151 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 Klaralvdalens Datakonsult AB (KDAB). -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt3D module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** 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-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import Qt3D.Core 2.0 -import Qt3D.Render 2.0 -import Qt3D.Extras 2.0 - -Entity { - property string baseName: ""; - property string extension: ".png" - - property TextureCubeMap skyboxTexture: TextureCubeMap { - generateMipMaps: false - magnificationFilter: Texture.Linear - minificationFilter: Texture.Linear - wrapMode { - x: WrapMode.ClampToEdge - y: WrapMode.ClampToEdge - } - TextureImage { mirrored: false; face: Texture.CubeMapPositiveX; source: baseName + "_posx" + extension } - TextureImage { mirrored: false; face: Texture.CubeMapPositiveY; source: baseName + "_posy" + extension } - TextureImage { mirrored: false; face: Texture.CubeMapPositiveZ; source: baseName + "_posz" + extension } - TextureImage { mirrored: false; face: Texture.CubeMapNegativeX; source: baseName + "_negx" + extension } - TextureImage { mirrored: false; face: Texture.CubeMapNegativeY; source: baseName + "_negy" + extension } - TextureImage { mirrored: false; face: Texture.CubeMapNegativeZ; source: baseName + "_negz" + extension } - } - - ShaderProgram { - id: gl3SkyboxShader - vertexShaderCode: loadSource("qrc:/shaders/gl3/skybox.vert") - fragmentShaderCode: loadSource("qrc:/shaders/gl3/skybox.frag") - } - - ShaderProgram { - id: gl2es2SkyboxShader - vertexShaderCode: loadSource("qrc:/shaders/es2/skybox.vert") - fragmentShaderCode: loadSource("qrc:/shaders/es2/skybox.frag") - } - - CuboidMesh { - id: cuboidMesh - yzMeshResolution: Qt.size(2, 2) - xzMeshResolution: Qt.size(2, 2) - xyMeshResolution: Qt.size(2, 2) - } - - Material { - id: skyboxMaterial - parameters: Parameter { name: "skyboxTexture"; value: skyboxTexture} - - effect: Effect { - FilterKey { - id: forward - name: "renderingStyle" - value: "forward" - } - - techniques: [ - // GL3 Technique - Technique { - filterKeys: [ forward ] - graphicsApiFilter { - api: GraphicsApiFilter.OpenGL - profile: GraphicsApiFilter.CoreProfile - majorVersion: 3 - minorVersion: 1 - } - renderPasses: RenderPass { - shaderProgram: gl3SkyboxShader - renderStates: [ - // cull front faces - CullFace { mode: CullFace.Front }, - DepthTest { depthFunction: DepthTest.LessOrEqual } - ] - } - }, - Technique { - filterKeys: [ forward ] - graphicsApiFilter { - api: GraphicsApiFilter.OpenGL - profile: GraphicsApiFilter.NoProfile - majorVersion: 2 - minorVersion: 0 - } - renderPasses: RenderPass { - shaderProgram: gl2es2SkyboxShader - renderStates: [ - CullFace { mode: CullFace.Front }, - DepthTest { depthFunction: DepthTest.LessOrEqual } - ] - } - }, - Technique { - filterKeys: [ forward ] - graphicsApiFilter { - api: GraphicsApiFilter.OpenGLES - profile: GraphicsApiFilter.NoProfile - majorVersion: 2 - minorVersion: 0 - } - renderPasses: RenderPass { - shaderProgram: gl2es2SkyboxShader - renderStates: [ - CullFace { mode: CullFace.Front }, - DepthTest { depthFunction: DepthTest.LessOrEqual } - ] - } - } - ] - } - } - - components: [cuboidMesh, skyboxMaterial] -} - diff --git a/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp b/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp index 00e090e5a..998d94cbf 100644 --- a/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp +++ b/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp @@ -52,6 +52,7 @@ #include #include #include +#include #include #include #include @@ -73,8 +74,6 @@ static const struct { } qmldir [] = { // Scene Graph { "LevelOfDetailLoader", 2, 2 }, - // Entities - { "SkyboxEntity", 2, 0 }, // Camera Controllers { "OrbitCameraController", 2, 0 }, { "FirstPersonCameraController", 2, 0 }, @@ -85,6 +84,9 @@ void Qt3DQuick3DExtrasPlugin::registerTypes(const char *uri) // Framegraphs qmlRegisterType(uri, 2, 0, "ForwardRenderer"); + // Entities + qmlRegisterType(uri, 2, 0, "SkyboxEntity"); + // Materials qmlRegisterType(uri, 2, 0, "PhongMaterial"); qmlRegisterType(uri, 2, 0, "PhongAlphaMaterial"); -- cgit v1.2.3 From 633c2efcc5b7d6d4943985e9ea0a9b6ff90becbf Mon Sep 17 00:00:00 2001 From: Kevin Ottens Date: Wed, 25 Jan 2017 15:22:04 +0100 Subject: Remove OrbitCameraController.qml It completely duplicates QOrbitCameraController behavior, let's use it instead. Change-Id: I5fee3c16360461f2a918b0ec1428b3cc7f20ec04 Reviewed-by: Sean Harmer --- src/quick3d/imports/extras/defaults/defaults.pri | 1 - .../extras/defaults/qml/OrbitCameraController.qml | 236 --------------------- .../imports/extras/qt3dquick3dextrasplugin.cpp | 5 +- 3 files changed, 4 insertions(+), 238 deletions(-) delete mode 100644 src/quick3d/imports/extras/defaults/qml/OrbitCameraController.qml diff --git a/src/quick3d/imports/extras/defaults/defaults.pri b/src/quick3d/imports/extras/defaults/defaults.pri index 57ef15f08..464c0ce6a 100644 --- a/src/quick3d/imports/extras/defaults/defaults.pri +++ b/src/quick3d/imports/extras/defaults/defaults.pri @@ -6,6 +6,5 @@ # To have the plugin register them as types, add an entries to the # qmldir array in qt3dquick3dextrasplugin.cpp QML_FILES = \ - $$PWD/qml/OrbitCameraController.qml \ $$PWD/qml/FirstPersonCameraController.qml \ $$PWD/qml/LevelOfDetailLoader.qml diff --git a/src/quick3d/imports/extras/defaults/qml/OrbitCameraController.qml b/src/quick3d/imports/extras/defaults/qml/OrbitCameraController.qml deleted file mode 100644 index ae8869473..000000000 --- a/src/quick3d/imports/extras/defaults/qml/OrbitCameraController.qml +++ /dev/null @@ -1,236 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 Paul Lemire -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt3D module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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. -** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import Qt3D.Core 2.0 -import Qt3D.Render 2.0 -import Qt3D.Input 2.0 -import Qt3D.Logic 2.0 -import QtQml 2.2 - -Entity { - id: root - property Camera camera - property real linearSpeed: 10.0 - property real lookSpeed: 180.0 - property real zoomLimit: 2.0 - - QtObject { - id: d - readonly property vector3d firstPersonUp: Qt.vector3d(0, 1, 0) - readonly property bool leftMouseButtonPressed: leftMouseButtonAction.active - readonly property bool rightMouseButtonPressed: rightMouseButtonAction.active - readonly property bool shiftPressed: shiftAction.active - readonly property bool altPressed: altAction.active - property real translationX: clampInputs(leftMouseButtonPressed ? mouseXAxis.value : 0, keyboardXAxis.value) * linearSpeed; - property real translationY: clampInputs(leftMouseButtonPressed ? mouseYAxis.value : 0, keyboardYAxis.value) * linearSpeed; - property real translationZ: keyboardZAxis.value * linearSpeed; - property real orbitX: clampInputs(rightMouseButtonPressed ? mouseXAxis.value : 0, keyboardXAxis.value) * lookSpeed; - property real orbitY: clampInputs(rightMouseButtonPressed ? mouseYAxis.value : 0, keyboardYAxis.value) * lookSpeed; - } - - function clampInputs(input1, input2) { - var axisValue = input1 + input2; - return (axisValue < -1) ? -1 : (axisValue > 1) ? 1 : axisValue; - } - - function zoomDistance(firstPoint, secondPoint) { - var u = secondPoint.minus(firstPoint); u = u.times(u); - return u.x + u.y + u.z; - } - - KeyboardDevice { - id: keyboardSourceDevice - } - - MouseDevice { - id: mouseSourceDevice - sensitivity: 0.1 - } - - components: [ - - LogicalDevice { - enabled: root.enabled - actions: [ - Action { - id: leftMouseButtonAction - ActionInput { - sourceDevice: mouseSourceDevice - buttons: [MouseEvent.LeftButton] - } - }, - Action { - id: rightMouseButtonAction - ActionInput { - sourceDevice: mouseSourceDevice - buttons: [MouseEvent.RightButton] - } - }, - Action { - id: shiftAction - ActionInput { - sourceDevice: keyboardSourceDevice - buttons: [Qt.Key_Shift] - } - }, - Action { - id: altAction - ActionInput { - sourceDevice: keyboardSourceDevice - buttons: [Qt.Key_Alt] - } - } - ] // actions - - axes: [ - // Mouse - Axis { - id: mouseXAxis - AnalogAxisInput { - sourceDevice: mouseSourceDevice - axis: MouseDevice.X - } - }, - Axis { - id: mouseYAxis - AnalogAxisInput { - sourceDevice: mouseSourceDevice - axis: MouseDevice.Y - } - }, - // Keyboard - Axis { - id: keyboardXAxis - ButtonAxisInput { - sourceDevice: keyboardSourceDevice - buttons: [Qt.Key_Left] - scale: -1.0 - } - ButtonAxisInput { - sourceDevice: keyboardSourceDevice - buttons: [Qt.Key_Right] - scale: 1.0 - } - }, - Axis { - id: keyboardZAxis - ButtonAxisInput { - sourceDevice: keyboardSourceDevice - buttons: [Qt.Key_PageUp] - scale: 1.0 - } - ButtonAxisInput { - sourceDevice: keyboardSourceDevice - buttons: [Qt.Key_PageDown] - scale: -1.0 - } - }, - Axis { - id: keyboardYAxis - ButtonAxisInput { - sourceDevice: keyboardSourceDevice - buttons: [Qt.Key_Up] - scale: 1.0 - } - ButtonAxisInput { - sourceDevice: keyboardSourceDevice - buttons: [Qt.Key_Down] - scale: -1.0 - } - } - ] // axes - }, - - FrameAction { - onTriggered: { - // The time difference since the last frame is passed in as the - // argument dt. It is a floating point value in units of seconds. - - // Mouse input - if (d.leftMouseButtonPressed) { - if (d.rightMouseButtonPressed) { - if (zoomDistance(root.camera.position, root.camera.viewCenter) > root.zoomLimit * root.zoomLimit) { - // Dolly up to limit - root.camera.translate(Qt.vector3d(0, 0, d.translationY).times(dt), Camera.DontTranslateViewCenter); - } else { - // Too close, Dolly backwards - root.camera.translate(Qt.vector3d(0, 0, -1).times(dt), Camera.DontTranslateViewCenter); - } - } else { - // Translate - root.camera.translate(Qt.vector3d(d.translationX, d.translationY, 0).times(dt)); - } - return - } else if (d.rightMouseButtonPressed) { - // Orbit - root.camera.panAboutViewCenter(d.orbitX * dt, d.firstPersonUp); - root.camera.tiltAboutViewCenter(d.orbitY * dt); - } - // Keyboard input - if (d.altPressed) { - // Orbit - root.camera.panAboutViewCenter(d.orbitX * dt, d.firstPersonUp); - root.camera.tiltAboutViewCenter(d.orbitY * dt); - } else if (d.shiftPressed) { - if (zoomDistance(root.camera.position, root.camera.viewCenter) > root.zoomLimit * root.zoomLimit) { - // Dolly up to limit - root.camera.translate(Qt.vector3d(0, 0, d.translationY).times(dt), Camera.DontTranslateViewCenter); - } else { - // Too close, Dolly backwards - root.camera.translate(Qt.vector3d(0, 0, -1).times(dt), Camera.DontTranslateViewCenter); - } - } else { - // Translate - root.camera.translate(Qt.vector3d(d.translationX, d.translationY, d.translationZ).times(dt)); - } - } - } - ] // components -} diff --git a/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp b/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp index 998d94cbf..c6223adf2 100644 --- a/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp +++ b/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp @@ -48,6 +48,7 @@ #include #include #include +#include #include #include #include @@ -75,7 +76,6 @@ static const struct { // Scene Graph { "LevelOfDetailLoader", 2, 2 }, // Camera Controllers - { "OrbitCameraController", 2, 0 }, { "FirstPersonCameraController", 2, 0 }, }; @@ -87,6 +87,9 @@ void Qt3DQuick3DExtrasPlugin::registerTypes(const char *uri) // Entities qmlRegisterType(uri, 2, 0, "SkyboxEntity"); + // Camera Controllers + qmlRegisterType(uri, 2, 0, "OrbitCameraController"); + // Materials qmlRegisterType(uri, 2, 0, "PhongMaterial"); qmlRegisterType(uri, 2, 0, "PhongAlphaMaterial"); -- cgit v1.2.3 From 3a895576bf188e15d5ff03e704e192a87d4c16a0 Mon Sep 17 00:00:00 2001 From: Kevin Ottens Date: Wed, 25 Jan 2017 15:40:47 +0100 Subject: Add (ac|de)celeration to QFirstPersonCameraController Those two properties were added to the QML variant but not the C++ one. Let's fix this. Change-Id: Ibd0765993f42a7562bd922f2db5456c1fa6d6ad1 Reviewed-by: Sean Harmer --- .../defaults/qfirstpersoncameracontroller.cpp | 63 ++++++++++++++++++++++ src/extras/defaults/qfirstpersoncameracontroller.h | 9 +++- .../defaults/qfirstpersoncameracontroller_p.h | 3 ++ .../tst_qfirstpersoncameracontroller.cpp | 40 ++++++++++++++ 4 files changed, 114 insertions(+), 1 deletion(-) diff --git a/src/extras/defaults/qfirstpersoncameracontroller.cpp b/src/extras/defaults/qfirstpersoncameracontroller.cpp index e31448eb8..c9ca34900 100644 --- a/src/extras/defaults/qfirstpersoncameracontroller.cpp +++ b/src/extras/defaults/qfirstpersoncameracontroller.cpp @@ -92,6 +92,8 @@ QFirstPersonCameraControllerPrivate::QFirstPersonCameraControllerPrivate() , m_frameAction(new Qt3DLogic::QFrameAction()) , m_linearSpeed(10.0f) , m_lookSpeed(180.0f) + , m_acceleration(-1.0f) + , m_deceleration(-1.0f) , m_firstPersonUp(QVector3D(0.0f, 1.0f, 0.0f)) {} @@ -167,6 +169,8 @@ void QFirstPersonCameraControllerPrivate::init() m_logicalDevice->addAxis(m_tyAxis); m_logicalDevice->addAxis(m_tzAxis); + applyAccelerations(); + Q_Q(QFirstPersonCameraController); //// FrameAction @@ -181,6 +185,23 @@ void QFirstPersonCameraControllerPrivate::init() q->addComponent(m_logicalDevice); } +void QFirstPersonCameraControllerPrivate::applyAccelerations() +{ + const auto inputs = { + m_keyboardTxPosInput, + m_keyboardTyPosInput, + m_keyboardTzPosInput, + m_keyboardTxNegInput, + m_keyboardTyNegInput, + m_keyboardTzNegInput + }; + + for (auto input : inputs) { + input->setAcceleration(m_acceleration); + input->setDeceleration(m_deceleration); + } +} + void QFirstPersonCameraControllerPrivate::_q_onTriggered(float dt) { if (m_camera != nullptr) { @@ -273,6 +294,28 @@ float QFirstPersonCameraController::lookSpeed() const return d->m_lookSpeed; } +/*! + \property QFirstPersonCameraController::acceleration + + Holds the current acceleration of the camera controller. +*/ +float QFirstPersonCameraController::acceleration() const +{ + Q_D(const QFirstPersonCameraController); + return d->m_acceleration; +} + +/*! + \property QFirstPersonCameraController::deceleration + + Holds the current deceleration of the camera controller. +*/ +float QFirstPersonCameraController::deceleration() const +{ + Q_D(const QFirstPersonCameraController); + return d->m_deceleration; +} + void QFirstPersonCameraController::setCamera(Qt3DRender::QCamera *camera) { Q_D(QFirstPersonCameraController); @@ -312,6 +355,26 @@ void QFirstPersonCameraController::setLookSpeed(float lookSpeed) } } +void QFirstPersonCameraController::setAcceleration(float acceleration) +{ + Q_D(QFirstPersonCameraController); + if (d->m_acceleration != acceleration) { + d->m_acceleration = acceleration; + d->applyAccelerations(); + emit accelerationChanged(); + } +} + +void QFirstPersonCameraController::setDeceleration(float deceleration) +{ + Q_D(QFirstPersonCameraController); + if (d->m_deceleration != deceleration) { + d->m_deceleration = deceleration; + d->applyAccelerations(); + emit decelerationChanged(); + } +} + } // Qt3DExtras QT_END_NAMESPACE diff --git a/src/extras/defaults/qfirstpersoncameracontroller.h b/src/extras/defaults/qfirstpersoncameracontroller.h index e50d4db5a..0c72d5513 100644 --- a/src/extras/defaults/qfirstpersoncameracontroller.h +++ b/src/extras/defaults/qfirstpersoncameracontroller.h @@ -70,7 +70,8 @@ class QT3DEXTRASSHARED_EXPORT QFirstPersonCameraController : public Qt3DCore::QE Q_PROPERTY(Qt3DRender::QCamera *camera READ camera WRITE setCamera NOTIFY cameraChanged) Q_PROPERTY(float linearSpeed READ linearSpeed WRITE setLinearSpeed NOTIFY linearSpeedChanged) Q_PROPERTY(float lookSpeed READ lookSpeed WRITE setLookSpeed NOTIFY lookSpeedChanged) - + Q_PROPERTY(float acceleration READ acceleration WRITE setAcceleration NOTIFY accelerationChanged) + Q_PROPERTY(float deceleration READ deceleration WRITE setDeceleration NOTIFY decelerationChanged) public: explicit QFirstPersonCameraController(Qt3DCore::QNode *parent = nullptr); ~QFirstPersonCameraController(); @@ -78,15 +79,21 @@ public: Qt3DRender::QCamera *camera() const; float linearSpeed() const; float lookSpeed() const; + float acceleration() const; + float deceleration() const; void setCamera(Qt3DRender::QCamera *camera); void setLinearSpeed(float linearSpeed); void setLookSpeed(float lookSpeed); + void setAcceleration(float acceleration); + void setDeceleration(float deceleration); Q_SIGNALS: void cameraChanged(); void linearSpeedChanged(); void lookSpeedChanged(); + void accelerationChanged(); + void decelerationChanged(); private: Q_DECLARE_PRIVATE(QFirstPersonCameraController) diff --git a/src/extras/defaults/qfirstpersoncameracontroller_p.h b/src/extras/defaults/qfirstpersoncameracontroller_p.h index 9ea830f85..a4f4fc5f9 100644 --- a/src/extras/defaults/qfirstpersoncameracontroller_p.h +++ b/src/extras/defaults/qfirstpersoncameracontroller_p.h @@ -98,6 +98,7 @@ public: QFirstPersonCameraControllerPrivate(); void init(); + void applyAccelerations(); Qt3DRender::QCamera *m_camera; @@ -131,6 +132,8 @@ public: float m_linearSpeed; float m_lookSpeed; + float m_acceleration; + float m_deceleration; QVector3D m_firstPersonUp; void _q_onTriggered(float); diff --git a/tests/auto/extras/qfirstpersoncameracontroller/tst_qfirstpersoncameracontroller.cpp b/tests/auto/extras/qfirstpersoncameracontroller/tst_qfirstpersoncameracontroller.cpp index 22046051b..2cf4d7ba2 100644 --- a/tests/auto/extras/qfirstpersoncameracontroller/tst_qfirstpersoncameracontroller.cpp +++ b/tests/auto/extras/qfirstpersoncameracontroller/tst_qfirstpersoncameracontroller.cpp @@ -48,6 +48,8 @@ private Q_SLOTS: QVERIFY(firstPersonCameraController.camera() == nullptr); QCOMPARE(firstPersonCameraController.linearSpeed(), 10.0f); QCOMPARE(firstPersonCameraController.lookSpeed(), 180.0f); + QCOMPARE(firstPersonCameraController.acceleration(), -1.0f); + QCOMPARE(firstPersonCameraController.deceleration(), -1.0f); } void checkPropertyChanges() @@ -120,6 +122,44 @@ private Q_SLOTS: QCOMPARE(spy.count(), 0); } + { + // WHEN + QSignalSpy spy(&firstPersonCameraController, SIGNAL(accelerationChanged())); + const float newValue = 0.001f; + firstPersonCameraController.setAcceleration(newValue); + + // THEN + QCOMPARE(firstPersonCameraController.acceleration(), newValue); + QCOMPARE(spy.count(), 1); + + // WHEN + spy.clear(); + firstPersonCameraController.setAcceleration(newValue); + + // THEN + QCOMPARE(firstPersonCameraController.acceleration(), newValue); + QCOMPARE(spy.count(), 0); + + } + { + // WHEN + QSignalSpy spy(&firstPersonCameraController, SIGNAL(decelerationChanged())); + const float newValue = 0.001f; + firstPersonCameraController.setDeceleration(newValue); + + // THEN + QCOMPARE(firstPersonCameraController.deceleration(), newValue); + QCOMPARE(spy.count(), 1); + + // WHEN + spy.clear(); + firstPersonCameraController.setDeceleration(newValue); + + // THEN + QCOMPARE(firstPersonCameraController.deceleration(), newValue); + QCOMPARE(spy.count(), 0); + + } } }; -- cgit v1.2.3 From 29d4516223a5b7850956bee9a225bfc35a5604cf Mon Sep 17 00:00:00 2001 From: Kevin Ottens Date: Wed, 25 Jan 2017 15:46:10 +0100 Subject: Remove FirstPersonCameraController.qml It completely duplicates QFirstPersonCameraController behavior, let's use it instead. Change-Id: Ie036ff5c1b8352ac23211d1bb628efd1a5e8032c Reviewed-by: Sean Harmer --- src/quick3d/imports/extras/defaults/defaults.pri | 1 - .../defaults/qml/FirstPersonCameraController.qml | 191 --------------------- .../imports/extras/qt3dquick3dextrasplugin.cpp | 4 +- 3 files changed, 2 insertions(+), 194 deletions(-) delete mode 100644 src/quick3d/imports/extras/defaults/qml/FirstPersonCameraController.qml diff --git a/src/quick3d/imports/extras/defaults/defaults.pri b/src/quick3d/imports/extras/defaults/defaults.pri index 464c0ce6a..26a0bb707 100644 --- a/src/quick3d/imports/extras/defaults/defaults.pri +++ b/src/quick3d/imports/extras/defaults/defaults.pri @@ -6,5 +6,4 @@ # To have the plugin register them as types, add an entries to the # qmldir array in qt3dquick3dextrasplugin.cpp QML_FILES = \ - $$PWD/qml/FirstPersonCameraController.qml \ $$PWD/qml/LevelOfDetailLoader.qml diff --git a/src/quick3d/imports/extras/defaults/qml/FirstPersonCameraController.qml b/src/quick3d/imports/extras/defaults/qml/FirstPersonCameraController.qml deleted file mode 100644 index 1003c0ea0..000000000 --- a/src/quick3d/imports/extras/defaults/qml/FirstPersonCameraController.qml +++ /dev/null @@ -1,191 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 Paul Lemire -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt3D module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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. -** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import Qt3D.Core 2.0 -import Qt3D.Render 2.0 -import Qt3D.Input 2.0 -import Qt3D.Logic 2.0 -import QtQml 2.2 - -Entity { - id: root - property Camera camera - property real linearSpeed: 10.0 - property real lookSpeed: 180.0 - property real acceleration: -1.0 - property real deceleration: -1.0 - - QtObject { - id: d - readonly property vector3d firstPersonUp: Qt.vector3d(0, 1, 0) - readonly property bool leftMouseButtonPressed: leftMouseButtonAction.active - readonly property real vx: txAxis.value * linearSpeed; - readonly property real vy: tyAxis.value * linearSpeed; - readonly property real vz: tzAxis.value * linearSpeed; - readonly property real dx: rxAxis.value * lookSpeed - readonly property real dy: ryAxis.value * lookSpeed - readonly property bool fineMotion: fineMotionAction.active - } - - KeyboardDevice { - id: keyboardSourceDevice - } - - MouseDevice { - id: mouseSourceDevice - sensitivity: d.fineMotion ? 0.01 : 0.1 - } - - components: [ - - LogicalDevice { - enabled: root.enabled - actions: [ - Action { - id: leftMouseButtonAction - ActionInput { - sourceDevice: mouseSourceDevice - buttons: [MouseEvent.LeftButton] - } - }, - Action { - id: fineMotionAction - ActionInput { - sourceDevice: keyboardSourceDevice - buttons: [Qt.Key_Shift] - } - } - ] // actions - - axes: [ - // Rotation - Axis { - id: rxAxis - AnalogAxisInput { - sourceDevice: mouseSourceDevice - axis: MouseDevice.X - } - }, - Axis { - id: ryAxis - AnalogAxisInput { - sourceDevice: mouseSourceDevice - axis: MouseDevice.Y - } - }, - // Translation - Axis { - id: txAxis - ButtonAxisInput { - sourceDevice: keyboardSourceDevice - buttons: [Qt.Key_Left] - scale: -1.0 - acceleration: root.acceleration - deceleration: root.deceleration - } - ButtonAxisInput { - sourceDevice: keyboardSourceDevice - buttons: [Qt.Key_Right] - scale: 1.0 - acceleration: root.acceleration - deceleration: root.deceleration - } - }, - Axis { - id: tzAxis - ButtonAxisInput { - sourceDevice: keyboardSourceDevice - buttons: [Qt.Key_Up] - scale: 1.0 - acceleration: root.acceleration - deceleration: root.deceleration - } - ButtonAxisInput { - sourceDevice: keyboardSourceDevice - buttons: [Qt.Key_Down] - scale: -1.0 - acceleration: root.acceleration - deceleration: root.deceleration - } - }, - Axis { - id: tyAxis - ButtonAxisInput { - sourceDevice: keyboardSourceDevice - buttons: [Qt.Key_PageUp] - scale: 1.0 - acceleration: root.acceleration - deceleration: root.deceleration - } - ButtonAxisInput { - sourceDevice: keyboardSourceDevice - buttons: [Qt.Key_PageDown] - scale: -1.0 - acceleration: root.acceleration - deceleration: root.deceleration - } - } - ] // axes - }, - - FrameAction { - onTriggered: { - // The time difference since the last frame is passed in as the - // argument dt. It is a floating point value in units of seconds. - root.camera.translate(Qt.vector3d(d.vx, d.vy, d.vz).times(dt)) - - if (d.leftMouseButtonPressed) { - root.camera.pan(d.dx * dt, d.firstPersonUp) - root.camera.tilt(d.dy * dt) - } - } - } - ] // components -} diff --git a/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp b/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp index c6223adf2..94aab4fac 100644 --- a/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp +++ b/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -75,8 +76,6 @@ static const struct { } qmldir [] = { // Scene Graph { "LevelOfDetailLoader", 2, 2 }, - // Camera Controllers - { "FirstPersonCameraController", 2, 0 }, }; void Qt3DQuick3DExtrasPlugin::registerTypes(const char *uri) @@ -88,6 +87,7 @@ void Qt3DQuick3DExtrasPlugin::registerTypes(const char *uri) qmlRegisterType(uri, 2, 0, "SkyboxEntity"); // Camera Controllers + qmlRegisterType(uri, 2, 0, "FirstPersonCameraController"); qmlRegisterType(uri, 2, 0, "OrbitCameraController"); // Materials -- cgit v1.2.3 From bb2e0a0685c5e727faa987dc8b69ee195b029ce1 Mon Sep 17 00:00:00 2001 From: Kevin Ottens Date: Thu, 26 Jan 2017 17:35:04 +0100 Subject: Allow Quick3DEntityLoader to work when created from C++ For that we try harder at finding the QML engine. If it's not known to the Quick3DEntityLoader instance, we climb up the parent/child relationship to find an object associated to the engine and we get the loader to work from there. In practice will be useful for LevelOfDetailLoader in the next commit. Change-Id: I64ab709d25e8edbecc3662eb96f5d92f99f1b13e Reviewed-by: Sean Harmer --- src/quick3d/quick3d/items/quick3dentityloader.cpp | 39 ++++++++++++++++++++--- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/src/quick3d/quick3d/items/quick3dentityloader.cpp b/src/quick3d/quick3d/items/quick3dentityloader.cpp index 9bc9d9d28..c978e22cb 100644 --- a/src/quick3d/quick3d/items/quick3dentityloader.cpp +++ b/src/quick3d/quick3d/items/quick3dentityloader.cpp @@ -50,6 +50,32 @@ QT_BEGIN_NAMESPACE namespace Qt3DCore { namespace Quick { +namespace { +struct Quick3DQmlOwner +{ + Quick3DQmlOwner(QQmlEngine *e, QObject *o) + : engine(e) + , object(o) + {} + + QQmlEngine *engine; + QObject *object; + + QQmlContext *context() const + { + return engine->contextForObject(object); + } +}; + +Quick3DQmlOwner _q_findQmlOwner(QObject *object) +{ + auto o = object; + while (!qmlEngine(o) && o->parent()) + o = o->parent(); + return Quick3DQmlOwner(qmlEngine(o), o); +} +} + class Quick3DEntityLoaderIncubator : public QQmlIncubator { public: @@ -81,7 +107,7 @@ protected: } case Error: { - QQmlEnginePrivate::warning(qmlEngine(m_loader), errors()); + QQmlEnginePrivate::warning(_q_findQmlOwner(m_loader).engine, errors()); priv->clear(); emit m_loader->entityChanged(); priv->setStatus(Quick3DEntityLoader::Error); @@ -238,7 +264,8 @@ void Quick3DEntityLoaderPrivate::loadComponent(const QUrl &source) Q_ASSERT(m_component == nullptr); Q_ASSERT(m_context == nullptr); - m_component = new QQmlComponent(qmlEngine(q), q); + auto owner = _q_findQmlOwner(q); + m_component = new QQmlComponent(owner.engine, owner.object); QObject::connect(m_component, SIGNAL(statusChanged(QQmlComponent::Status)), q, SLOT(_q_componentStatusChanged(QQmlComponent::Status))); m_component->loadUrl(source, QQmlComponent::Asynchronous); @@ -253,8 +280,10 @@ void Quick3DEntityLoaderPrivate::_q_componentStatusChanged(QQmlComponent::Status Q_ASSERT(m_context == nullptr); Q_ASSERT(m_incubator == nullptr); + auto owner = _q_findQmlOwner(q); + if (!m_component->errors().isEmpty()) { - QQmlEnginePrivate::warning(qmlEngine(q), m_component->errors()); + QQmlEnginePrivate::warning(owner.engine, m_component->errors()); clear(); emit q->entityChanged(); return; @@ -264,8 +293,8 @@ void Quick3DEntityLoaderPrivate::_q_componentStatusChanged(QQmlComponent::Status if (status != QQmlComponent::Ready) return; - m_context = new QQmlContext(qmlContext(q)); - m_context->setContextObject(q); + m_context = new QQmlContext(owner.context()); + m_context->setContextObject(owner.object); m_incubator = new Quick3DEntityLoaderIncubator(q); m_component->create(*m_incubator, m_context); -- cgit v1.2.3 From a110e49dad9179e3cb8f1c0a4399e6a37104c194 Mon Sep 17 00:00:00 2001 From: Kevin Ottens Date: Thu, 26 Jan 2017 17:34:16 +0100 Subject: Port LevelOfDetailLoader to a C++ implementation tests/manual/lod still works after the port Change-Id: Idee18aa68724f726789bd74044a989c883dae579 Reviewed-by: Sean Harmer --- src/quick3d/imports/extras/defaults/defaults.pri | 3 +- .../extras/defaults/qml/LevelOfDetailLoader.qml | 80 --------- src/quick3d/imports/extras/importsextras.pro | 2 +- .../imports/extras/qt3dquick3dextrasplugin.cpp | 6 +- src/quick3d/quick3dextras/items/items.pri | 8 + .../items/quick3dlevelofdetailloader.cpp | 189 +++++++++++++++++++++ .../items/quick3dlevelofdetailloader_p.h | 119 +++++++++++++ .../items/quick3dlevelofdetailloader_p_p.h | 87 ++++++++++ .../quick3dextras/qt3dquickextras_global_p.h | 63 +++++++ src/quick3d/quick3dextras/quick3dextras.pro | 5 +- 10 files changed, 476 insertions(+), 86 deletions(-) delete mode 100644 src/quick3d/imports/extras/defaults/qml/LevelOfDetailLoader.qml create mode 100644 src/quick3d/quick3dextras/items/items.pri create mode 100644 src/quick3d/quick3dextras/items/quick3dlevelofdetailloader.cpp create mode 100644 src/quick3d/quick3dextras/items/quick3dlevelofdetailloader_p.h create mode 100644 src/quick3d/quick3dextras/items/quick3dlevelofdetailloader_p_p.h create mode 100644 src/quick3d/quick3dextras/qt3dquickextras_global_p.h diff --git a/src/quick3d/imports/extras/defaults/defaults.pri b/src/quick3d/imports/extras/defaults/defaults.pri index 26a0bb707..27d439e93 100644 --- a/src/quick3d/imports/extras/defaults/defaults.pri +++ b/src/quick3d/imports/extras/defaults/defaults.pri @@ -5,5 +5,4 @@ # # To have the plugin register them as types, add an entries to the # qmldir array in qt3dquick3dextrasplugin.cpp -QML_FILES = \ - $$PWD/qml/LevelOfDetailLoader.qml +QML_FILES = diff --git a/src/quick3d/imports/extras/defaults/qml/LevelOfDetailLoader.qml b/src/quick3d/imports/extras/defaults/qml/LevelOfDetailLoader.qml deleted file mode 100644 index 83655a7bc..000000000 --- a/src/quick3d/imports/extras/defaults/qml/LevelOfDetailLoader.qml +++ /dev/null @@ -1,80 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt3D module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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. -** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import Qt3D.Core 2.0 -import Qt3D.Render 2.2 - -Entity { - id:root - - property var sources: [] - readonly property alias entity: loader.entity - readonly property alias source: loader.source - - property alias camera: lod.camera - property alias currentIndex: lod.currentIndex - property alias thresholdType: lod.thresholdType - property alias thresholds: lod.thresholds - property alias volumeOverride: lod.volumeOverride - - EntityLoader { - id: loader - components: [ - LevelOfDetail { - id: lod - enabled: root.enabled - currentIndex: -1 - onCurrentIndexChanged: if (currentIndex >= 0 && currentIndex < root.sources.length) - loader.source = root.sources[currentIndex] - } - ] - } -} - diff --git a/src/quick3d/imports/extras/importsextras.pro b/src/quick3d/imports/extras/importsextras.pro index acc993fa7..3b6735572 100644 --- a/src/quick3d/imports/extras/importsextras.pro +++ b/src/quick3d/imports/extras/importsextras.pro @@ -3,7 +3,7 @@ TARGET = quick3dextrasplugin TARGETPATH = Qt3D/Extras IMPORT_VERSION = 2.0 -QT += core-private qml qml-private quick quick-private 3dcore 3dcore-private 3dquick 3dquick-private 3dextras 3dlogic +QT += core-private qml qml-private quick quick-private 3dcore 3dcore-private 3dquick 3dquick-private 3dextras 3dquickextras-private 3dlogic # Qt3D is free of Q_FOREACH - make sure it stays that way: DEFINES += QT_NO_FOREACH diff --git a/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp b/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp index 94aab4fac..ed98ae407 100644 --- a/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp +++ b/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp @@ -66,6 +66,9 @@ #include #include #include + +#include + #include QT_BEGIN_NAMESPACE @@ -74,8 +77,6 @@ static const struct { const char *type; int major, minor; } qmldir [] = { - // Scene Graph - { "LevelOfDetailLoader", 2, 2 }, }; void Qt3DQuick3DExtrasPlugin::registerTypes(const char *uri) @@ -85,6 +86,7 @@ void Qt3DQuick3DExtrasPlugin::registerTypes(const char *uri) // Entities qmlRegisterType(uri, 2, 0, "SkyboxEntity"); + qmlRegisterType(uri, 2, 2, "LevelOfDetailLoader"); // Camera Controllers qmlRegisterType(uri, 2, 0, "FirstPersonCameraController"); diff --git a/src/quick3d/quick3dextras/items/items.pri b/src/quick3d/quick3dextras/items/items.pri new file mode 100644 index 000000000..b6f5d1877 --- /dev/null +++ b/src/quick3d/quick3dextras/items/items.pri @@ -0,0 +1,8 @@ +HEADERS += \ + $$PWD/quick3dlevelofdetailloader_p.h \ + $$PWD/quick3dlevelofdetailloader_p_p.h + +SOURCES += \ + $$PWD/quick3dlevelofdetailloader.cpp + +INCLUDEPATH += $$PWD diff --git a/src/quick3d/quick3dextras/items/quick3dlevelofdetailloader.cpp b/src/quick3d/quick3dextras/items/quick3dlevelofdetailloader.cpp new file mode 100644 index 000000000..f3d3f4323 --- /dev/null +++ b/src/quick3d/quick3dextras/items/quick3dlevelofdetailloader.cpp @@ -0,0 +1,189 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "quick3dlevelofdetailloader_p_p.h" +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DExtras { +namespace Extras { +namespace Quick { + +Quick3DLevelOfDetailLoaderPrivate::Quick3DLevelOfDetailLoaderPrivate() + : QEntityPrivate() + , m_loader(new Qt3DCore::Quick::Quick3DEntityLoader) + , m_lod(new Qt3DRender::QLevelOfDetail) +{ +} + +Quick3DLevelOfDetailLoader::Quick3DLevelOfDetailLoader(QNode *parent) + : QEntity(*new Quick3DLevelOfDetailLoaderPrivate, parent) +{ + Q_D(Quick3DLevelOfDetailLoader); + d->m_loader->setParent(this); + d->m_loader->addComponent(d->m_lod); + + connect(d->m_lod, &Qt3DRender::QLevelOfDetail::cameraChanged, + this, &Quick3DLevelOfDetailLoader::cameraChanged); + connect(d->m_lod, &Qt3DRender::QLevelOfDetail::currentIndexChanged, + this, &Quick3DLevelOfDetailLoader::currentIndexChanged); + connect(d->m_lod, &Qt3DRender::QLevelOfDetail::thresholdTypeChanged, + this, &Quick3DLevelOfDetailLoader::thresholdTypeChanged); + connect(d->m_lod, &Qt3DRender::QLevelOfDetail::thresholdsChanged, + this, &Quick3DLevelOfDetailLoader::thresholdsChanged); + connect(d->m_lod, &Qt3DRender::QLevelOfDetail::volumeOverrideChanged, + this, &Quick3DLevelOfDetailLoader::volumeOverrideChanged); + connect(d->m_loader, &Qt3DCore::Quick::Quick3DEntityLoader::entityChanged, + this, &Quick3DLevelOfDetailLoader::entityChanged); + connect(d->m_loader, &Qt3DCore::Quick::Quick3DEntityLoader::sourceChanged, + this, &Quick3DLevelOfDetailLoader::sourceChanged); + + connect(this, &Quick3DLevelOfDetailLoader::enabledChanged, + d->m_lod, &Qt3DRender::QLevelOfDetail::setEnabled); + + auto applyCurrentSource = [this] { + Q_D(Quick3DLevelOfDetailLoader); + const auto index = currentIndex(); + if (index >= 0 && index < d->m_sources.size()) + d->m_loader->setSource(d->m_sources.at(index).toUrl()); + }; + + connect(this, &Quick3DLevelOfDetailLoader::sourcesChanged, + this, applyCurrentSource); + connect(this, &Quick3DLevelOfDetailLoader::currentIndexChanged, + this, applyCurrentSource); +} + +QVariantList Quick3DLevelOfDetailLoader::sources() const +{ + Q_D(const Quick3DLevelOfDetailLoader); + return d->m_sources; +} + +void Quick3DLevelOfDetailLoader::setSources(const QVariantList &sources) +{ + Q_D(Quick3DLevelOfDetailLoader); + if (d->m_sources != sources) { + d->m_sources = sources; + emit sourcesChanged(); + } +} + +Qt3DRender::QCamera *Quick3DLevelOfDetailLoader::camera() const +{ + Q_D(const Quick3DLevelOfDetailLoader); + return d->m_lod->camera(); +} + +void Quick3DLevelOfDetailLoader::setCamera(Qt3DRender::QCamera *camera) +{ + Q_D(Quick3DLevelOfDetailLoader); + d->m_lod->setCamera(camera); +} + +int Quick3DLevelOfDetailLoader::currentIndex() const +{ + Q_D(const Quick3DLevelOfDetailLoader); + return d->m_lod->currentIndex(); +} + +void Quick3DLevelOfDetailLoader::setCurrentIndex(int currentIndex) +{ + Q_D(Quick3DLevelOfDetailLoader); + d->m_lod->setCurrentIndex(currentIndex); +} + +Qt3DRender::QLevelOfDetail::ThresholdType Quick3DLevelOfDetailLoader::thresholdType() const +{ + Q_D(const Quick3DLevelOfDetailLoader); + return d->m_lod->thresholdType(); +} + +void Quick3DLevelOfDetailLoader::setThresholdType(Qt3DRender::QLevelOfDetail::ThresholdType thresholdType) +{ + Q_D(Quick3DLevelOfDetailLoader); + d->m_lod->setThresholdType(thresholdType); +} + +QVector Quick3DLevelOfDetailLoader::thresholds() const +{ + Q_D(const Quick3DLevelOfDetailLoader); + return d->m_lod->thresholds(); +} + +void Quick3DLevelOfDetailLoader::setThresholds(const QVector &thresholds) +{ + Q_D(Quick3DLevelOfDetailLoader); + d->m_lod->setThresholds(thresholds); +} + +Qt3DRender::QBoundingSphere *Quick3DLevelOfDetailLoader::volumeOverride() const +{ + Q_D(const Quick3DLevelOfDetailLoader); + return d->m_lod->volumeOverride(); +} + +void Quick3DLevelOfDetailLoader::setVolumeOverride(Qt3DRender::QBoundingSphere *volumeOverride) +{ + Q_D(Quick3DLevelOfDetailLoader); + d->m_lod->setVolumeOverride(volumeOverride); +} + +QObject *Quick3DLevelOfDetailLoader::entity() const +{ + Q_D(const Quick3DLevelOfDetailLoader); + return d->m_loader->entity(); +} + +QUrl Quick3DLevelOfDetailLoader::source() const +{ + Q_D(const Quick3DLevelOfDetailLoader); + return d->m_loader->source(); +} + +} // namespace Quick +} // namespace Extras +} // namespace Qt3DExtras + +QT_END_NAMESPACE + + diff --git a/src/quick3d/quick3dextras/items/quick3dlevelofdetailloader_p.h b/src/quick3d/quick3dextras/items/quick3dlevelofdetailloader_p.h new file mode 100644 index 000000000..1ef359fe7 --- /dev/null +++ b/src/quick3d/quick3dextras/items/quick3dlevelofdetailloader_p.h @@ -0,0 +1,119 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3DEXTRAS_EXTRAS_QUICK_QUICK3DLEVELOFDETAILLOADER_P_H +#define QT3DEXTRAS_EXTRAS_QUICK_QUICK3DLEVELOFDETAILLOADER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DExtras { +namespace Extras { +namespace Quick { + +class Quick3DLevelOfDetailLoaderPrivate; + +class QT3DQUICKEXTRASSHARED_PRIVATE_EXPORT Quick3DLevelOfDetailLoader : public Qt3DCore::QEntity +{ + Q_OBJECT + Q_PROPERTY(QVariantList sources READ sources WRITE setSources NOTIFY sourcesChanged) + + Q_PROPERTY(Qt3DRender::QCamera *camera READ camera WRITE setCamera NOTIFY cameraChanged) + Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged) + Q_PROPERTY(Qt3DRender::QLevelOfDetail::ThresholdType thresholdType READ thresholdType WRITE setThresholdType NOTIFY thresholdTypeChanged) + Q_PROPERTY(QVector thresholds READ thresholds WRITE setThresholds NOTIFY thresholdsChanged) + Q_PROPERTY(Qt3DRender::QBoundingSphere *volumeOverride READ volumeOverride WRITE setVolumeOverride NOTIFY volumeOverrideChanged) + + Q_PROPERTY(QObject *entity READ entity NOTIFY entityChanged) + Q_PROPERTY(QUrl source READ source NOTIFY sourceChanged) +public: + explicit Quick3DLevelOfDetailLoader(QNode *parent = 0); + + QVariantList sources() const; + void setSources(const QVariantList &sources); + + Qt3DRender::QCamera *camera() const; + void setCamera(Qt3DRender::QCamera *camera); + int currentIndex() const; + void setCurrentIndex(int currentIndex); + Qt3DRender::QLevelOfDetail::ThresholdType thresholdType() const; + void setThresholdType(Qt3DRender::QLevelOfDetail::ThresholdType thresholdType); + QVector thresholds() const; + void setThresholds(const QVector &thresholds); + Qt3DRender::QBoundingSphere *volumeOverride() const; + void setVolumeOverride(Qt3DRender::QBoundingSphere *volumeOverride); + + QObject *entity() const; + QUrl source() const; + +signals: + void sourcesChanged(); + void cameraChanged(); + void currentIndexChanged(); + void thresholdTypeChanged(); + void thresholdsChanged(); + void volumeOverrideChanged(); + void entityChanged(); + void sourceChanged(); + +private: + Q_DECLARE_PRIVATE(Quick3DLevelOfDetailLoader) +}; + +} // namespace Quick +} // namespace Extras +} // namespace Qt3DExtras + +QT_END_NAMESPACE + +#endif // QT3DEXTRAS_EXTRAS_QUICK_QUICK3DLEVELOFDETAILLOADER_P_H diff --git a/src/quick3d/quick3dextras/items/quick3dlevelofdetailloader_p_p.h b/src/quick3d/quick3dextras/items/quick3dlevelofdetailloader_p_p.h new file mode 100644 index 000000000..b123ea30b --- /dev/null +++ b/src/quick3d/quick3dextras/items/quick3dlevelofdetailloader_p_p.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3DEXTRAS_EXTRAS_QUICK_QUICK3DLEVELOFDETAILLOADER_P_P_H +#define QT3DEXTRAS_EXTRAS_QUICK_QUICK3DLEVELOFDETAILLOADER_P_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "quick3dlevelofdetailloader_p.h" +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DCore { +namespace Quick { +class Quick3DEntityLoader; +} +} + +namespace Qt3DExtras { +namespace Extras { +namespace Quick { + +class Quick3DLevelOfDetailLoaderPrivate : public Qt3DCore::QEntityPrivate +{ +public: + Quick3DLevelOfDetailLoaderPrivate(); + + Q_DECLARE_PUBLIC(Quick3DLevelOfDetailLoader) + + QVariantList m_sources; + Qt3DCore::Quick::Quick3DEntityLoader *m_loader; + Qt3DRender::QLevelOfDetail *m_lod; +}; + +} // namespace Quick +} // namespace Extras +} // namespace Qt3DExtras + +QT_END_NAMESPACE + +#endif // QT3DEXTRAS_EXTRAS_QUICK_QUICK3DLEVELOFDETAILLOADER_P_P_H diff --git a/src/quick3d/quick3dextras/qt3dquickextras_global_p.h b/src/quick3d/quick3dextras/qt3dquickextras_global_p.h new file mode 100644 index 000000000..524393743 --- /dev/null +++ b/src/quick3d/quick3dextras/qt3dquickextras_global_p.h @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3DQUICKEXTRAS_GLOBAL_P_H +#define QT3DQUICKEXTRAS_GLOBAL_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include + +#define QT3DQUICKEXTRASSHARED_PRIVATE_EXPORT QT3DQUICKEXTRASSHARED_EXPORT + +QT_BEGIN_NAMESPACE + +QT_END_NAMESPACE + +#endif // QT3DQUICKEXTRAS_GLOBAL_P_H diff --git a/src/quick3d/quick3dextras/quick3dextras.pro b/src/quick3d/quick3dextras/quick3dextras.pro index 8965e9f5d..5b00d5dc3 100644 --- a/src/quick3d/quick3dextras/quick3dextras.pro +++ b/src/quick3d/quick3dextras/quick3dextras.pro @@ -1,7 +1,7 @@ TARGET = Qt3DQuickExtras MODULE = 3dquickextras -QT += core core-private qml qml-private 3dcore 3dinput 3dquick 3drender 3drender-private 3dlogic +QT += core core-private qml qml-private 3dcore 3dinput 3dquick 3dquick-private 3drender 3drender-private 3dlogic CONFIG -= precompile_header # Qt3D is free of Q_FOREACH - make sure it stays that way: @@ -18,9 +18,12 @@ SOURCES += \ HEADERS += \ qt3dquickextras_global.h \ + qt3dquickextras_global_p.h \ qt3dquickwindow.h # otherwise mingw headers do not declare common functions like ::strcasecmp win32-g++*:QMAKE_CXXFLAGS_CXX11 = -std=gnu++0x +include(./items/items.pri) + load(qt_module) -- cgit v1.2.3 From 6cf633a639939c6cc7d56812d774d43a6f91d9a8 Mon Sep 17 00:00:00 2001 From: Kevin Ottens Date: Wed, 25 Jan 2017 15:50:39 +0100 Subject: Remove resources generation in importextras Now that all QML files are gone in importextras, this is not necessary anymore Change-Id: Ie97d95209a9de062b3de215e0dc13ea2127f0830 Reviewed-by: Sean Harmer --- src/quick3d/imports/extras/defaults/defaults.pri | 8 ------ src/quick3d/imports/extras/importsextras.pro | 30 ++-------------------- .../imports/extras/qt3dquick3dextrasplugin.cpp | 15 ----------- 3 files changed, 2 insertions(+), 51 deletions(-) delete mode 100644 src/quick3d/imports/extras/defaults/defaults.pri diff --git a/src/quick3d/imports/extras/defaults/defaults.pri b/src/quick3d/imports/extras/defaults/defaults.pri deleted file mode 100644 index 27d439e93..000000000 --- a/src/quick3d/imports/extras/defaults/defaults.pri +++ /dev/null @@ -1,8 +0,0 @@ - -# When adding new QML files that should be built into the plugin, -# add them to this variable and they will be listed into a generated -# resource file. -# -# To have the plugin register them as types, add an entries to the -# qmldir array in qt3dquick3dextrasplugin.cpp -QML_FILES = diff --git a/src/quick3d/imports/extras/importsextras.pro b/src/quick3d/imports/extras/importsextras.pro index 3b6735572..52a316216 100644 --- a/src/quick3d/imports/extras/importsextras.pro +++ b/src/quick3d/imports/extras/importsextras.pro @@ -14,32 +14,6 @@ HEADERS += \ SOURCES += \ qt3dquick3dextrasplugin.cpp -load(qml_plugin) - -include(./defaults/defaults.pri) - -OTHER_FILES += \ - qmldir \ - $$QML_FILES - -# Create a resource file for qml files that need to be registered by the plugin -GENERATED_RESOURCE_FILE = $$OUT_PWD/defaults.qrc -INCLUDED_RESOURCE_FILES = $$QML_FILES -RESOURCE_CONTENT = \ - "" \ - "" +OTHER_FILES += qmldir -for(resourcefile, INCLUDED_RESOURCE_FILES) { - resourcefileabsolutepath = $$absolute_path($$resourcefile) - relativepath_in = $$relative_path($$resourcefileabsolutepath, $$_PRO_FILE_PWD_) - relativepath_out = $$relative_path($$resourcefileabsolutepath, $$OUT_PWD) - RESOURCE_CONTENT += "$$relativepath_out" -} - -RESOURCE_CONTENT += \ - "" \ - "" - -write_file($$GENERATED_RESOURCE_FILE, RESOURCE_CONTENT)|error("Aborting.") - -RESOURCES += $$GENERATED_RESOURCE_FILE +load(qml_plugin) diff --git a/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp b/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp index ed98ae407..608e0b321 100644 --- a/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp +++ b/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp @@ -73,12 +73,6 @@ QT_BEGIN_NAMESPACE -static const struct { - const char *type; - int major, minor; -} qmldir [] = { -}; - void Qt3DQuick3DExtrasPlugin::registerTypes(const char *uri) { // Framegraphs @@ -121,15 +115,6 @@ void Qt3DQuick3DExtrasPlugin::registerTypes(const char *uri) // 3D Text qmlRegisterType(uri, 2, 2, "Text3DGeometry"); qmlRegisterType(uri, 2, 2, "Text3DMesh"); - - // Register types provided as QML files compiled into the plugin - for (int i = 0; i < int(sizeof(qmldir) / sizeof(qmldir[0])); i++) { - auto path = QLatin1String("qrc:/qt-project.org/imports/Qt3D/Extras/defaults/qml/"); - qmlRegisterType(QUrl(path + qmldir[i].type + QLatin1String(".qml")), - uri, - qmldir[i].major, qmldir[i].minor, - qmldir[i].type); - } } -- cgit v1.2.3 From 35bbe830ff61677d5de130bfedb2f5301b8a4e0a Mon Sep 17 00:00:00 2001 From: Kevin Ottens Date: Wed, 25 Jan 2017 15:57:24 +0100 Subject: Update Qt3D.Extras qmltypes file Change-Id: Icd5b638b154e52aac7635ef35afb208909496772 Reviewed-by: Sean Harmer --- src/quick3d/imports/extras/plugins.qmltypes | 1425 +++++++++++++++++---------- 1 file changed, 931 insertions(+), 494 deletions(-) diff --git a/src/quick3d/imports/extras/plugins.qmltypes b/src/quick3d/imports/extras/plugins.qmltypes index 6a7e1203d..e6cff3ab8 100644 --- a/src/quick3d/imports/extras/plugins.qmltypes +++ b/src/quick3d/imports/extras/plugins.qmltypes @@ -7,7 +7,66 @@ import QtQuick.tooling 1.2 // 'qmlplugindump -nonrelocatable Qt3D.Extras 2.0' Module { - dependencies: ["Qt3D.Logic 2.0"] + dependencies: [] + Component { + name: "Qt3DCore::QComponent" + prototype: "Qt3DCore::QNode" + Property { name: "isShareable"; type: "bool" } + Signal { + name: "shareableChanged" + Parameter { name: "isShareable"; type: "bool" } + } + Signal { + name: "addedToEntity" + Parameter { name: "entity"; type: "QEntity"; isPointer: true } + } + Signal { + name: "removedFromEntity" + Parameter { name: "entity"; type: "QEntity"; isPointer: true } + } + Method { + name: "setShareable" + Parameter { name: "isShareable"; type: "bool" } + } + } + Component { name: "Qt3DCore::QEntity"; prototype: "Qt3DCore::QNode" } + Component { + name: "Qt3DCore::QNode" + prototype: "QObject" + Property { name: "parent"; type: "Qt3DCore::QNode"; isPointer: true } + Property { name: "enabled"; type: "bool" } + Signal { + name: "parentChanged" + Parameter { name: "parent"; type: "QObject"; isPointer: true } + } + Signal { + name: "enabledChanged" + Parameter { name: "enabled"; type: "bool" } + } + Signal { name: "nodeDestroyed" } + Method { + name: "setParent" + Parameter { name: "parent"; type: "QNode"; isPointer: true } + } + Method { + name: "setEnabled" + Parameter { name: "isEnabled"; type: "bool" } + } + } + Component { + name: "Qt3DExtras::Extras::Quick::Quick3DLevelOfDetailLoader" + prototype: "Qt3DCore::QEntity" + exports: ["Qt3D.Extras/LevelOfDetailLoader 2.2"] + exportMetaObjectRevisions: [0] + Property { name: "sources"; type: "QVariantList" } + Property { name: "camera"; type: "Qt3DRender::QCamera"; isPointer: true } + Property { name: "currentIndex"; type: "int" } + Property { name: "thresholdType"; type: "Qt3DRender::QLevelOfDetail::ThresholdType" } + Property { name: "thresholds"; type: "QVector" } + Property { name: "volumeOverride"; type: "Qt3DRender::QBoundingSphere"; isPointer: true } + Property { name: "entity"; type: "QObject"; isReadonly: true; isPointer: true } + Property { name: "source"; type: "QUrl"; isReadonly: true } + } Component { name: "Qt3DExtras::QConeGeometry" prototype: "Qt3DRender::QGeometry" @@ -429,279 +488,953 @@ Module { } } Component { - name: "Qt3DExtras::QPlaneGeometry" - prototype: "Qt3DRender::QGeometry" - exports: ["Qt3D.Extras/PlaneGeometry 2.0"] + name: "Qt3DExtras::QDiffuseMapMaterial" + prototype: "Qt3DRender::QMaterial" + exports: ["Qt3D.Extras/DiffuseMapMaterial 2.0"] exportMetaObjectRevisions: [0] - Property { name: "width"; type: "float" } - Property { name: "height"; type: "float" } - Property { name: "resolution"; type: "QSize" } - Property { - name: "positionAttribute" - type: "Qt3DRender::QAttribute" - isReadonly: true - isPointer: true - } - Property { - name: "normalAttribute" - type: "Qt3DRender::QAttribute" - isReadonly: true - isPointer: true - } - Property { - name: "texCoordAttribute" - type: "Qt3DRender::QAttribute" - isReadonly: true - isPointer: true - } - Property { - name: "tangentAttribute" - type: "Qt3DRender::QAttribute" - isReadonly: true - isPointer: true - } - Property { - name: "indexAttribute" - type: "Qt3DRender::QAttribute" - isReadonly: true - isPointer: true + Property { name: "ambient"; type: "QColor" } + Property { name: "specular"; type: "QColor" } + Property { name: "shininess"; type: "float" } + Property { name: "diffuse"; type: "Qt3DRender::QAbstractTexture"; isPointer: true } + Property { name: "textureScale"; type: "float" } + Signal { + name: "ambientChanged" + Parameter { name: "ambient"; type: "QColor" } } Signal { - name: "resolutionChanged" - Parameter { name: "resolution"; type: "QSize" } + name: "diffuseChanged" + Parameter { name: "diffuse"; type: "Qt3DRender::QAbstractTexture"; isPointer: true } } Signal { - name: "widthChanged" - Parameter { name: "width"; type: "float" } + name: "specularChanged" + Parameter { name: "specular"; type: "QColor" } } Signal { - name: "heightChanged" - Parameter { name: "height"; type: "float" } + name: "shininessChanged" + Parameter { name: "shininess"; type: "float" } } - Method { - name: "setResolution" - Parameter { name: "resolution"; type: "QSize" } + Signal { + name: "textureScaleChanged" + Parameter { name: "textureScale"; type: "float" } } Method { - name: "setWidth" - Parameter { name: "width"; type: "float" } + name: "setAmbient" + Parameter { name: "color"; type: "QColor" } } Method { - name: "setHeight" - Parameter { name: "height"; type: "float" } - } - } - Component { - name: "Qt3DExtras::QPlaneMesh" - prototype: "Qt3DRender::QGeometryRenderer" - exports: ["Qt3D.Extras/PlaneMesh 2.0"] - exportMetaObjectRevisions: [0] - Property { name: "width"; type: "float" } - Property { name: "height"; type: "float" } - Property { name: "meshResolution"; type: "QSize" } - Signal { - name: "meshResolutionChanged" - Parameter { name: "meshResolution"; type: "QSize" } - } - Signal { - name: "widthChanged" - Parameter { name: "width"; type: "float" } - } - Signal { - name: "heightChanged" - Parameter { name: "height"; type: "float" } + name: "setSpecular" + Parameter { name: "specular"; type: "QColor" } } Method { - name: "setWidth" - Parameter { name: "width"; type: "float" } + name: "setShininess" + Parameter { name: "shininess"; type: "float" } } Method { - name: "setHeight" - Parameter { name: "height"; type: "float" } + name: "setDiffuse" + Parameter { name: "diffuse"; type: "Qt3DRender::QAbstractTexture"; isPointer: true } } Method { - name: "setMeshResolution" - Parameter { name: "resolution"; type: "QSize" } + name: "setTextureScale" + Parameter { name: "textureScale"; type: "float" } } } Component { - name: "Qt3DExtras::QSphereGeometry" - prototype: "Qt3DRender::QGeometry" - exports: ["Qt3D.Extras/SphereGeometry 2.0"] + name: "Qt3DExtras::QDiffuseSpecularMapMaterial" + prototype: "Qt3DRender::QMaterial" + exports: ["Qt3D.Extras/DiffuseSpecularMapMaterial 2.0"] exportMetaObjectRevisions: [0] - Property { name: "rings"; type: "int" } - Property { name: "slices"; type: "int" } - Property { name: "radius"; type: "float" } - Property { name: "generateTangents"; type: "bool" } - Property { - name: "positionAttribute" - type: "Qt3DRender::QAttribute" - isReadonly: true - isPointer: true - } - Property { - name: "normalAttribute" - type: "Qt3DRender::QAttribute" - isReadonly: true - isPointer: true - } - Property { - name: "texCoordAttribute" - type: "Qt3DRender::QAttribute" - isReadonly: true - isPointer: true - } - Property { - name: "tangentAttribute" - type: "Qt3DRender::QAttribute" - isReadonly: true - isPointer: true - } - Property { - name: "indexAttribute" - type: "Qt3DRender::QAttribute" - isReadonly: true - isPointer: true + Property { name: "ambient"; type: "QColor" } + Property { name: "shininess"; type: "float" } + Property { name: "specular"; type: "Qt3DRender::QAbstractTexture"; isPointer: true } + Property { name: "diffuse"; type: "Qt3DRender::QAbstractTexture"; isPointer: true } + Property { name: "textureScale"; type: "float" } + Signal { + name: "ambientChanged" + Parameter { name: "ambient"; type: "QColor" } } Signal { - name: "radiusChanged" - Parameter { name: "radius"; type: "float" } + name: "diffuseChanged" + Parameter { name: "diffuse"; type: "Qt3DRender::QAbstractTexture"; isPointer: true } } Signal { - name: "ringsChanged" - Parameter { name: "rings"; type: "int" } + name: "specularChanged" + Parameter { name: "specular"; type: "Qt3DRender::QAbstractTexture"; isPointer: true } } Signal { - name: "slicesChanged" - Parameter { name: "slices"; type: "int" } + name: "shininessChanged" + Parameter { name: "shininess"; type: "float" } } Signal { - name: "generateTangentsChanged" - Parameter { name: "generateTangents"; type: "bool" } + name: "textureScaleChanged" + Parameter { name: "textureScale"; type: "float" } } Method { - name: "setRings" - Parameter { name: "rings"; type: "int" } + name: "setAmbient" + Parameter { name: "ambient"; type: "QColor" } } Method { - name: "setSlices" - Parameter { name: "slices"; type: "int" } + name: "setDiffuse" + Parameter { name: "diffuse"; type: "Qt3DRender::QAbstractTexture"; isPointer: true } } Method { - name: "setRadius" - Parameter { name: "radius"; type: "float" } + name: "setSpecular" + Parameter { name: "specular"; type: "Qt3DRender::QAbstractTexture"; isPointer: true } } Method { - name: "setGenerateTangents" - Parameter { name: "gen"; type: "bool" } + name: "setShininess" + Parameter { name: "shininess"; type: "float" } + } + Method { + name: "setTextureScale" + Parameter { name: "textureScale"; type: "float" } } } Component { - name: "Qt3DExtras::QSphereMesh" - prototype: "Qt3DRender::QGeometryRenderer" - exports: ["Qt3D.Extras/SphereMesh 2.0"] + name: "Qt3DExtras::QFirstPersonCameraController" + prototype: "Qt3DCore::QEntity" + exports: ["Qt3D.Extras/FirstPersonCameraController 2.0"] exportMetaObjectRevisions: [0] - Property { name: "rings"; type: "int" } - Property { name: "slices"; type: "int" } - Property { name: "radius"; type: "float" } - Property { name: "generateTangents"; type: "bool" } + Property { name: "camera"; type: "Qt3DRender::QCamera"; isPointer: true } + Property { name: "linearSpeed"; type: "float" } + Property { name: "lookSpeed"; type: "float" } + Property { name: "acceleration"; type: "float" } + Property { name: "deceleration"; type: "float" } + } + Component { + name: "Qt3DExtras::QForwardRenderer" + prototype: "Qt3DRender::QTechniqueFilter" + exports: ["Qt3D.Extras/ForwardRenderer 2.0"] + exportMetaObjectRevisions: [0] + Property { name: "surface"; type: "QObject"; isPointer: true } + Property { name: "window"; type: "QObject"; isPointer: true } + Property { name: "viewportRect"; type: "QRectF" } + Property { name: "clearColor"; type: "QColor" } + Property { name: "camera"; type: "Qt3DCore::QEntity"; isPointer: true } + Property { name: "externalRenderTargetSize"; type: "QSize" } + Property { name: "frustumCulling"; type: "bool" } Signal { - name: "radiusChanged" - Parameter { name: "radius"; type: "float" } + name: "viewportRectChanged" + Parameter { name: "viewportRect"; type: "QRectF" } } Signal { - name: "ringsChanged" - Parameter { name: "rings"; type: "int" } + name: "clearColorChanged" + Parameter { name: "clearColor"; type: "QColor" } } Signal { - name: "slicesChanged" - Parameter { name: "slices"; type: "int" } + name: "cameraChanged" + Parameter { name: "camera"; type: "Qt3DCore::QEntity"; isPointer: true } } Signal { - name: "generateTangentsChanged" - Parameter { name: "generateTangents"; type: "bool" } + name: "surfaceChanged" + Parameter { name: "surface"; type: "QObject"; isPointer: true } + } + Signal { + name: "externalRenderTargetSizeChanged" + Parameter { name: "size"; type: "QSize" } + } + Signal { + name: "frustumCullingEnabledChanged" + Parameter { name: "enabled"; type: "bool" } } Method { - name: "setRings" - Parameter { name: "rings"; type: "int" } + name: "setViewportRect" + Parameter { name: "viewportRect"; type: "QRectF" } } Method { - name: "setSlices" - Parameter { name: "slices"; type: "int" } + name: "setClearColor" + Parameter { name: "clearColor"; type: "QColor" } } Method { - name: "setRadius" - Parameter { name: "radius"; type: "float" } + name: "setCamera" + Parameter { name: "camera"; type: "Qt3DCore::QEntity"; isPointer: true } } Method { - name: "setGenerateTangents" - Parameter { name: "gen"; type: "bool" } + name: "setSurface" + Parameter { name: "surface"; type: "QObject"; isPointer: true } + } + Method { + name: "setExternalRenderTargetSize" + Parameter { name: "size"; type: "QSize" } + } + Method { + name: "setFrustumCullingEnabled" + Parameter { name: "enabled"; type: "bool" } } } Component { - name: "Qt3DExtras::QTorusGeometry" - prototype: "Qt3DRender::QGeometry" - exports: ["Qt3D.Extras/TorusGeometry 2.0"] + name: "Qt3DExtras::QGoochMaterial" + prototype: "Qt3DRender::QMaterial" + exports: ["Qt3D.Extras/GoochMaterial 2.0"] exportMetaObjectRevisions: [0] - Property { name: "rings"; type: "int" } - Property { name: "slices"; type: "int" } - Property { name: "radius"; type: "float" } - Property { name: "minorRadius"; type: "float" } - Property { - name: "positionAttribute" - type: "Qt3DRender::QAttribute" - isReadonly: true - isPointer: true - } - Property { - name: "normalAttribute" - type: "Qt3DRender::QAttribute" - isReadonly: true - isPointer: true + Property { name: "diffuse"; type: "QColor" } + Property { name: "specular"; type: "QColor" } + Property { name: "cool"; type: "QColor" } + Property { name: "warm"; type: "QColor" } + Property { name: "alpha"; type: "float" } + Property { name: "beta"; type: "float" } + Property { name: "shininess"; type: "float" } + Signal { + name: "diffuseChanged" + Parameter { name: "diffuse"; type: "QColor" } } - Property { - name: "texCoordAttribute" - type: "Qt3DRender::QAttribute" - isReadonly: true - isPointer: true + Signal { + name: "specularChanged" + Parameter { name: "specular"; type: "QColor" } } - Property { - name: "indexAttribute" - type: "Qt3DRender::QAttribute" - isReadonly: true - isPointer: true + Signal { + name: "coolChanged" + Parameter { name: "cool"; type: "QColor" } } Signal { - name: "radiusChanged" - Parameter { name: "radius"; type: "float" } + name: "warmChanged" + Parameter { name: "warm"; type: "QColor" } } Signal { - name: "ringsChanged" - Parameter { name: "rings"; type: "int" } + name: "alphaChanged" + Parameter { name: "alpha"; type: "float" } } Signal { - name: "slicesChanged" - Parameter { name: "slices"; type: "int" } + name: "betaChanged" + Parameter { name: "beta"; type: "float" } } Signal { - name: "minorRadiusChanged" - Parameter { name: "minorRadius"; type: "float" } + name: "shininessChanged" + Parameter { name: "shininess"; type: "float" } } Method { - name: "setRings" - Parameter { name: "rings"; type: "int" } + name: "setDiffuse" + Parameter { name: "diffuse"; type: "QColor" } } Method { - name: "setSlices" - Parameter { name: "slices"; type: "int" } + name: "setSpecular" + Parameter { name: "specular"; type: "QColor" } } Method { - name: "setRadius" - Parameter { name: "radius"; type: "float" } + name: "setCool" + Parameter { name: "cool"; type: "QColor" } } Method { - name: "setMinorRadius" - Parameter { name: "minorRadius"; type: "float" } + name: "setWarm" + Parameter { name: "warm"; type: "QColor" } + } + Method { + name: "setAlpha" + Parameter { name: "alpha"; type: "float" } + } + Method { + name: "setBeta" + Parameter { name: "beta"; type: "float" } + } + Method { + name: "setShininess" + Parameter { name: "shininess"; type: "float" } + } + } + Component { + name: "Qt3DExtras::QNormalDiffuseMapAlphaMaterial" + prototype: "Qt3DExtras::QNormalDiffuseMapMaterial" + exports: ["Qt3D.Extras/NormalDiffuseMapAlphaMaterial 2.0"] + exportMetaObjectRevisions: [0] + } + Component { + name: "Qt3DExtras::QNormalDiffuseMapMaterial" + prototype: "Qt3DRender::QMaterial" + exports: ["Qt3D.Extras/NormalDiffuseMapMaterial 2.0"] + exportMetaObjectRevisions: [0] + Property { name: "ambient"; type: "QColor" } + Property { name: "specular"; type: "QColor" } + Property { name: "diffuse"; type: "Qt3DRender::QAbstractTexture"; isPointer: true } + Property { name: "normal"; type: "Qt3DRender::QAbstractTexture"; isPointer: true } + Property { name: "shininess"; type: "float" } + Property { name: "textureScale"; type: "float" } + Signal { + name: "ambientChanged" + Parameter { name: "ambient"; type: "QColor" } + } + Signal { + name: "diffuseChanged" + Parameter { name: "diffuse"; type: "Qt3DRender::QAbstractTexture"; isPointer: true } + } + Signal { + name: "normalChanged" + Parameter { name: "normal"; type: "Qt3DRender::QAbstractTexture"; isPointer: true } + } + Signal { + name: "specularChanged" + Parameter { name: "specular"; type: "QColor" } + } + Signal { + name: "shininessChanged" + Parameter { name: "shininess"; type: "float" } + } + Signal { + name: "textureScaleChanged" + Parameter { name: "textureScale"; type: "float" } + } + Method { + name: "setAmbient" + Parameter { name: "ambient"; type: "QColor" } + } + Method { + name: "setSpecular" + Parameter { name: "specular"; type: "QColor" } + } + Method { + name: "setDiffuse" + Parameter { name: "diffuse"; type: "Qt3DRender::QAbstractTexture"; isPointer: true } + } + Method { + name: "setNormal" + Parameter { name: "normal"; type: "Qt3DRender::QAbstractTexture"; isPointer: true } + } + Method { + name: "setShininess" + Parameter { name: "shininess"; type: "float" } + } + Method { + name: "setTextureScale" + Parameter { name: "textureScale"; type: "float" } + } + } + Component { + name: "Qt3DExtras::QNormalDiffuseSpecularMapMaterial" + prototype: "Qt3DRender::QMaterial" + exports: ["Qt3D.Extras/NormalDiffuseSpecularMapMaterial 2.0"] + exportMetaObjectRevisions: [0] + Property { name: "ambient"; type: "QColor" } + Property { name: "diffuse"; type: "Qt3DRender::QAbstractTexture"; isPointer: true } + Property { name: "normal"; type: "Qt3DRender::QAbstractTexture"; isPointer: true } + Property { name: "specular"; type: "Qt3DRender::QAbstractTexture"; isPointer: true } + Property { name: "shininess"; type: "float" } + Property { name: "textureScale"; type: "float" } + Signal { + name: "ambientChanged" + Parameter { name: "ambient"; type: "QColor" } + } + Signal { + name: "diffuseChanged" + Parameter { name: "diffuse"; type: "Qt3DRender::QAbstractTexture"; isPointer: true } + } + Signal { + name: "normalChanged" + Parameter { name: "normal"; type: "Qt3DRender::QAbstractTexture"; isPointer: true } + } + Signal { + name: "specularChanged" + Parameter { name: "specular"; type: "Qt3DRender::QAbstractTexture"; isPointer: true } + } + Signal { + name: "shininessChanged" + Parameter { name: "shininess"; type: "float" } + } + Signal { + name: "textureScaleChanged" + Parameter { name: "textureScale"; type: "float" } + } + Method { + name: "setAmbient" + Parameter { name: "ambient"; type: "QColor" } + } + Method { + name: "setDiffuse" + Parameter { name: "diffuse"; type: "Qt3DRender::QAbstractTexture"; isPointer: true } + } + Method { + name: "setNormal" + Parameter { name: "normal"; type: "Qt3DRender::QAbstractTexture"; isPointer: true } + } + Method { + name: "setSpecular" + Parameter { name: "specular"; type: "Qt3DRender::QAbstractTexture"; isPointer: true } + } + Method { + name: "setShininess" + Parameter { name: "shininess"; type: "float" } + } + Method { + name: "setTextureScale" + Parameter { name: "textureScale"; type: "float" } + } + } + Component { + name: "Qt3DExtras::QOrbitCameraController" + prototype: "Qt3DCore::QEntity" + exports: ["Qt3D.Extras/OrbitCameraController 2.0"] + exportMetaObjectRevisions: [0] + Property { name: "camera"; type: "Qt3DRender::QCamera"; isPointer: true } + Property { name: "linearSpeed"; type: "float" } + Property { name: "lookSpeed"; type: "float" } + Property { name: "zoomInLimit"; type: "float" } + } + Component { + name: "Qt3DExtras::QPerVertexColorMaterial" + prototype: "Qt3DRender::QMaterial" + exports: ["Qt3D.Extras/PerVertexColorMaterial 2.0"] + exportMetaObjectRevisions: [0] + } + Component { + name: "Qt3DExtras::QPhongAlphaMaterial" + prototype: "Qt3DRender::QMaterial" + exports: ["Qt3D.Extras/PhongAlphaMaterial 2.0"] + exportMetaObjectRevisions: [0] + Property { name: "ambient"; type: "QColor" } + Property { name: "diffuse"; type: "QColor" } + Property { name: "specular"; type: "QColor" } + Property { name: "shininess"; type: "float" } + Property { name: "alpha"; type: "float" } + Property { name: "sourceRgbArg"; type: "Qt3DRender::QBlendEquationArguments::Blending" } + Property { name: "destinationRgbArg"; type: "Qt3DRender::QBlendEquationArguments::Blending" } + Property { name: "sourceAlphaArg"; type: "Qt3DRender::QBlendEquationArguments::Blending" } + Property { + name: "destinationAlphaArg" + type: "Qt3DRender::QBlendEquationArguments::Blending" + } + Property { name: "blendFunctionArg"; type: "Qt3DRender::QBlendEquation::BlendFunction" } + Signal { + name: "ambientChanged" + Parameter { name: "ambient"; type: "QColor" } + } + Signal { + name: "diffuseChanged" + Parameter { name: "diffuse"; type: "QColor" } + } + Signal { + name: "specularChanged" + Parameter { name: "specular"; type: "QColor" } + } + Signal { + name: "shininessChanged" + Parameter { name: "shininess"; type: "float" } + } + Signal { + name: "alphaChanged" + Parameter { name: "alpha"; type: "float" } + } + Signal { + name: "sourceRgbArgChanged" + Parameter { name: "sourceRgbArg"; type: "Qt3DRender::QBlendEquationArguments::Blending" } + } + Signal { + name: "destinationRgbArgChanged" + Parameter { name: "destinationRgbArg"; type: "Qt3DRender::QBlendEquationArguments::Blending" } + } + Signal { + name: "sourceAlphaArgChanged" + Parameter { name: "sourceAlphaArg"; type: "Qt3DRender::QBlendEquationArguments::Blending" } + } + Signal { + name: "destinationAlphaArgChanged" + Parameter { + name: "destinationAlphaArg" + type: "Qt3DRender::QBlendEquationArguments::Blending" + } + } + Signal { + name: "blendFunctionArgChanged" + Parameter { name: "blendFunctionArg"; type: "Qt3DRender::QBlendEquation::BlendFunction" } + } + Method { + name: "setAmbient" + Parameter { name: "ambient"; type: "QColor" } + } + Method { + name: "setDiffuse" + Parameter { name: "diffuse"; type: "QColor" } + } + Method { + name: "setSpecular" + Parameter { name: "specular"; type: "QColor" } + } + Method { + name: "setShininess" + Parameter { name: "shininess"; type: "float" } + } + Method { + name: "setAlpha" + Parameter { name: "alpha"; type: "float" } + } + Method { + name: "setSourceRgbArg" + Parameter { name: "sourceRgbArg"; type: "Qt3DRender::QBlendEquationArguments::Blending" } + } + Method { + name: "setDestinationRgbArg" + Parameter { name: "destinationRgbArg"; type: "Qt3DRender::QBlendEquationArguments::Blending" } + } + Method { + name: "setSourceAlphaArg" + Parameter { name: "sourceAlphaArg"; type: "Qt3DRender::QBlendEquationArguments::Blending" } + } + Method { + name: "setDestinationAlphaArg" + Parameter { + name: "destinationAlphaArg" + type: "Qt3DRender::QBlendEquationArguments::Blending" + } + } + Method { + name: "setBlendFunctionArg" + Parameter { name: "blendFunctionArg"; type: "Qt3DRender::QBlendEquation::BlendFunction" } + } + } + Component { + name: "Qt3DExtras::QPhongMaterial" + prototype: "Qt3DRender::QMaterial" + exports: ["Qt3D.Extras/PhongMaterial 2.0"] + exportMetaObjectRevisions: [0] + Property { name: "ambient"; type: "QColor" } + Property { name: "diffuse"; type: "QColor" } + Property { name: "specular"; type: "QColor" } + Property { name: "shininess"; type: "float" } + Signal { + name: "ambientChanged" + Parameter { name: "ambient"; type: "QColor" } + } + Signal { + name: "diffuseChanged" + Parameter { name: "diffuse"; type: "QColor" } + } + Signal { + name: "specularChanged" + Parameter { name: "specular"; type: "QColor" } + } + Signal { + name: "shininessChanged" + Parameter { name: "shininess"; type: "float" } + } + Method { + name: "setAmbient" + Parameter { name: "ambient"; type: "QColor" } + } + Method { + name: "setDiffuse" + Parameter { name: "diffuse"; type: "QColor" } + } + Method { + name: "setSpecular" + Parameter { name: "specular"; type: "QColor" } + } + Method { + name: "setShininess" + Parameter { name: "shininess"; type: "float" } + } + } + Component { + name: "Qt3DExtras::QPlaneGeometry" + prototype: "Qt3DRender::QGeometry" + exports: ["Qt3D.Extras/PlaneGeometry 2.0"] + exportMetaObjectRevisions: [0] + Property { name: "width"; type: "float" } + Property { name: "height"; type: "float" } + Property { name: "resolution"; type: "QSize" } + Property { + name: "positionAttribute" + type: "Qt3DRender::QAttribute" + isReadonly: true + isPointer: true + } + Property { + name: "normalAttribute" + type: "Qt3DRender::QAttribute" + isReadonly: true + isPointer: true + } + Property { + name: "texCoordAttribute" + type: "Qt3DRender::QAttribute" + isReadonly: true + isPointer: true + } + Property { + name: "tangentAttribute" + type: "Qt3DRender::QAttribute" + isReadonly: true + isPointer: true + } + Property { + name: "indexAttribute" + type: "Qt3DRender::QAttribute" + isReadonly: true + isPointer: true + } + Signal { + name: "resolutionChanged" + Parameter { name: "resolution"; type: "QSize" } + } + Signal { + name: "widthChanged" + Parameter { name: "width"; type: "float" } + } + Signal { + name: "heightChanged" + Parameter { name: "height"; type: "float" } + } + Method { + name: "setResolution" + Parameter { name: "resolution"; type: "QSize" } + } + Method { + name: "setWidth" + Parameter { name: "width"; type: "float" } + } + Method { + name: "setHeight" + Parameter { name: "height"; type: "float" } + } + } + Component { + name: "Qt3DExtras::QPlaneMesh" + prototype: "Qt3DRender::QGeometryRenderer" + exports: ["Qt3D.Extras/PlaneMesh 2.0"] + exportMetaObjectRevisions: [0] + Property { name: "width"; type: "float" } + Property { name: "height"; type: "float" } + Property { name: "meshResolution"; type: "QSize" } + Signal { + name: "meshResolutionChanged" + Parameter { name: "meshResolution"; type: "QSize" } + } + Signal { + name: "widthChanged" + Parameter { name: "width"; type: "float" } + } + Signal { + name: "heightChanged" + Parameter { name: "height"; type: "float" } + } + Method { + name: "setWidth" + Parameter { name: "width"; type: "float" } + } + Method { + name: "setHeight" + Parameter { name: "height"; type: "float" } + } + Method { + name: "setMeshResolution" + Parameter { name: "resolution"; type: "QSize" } + } + } + Component { + name: "Qt3DExtras::QSkyboxEntity" + prototype: "Qt3DCore::QEntity" + exports: ["Qt3D.Extras/SkyboxEntity 2.0"] + exportMetaObjectRevisions: [0] + Property { name: "baseName"; type: "string" } + Property { name: "extension"; type: "string" } + Signal { + name: "baseNameChanged" + Parameter { name: "path"; type: "string" } + } + Signal { + name: "extensionChanged" + Parameter { name: "extension"; type: "string" } + } + } + Component { + name: "Qt3DExtras::QSphereGeometry" + prototype: "Qt3DRender::QGeometry" + exports: ["Qt3D.Extras/SphereGeometry 2.0"] + exportMetaObjectRevisions: [0] + Property { name: "rings"; type: "int" } + Property { name: "slices"; type: "int" } + Property { name: "radius"; type: "float" } + Property { name: "generateTangents"; type: "bool" } + Property { + name: "positionAttribute" + type: "Qt3DRender::QAttribute" + isReadonly: true + isPointer: true + } + Property { + name: "normalAttribute" + type: "Qt3DRender::QAttribute" + isReadonly: true + isPointer: true + } + Property { + name: "texCoordAttribute" + type: "Qt3DRender::QAttribute" + isReadonly: true + isPointer: true + } + Property { + name: "tangentAttribute" + type: "Qt3DRender::QAttribute" + isReadonly: true + isPointer: true + } + Property { + name: "indexAttribute" + type: "Qt3DRender::QAttribute" + isReadonly: true + isPointer: true + } + Signal { + name: "radiusChanged" + Parameter { name: "radius"; type: "float" } + } + Signal { + name: "ringsChanged" + Parameter { name: "rings"; type: "int" } + } + Signal { + name: "slicesChanged" + Parameter { name: "slices"; type: "int" } + } + Signal { + name: "generateTangentsChanged" + Parameter { name: "generateTangents"; type: "bool" } + } + Method { + name: "setRings" + Parameter { name: "rings"; type: "int" } + } + Method { + name: "setSlices" + Parameter { name: "slices"; type: "int" } + } + Method { + name: "setRadius" + Parameter { name: "radius"; type: "float" } + } + Method { + name: "setGenerateTangents" + Parameter { name: "gen"; type: "bool" } + } + } + Component { + name: "Qt3DExtras::QSphereMesh" + prototype: "Qt3DRender::QGeometryRenderer" + exports: ["Qt3D.Extras/SphereMesh 2.0"] + exportMetaObjectRevisions: [0] + Property { name: "rings"; type: "int" } + Property { name: "slices"; type: "int" } + Property { name: "radius"; type: "float" } + Property { name: "generateTangents"; type: "bool" } + Signal { + name: "radiusChanged" + Parameter { name: "radius"; type: "float" } + } + Signal { + name: "ringsChanged" + Parameter { name: "rings"; type: "int" } + } + Signal { + name: "slicesChanged" + Parameter { name: "slices"; type: "int" } + } + Signal { + name: "generateTangentsChanged" + Parameter { name: "generateTangents"; type: "bool" } + } + Method { + name: "setRings" + Parameter { name: "rings"; type: "int" } + } + Method { + name: "setSlices" + Parameter { name: "slices"; type: "int" } + } + Method { + name: "setRadius" + Parameter { name: "radius"; type: "float" } + } + Method { + name: "setGenerateTangents" + Parameter { name: "gen"; type: "bool" } + } + } + Component { + name: "Qt3DExtras::QText3DGeometry" + prototype: "Qt3DRender::QGeometry" + exports: ["Qt3D.Extras/Text3DGeometry 2.2"] + exportMetaObjectRevisions: [0] + Property { name: "text"; type: "string" } + Property { name: "font"; type: "QFont" } + Property { name: "depth"; type: "float" } + Property { name: "edgeSplitAngle"; type: "float" } + Property { + name: "positionAttribute" + type: "Qt3DRender::QAttribute" + isReadonly: true + isPointer: true + } + Property { + name: "normalAttribute" + type: "Qt3DRender::QAttribute" + isReadonly: true + isPointer: true + } + Property { + name: "indexAttribute" + type: "Qt3DRender::QAttribute" + isReadonly: true + isPointer: true + } + Signal { + name: "textChanged" + Parameter { name: "text"; type: "string" } + } + Signal { + name: "fontChanged" + Parameter { name: "font"; type: "QFont" } + } + Signal { + name: "depthChanged" + Parameter { name: "depth"; type: "float" } + } + Signal { + name: "edgeSplitAngleChanged" + Parameter { name: "edgeSplitAngle"; type: "float" } + } + Method { + name: "setText" + Parameter { name: "text"; type: "string" } + } + Method { + name: "setFont" + Parameter { name: "font"; type: "QFont" } + } + Method { + name: "setDepth" + Parameter { name: "depth"; type: "float" } + } + Method { + name: "setEdgeSplitAngle" + Parameter { name: "edgeSplitAngle"; type: "float" } + } + } + Component { + name: "Qt3DExtras::QText3DMesh" + prototype: "Qt3DRender::QGeometryRenderer" + exports: ["Qt3D.Extras/Text3DMesh 2.2"] + exportMetaObjectRevisions: [0] + Property { name: "text"; type: "string" } + Property { name: "font"; type: "QFont" } + Property { name: "depth"; type: "float" } + Property { name: "edgeSplitAngle"; type: "float" } + Signal { + name: "textChanged" + Parameter { name: "text"; type: "string" } + } + Signal { + name: "fontChanged" + Parameter { name: "font"; type: "QFont" } + } + Signal { + name: "depthChanged" + Parameter { name: "depth"; type: "float" } + } + Signal { + name: "edgeSplitAngleChanged" + Parameter { name: "edgeSplitAngle"; type: "float" } + } + Method { + name: "setText" + Parameter { name: "text"; type: "string" } + } + Method { + name: "setFont" + Parameter { name: "font"; type: "QFont" } + } + Method { + name: "setDepth" + Parameter { name: "depth"; type: "float" } + } + Method { + name: "setEdgeSplitAngle" + Parameter { name: "edgeSplitAngle"; type: "float" } + } + } + Component { + name: "Qt3DExtras::QTextureMaterial" + prototype: "Qt3DRender::QMaterial" + exports: ["Qt3D.Extras/TextureMaterial 2.0"] + exportMetaObjectRevisions: [0] + Property { name: "texture"; type: "Qt3DRender::QAbstractTexture"; isPointer: true } + Property { name: "textureOffset"; type: "QVector2D" } + Signal { + name: "textureChanged" + Parameter { name: "texture"; type: "Qt3DRender::QAbstractTexture"; isPointer: true } + } + Signal { + name: "textureOffsetChanged" + Parameter { name: "textureOffset"; type: "QVector2D" } + } + Method { + name: "setTexture" + Parameter { name: "texture"; type: "Qt3DRender::QAbstractTexture"; isPointer: true } + } + Method { + name: "setTextureOffset" + Parameter { name: "textureOffset"; type: "QVector2D" } + } + } + Component { + name: "Qt3DExtras::QTorusGeometry" + prototype: "Qt3DRender::QGeometry" + exports: ["Qt3D.Extras/TorusGeometry 2.0"] + exportMetaObjectRevisions: [0] + Property { name: "rings"; type: "int" } + Property { name: "slices"; type: "int" } + Property { name: "radius"; type: "float" } + Property { name: "minorRadius"; type: "float" } + Property { + name: "positionAttribute" + type: "Qt3DRender::QAttribute" + isReadonly: true + isPointer: true + } + Property { + name: "normalAttribute" + type: "Qt3DRender::QAttribute" + isReadonly: true + isPointer: true + } + Property { + name: "texCoordAttribute" + type: "Qt3DRender::QAttribute" + isReadonly: true + isPointer: true + } + Property { + name: "indexAttribute" + type: "Qt3DRender::QAttribute" + isReadonly: true + isPointer: true + } + Signal { + name: "radiusChanged" + Parameter { name: "radius"; type: "float" } + } + Signal { + name: "ringsChanged" + Parameter { name: "rings"; type: "int" } + } + Signal { + name: "slicesChanged" + Parameter { name: "slices"; type: "int" } + } + Signal { + name: "minorRadiusChanged" + Parameter { name: "minorRadius"; type: "float" } + } + Method { + name: "setRings" + Parameter { name: "rings"; type: "int" } + } + Method { + name: "setSlices" + Parameter { name: "slices"; type: "int" } + } + Method { + name: "setRadius" + Parameter { name: "radius"; type: "float" } + } + Method { + name: "setMinorRadius" + Parameter { name: "minorRadius"; type: "float" } } } Component { @@ -746,6 +1479,7 @@ Module { Parameter { name: "minorRadius"; type: "float" } } } + Component { name: "Qt3DRender::QFrameGraphNode"; prototype: "Qt3DCore::QNode" } Component { name: "Qt3DRender::QGeometry" prototype: "Qt3DCore::QNode" @@ -883,306 +1617,8 @@ Module { } } Component { - prototype: "Qt3DCore::QNode" - name: "Qt3D.Extras/DefaultAlphaEffect 2.0" - exports: ["Qt3D.Extras/DefaultAlphaEffect 2.0"] - exportMetaObjectRevisions: [0] - isComposite: true - defaultProperty: "data" - Property { name: "vertexES"; type: "string" } - Property { name: "fragmentES"; type: "string" } - Property { name: "vertex"; type: "string" } - Property { name: "fragment"; type: "string" } - Property { name: "sourceRgbArg"; type: "int" } - Property { name: "destinationRgbArg"; type: "int" } - Property { name: "sourceAlphaArg"; type: "int" } - Property { name: "destinationAlphaArg"; type: "int" } - Property { name: "blendFunctionArg"; type: "int" } - } - Component { - prototype: "Qt3DCore::QNode" - name: "Qt3D.Extras/DefaultEffect 2.0" - exports: ["Qt3D.Extras/DefaultEffect 2.0"] - exportMetaObjectRevisions: [0] - isComposite: true - defaultProperty: "data" - Property { name: "vertexES"; type: "string" } - Property { name: "fragmentES"; type: "string" } - Property { name: "vertex"; type: "string" } - Property { name: "fragment"; type: "string" } - } - Component { - prototype: "Qt3DCore::QComponent" - name: "Qt3D.Extras/DiffuseMapMaterial 2.0" - exports: ["Qt3D.Extras/DiffuseMapMaterial 2.0"] - exportMetaObjectRevisions: [0] - isComposite: true - defaultProperty: "data" - Property { name: "ambient"; type: "QColor" } - Property { name: "specular"; type: "QColor" } - Property { name: "shininess"; type: "double" } - Property { name: "textureScale"; type: "double" } - Property { name: "diffuse"; type: "QUrl" } - Property { name: "effect"; type: "Qt3DRender::QEffect"; isPointer: true } - Signal { - name: "effectChanged" - Parameter { name: "effect"; type: "QEffect"; isPointer: true } - } - Method { - name: "setEffect" - Parameter { name: "effect"; type: "QEffect"; isPointer: true } - } - } - Component { - prototype: "Qt3DCore::QComponent" - name: "Qt3D.Extras/DiffuseSpecularMapMaterial 2.0" - exports: ["Qt3D.Extras/DiffuseSpecularMapMaterial 2.0"] - exportMetaObjectRevisions: [0] - isComposite: true - defaultProperty: "data" - Property { name: "ambient"; type: "QColor" } - Property { name: "shininess"; type: "double" } - Property { name: "textureScale"; type: "double" } - Property { name: "diffuse"; type: "QUrl" } - Property { name: "specular"; type: "QUrl" } - Property { name: "effect"; type: "Qt3DRender::QEffect"; isPointer: true } - Signal { - name: "effectChanged" - Parameter { name: "effect"; type: "QEffect"; isPointer: true } - } - Method { - name: "setEffect" - Parameter { name: "effect"; type: "QEffect"; isPointer: true } - } - } - Component { - prototype: "Qt3DCore::QNode" - name: "Qt3D.Extras/FirstPersonCameraController 2.0" - exports: ["Qt3D.Extras/FirstPersonCameraController 2.0"] - exportMetaObjectRevisions: [0] - isComposite: true - defaultProperty: "data" - Property { name: "camera"; type: "Qt3DRender::QCamera"; isPointer: true } - Property { name: "linearSpeed"; type: "double" } - Property { name: "lookSpeed"; type: "double" } - Property { name: "acceleration"; type: "double" } - Property { name: "deceleration"; type: "double" } - } - Component { - prototype: "Qt3DCore::QNode" - name: "Qt3D.Extras/ForwardRenderer 2.0" - exports: ["Qt3D.Extras/ForwardRenderer 2.0"] - exportMetaObjectRevisions: [0] - isComposite: true - defaultProperty: "data" - Property { name: "camera"; type: "Qt3DCore::QEntity"; isPointer: true } - Property { name: "clearColor"; type: "QColor" } - Property { name: "viewportRect"; type: "QRectF" } - Property { name: "window"; type: "QObject"; isPointer: true } - } - Component { - prototype: "Qt3DCore::QComponent" - name: "Qt3D.Extras/GoochMaterial 2.0" - exports: ["Qt3D.Extras/GoochMaterial 2.0"] - exportMetaObjectRevisions: [0] - isComposite: true - defaultProperty: "data" - Property { name: "diffuse"; type: "QColor" } - Property { name: "specular"; type: "QColor" } - Property { name: "coolColor"; type: "QColor" } - Property { name: "warmColor"; type: "QColor" } - Property { name: "alpha"; type: "double" } - Property { name: "beta"; type: "double" } - Property { name: "shininess"; type: "double" } - Property { name: "effect"; type: "Qt3DRender::QEffect"; isPointer: true } - Signal { - name: "effectChanged" - Parameter { name: "effect"; type: "QEffect"; isPointer: true } - } - Method { - name: "setEffect" - Parameter { name: "effect"; type: "QEffect"; isPointer: true } - } - } - Component { - prototype: "Qt3DCore::QNode" - name: "Qt3D.Extras/NormalDiffuseMapAlphaEffect 2.0" - exports: ["Qt3D.Extras/NormalDiffuseMapAlphaEffect 2.0"] - exportMetaObjectRevisions: [0] - isComposite: true - defaultProperty: "data" - Property { name: "vertexES"; type: "string" } - Property { name: "fragmentES"; type: "string" } - Property { name: "vertex"; type: "string" } - Property { name: "fragment"; type: "string" } - } - Component { - prototype: "Qt3DCore::QComponent" - name: "Qt3D.Extras/NormalDiffuseMapAlphaMaterial 2.0" - exports: ["Qt3D.Extras/NormalDiffuseMapAlphaMaterial 2.0"] - exportMetaObjectRevisions: [0] - isComposite: true - defaultProperty: "data" - Property { name: "ambient"; type: "QColor" } - Property { name: "specular"; type: "QColor" } - Property { name: "shininess"; type: "double" } - Property { name: "textureScale"; type: "double" } - Property { name: "diffuse"; type: "QUrl" } - Property { name: "normal"; type: "QUrl" } - Property { name: "effect"; type: "Qt3DRender::QEffect"; isPointer: true } - Signal { - name: "effectChanged" - Parameter { name: "effect"; type: "QEffect"; isPointer: true } - } - Method { - name: "setEffect" - Parameter { name: "effect"; type: "QEffect"; isPointer: true } - } - } - Component { - prototype: "Qt3DCore::QComponent" - name: "Qt3D.Extras/NormalDiffuseMapMaterial 2.0" - exports: ["Qt3D.Extras/NormalDiffuseMapMaterial 2.0"] - exportMetaObjectRevisions: [0] - isComposite: true - defaultProperty: "data" - Property { name: "ambient"; type: "QColor" } - Property { name: "specular"; type: "QColor" } - Property { name: "shininess"; type: "double" } - Property { name: "textureScale"; type: "double" } - Property { name: "diffuse"; type: "QUrl" } - Property { name: "normal"; type: "QUrl" } - Property { name: "effect"; type: "Qt3DRender::QEffect"; isPointer: true } - Signal { - name: "effectChanged" - Parameter { name: "effect"; type: "QEffect"; isPointer: true } - } - Method { - name: "setEffect" - Parameter { name: "effect"; type: "QEffect"; isPointer: true } - } - } - Component { - prototype: "Qt3DCore::QComponent" - name: "Qt3D.Extras/NormalDiffuseSpecularMapMaterial 2.0" - exports: ["Qt3D.Extras/NormalDiffuseSpecularMapMaterial 2.0"] - exportMetaObjectRevisions: [0] - isComposite: true - defaultProperty: "data" - Property { name: "ambient"; type: "QColor" } - Property { name: "shininess"; type: "double" } - Property { name: "textureScale"; type: "double" } - Property { name: "diffuse"; type: "QUrl" } - Property { name: "specular"; type: "QUrl" } - Property { name: "normal"; type: "QUrl" } - Property { name: "effect"; type: "Qt3DRender::QEffect"; isPointer: true } - Signal { - name: "effectChanged" - Parameter { name: "effect"; type: "QEffect"; isPointer: true } - } - Method { - name: "setEffect" - Parameter { name: "effect"; type: "QEffect"; isPointer: true } - } - } - Component { - prototype: "Qt3DCore::QNode" - name: "Qt3D.Extras/OrbitCameraController 2.0" - exports: ["Qt3D.Extras/OrbitCameraController 2.0"] - exportMetaObjectRevisions: [0] - isComposite: true - defaultProperty: "data" - Property { name: "camera"; type: "Qt3DRender::QCamera"; isPointer: true } - Property { name: "linearSpeed"; type: "double" } - Property { name: "lookSpeed"; type: "double" } - Property { name: "zoomLimit"; type: "double" } - Method { - name: "clampInputs" - type: "QVariant" - Parameter { name: "input1"; type: "QVariant" } - Parameter { name: "input2"; type: "QVariant" } - } - Method { - name: "zoomDistance" - type: "QVariant" - Parameter { name: "firstPoint"; type: "QVariant" } - Parameter { name: "secondPoint"; type: "QVariant" } - } - } - Component { - prototype: "Qt3DCore::QComponent" - name: "Qt3D.Extras/PerVertexColorMaterial 2.0" - exports: ["Qt3D.Extras/PerVertexColorMaterial 2.0"] - exportMetaObjectRevisions: [0] - isComposite: true - defaultProperty: "data" - Property { name: "effect"; type: "Qt3DRender::QEffect"; isPointer: true } - Signal { - name: "effectChanged" - Parameter { name: "effect"; type: "QEffect"; isPointer: true } - } - Method { - name: "setEffect" - Parameter { name: "effect"; type: "QEffect"; isPointer: true } - } - } - Component { - prototype: "Qt3DCore::QComponent" - name: "Qt3D.Extras/PhongAlphaMaterial 2.0" - exports: ["Qt3D.Extras/PhongAlphaMaterial 2.0"] - exportMetaObjectRevisions: [0] - isComposite: true - defaultProperty: "data" - Property { name: "ambient"; type: "QColor" } - Property { name: "diffuse"; type: "QColor" } - Property { name: "specular"; type: "QColor" } - Property { name: "shininess"; type: "double" } - Property { name: "alpha"; type: "double" } - Property { name: "sourceRgbArg"; type: "int" } - Property { name: "destinationRgbArg"; type: "int" } - Property { name: "sourceAlphaArg"; type: "int" } - Property { name: "destinationAlphaArg"; type: "int" } - Property { name: "blendFunctionArg"; type: "int" } - Property { name: "effect"; type: "Qt3DRender::QEffect"; isPointer: true } - Signal { - name: "effectChanged" - Parameter { name: "effect"; type: "QEffect"; isPointer: true } - } - Method { - name: "setEffect" - Parameter { name: "effect"; type: "QEffect"; isPointer: true } - } - } - Component { - prototype: "Qt3DCore::QComponent" - name: "Qt3D.Extras/PhongMaterial 2.0" - exports: ["Qt3D.Extras/PhongMaterial 2.0"] - exportMetaObjectRevisions: [0] - isComposite: true - defaultProperty: "data" - Property { name: "ambient"; type: "QColor" } - Property { name: "diffuse"; type: "QColor" } - Property { name: "specular"; type: "QColor" } - Property { name: "shininess"; type: "double" } - Property { name: "effect"; type: "Qt3DRender::QEffect"; isPointer: true } - Signal { - name: "effectChanged" - Parameter { name: "effect"; type: "QEffect"; isPointer: true } - } - Method { - name: "setEffect" - Parameter { name: "effect"; type: "QEffect"; isPointer: true } - } - } - Component { + name: "Qt3DRender::QMaterial" prototype: "Qt3DCore::QComponent" - name: "Qt3D.Extras/TextureMaterial 2.0" - exports: ["Qt3D.Extras/TextureMaterial 2.0"] - exportMetaObjectRevisions: [0] - isComposite: true - defaultProperty: "data" - Property { name: "texture"; type: "Qt3DRender::QTexture2D"; isPointer: true } - Property { name: "textureOffset"; type: "QVector2D" } Property { name: "effect"; type: "Qt3DRender::QEffect"; isPointer: true } Signal { name: "effectChanged" @@ -1193,4 +1629,5 @@ Module { Parameter { name: "effect"; type: "QEffect"; isPointer: true } } } + Component { name: "Qt3DRender::QTechniqueFilter"; prototype: "Qt3DRender::QFrameGraphNode" } } -- cgit v1.2.3 From e6444f7d6626390711c31dd2cb3f3d25eb60c812 Mon Sep 17 00:00:00 2001 From: Kevin Ottens Date: Fri, 27 Jan 2017 10:35:42 +0100 Subject: Resurect ForwardRenderer.qml in an example Could be useful to have it around in an example still, so that people get an idea on how to make their own framegraph in QML from scratch. Some other examples have QML framegraphs too, but this one is simpler. Change-Id: I9065af920b1233d3f06cfee71c59afe98359cb7e Reviewed-by: Sean Harmer --- examples/qt3d/lights/SimpleForwardRenderer.qml | 77 ++++++++++++++++++++++++++ examples/qt3d/lights/lights.qrc | 1 + examples/qt3d/lights/main.qml | 2 +- 3 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 examples/qt3d/lights/SimpleForwardRenderer.qml diff --git a/examples/qt3d/lights/SimpleForwardRenderer.qml b/examples/qt3d/lights/SimpleForwardRenderer.qml new file mode 100644 index 000000000..b7ad3188c --- /dev/null +++ b/examples/qt3d/lights/SimpleForwardRenderer.qml @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import Qt3D.Core 2.0 +import Qt3D.Render 2.0 + +TechniqueFilter { + // Expose camera to allow user to choose which camera to use for rendering + property alias camera: cameraSelector.camera + property alias clearColor: clearBuffer.clearColor + property alias viewportRect: viewport.normalizedRect + property alias window: surfaceSelector.surface + property alias externalRenderTargetSize: surfaceSelector.externalRenderTargetSize + property alias frustumCulling: frustumCulling.enabled + + // Select the forward rendering Technique of any used Effect + matchAll: [ FilterKey { name: "renderingStyle"; value: "forward" } ] + + RenderSurfaceSelector { + id: surfaceSelector + + // Use the whole viewport + Viewport { + id: viewport + normalizedRect: Qt.rect(0.0, 0.0, 1.0, 1.0) + + // Use the specified camera + CameraSelector { + id : cameraSelector + FrustumCulling { + id: frustumCulling + ClearBuffers { + id: clearBuffer + clearColor: "white" + buffers : ClearBuffers.ColorDepthBuffer + } + } + } + } + } +} diff --git a/examples/qt3d/lights/lights.qrc b/examples/qt3d/lights/lights.qrc index caa3f2d28..278abe5ae 100644 --- a/examples/qt3d/lights/lights.qrc +++ b/examples/qt3d/lights/lights.qrc @@ -2,5 +2,6 @@ main.qml PlaneEntity.qml + SimpleForwardRenderer.qml diff --git a/examples/qt3d/lights/main.qml b/examples/qt3d/lights/main.qml index 69250da13..c676335c4 100644 --- a/examples/qt3d/lights/main.qml +++ b/examples/qt3d/lights/main.qml @@ -58,7 +58,7 @@ Entity { components: [ RenderSettings { - activeFrameGraph: ForwardRenderer { + activeFrameGraph: SimpleForwardRenderer { clearColor: Qt.rgba(0, 0, 0, 1) camera: camera } -- cgit v1.2.3 From 9c5bf588ab310e274fddffb252962e8abfa66bd2 Mon Sep 17 00:00:00 2001 From: Kevin Ottens Date: Fri, 27 Jan 2017 15:39:09 +0100 Subject: Adding PBR lighting to Qt3DExtras This is a first implementation which only exploits environment maps for lighting. It still needs to interact with the lights coming from Qt 3D API. It also provided a fully texture map based material. Improvements and plain colors variant of the material will come in later commits. Change-Id: Ifc6079e5c40484b6daac05692780495013b7c401 Reviewed-by: Sean Harmer --- src/extras/defaults/defaults.pri | 8 +- .../defaults/qtexturedmetalroughmaterial.cpp | 460 +++++++++++++++++++++ src/extras/defaults/qtexturedmetalroughmaterial.h | 108 +++++ .../defaults/qtexturedmetalroughmaterial_p.h | 119 ++++++ src/extras/extras.qrc | 2 + src/extras/shaders/gl3/metalrough.frag | 239 +++++++++++ src/extras/shaders/gl3/metalrough.vert | 79 ++++ .../imports/extras/qt3dquick3dextrasplugin.cpp | 2 + 8 files changed, 1015 insertions(+), 2 deletions(-) create mode 100644 src/extras/defaults/qtexturedmetalroughmaterial.cpp create mode 100644 src/extras/defaults/qtexturedmetalroughmaterial.h create mode 100644 src/extras/defaults/qtexturedmetalroughmaterial_p.h create mode 100644 src/extras/shaders/gl3/metalrough.frag create mode 100644 src/extras/shaders/gl3/metalrough.vert diff --git a/src/extras/defaults/defaults.pri b/src/extras/defaults/defaults.pri index 8e6a5861a..58204bd71 100644 --- a/src/extras/defaults/defaults.pri +++ b/src/extras/defaults/defaults.pri @@ -29,7 +29,10 @@ HEADERS += \ $$PWD/qorbitcameracontroller.h \ $$PWD/qorbitcameracontroller_p.h \ $$PWD/qtexturematerial.h \ - $$PWD/qtexturematerial_p.h + $$PWD/qtexturematerial_p.h \ + $$PWD/qtexturedmetalroughmaterial.h \ + $$PWD/qtexturedmetalroughmaterial_p.h + SOURCES += \ $$PWD/qphongmaterial.cpp \ @@ -46,5 +49,6 @@ SOURCES += \ $$PWD/qt3dwindow.cpp \ $$PWD/qfirstpersoncameracontroller.cpp \ $$PWD/qorbitcameracontroller.cpp \ - $$PWD/qtexturematerial.cpp + $$PWD/qtexturematerial.cpp \ + $$PWD/qtexturedmetalroughmaterial.cpp diff --git a/src/extras/defaults/qtexturedmetalroughmaterial.cpp b/src/extras/defaults/qtexturedmetalroughmaterial.cpp new file mode 100644 index 000000000..25fe5e344 --- /dev/null +++ b/src/extras/defaults/qtexturedmetalroughmaterial.cpp @@ -0,0 +1,460 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtexturedmetalroughmaterial.h" +#include "qtexturedmetalroughmaterial_p.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +using namespace Qt3DRender; + +namespace Qt3DExtras { + +QTexturedMetalRoughMaterialPrivate::QTexturedMetalRoughMaterialPrivate() + : QMaterialPrivate() + , m_albedoTexture(new QTexture2D()) + , m_metallicTexture(new QTexture2D()) + , m_roughnessTexture(new QTexture2D()) + , m_ambientOcclusionTexture(new QTexture2D()) + , m_normalTexture(new QTexture2D()) + , m_environmentIrradianceTexture(new QTexture2D()) + , m_environmentSpecularTexture(new QTexture2D()) + , m_albedoParameter(new QParameter(QStringLiteral("albedoMap"), m_albedoTexture)) + , m_metallicParameter(new QParameter(QStringLiteral("metallicMap"), m_metallicTexture)) + , m_roughnessParameter(new QParameter(QStringLiteral("roughnessMap"), m_roughnessTexture)) + , m_ambientOcclusionParameter(new QParameter(QStringLiteral("ambientOcclusionMap"), m_ambientOcclusionTexture)) + , m_normalParameter(new QParameter(QStringLiteral("normalMap"), m_normalTexture)) + , m_environmentIrradianceParameter(new QParameter(QStringLiteral("skyIrradiance"), m_environmentIrradianceTexture)) + , m_environmentSpecularParameter(new QParameter(QStringLiteral("skySpecular"), m_environmentSpecularTexture)) + , m_exposureParameter(new QParameter(QStringLiteral("exposure"), 0.0f)) + , m_metalRoughEffect(new QEffect()) + , m_metalRoughGL3Technique(new QTechnique()) + , m_metalRoughGL3RenderPass(new QRenderPass()) + , m_metalRoughGL3Shader(new QShaderProgram()) + , m_filterKey(new QFilterKey) +{ + m_albedoTexture->setMagnificationFilter(QAbstractTexture::Linear); + m_albedoTexture->setMinificationFilter(QAbstractTexture::LinearMipMapLinear); + m_albedoTexture->setWrapMode(QTextureWrapMode(QTextureWrapMode::Repeat)); + m_albedoTexture->setGenerateMipMaps(true); + m_albedoTexture->setMaximumAnisotropy(16.0f); + + m_metallicTexture->setMagnificationFilter(QAbstractTexture::Linear); + m_metallicTexture->setMinificationFilter(QAbstractTexture::LinearMipMapLinear); + m_metallicTexture->setWrapMode(QTextureWrapMode(QTextureWrapMode::Repeat)); + m_metallicTexture->setGenerateMipMaps(true); + m_metallicTexture->setMaximumAnisotropy(16.0f); + + m_roughnessTexture->setMagnificationFilter(QAbstractTexture::Linear); + m_roughnessTexture->setMinificationFilter(QAbstractTexture::LinearMipMapLinear); + m_roughnessTexture->setWrapMode(QTextureWrapMode(QTextureWrapMode::Repeat)); + m_roughnessTexture->setGenerateMipMaps(true); + m_roughnessTexture->setMaximumAnisotropy(16.0f); + + m_ambientOcclusionTexture->setMagnificationFilter(QAbstractTexture::Linear); + m_ambientOcclusionTexture->setMinificationFilter(QAbstractTexture::LinearMipMapLinear); + m_ambientOcclusionTexture->setWrapMode(QTextureWrapMode(QTextureWrapMode::Repeat)); + m_ambientOcclusionTexture->setGenerateMipMaps(true); + m_ambientOcclusionTexture->setMaximumAnisotropy(16.0f); + + m_normalTexture->setMagnificationFilter(QAbstractTexture::Linear); + m_normalTexture->setMinificationFilter(QAbstractTexture::LinearMipMapLinear); + m_normalTexture->setWrapMode(QTextureWrapMode(QTextureWrapMode::Repeat)); + m_normalTexture->setGenerateMipMaps(true); + m_normalTexture->setMaximumAnisotropy(16.0f); + + m_environmentIrradianceTexture->setMagnificationFilter(QAbstractTexture::Linear); + m_environmentIrradianceTexture->setMinificationFilter(QAbstractTexture::LinearMipMapLinear); + m_environmentIrradianceTexture->setWrapMode(QTextureWrapMode(QTextureWrapMode::Repeat)); + m_environmentIrradianceTexture->setGenerateMipMaps(true); + m_environmentIrradianceTexture->setMaximumAnisotropy(16.0f); + + m_environmentSpecularTexture->setMagnificationFilter(QAbstractTexture::Linear); + m_environmentSpecularTexture->setMinificationFilter(QAbstractTexture::LinearMipMapLinear); + m_environmentSpecularTexture->setWrapMode(QTextureWrapMode(QTextureWrapMode::Repeat)); + m_environmentSpecularTexture->setGenerateMipMaps(true); + m_environmentSpecularTexture->setMaximumAnisotropy(16.0f); +} + +void QTexturedMetalRoughMaterialPrivate::init() +{ + connect(m_albedoParameter, &Qt3DRender::QParameter::valueChanged, + this, &QTexturedMetalRoughMaterialPrivate::handleAlbedoChanged); + connect(m_metallicParameter, &Qt3DRender::QParameter::valueChanged, + this, &QTexturedMetalRoughMaterialPrivate::handleMetallicChanged); + connect(m_roughnessParameter, &Qt3DRender::QParameter::valueChanged, + this, &QTexturedMetalRoughMaterialPrivate::handleRoughnessChanged); + connect(m_ambientOcclusionParameter, &Qt3DRender::QParameter::valueChanged, + this, &QTexturedMetalRoughMaterialPrivate::handleAmbientOcclusionChanged); + connect(m_normalParameter, &Qt3DRender::QParameter::valueChanged, + this, &QTexturedMetalRoughMaterialPrivate::handleNormalChanged); + connect(m_environmentIrradianceParameter, &Qt3DRender::QParameter::valueChanged, + this, &QTexturedMetalRoughMaterialPrivate::handleEnvironmentIrradianceChanged); + connect(m_environmentSpecularParameter, &Qt3DRender::QParameter::valueChanged, + this, &QTexturedMetalRoughMaterialPrivate::handleEnvironmentSpecularChanged); + connect(m_exposureParameter, &Qt3DRender::QParameter::valueChanged, + this, &QTexturedMetalRoughMaterialPrivate::handleExposureChanged); + + m_metalRoughGL3Shader->setVertexShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/gl3/metalrough.vert")))); + m_metalRoughGL3Shader->setFragmentShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/gl3/metalrough.frag")))); + + m_metalRoughGL3Technique->graphicsApiFilter()->setApi(QGraphicsApiFilter::OpenGL); + m_metalRoughGL3Technique->graphicsApiFilter()->setMajorVersion(3); + m_metalRoughGL3Technique->graphicsApiFilter()->setMinorVersion(1); + m_metalRoughGL3Technique->graphicsApiFilter()->setProfile(QGraphicsApiFilter::CoreProfile); + + Q_Q(QTexturedMetalRoughMaterial); + m_filterKey->setParent(q); + m_filterKey->setName(QStringLiteral("renderingStyle")); + m_filterKey->setValue(QStringLiteral("forward")); + + m_metalRoughGL3Technique->addFilterKey(m_filterKey); + m_metalRoughGL3RenderPass->setShaderProgram(m_metalRoughGL3Shader); + m_metalRoughGL3Technique->addRenderPass(m_metalRoughGL3RenderPass); + m_metalRoughEffect->addTechnique(m_metalRoughGL3Technique); + + m_metalRoughEffect->addParameter(m_albedoParameter); + m_metalRoughEffect->addParameter(m_metallicParameter); + m_metalRoughEffect->addParameter(m_roughnessParameter); + m_metalRoughEffect->addParameter(m_ambientOcclusionParameter); + m_metalRoughEffect->addParameter(m_normalParameter); + m_metalRoughEffect->addParameter(m_environmentIrradianceParameter); + m_metalRoughEffect->addParameter(m_environmentSpecularParameter); + m_metalRoughEffect->addParameter(m_exposureParameter); + + q->setEffect(m_metalRoughEffect); +} + +void QTexturedMetalRoughMaterialPrivate::handleAlbedoChanged(const QVariant &var) +{ + Q_Q(QTexturedMetalRoughMaterial); + emit q->albedoChanged(var.value()); +} + +void QTexturedMetalRoughMaterialPrivate::handleMetallicChanged(const QVariant &var) +{ + Q_Q(QTexturedMetalRoughMaterial); + emit q->metallicChanged(var.value()); +} +void QTexturedMetalRoughMaterialPrivate::handleRoughnessChanged(const QVariant &var) +{ + Q_Q(QTexturedMetalRoughMaterial); + emit q->roughnessChanged(var.value()); +} +void QTexturedMetalRoughMaterialPrivate::handleAmbientOcclusionChanged(const QVariant &var) +{ + Q_Q(QTexturedMetalRoughMaterial); + emit q->ambientOcclusionChanged(var.value()); +} + +void QTexturedMetalRoughMaterialPrivate::handleNormalChanged(const QVariant &var) +{ + Q_Q(QTexturedMetalRoughMaterial); + emit q->normalChanged(var.value()); +} + +void QTexturedMetalRoughMaterialPrivate::handleEnvironmentIrradianceChanged(const QVariant &var) +{ + Q_Q(QTexturedMetalRoughMaterial); + emit q->environmentIrradianceChanged(var.value()); +} + +void QTexturedMetalRoughMaterialPrivate::handleEnvironmentSpecularChanged(const QVariant &var) +{ + Q_Q(QTexturedMetalRoughMaterial); + emit q->environmentSpecularChanged(var.value()); +} + +void QTexturedMetalRoughMaterialPrivate::handleExposureChanged(const QVariant &var) +{ + Q_Q(QTexturedMetalRoughMaterial); + emit q->exposureChanged(var.toFloat()); +} + +/*! + \class Qt3DExtras::QTexturedMetalRoughMaterial + \brief The QTexturedMetalRoughMaterial provides a default implementation of PBR + lighting, environment maps and bump effect where the components are read from texture + maps (including normal maps). + \inmodule Qt3DExtras + \since 5.9 + \inherits Qt3DRender::QMaterial + + This material uses an effect with a single render pass approach and performs per fragment + lighting. Techniques are provided for OpenGL 3 only. +*/ + +/*! + Constructs a new QTexturedMetalRoughMaterial instance with parent object \a parent. +*/ +QTexturedMetalRoughMaterial::QTexturedMetalRoughMaterial(QNode *parent) + : QMaterial(*new QTexturedMetalRoughMaterialPrivate, parent) +{ + Q_D(QTexturedMetalRoughMaterial); + d->init(); +} + +/*! \internal */ +QTexturedMetalRoughMaterial::QTexturedMetalRoughMaterial(QTexturedMetalRoughMaterialPrivate &dd, QNode *parent) + : QMaterial(dd, parent) +{ + Q_D(QTexturedMetalRoughMaterial); + d->init(); +} + +/*! + Destroys the QTexturedMetalRoughMaterial instance. +*/ +QTexturedMetalRoughMaterial::~QTexturedMetalRoughMaterial() +{ +} + +/*! + \property QTexturedMetalRoughMaterial::albedo + + Holds the current albedo map texture. + + By default, the albedo texture has the following properties: + + \list + \li Linear minification and magnification filters + \li Linear mipmap with mipmapping enabled + \li Repeat wrap mode + \li Maximum anisotropy of 16.0 + \endlist +*/ +QAbstractTexture *QTexturedMetalRoughMaterial::albedo() const +{ + Q_D(const QTexturedMetalRoughMaterial); + return d->m_albedoParameter->value().value(); +} + +/*! + \property QTexturedMetalRoughMaterial::metallic + + Holds the current metallic map texture. + + By default, the metallic texture has the following properties: + + \list + \li Linear minification and magnification filters + \li Linear mipmap with mipmapping enabled + \li Repeat wrap mode + \li Maximum anisotropy of 16.0 + \endlist +*/ +QAbstractTexture *QTexturedMetalRoughMaterial::metallic() const +{ + Q_D(const QTexturedMetalRoughMaterial); + return d->m_metallicParameter->value().value(); +} + +/*! + \property QTexturedMetalRoughMaterial::roughness + + Holds the current roughness map texture. + + By default, the roughness texture has the following properties: + + \list + \li Linear minification and magnification filters + \li Linear mipmap with mipmapping enabled + \li Repeat wrap mode + \li Maximum anisotropy of 16.0 + \endlist +*/ +QAbstractTexture *QTexturedMetalRoughMaterial::roughness() const +{ + Q_D(const QTexturedMetalRoughMaterial); + return d->m_roughnessParameter->value().value(); +} + +/*! + \property QTexturedMetalRoughMaterial::ambientOcclusion + + Holds the current ambient occlusion map texture. + + By default, the ambient occlusion texture has the following properties: + + \list + \li Linear minification and magnification filters + \li Linear mipmap with mipmapping enabled + \li Repeat wrap mode + \li Maximum anisotropy of 16.0 + \endlist +*/ +QAbstractTexture *QTexturedMetalRoughMaterial::ambientOcclusion() const +{ + Q_D(const QTexturedMetalRoughMaterial); + return d->m_ambientOcclusionParameter->value().value(); +} + +/*! + \property QTexturedMetalRoughMaterial::normal + + Holds the current normal map texture. + + By default, the normal texture has the following properties: + + \list + \li Linear minification and magnification filters + \li Repeat wrap mode + \li Maximum anisotropy of 16.0 + \endlist +*/ +QAbstractTexture *QTexturedMetalRoughMaterial::normal() const +{ + Q_D(const QTexturedMetalRoughMaterial); + return d->m_normalParameter->value().value(); +} + +/*! + \property QTexturedMetalRoughMaterial::environmentIrradiance + + Holds the current environment irradiance map texture. + + By default, the environment irradiance texture has the following properties: + + \list + \li Linear minification and magnification filters + \li Linear mipmap with mipmapping enabled + \li Repeat wrap mode + \li Maximum anisotropy of 16.0 + \endlist +*/ +QAbstractTexture *QTexturedMetalRoughMaterial::environmentIrradiance() const +{ + Q_D(const QTexturedMetalRoughMaterial); + return d->m_environmentIrradianceParameter->value().value(); +} + +/*! + \property QTexturedMetalRoughMaterial::environmentSpecular + + Holds the current environment specular map texture. + + By default, the environment specular texture has the following properties: + + \list + \li Linear minification and magnification filters + \li Linear mipmap with mipmapping enabled + \li Repeat wrap mode + \li Maximum anisotropy of 16.0 + \endlist +*/ +QAbstractTexture *QTexturedMetalRoughMaterial::environmentSpecular() const +{ + Q_D(const QTexturedMetalRoughMaterial); + return d->m_environmentSpecularParameter->value().value(); +} + +/*! + \property QTexturedMetalRoughMaterial::exposure + + Holds the current exposure as a float value. +*/ +float QTexturedMetalRoughMaterial::exposure() const +{ + Q_D(const QTexturedMetalRoughMaterial); + return d->m_exposureParameter->value().toFloat(); +} + +void QTexturedMetalRoughMaterial::setAlbedo(QAbstractTexture *albedo) +{ + Q_D(QTexturedMetalRoughMaterial); + d->m_albedoParameter->setValue(QVariant::fromValue(albedo)); +} + +void QTexturedMetalRoughMaterial::setMetallic(QAbstractTexture *metallic) +{ + Q_D(QTexturedMetalRoughMaterial); + d->m_metallicParameter->setValue(QVariant::fromValue(metallic)); +} + +void QTexturedMetalRoughMaterial::setRoughness(QAbstractTexture *roughness) +{ + Q_D(QTexturedMetalRoughMaterial); + d->m_roughnessParameter->setValue(QVariant::fromValue(roughness)); +} + +void QTexturedMetalRoughMaterial::setAmbientOcclusion(QAbstractTexture *ambientOcclusion) +{ + Q_D(QTexturedMetalRoughMaterial); + d->m_ambientOcclusionParameter->setValue(QVariant::fromValue(ambientOcclusion)); +} + +void QTexturedMetalRoughMaterial::setNormal(QAbstractTexture *normal) +{ + Q_D(QTexturedMetalRoughMaterial); + d->m_normalParameter->setValue(QVariant::fromValue(normal)); +} + +void QTexturedMetalRoughMaterial::setEnvironmentIrradiance(QAbstractTexture *environmentIrradiance) +{ + Q_D(QTexturedMetalRoughMaterial); + d->m_environmentIrradianceParameter->setValue(QVariant::fromValue(environmentIrradiance)); +} + +void QTexturedMetalRoughMaterial::setEnvironmentSpecular(QAbstractTexture *environmentSpecular) +{ + Q_D(QTexturedMetalRoughMaterial); + d->m_environmentSpecularParameter->setValue(QVariant::fromValue(environmentSpecular)); +} + +void QTexturedMetalRoughMaterial::setExposure(float exposure) +{ + Q_D(QTexturedMetalRoughMaterial); + d->m_exposureParameter->setValue(exposure); +} + +} // namespace Qt3DExtras + +QT_END_NAMESPACE diff --git a/src/extras/defaults/qtexturedmetalroughmaterial.h b/src/extras/defaults/qtexturedmetalroughmaterial.h new file mode 100644 index 000000000..755dd3e5a --- /dev/null +++ b/src/extras/defaults/qtexturedmetalroughmaterial.h @@ -0,0 +1,108 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3DEXTRAS_QTEXTUREDMETALROUGHMATERIAL_H +#define QT3DEXTRAS_QTEXTUREDMETALROUGHMATERIAL_H + +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DExtras { + +class QTexturedMetalRoughMaterialPrivate; + +class QT3DEXTRASSHARED_EXPORT QTexturedMetalRoughMaterial : public Qt3DRender::QMaterial +{ + Q_OBJECT + Q_PROPERTY(Qt3DRender::QAbstractTexture *albedo READ albedo WRITE setAlbedo NOTIFY albedoChanged) + Q_PROPERTY(Qt3DRender::QAbstractTexture *metallic READ metallic WRITE setMetallic NOTIFY metallicChanged) + Q_PROPERTY(Qt3DRender::QAbstractTexture *roughness READ roughness WRITE setRoughness NOTIFY roughnessChanged) + Q_PROPERTY(Qt3DRender::QAbstractTexture *ambientOcclusion READ ambientOcclusion WRITE setAmbientOcclusion NOTIFY ambientOcclusionChanged) + Q_PROPERTY(Qt3DRender::QAbstractTexture *normal READ normal WRITE setNormal NOTIFY normalChanged) + Q_PROPERTY(Qt3DRender::QAbstractTexture *environmentIrradiance READ environmentIrradiance WRITE setEnvironmentIrradiance NOTIFY environmentIrradianceChanged) + Q_PROPERTY(Qt3DRender::QAbstractTexture *environmentSpecular READ environmentSpecular WRITE setEnvironmentSpecular NOTIFY environmentSpecularChanged) + Q_PROPERTY(float exposure READ exposure WRITE setExposure NOTIFY exposureChanged) + +public: + explicit QTexturedMetalRoughMaterial(Qt3DCore::QNode *parent = nullptr); + ~QTexturedMetalRoughMaterial(); + + Qt3DRender::QAbstractTexture *albedo() const; + Qt3DRender::QAbstractTexture *metallic() const; + Qt3DRender::QAbstractTexture *roughness() const; + Qt3DRender::QAbstractTexture *ambientOcclusion() const; + Qt3DRender::QAbstractTexture *normal() const; + Qt3DRender::QAbstractTexture *environmentIrradiance() const; + Qt3DRender::QAbstractTexture *environmentSpecular() const; + float exposure() const; + +public Q_SLOTS: + void setAlbedo(Qt3DRender::QAbstractTexture *albedo); + void setMetallic(Qt3DRender::QAbstractTexture *metallic); + void setRoughness(Qt3DRender::QAbstractTexture *roughness); + void setAmbientOcclusion(Qt3DRender::QAbstractTexture *ambientOcclusion); + void setNormal(Qt3DRender::QAbstractTexture *normal); + void setEnvironmentIrradiance(Qt3DRender::QAbstractTexture *environmentIrradiance); + void setEnvironmentSpecular(Qt3DRender::QAbstractTexture *environmentSpecular); + void setExposure(float exposure); + +Q_SIGNALS: + void albedoChanged(Qt3DRender::QAbstractTexture *albedo); + void metallicChanged(Qt3DRender::QAbstractTexture *metallic); + void roughnessChanged(Qt3DRender::QAbstractTexture *roughness); + void ambientOcclusionChanged(Qt3DRender::QAbstractTexture *ambientOcclusion); + void normalChanged(Qt3DRender::QAbstractTexture *normal); + void environmentIrradianceChanged(Qt3DRender::QAbstractTexture *environmentIrradiance); + void environmentSpecularChanged(Qt3DRender::QAbstractTexture *environmentSpecular); + void exposureChanged(float exposure); + +protected: + QTexturedMetalRoughMaterial(QTexturedMetalRoughMaterialPrivate &dd, Qt3DCore::QNode *parent = nullptr); + +private: + Q_DECLARE_PRIVATE(QTexturedMetalRoughMaterial) +}; + +} // namespace Qt3DExtras + +QT_END_NAMESPACE + +#endif // QT3DEXTRAS_QTEXTUREDMETALROUGHMATERIAL_H diff --git a/src/extras/defaults/qtexturedmetalroughmaterial_p.h b/src/extras/defaults/qtexturedmetalroughmaterial_p.h new file mode 100644 index 000000000..9a5825efa --- /dev/null +++ b/src/extras/defaults/qtexturedmetalroughmaterial_p.h @@ -0,0 +1,119 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3DEXTRAS_QTEXTUREDMETALROUGHMATERIAL_P_H +#define QT3DEXTRAS_QTEXTUREDMETALROUGHMATERIAL_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +class QFilterKey; +class QEffect; +class QAbstractTexture; +class QTechnique; +class QParameter; +class QShaderProgram; +class QRenderPass; + +} // namespace Qt3DRender + +namespace Qt3DExtras { + +class QTexturedMetalRoughMaterial; + +class QTexturedMetalRoughMaterialPrivate : public Qt3DRender::QMaterialPrivate +{ +public: + QTexturedMetalRoughMaterialPrivate(); + + void init(); + + void handleAlbedoChanged(const QVariant &var); + void handleMetallicChanged(const QVariant &var); + void handleRoughnessChanged(const QVariant &var); + void handleAmbientOcclusionChanged(const QVariant &var); + void handleNormalChanged(const QVariant &var); + void handleEnvironmentIrradianceChanged(const QVariant &var); + void handleEnvironmentSpecularChanged(const QVariant &var); + void handleExposureChanged(const QVariant &var); + + Qt3DRender::QAbstractTexture *m_albedoTexture; + Qt3DRender::QAbstractTexture *m_metallicTexture; + Qt3DRender::QAbstractTexture *m_roughnessTexture; + Qt3DRender::QAbstractTexture *m_ambientOcclusionTexture; + Qt3DRender::QAbstractTexture *m_normalTexture; + Qt3DRender::QAbstractTexture *m_environmentIrradianceTexture; + Qt3DRender::QAbstractTexture *m_environmentSpecularTexture; + Qt3DRender::QParameter *m_albedoParameter; + Qt3DRender::QParameter *m_metallicParameter; + Qt3DRender::QParameter *m_roughnessParameter; + Qt3DRender::QParameter *m_ambientOcclusionParameter; + Qt3DRender::QParameter *m_normalParameter; + Qt3DRender::QParameter *m_environmentIrradianceParameter; + Qt3DRender::QParameter *m_environmentSpecularParameter; + Qt3DRender::QParameter *m_exposureParameter; + Qt3DRender::QEffect *m_metalRoughEffect; + Qt3DRender::QTechnique *m_metalRoughGL3Technique; + Qt3DRender::QRenderPass *m_metalRoughGL3RenderPass; + Qt3DRender::QShaderProgram *m_metalRoughGL3Shader; + Qt3DRender::QFilterKey *m_filterKey; + + Q_DECLARE_PUBLIC(QTexturedMetalRoughMaterial) +}; + +} // Qt3DExtras + +QT_END_NAMESPACE + +#endif // QT3DEXTRAS_QTEXTUREDMETALROUGHMATERIAL_P_H + diff --git a/src/extras/extras.qrc b/src/extras/extras.qrc index e7b1c1d9a..1319b10a5 100644 --- a/src/extras/extras.qrc +++ b/src/extras/extras.qrc @@ -39,5 +39,7 @@ shaders/gl3/unlittexture.frag shaders/es2/unlittexture.frag shaders/es2/unlittexture.vert + shaders/gl3/metalrough.vert + shaders/gl3/metalrough.frag diff --git a/src/extras/shaders/gl3/metalrough.frag b/src/extras/shaders/gl3/metalrough.frag new file mode 100644 index 000000000..385bb2db9 --- /dev/null +++ b/src/extras/shaders/gl3/metalrough.frag @@ -0,0 +1,239 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#version 150 + +in vec2 texCoord; +in vec3 worldPosition; +in vec3 worldNormal; +in vec4 worldTangent; + +out vec4 fragColor; + +// Qt 3D built in uniforms +uniform vec3 eyePosition; // World space eye position +uniform float time; // Time in seconds + +// Pre-convolved environment maps +uniform samplerCube skyIrradiance; // For diffuse contribution +uniform samplerCube skySpecular; // For specular contribution + +// PBR Material maps +uniform sampler2D albedoMap; +uniform sampler2D metallicMap; +uniform sampler2D roughnessMap; +uniform sampler2D normalMap; +uniform sampler2D ambientOcclusionMap; + +// User control parameters +uniform float metalFactor = 1.0; + +// Roughness -> mip level mapping +uniform float maxT = 0.939824; +uniform float mipLevels = 11.0; +uniform float mipOffset = 5.0; + +// Exposure correction +uniform float exposure = 0.0; + +mat3 calcWorldSpaceToTangentSpaceMatrix(const in vec3 wNormal, const in vec4 wTangent) +{ + // Make the tangent truly orthogonal to the normal by using Gram-Schmidt. + // This allows to build the tangentMatrix below by simply transposing the + // tangent -> eyespace matrix (which would now be orthogonal) + vec3 wFixedTangent = normalize(wTangent.xyz - dot(wTangent.xyz, wNormal) * wNormal); + + // Calculate binormal vector. No "real" need to renormalize it, + // as built by crossing two normal vectors. + // To orient the binormal correctly, use the fourth coordinate of the tangent, + // which is +1 for a right hand system, and -1 for a left hand system. + vec3 wBinormal = cross(wNormal, wFixedTangent.xyz) * wTangent.w; + + // Construct matrix to transform from world space to tangent space + // This is the transpose of the tangentToWorld transformation matrix + mat3 tangentToWorldMatrix = mat3(wFixedTangent, wBinormal, wNormal); + mat3 worldToTangentMatrix = transpose(tangentToWorldMatrix); + return worldToTangentMatrix; +} + +float roughnessToMipLevel(float roughness) +{ + // HACK: Improve the roughness -> mip level mapping for roughness map from substace painter + // TODO: Use mathematica or similar to improve this mapping more generally + roughness = 0.75 + (1.7 * (roughness - 0.5)); + return (mipLevels - 1.0 - mipOffset) * (1.0 - (1.0 - roughness) / maxT); +} + +vec3 fresnelFactor(const in vec3 color, const in float cosineFactor) +{ + // Calculate the Fresnel effect value + vec3 f = color; + vec3 F = f + (1.0 - f) * pow(1.0 - cosineFactor, 5.0); + return clamp(F, f, vec3(1.0)); +} + +float geometricModel(const in float lDotN, + const in float vDotN, + const in vec3 h) +{ + // Implicit geometric model (equal to denominator in specular model). + // This currently assumes that there is no attenuation by geometric shadowing or + // masking according to the microfacet theory. + return 1.0; +} + +vec3 specularModel(const in vec3 F0, + const in float lDotH, + const in float lDotN, + const in float vDotN, + const in vec3 n, + const in vec3 h) +{ + // Clamp lDotN and vDotN to small positive value to prevent the + // denominator in the reflection equation going to infinity. Balance this + // by using the clamped values in the geometric factor function to + // avoid ugly seams in the specular lighting. + float sDotNPrime = max(lDotN, 0.001); + float vDotNPrime = max(vDotN, 0.001); + + vec3 F = fresnelFactor(F0, lDotH); + float G = geometricModel(sDotNPrime, vDotNPrime, h); + + // TODO: Verify which parts of the BRDF Lys is preconvolving and multiply + // by the remaining factors here. + vec3 cSpec = F * G / (4.0 * sDotNPrime * vDotNPrime); + return clamp(cSpec, vec3(0.0), vec3(1.0)); +} + +vec3 pbrIblModel(const in vec3 wNormal, + const in vec3 wView, + const in vec3 baseColor, + const in float metallic, + const in float roughness, + const in float ambientOcclusion) +{ + // Calculate reflection direction of view vector about surface normal + // vector in world space. This is used in the fragment shader to sample + // from the environment textures for a light source. This is equivalent + // to the l vector for punctual light sources. Armed with this, calculate + // the usual factors needed + vec3 n = wNormal; + vec3 l = reflect(-wView, n); + vec3 v = wView; + vec3 h = normalize(l + v); + float vDotN = dot(v, n); + float lDotN = dot(l, n); + float lDotH = dot(l, h); + + // Calculate diffuse component + vec3 diffuseColor = (1.0 - metallic) * baseColor; + vec3 diffuse = diffuseColor * texture(skyIrradiance, l).rgb; + + // Calculate specular component + vec3 dielectricColor = vec3(0.04); + vec3 F0 = mix(dielectricColor, baseColor, metallic); + vec3 specularFactor = specularModel(F0, lDotH, lDotN, vDotN, n, h); + + float lod = roughnessToMipLevel(roughness); + vec3 specularSkyColor = textureLod(skySpecular, l, lod).rgb; + vec3 specular = specularSkyColor * specularFactor; + + // Blend between diffuse and specular to conserve energy + vec3 iblColor = specular + diffuse * (vec3(1.0) - specularFactor); + + // Reduce by ambient occlusion amount + iblColor *= ambientOcclusion; + + // Apply exposure correction + iblColor *= pow(2.0, exposure); + + return iblColor; +} + +vec3 toneMap(const in vec3 c) +{ + return c / (c + vec3(1.0)); +} + +vec3 gammaCorrect(const in vec3 color) +{ + const float gamma = 1.0 / 2.2; + return pow(color, vec3(gamma)); +} + +void main() +{ + // Calculate the perturbed texture coordinates from parallax occlusion mapping + mat3 worldToTangentMatrix = calcWorldSpaceToTangentSpaceMatrix(worldNormal, worldTangent); + vec3 wView = normalize(eyePosition - worldPosition); + vec3 tView = worldToTangentMatrix * wView; + + // Sample the inputs needed for the metal-roughness PBR BRDF + vec3 baseColor = texture(albedoMap, texCoord).rgb; + float metallic = texture(metallicMap, texCoord).r * metalFactor; + float roughness = texture(roughnessMap, texCoord).r; + float ambientOcclusion = texture(ambientOcclusionMap, texCoord).r; + vec3 tNormal = 2.0 * texture(normalMap, texCoord).rgb - vec3(1.0); + vec3 wNormal = normalize(transpose(worldToTangentMatrix) * tNormal); + + vec3 cLinear = pbrIblModel(wNormal, + wView, + baseColor, + metallic, + roughness, + ambientOcclusion); + + // Apply simple (Reinhard) tonemap transform to get into LDR range [0, 1] + vec3 cToneMapped = toneMap(cLinear); + + // Apply gamma correction prior to display + vec3 cGamma = gammaCorrect(cToneMapped); + fragColor = vec4(cGamma, 1.0); +} diff --git a/src/extras/shaders/gl3/metalrough.vert b/src/extras/shaders/gl3/metalrough.vert new file mode 100644 index 000000000..6d3a60ef6 --- /dev/null +++ b/src/extras/shaders/gl3/metalrough.vert @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#version 150 + +in vec3 vertexPosition; +in vec3 vertexNormal; +in vec4 vertexTangent; +in vec2 vertexTexCoord; + +out vec3 worldPosition; +out vec3 worldNormal; +out vec4 worldTangent; +out vec2 texCoord; + +uniform mat4 modelMatrix; +uniform mat3 modelNormalMatrix; +uniform mat4 mvp; + +void main() +{ + // Pass the texture coordinates through + texCoord = vertexTexCoord; + + // Transform position, normal, and tangent to world space + worldPosition = vec3(modelMatrix * vec4(vertexPosition, 1.0)); + worldNormal = normalize(modelNormalMatrix * vertexNormal); + worldTangent.xyz = normalize(vec3(modelMatrix * vec4(vertexTangent.xyz, 0.0))); + worldTangent.w = vertexTangent.w; + + gl_Position = mvp * vec4(vertexPosition, 1.0); +} diff --git a/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp b/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp index 608e0b321..2f3763c06 100644 --- a/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp +++ b/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp @@ -57,6 +57,7 @@ #include #include #include +#include #include #include #include @@ -97,6 +98,7 @@ void Qt3DQuick3DExtrasPlugin::registerTypes(const char *uri) qmlRegisterType(uri, 2, 0, "PerVertexColorMaterial"); qmlRegisterType(uri, 2, 0, "GoochMaterial"); qmlRegisterType(uri, 2, 0, "TextureMaterial"); + qmlRegisterType(uri, 2, 2, "TexturedMetalRoughMaterial"); // Meshes qmlRegisterType(uri, 2, 0, "ConeMesh"); -- cgit v1.2.3 From 19847a8c247709a7b9825f494ede56aad7ed231f Mon Sep 17 00:00:00 2001 From: Mike Krus Date: Sun, 29 Jan 2017 10:32:42 +0000 Subject: Shutdown fixes Wait for render thread to finish when shutting down. Was causing crashes in some background nodes still being accessed after the node manager was destroyed. Shader disconnects from glcontext destroy messages when that context is reset. Thread affinity of glcontext and shader meant the destroyed signal from the glcontext could be delivered to a shader that had already been destroyed. Change-Id: I283701e8d008343b3fccf6769d71695b1c6a1ea4 Reviewed-by: Sean Harmer Reviewed-by: Paul Lemire --- src/render/backend/renderer.cpp | 1 + src/render/materialsystem/shader.cpp | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/render/backend/renderer.cpp b/src/render/backend/renderer.cpp index 1c8875b58..6928a2b1a 100644 --- a/src/render/backend/renderer.cpp +++ b/src/render/backend/renderer.cpp @@ -374,6 +374,7 @@ void Renderer::shutdown() // to be ready. The isReadyToSubmit() function checks for a shutdown // having been requested. m_submitRenderViewsSemaphore.release(1); + m_renderThread->wait(); } } diff --git a/src/render/materialsystem/shader.cpp b/src/render/materialsystem/shader.cpp index ae547836a..02f58dfbc 100644 --- a/src/render/materialsystem/shader.cpp +++ b/src/render/materialsystem/shader.cpp @@ -72,8 +72,6 @@ Shader::~Shader() { // TO DO: ShaderProgram is leaked as of now // Fix that taking care that they may be shared given a same dna - - QObject::disconnect(m_contextConnection); } void Shader::cleanup() @@ -85,6 +83,7 @@ void Shader::cleanup() if (m_graphicsContext) m_graphicsContext->removeShaderProgramReference(this); m_graphicsContext = nullptr; + QObject::disconnect(m_contextConnection); } QBackendNode::setEnabled(false); -- cgit v1.2.3 From e72560976ea41ddf0a9940b322692cb425caa226 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Mon, 30 Jan 2017 11:09:51 +0200 Subject: Fix scene2d autotest shutdown crash Change-Id: I0a4e12243b8fcf80d4849879211b87448096fab0 Reviewed-by: Sean Harmer --- src/quick3d/quick3drender/scene2d/scene2d.cpp | 8 +++++--- tests/auto/render/render.pro | 2 +- tests/auto/render/scene2d/tst_scene2d.cpp | 1 + 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/quick3d/quick3drender/scene2d/scene2d.cpp b/src/quick3d/quick3drender/scene2d/scene2d.cpp index 227829f3e..4e92739a4 100644 --- a/src/quick3d/quick3drender/scene2d/scene2d.cpp +++ b/src/quick3d/quick3drender/scene2d/scene2d.cpp @@ -347,9 +347,11 @@ void Scene2D::cleanup() m_context = nullptr; m_initialized = false; } - // wake up the main thread - m_sharedObject->wake(); - m_sharedObject = nullptr; + if (m_sharedObject) { + // wake up the main thread + m_sharedObject->wake(); + m_sharedObject = nullptr; + } renderThreadClientCount->fetchAndSubAcquire(1); if (renderThreadClientCount->load() == 0) diff --git a/tests/auto/render/render.pro b/tests/auto/render/render.pro index 5a8b16e93..4f536d3f4 100644 --- a/tests/auto/render/render.pro +++ b/tests/auto/render/render.pro @@ -105,7 +105,7 @@ qtConfig(private_tests) { qeventforward \ eventforward \ qscene2d \ - #scene2d \ + scene2d \ coordinatereader !macos: SUBDIRS += graphicshelpergl4 diff --git a/tests/auto/render/scene2d/tst_scene2d.cpp b/tests/auto/render/scene2d/tst_scene2d.cpp index f07a35b19..45ea85b42 100644 --- a/tests/auto/render/scene2d/tst_scene2d.cpp +++ b/tests/auto/render/scene2d/tst_scene2d.cpp @@ -58,6 +58,7 @@ private Q_SLOTS: QCOMPARE(backendScene2d.m_initialized, false); QCOMPARE(backendScene2d.m_renderInitialized, false); QCOMPARE(backendScene2d.m_renderPolicy, QScene2D::Continuous); + backendScene2d.cleanup(); } void checkInitializeFromPeer() -- cgit v1.2.3 From 14f4677e2f8e125495d401c5ea657bf0708a417b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Mon, 30 Jan 2017 15:24:59 +0200 Subject: Fix texture binding on macos It seems that the format of the context being shared must be the same, otherwise sharing doesn't work. Also fix crash at the startup, which happens because the m_shareContext is not initialized. Change-Id: Ie654b684bcead1d85dee239dba02be798672f278 Reviewed-by: Mike Krus Reviewed-by: Sean Harmer --- src/quick3d/quick3drender/scene2d/scene2d.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/quick3d/quick3drender/scene2d/scene2d.cpp b/src/quick3d/quick3drender/scene2d/scene2d.cpp index 4e92739a4..710284be2 100644 --- a/src/quick3d/quick3drender/scene2d/scene2d.cpp +++ b/src/quick3d/quick3drender/scene2d/scene2d.cpp @@ -163,7 +163,6 @@ void Scene2D::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &chan m_renderPolicy = data.renderPolicy; setSharedObject(data.sharedObject); setOutput(data.output); - m_shareContext = renderer()->shareContext(); } void Scene2D::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) @@ -195,13 +194,21 @@ void Scene2D::setSharedObject(Qt3DRender::Quick::Scene2DSharedObjectPtr sharedOb void Scene2D::initializeRender() { if (!m_renderInitialized && m_sharedObject.data() != nullptr) { - + m_shareContext = renderer()->shareContext(); + if (!m_shareContext){ + qCWarning(Qt3DRender::Quick::Scene2D) << Q_FUNC_INFO << "Renderer not initialized."; + QCoreApplication::postEvent(m_sharedObject->m_renderObject, new QEvent(INITIALIZE)); + return; + } + m_context = new QOpenGLContext(); +#ifdef Q_OS_MACOS + m_context->setFormat(m_shareContext->format()); +#else QSurfaceFormat format; format.setDepthBufferSize(24); format.setStencilBufferSize(8); - - m_context = new QOpenGLContext(); m_context->setFormat(format); +#endif m_context->setShareContext(m_shareContext); m_context->create(); -- cgit v1.2.3 From 989ce5f0e3d128c0d47a410e53ca57578a25d202 Mon Sep 17 00:00:00 2001 From: Paul Lemire Date: Mon, 30 Jan 2017 12:41:26 +0100 Subject: ClipBlendNode: add a virtual pure blend method Allows to make each subclass perform its own blending Change-Id: I0a8e32ebc549c988cf4cab59806152c7aa0825f4 Reviewed-by: Sean Harmer --- src/animation/backend/clipblendnode_p.h | 1 + src/animation/backend/lerpblend.cpp | 5 ++++ src/animation/backend/lerpblend_p.h | 2 ++ .../animation/clipblendnode/tst_clipblendnode.cpp | 2 ++ .../tst_clipblendnodemanager.cpp | 3 +++ tests/auto/animation/lerpblend/tst_lerpblend.cpp | 30 ++++++++++++++++++++++ 6 files changed, 43 insertions(+) diff --git a/src/animation/backend/clipblendnode_p.h b/src/animation/backend/clipblendnode_p.h index d3af9301b..a1d77d827 100644 --- a/src/animation/backend/clipblendnode_p.h +++ b/src/animation/backend/clipblendnode_p.h @@ -79,6 +79,7 @@ public: Qt3DCore::QNodeIdVector clipIds() const; void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_OVERRIDE; + virtual float blend(float value1, float value2) const = 0; protected: explicit ClipBlendNode(BlendType blendType); diff --git a/src/animation/backend/lerpblend.cpp b/src/animation/backend/lerpblend.cpp index 29261aadf..f4423aee9 100644 --- a/src/animation/backend/lerpblend.cpp +++ b/src/animation/backend/lerpblend.cpp @@ -64,6 +64,11 @@ void LerpBlend::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) } } +float LerpBlend::blend(float value1, float value2) const +{ + return ((1.0f - m_blendFactor) * value1) + (m_blendFactor * value2); +} + void LerpBlend::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) { ClipBlendNode::initializeFromPeer(change); diff --git a/src/animation/backend/lerpblend_p.h b/src/animation/backend/lerpblend_p.h index a28815349..6538b38e3 100644 --- a/src/animation/backend/lerpblend_p.h +++ b/src/animation/backend/lerpblend_p.h @@ -63,8 +63,10 @@ public: ~LerpBlend(); inline float blendFactor() const { return m_blendFactor; } + void setBlendFactor(float blendFactor) { m_blendFactor = blendFactor; } // For unit tests void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_FINAL; + float blend(float value1, float value2) const Q_DECL_FINAL; private: void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL; diff --git a/tests/auto/animation/clipblendnode/tst_clipblendnode.cpp b/tests/auto/animation/clipblendnode/tst_clipblendnode.cpp index c045c2112..085979267 100644 --- a/tests/auto/animation/clipblendnode/tst_clipblendnode.cpp +++ b/tests/auto/animation/clipblendnode/tst_clipblendnode.cpp @@ -47,6 +47,8 @@ public: TestClipBlendNode() : Qt3DAnimation::Animation::ClipBlendNode(Qt3DAnimation::Animation::ClipBlendNode::LerpBlendType) {} + + float blend(float , float ) const Q_DECL_FINAL { return 0.0f; } }; } // anonymous diff --git a/tests/auto/animation/clipblendnodemanager/tst_clipblendnodemanager.cpp b/tests/auto/animation/clipblendnodemanager/tst_clipblendnodemanager.cpp index 2cf549f7e..962813d15 100644 --- a/tests/auto/animation/clipblendnodemanager/tst_clipblendnodemanager.cpp +++ b/tests/auto/animation/clipblendnodemanager/tst_clipblendnodemanager.cpp @@ -48,6 +48,9 @@ public: { deadCount += 1; } + + float blend(float , float ) const Q_DECL_FINAL { return 0.0f; } + }; } // anonymous diff --git a/tests/auto/animation/lerpblend/tst_lerpblend.cpp b/tests/auto/animation/lerpblend/tst_lerpblend.cpp index 9d758e7c4..5f494d9ec 100644 --- a/tests/auto/animation/lerpblend/tst_lerpblend.cpp +++ b/tests/auto/animation/lerpblend/tst_lerpblend.cpp @@ -50,6 +50,7 @@ private Q_SLOTS: QCOMPARE(backendLerpBlend.isEnabled(), false); QVERIFY(backendLerpBlend.peerId().isNull()); QCOMPARE(backendLerpBlend.blendFactor(), 0.0f); + QCOMPARE(backendLerpBlend.blendType(), Qt3DAnimation::Animation::ClipBlendNode::LerpBlendType); } void checkInitializeFromPeer() @@ -112,6 +113,35 @@ private Q_SLOTS: } } + void checkBlend_data() + { + QTest::addColumn("value1"); + QTest::addColumn("value2"); + QTest::addColumn("blendFactor"); + QTest::addColumn("result"); + + QTest::newRow("0_blending") << 8.0f << 5.0f << 0.0f << 8.0f; + QTest::newRow("0.5_blending") << 8.0f << 5.0f << 0.5f << 6.5f; + QTest::newRow("1_blending") << 8.0f << 5.0f << 1.0f << 5.0f; + } + + void checkBlend() + { + // GIVEN + QFETCH(float, value1); + QFETCH(float, value2); + QFETCH(float, blendFactor); + QFETCH(float, result); + Qt3DAnimation::Animation::LerpBlend lerpBlend; + + // WHEN + lerpBlend.setBlendFactor(blendFactor); + const float computed = lerpBlend.blend(value1, value2); + + // THEN + QCOMPARE(computed, result); + } + }; QTEST_MAIN(tst_LerpBlend) -- cgit v1.2.3 From a019b0343258a4741c3337e50eb6991c5d5c94a5 Mon Sep 17 00:00:00 2001 From: Paul Lemire Date: Mon, 30 Jan 2017 12:42:56 +0100 Subject: Improve the clip evalution code Change-Id: Id536ec0433f0f2f25c42d115fbf90b99e6d3844e Reviewed-by: Sean Harmer --- src/animation/backend/animationutils.cpp | 45 +++++++------------ src/animation/backend/animationutils_p.h | 49 ++++++++++++++------- .../backend/evaluateblendclipanimatorjob.cpp | 50 ++++++++-------------- src/animation/backend/evaluateclipanimatorjob.cpp | 18 +++----- 4 files changed, 74 insertions(+), 88 deletions(-) diff --git a/src/animation/backend/animationutils.cpp b/src/animation/backend/animationutils.cpp index 65a455144..0e202a5b3 100644 --- a/src/animation/backend/animationutils.cpp +++ b/src/animation/backend/animationutils.cpp @@ -51,6 +51,20 @@ QT_BEGIN_NAMESPACE namespace Qt3DAnimation { namespace Animation { +AnimationUtils::ClipPreEvaluationData AnimationUtils::evaluationDataForClip(AnimationClip *clip, + const AnimationUtils::AnimatorEvaluationData &animatorData) +{ + // global time values expected in seconds + ClipPreEvaluationData result; + result.localTime = localTimeFromGlobalTime(animatorData.globalTime, animatorData.startTime, + animatorData.playbackRate, clip->duration(), + animatorData.loopCount, result.currentLoop); + result.isFinalFrame = (result.localTime >= clip->duration() && + animatorData.loopCount != 0 && + result.currentLoop >= animatorData.loopCount - 1); + return result; +} + double AnimationUtils::localTimeFromGlobalTime(double t_global, double t_start_global, double playbackRate, @@ -151,40 +165,11 @@ QVector AnimationUtils::channelsToIndicesHelper(const ChannelGroup &channel return indices; } -QVector AnimationUtils::evaluateAtGlobalTime(AnimationClip *clip, - qint64 globalTime, - qint64 startTime, - int loopCount, - int ¤tLoop, - bool &finalFrame) -{ - // Calculate local time from global time - const double t_global = double(globalTime) / 1.0e9; - const double t_start_global = double(startTime) / 1.0e9; - const double playbackRate = 1.0; // Assume standard playback rate for now - const double duration = clip->duration(); - - const double localTime = localTimeFromGlobalTime(t_global, t_start_global, - playbackRate, duration, - loopCount, currentLoop); - return AnimationUtils::evaluateAtLocalTime(clip, localTime, - currentLoop, loopCount, - finalFrame); -} - -QVector AnimationUtils::evaluateAtLocalTime(AnimationClip *clip, float localTime, - int currentLoop, int loopCount, - bool &finalFrame) +QVector AnimationUtils::evaluateClipAtLocalTime(AnimationClip *clip, float localTime) { QVector channelResults; Q_ASSERT(clip); - // TODO: Uncomment when we add loopCount property - if (localTime >= clip->duration() - && loopCount != 0 - && currentLoop == loopCount - 1) - finalFrame = true; - // Ensure we have enough storage to hold the evaluations channelResults.resize(clip->channelCount()); diff --git a/src/animation/backend/animationutils_p.h b/src/animation/backend/animationutils_p.h index e7f019aee..e89dd5d6f 100644 --- a/src/animation/backend/animationutils_p.h +++ b/src/animation/backend/animationutils_p.h @@ -87,9 +87,35 @@ public: BlendAction blendAction; }; - static double localTimeFromGlobalTime(double t_global, double t_start_global, - double playbackRate, double duration, - int loopCount, int ¤tLoop); + struct AnimatorEvaluationData + { + double globalTime; + double startTime; + int loopCount; + double playbackRate; + }; + + struct ClipPreEvaluationData + { + int currentLoop; + double localTime; + bool isFinalFrame; + }; + + template + static AnimatorEvaluationData animatorEvaluationDataForAnimator(Animator animator, qint64 globalTime) + { + AnimationUtils::AnimatorEvaluationData data; + data.loopCount = animator->loops(); + data.playbackRate = 1.0; // should be a property on the animator + // Convert global time from nsec to sec + data.startTime = double(animator->startTime()) / 1.0e9; + data.globalTime = double(globalTime) / 1.0e9; + return data; + } + + static ClipPreEvaluationData evaluationDataForClip(AnimationClip *clip, const AnimatorEvaluationData &animatorData); + static QVector channelsToIndices(const ChannelGroup &channelGroup, int dataType, int offset = 0); @@ -97,12 +123,8 @@ public: int dataType, int offset, const QStringList &suffixes); - static QVector evaluateAtGlobalTime(AnimationClip *clip, - qint64 globalTime, - qint64 startTime, - int loopCount, - int ¤tLoop, - bool &finalFrame); + static QVector evaluateClipAtLocalTime(AnimationClip *clip, + float localTime); static QVector preparePropertyChanges(Qt3DCore::QNodeId peerId, const QVector &mappingData, const QVector &channelResults, @@ -111,13 +133,10 @@ public: const AnimationClip *clip, const ChannelMapper *mapper); - private: - static QVector evaluateAtLocalTime(AnimationClip *clip, - float localTime, - int currentLoop, - int loopCount, - bool &finalFrame); + static double localTimeFromGlobalTime(double t_global, double t_start_global, + double playbackRate, double duration, + int loopCount, int ¤tLoop); }; } // Animation diff --git a/src/animation/backend/evaluateblendclipanimatorjob.cpp b/src/animation/backend/evaluateblendclipanimatorjob.cpp index e15a419b1..349156f39 100644 --- a/src/animation/backend/evaluateblendclipanimatorjob.cpp +++ b/src/animation/backend/evaluateblendclipanimatorjob.cpp @@ -55,46 +55,36 @@ EvaluateBlendClipAnimatorJob::EvaluateBlendClipAnimatorJob() void EvaluateBlendClipAnimatorJob::run() { const qint64 globalTime = m_handler->simulationTime(); - //qDebug() << Q_FUNC_INFO << "t_global =" << globalTime; BlendedClipAnimator *blendedClipAnimator = m_handler->blendedClipAnimatorManager()->data(m_blendClipAnimatorHandle); Q_ASSERT(blendedClipAnimator); // TO DO: Right now we are doing LERP but refactor to handle other types ClipBlendNode *blendNode = m_handler->clipBlendNodeManager()->lookupNode(blendedClipAnimator->blendTreeRootId()); - Q_ASSERT(blendNode->blendType() == ClipBlendNode::LerpBlendType); - LerpBlend *lerpBlendNode = static_cast(blendNode); - const Qt3DCore::QNodeIdVector clipIds = lerpBlendNode->clipIds(); - - bool globalFinalFrame = false; + const Qt3DCore::QNodeIdVector clipIds = blendNode->clipIds(); // Evaluate the fcurves for both clip AnimationClip *clip1 = m_handler->animationClipManager()->lookupResource(clipIds.first()); AnimationClip *clip2 = m_handler->animationClipManager()->lookupResource(clipIds.last()); Q_ASSERT(clip1 && clip2); - bool finalFrame1 = false; - bool finalFrame2 = false; - int currentLoop = 0; - const QVector channelResultsClip1 = AnimationUtils::evaluateAtGlobalTime(clip1, - globalTime, - blendedClipAnimator->startTime(), - blendedClipAnimator->loops(), - currentLoop, - finalFrame1); - const QVector channelResultsClip2 = AnimationUtils::evaluateAtGlobalTime(clip2, - globalTime, - blendedClipAnimator->startTime(), - blendedClipAnimator->loops(), - currentLoop, - finalFrame2); - globalFinalFrame = (finalFrame1 && finalFrame2); - - blendedClipAnimator->setCurrentLoop(currentLoop); - // Perform blending between the two clips - const float blendFactor = lerpBlendNode->blendFactor(); + // Prepare for evaluation (convert global time to local time ....) + const AnimationUtils::AnimatorEvaluationData animatorEvaluationData = AnimationUtils::animatorEvaluationDataForAnimator(blendedClipAnimator, globalTime); + const AnimationUtils::ClipPreEvaluationData preEvaluationDataForClip1 = AnimationUtils::evaluationDataForClip(clip1, animatorEvaluationData); + const AnimationUtils::ClipPreEvaluationData preEvaluationDataForClip2 = AnimationUtils::evaluationDataForClip(clip2, animatorEvaluationData); + + // Evaluate the clips + const QVector channelResultsClip1 = AnimationUtils::evaluateClipAtLocalTime(clip1, preEvaluationDataForClip1.localTime); + const QVector channelResultsClip2 = AnimationUtils::evaluateClipAtLocalTime(clip2, preEvaluationDataForClip2.localTime); + + // Update loops and running of the animator + blendedClipAnimator->setCurrentLoop(std::min(preEvaluationDataForClip1.currentLoop, preEvaluationDataForClip2.currentLoop)); + const bool isFinalFrame = preEvaluationDataForClip1.isFinalFrame && preEvaluationDataForClip2.isFinalFrame; + if (isFinalFrame) + blendedClipAnimator->setRunning(false); + // Perform blending between the two clips QVector blendedMappingData; QVector blendedValues; @@ -113,7 +103,7 @@ void EvaluateBlendClipAnimatorJob::run() for (int i = 0, m = mapping.channelIndicesClip1.size(); i < m; ++i) { const float value1 = channelResultsClip1.at(mapping.channelIndicesClip1[i]); const float value2 = channelResultsClip2.at(mapping.channelIndicesClip2[i]); - const float blendedValue = ((1.0f - blendFactor) * value1) + (blendFactor * value2); + const float blendedValue = blendNode->blend(value1, value2); finalMapping.channelIndices.push_back(blendedValues.size()); blendedValues.push_back(blendedValue); } @@ -138,18 +128,14 @@ void EvaluateBlendClipAnimatorJob::run() blendedMappingData.push_back(finalMapping); } - if (globalFinalFrame) - blendedClipAnimator->setRunning(false); - // Prepare property changes (if finalFrame it also prepares the change for the running property for the frontend) const QVector changes = AnimationUtils::preparePropertyChanges(blendedClipAnimator->peerId(), blendedMappingData, blendedValues, - globalFinalFrame); + isFinalFrame); // Send the property changes blendedClipAnimator->sendPropertyChanges(changes); - } diff --git a/src/animation/backend/evaluateclipanimatorjob.cpp b/src/animation/backend/evaluateclipanimatorjob.cpp index e547ec441..406a46dcd 100644 --- a/src/animation/backend/evaluateclipanimatorjob.cpp +++ b/src/animation/backend/evaluateclipanimatorjob.cpp @@ -63,25 +63,21 @@ void EvaluateClipAnimatorJob::run() // Evaluate the fcurves AnimationClip *clip = m_handler->animationClipManager()->lookupResource(clipAnimator->clipId()); Q_ASSERT(clip); - bool finalFrame = false; - int currentLoop = 0; - const QVector channelResults = AnimationUtils::evaluateAtGlobalTime(clip, - globalTime, - clipAnimator->startTime(), - clipAnimator->loops(), - currentLoop, - finalFrame); + // Prepare for evaluation (convert global time to local time ....) + const AnimationUtils::AnimatorEvaluationData animatorEvaluationData = AnimationUtils::animatorEvaluationDataForAnimator(clipAnimator, globalTime); + const AnimationUtils::ClipPreEvaluationData preEvaluationDataForClip = AnimationUtils::evaluationDataForClip(clip, animatorEvaluationData); + const QVector channelResults = AnimationUtils::evaluateClipAtLocalTime(clip, preEvaluationDataForClip.localTime); - if (finalFrame) + if (preEvaluationDataForClip.isFinalFrame) clipAnimator->setRunning(false); - clipAnimator->setCurrentLoop(currentLoop); + clipAnimator->setCurrentLoop(preEvaluationDataForClip.currentLoop); // Prepare property changes (if finalFrame it also prepares the change for the running property for the frontend) const QVector changes = AnimationUtils::preparePropertyChanges(clipAnimator->peerId(), clipAnimator->mappingData(), channelResults, - finalFrame); + preEvaluationDataForClip.isFinalFrame); // Send the property changes clipAnimator->sendPropertyChanges(changes); -- cgit v1.2.3 From bc0bf7accb22206a6e5d30b7d43d707cdc072f67 Mon Sep 17 00:00:00 2001 From: Paul Lemire Date: Mon, 30 Jan 2017 13:05:56 +0100 Subject: Add QAddBlend frontend node Change-Id: If18e8dee32503c6172e67107adac57a158effc37 Reviewed-by: Sean Harmer --- src/animation/frontend/frontend.pri | 7 +- src/animation/frontend/qaddblend.cpp | 175 +++++++++++++++++++++ src/animation/frontend/qaddblend.h | 76 ++++++++++ src/animation/frontend/qaddblend_p.h | 78 ++++++++++ tests/auto/animation/animation.pro | 3 +- tests/auto/animation/qaddblend/qaddblend.pro | 11 ++ tests/auto/animation/qaddblend/tst_qaddblend.cpp | 185 +++++++++++++++++++++++ 7 files changed, 532 insertions(+), 3 deletions(-) create mode 100644 src/animation/frontend/qaddblend.cpp create mode 100644 src/animation/frontend/qaddblend.h create mode 100644 src/animation/frontend/qaddblend_p.h create mode 100644 tests/auto/animation/qaddblend/qaddblend.pro create mode 100644 tests/auto/animation/qaddblend/tst_qaddblend.cpp diff --git a/src/animation/frontend/frontend.pri b/src/animation/frontend/frontend.pri index 9eeeede97..f41de531e 100644 --- a/src/animation/frontend/frontend.pri +++ b/src/animation/frontend/frontend.pri @@ -18,7 +18,9 @@ HEADERS += \ $$PWD/qlerpblend.h \ $$PWD/qlerpblend_p.h \ $$PWD/qclipblendnodecreatedchange.h \ - $$PWD/qclipblendnodecreatedchange_p.h + $$PWD/qclipblendnodecreatedchange_p.h \ + $$PWD/qaddblend.h \ + $$PWD/qaddblend_p.h SOURCES += \ $$PWD/qanimationaspect.cpp \ @@ -30,6 +32,7 @@ SOURCES += \ $$PWD/qchannelmapper.cpp \ $$PWD/qchannelmapping.cpp \ $$PWD/qlerpblend.cpp \ - $$PWD/qclipblendnodecreatedchange.cpp + $$PWD/qclipblendnodecreatedchange.cpp \ + $$PWD/qaddblend.cpp INCLUDEPATH += $$PWD diff --git a/src/animation/frontend/qaddblend.cpp b/src/animation/frontend/qaddblend.cpp new file mode 100644 index 000000000..fdf99f2c0 --- /dev/null +++ b/src/animation/frontend/qaddblend.cpp @@ -0,0 +1,175 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** 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 "qaddblend.h" +#include "qaddblend_p.h" +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { + + +/*! + \qmltype AddBlend + \instantiates Qt3DAnimation::QAddBlend + \inqmlmodule Qt3D.Animation + + \brief Performs an addition of two animation clips based on a + normalized factor + + \since 5.9 + + AddBlend can be useful to create advanced animation effects based on + individual animation clips. For instance, given a player character, additive + blending could be used to combine a walking animation clip with an injured + animation clip based on a blend factor that increases the more the player + gets injured. This would then allow with blend factor == 0 to have a non + injured walking player, with blend factor == 1 a fully injured player, with + blend factor == 0.5 a partially walking and injured player. + + \sa BlendedClipAnimator +*/ + +/*! + \class Qt3DAnimation::QAddBlend + \inmodule Qt3DAnimation + \inherits Qt3DAnimation::QAbstractClipBlendNode + + \brief Performs an addition of two animation clips based on a + normalized factor + + \since 5.9 + + QAddBlend can be useful to create advanced animation effects based on + individual animation clips. For instance, given a player character, additive + blending could be used to combine a walking animation clip with an injured + animation clip based on a blend factor that increases the more the player + gets injured. This would then allow with blend factor == 0 to have a non + injured walking player, with blend factor == 1 a fully injured player, with + blend factor == 0.5 a partially walking and injured player. + + \sa QBlendedClipAnimator +*/ + +QAddBlendPrivate::QAddBlendPrivate() + : QAbstractClipBlendNodePrivate() + , m_blendFactor(0.0f) +{ +} + +QAddBlend::QAddBlend(Qt3DCore::QNode *parent) + : QAbstractClipBlendNode(*new QAddBlendPrivate(), parent) +{ +} + +QAddBlend::QAddBlend(QAddBlendPrivate &dd, Qt3DCore::QNode *parent) + : QAbstractClipBlendNode(dd, parent) +{ +} + +QAddBlend::~QAddBlend() +{ +} + +Qt3DCore::QNodeCreatedChangeBasePtr QAddBlend::createNodeCreationChange() const +{ + Q_D(const QAddBlend); + auto creationChange = QClipBlendNodeCreatedChangePtr::create(this); + QAddBlendData &data = creationChange->data; + data.blendFactor = d->m_blendFactor; + return creationChange; +} + +/*! + \qmlproperty real AddBlend::blendFactor + + Specifies the blending factor between 0 and 1 to control the blending of + two animation clips. +*/ +/*! + \property QAddBlend::blendFactor + + Specifies the blending factor between 0 and 1 to control the blending of + two animation clips. + */ +float QAddBlend::blendFactor() const +{ + Q_D(const QAddBlend); + return d->m_blendFactor; +} + +void QAddBlend::setBlendFactor(float blendFactor) +{ + Q_D(QAddBlend); + if (d->m_blendFactor == blendFactor) + return; + + d->m_blendFactor = blendFactor; + emit blendFactorChanged(blendFactor); +} + +/*! + \qmlproperty list AddBlend::clips + + Holds the list of AnimationClip nodes against which the blending is performed. + + \note Only the two first AnimationClip are used, subsequent ones are ignored +*/ + + +/*! + \fn void QAddBlend::addClip(QAnimationClip *clip); + Adds a \a clip to the blending node's clips list. + + \note Only the two first AnimationClip are used, subsequent ones are ignored + */ + +/*! + \fn void QAddBlend::removeClip(QAnimationClip *clip); + Removes a \a clip from the blending node's clips list. + */ + +/*! + \fn QVector QAddBlend::clips() const; + Returns the list of QAnimationClip against which the blending is performed. + */ + + +} // Qt3DAnimation + +QT_END_NAMESPACE diff --git a/src/animation/frontend/qaddblend.h b/src/animation/frontend/qaddblend.h new file mode 100644 index 000000000..034bc7ee0 --- /dev/null +++ b/src/animation/frontend/qaddblend.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** 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$ +** +****************************************************************************/ + +#ifndef QT3DANIMATION_QADDBLEND_H +#define QT3DANIMATION_QADDBLEND_H + +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { + +class QAddBlendPrivate; + +class QT3DANIMATIONSHARED_EXPORT QAddBlend : public QAbstractClipBlendNode +{ + Q_OBJECT + Q_PROPERTY(float blendFactor READ blendFactor WRITE setBlendFactor NOTIFY blendFactorChanged) +public: + explicit QAddBlend(Qt3DCore::QNode *parent = nullptr); + ~QAddBlend(); + + float blendFactor() const; + +public Q_SLOTS: + void setBlendFactor(float blendFactor); + +Q_SIGNALS: + void blendFactorChanged(float blendFactor); + +protected: + explicit QAddBlend(QAddBlendPrivate &dd, Qt3DCore::QNode *parent = nullptr); + +private: + Q_DECLARE_PRIVATE(QAddBlend) + Qt3DCore::QNodeCreatedChangeBasePtr createNodeCreationChange() const Q_DECL_OVERRIDE; +}; + +} // Qt3DAnimation + +QT_END_NAMESPACE + +#endif // QT3DANIMATION_QADDBLEND_H diff --git a/src/animation/frontend/qaddblend_p.h b/src/animation/frontend/qaddblend_p.h new file mode 100644 index 000000000..002747045 --- /dev/null +++ b/src/animation/frontend/qaddblend_p.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** 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$ +** +****************************************************************************/ + +#ifndef QT3DANIMATION_QADDBLEND_P_H +#define QT3DANIMATION_QADDBLEND_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { + +class QAddBlend; + +class QAddBlendPrivate : public QAbstractClipBlendNodePrivate +{ +public: + QAddBlendPrivate(); + + Q_DECLARE_PUBLIC(QAddBlend) + float m_blendFactor; +}; + +struct QAddBlendData +{ + float blendFactor; +}; + +} // Qt3DAnimation + +QT_END_NAMESPACE + +#endif // QT3DANIMATION_QADDBLEND_P_H diff --git a/tests/auto/animation/animation.pro b/tests/auto/animation/animation.pro index 43844ed88..6e255f6c0 100644 --- a/tests/auto/animation/animation.pro +++ b/tests/auto/animation/animation.pro @@ -25,5 +25,6 @@ qtConfig(private_tests) { clipblendnodemanager \ clipblendnode \ lerpblend \ - clipblendnodevisitor + clipblendnodevisitor \ + qaddblend } diff --git a/tests/auto/animation/qaddblend/qaddblend.pro b/tests/auto/animation/qaddblend/qaddblend.pro new file mode 100644 index 000000000..e633576f6 --- /dev/null +++ b/tests/auto/animation/qaddblend/qaddblend.pro @@ -0,0 +1,11 @@ +TEMPLATE = app + +TARGET = tst_qaddblend + +QT += 3dcore 3dcore-private 3danimation 3danimation-private testlib + +CONFIG += testcase + +SOURCES += tst_qaddblend.cpp + +include(../../core/common/common.pri) diff --git a/tests/auto/animation/qaddblend/tst_qaddblend.cpp b/tests/auto/animation/qaddblend/tst_qaddblend.cpp new file mode 100644 index 000000000..57377b3c4 --- /dev/null +++ b/tests/auto/animation/qaddblend/tst_qaddblend.cpp @@ -0,0 +1,185 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Paul Lemire +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "testpostmanarbiter.h" + +class tst_QAddBlend : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + + void checkDefaultConstruction() + { + // GIVEN + Qt3DAnimation::QAddBlend addBlend; + + // THEN + QCOMPARE(addBlend.blendFactor(), 0.0f); + } + + void checkPropertyChanges() + { + // GIVEN + Qt3DAnimation::QAddBlend addBlend; + + { + // WHEN + QSignalSpy spy(&addBlend, SIGNAL(blendFactorChanged(float))); + const float newValue = 0.5f; + addBlend.setBlendFactor(newValue); + + // THEN + QVERIFY(spy.isValid()); + QCOMPARE(addBlend.blendFactor(), newValue); + QCOMPARE(spy.count(), 1); + + // WHEN + spy.clear(); + addBlend.setBlendFactor(newValue); + + // THEN + QCOMPARE(addBlend.blendFactor(), newValue); + QCOMPARE(spy.count(), 0); + } + } + + void checkCreationData() + { + // GIVEN + Qt3DAnimation::QAddBlend addBlend; + Qt3DAnimation::QAnimationClip clip1; + Qt3DAnimation::QAnimationClip clip2; + + addBlend.addClip(&clip1); + addBlend.addClip(&clip2); + addBlend.setBlendFactor(0.8f); + + + // WHEN + QVector creationChanges; + + { + Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&addBlend); + creationChanges = creationChangeGenerator.creationChanges(); + } + + // THEN + { + QCOMPARE(creationChanges.size(), 3); // 1 + 2 clips + + const auto creationChangeData = qSharedPointerCast>(creationChanges.first()); + const Qt3DAnimation::QAddBlendData cloneData = creationChangeData->data; + + QCOMPARE(addBlend.blendFactor(), cloneData.blendFactor); + QCOMPARE(addBlend.id(), creationChangeData->subjectId()); + QCOMPARE(addBlend.isEnabled(), true); + QCOMPARE(addBlend.isEnabled(), creationChangeData->isNodeEnabled()); + QCOMPARE(addBlend.metaObject(), creationChangeData->metaObject()); + QCOMPARE(creationChangeData->clips().size(), 2); + QCOMPARE(creationChangeData->clips().first(), clip1.id()); + QCOMPARE(creationChangeData->clips().last(), clip2.id()); + QCOMPARE(creationChangeData->parentClipBlendNodeId(), Qt3DCore::QNodeId()); + } + + // WHEN + addBlend.setEnabled(false); + + { + Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&addBlend); + creationChanges = creationChangeGenerator.creationChanges(); + } + + // THEN + { + QCOMPARE(creationChanges.size(), 3); // 1 + 2 clips + + const auto creationChangeData = qSharedPointerCast>(creationChanges.first()); + const Qt3DAnimation::QAddBlendData cloneData = creationChangeData->data; + + QCOMPARE(addBlend.blendFactor(), cloneData.blendFactor); + QCOMPARE(addBlend.id(), creationChangeData->subjectId()); + QCOMPARE(addBlend.isEnabled(), false); + QCOMPARE(addBlend.isEnabled(), creationChangeData->isNodeEnabled()); + QCOMPARE(addBlend.metaObject(), creationChangeData->metaObject()); + QCOMPARE(creationChangeData->clips().size(), 2); + QCOMPARE(creationChangeData->clips().first(), clip1.id()); + QCOMPARE(creationChangeData->clips().last(), clip2.id()); + QCOMPARE(creationChangeData->parentClipBlendNodeId(), Qt3DCore::QNodeId()); + } + } + + void checkBlendFactorUpdate() + { + // GIVEN + TestArbiter arbiter; + Qt3DAnimation::QAddBlend addBlend; + arbiter.setArbiterOnNode(&addBlend); + + { + // WHEN + addBlend.setBlendFactor(0.4f); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 1); + auto change = arbiter.events.first().staticCast(); + QCOMPARE(change->propertyName(), "blendFactor"); + QCOMPARE(change->value().value(), addBlend.blendFactor()); + QCOMPARE(change->type(), Qt3DCore::PropertyUpdated); + + arbiter.events.clear(); + } + + { + // WHEN + addBlend.setBlendFactor(0.4f); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 0); + } + + } + +}; + +QTEST_MAIN(tst_QAddBlend) + +#include "tst_qaddblend.moc" -- cgit v1.2.3 From 80f4cdd7a4dc662678a44e32053214237de3ad9d Mon Sep 17 00:00:00 2001 From: Paul Lemire Date: Mon, 30 Jan 2017 13:07:05 +0100 Subject: Quick3DAnimations: register QAddBlend Change-Id: Ia1e4bb045823a827deba675f9a11f126cf7a33d2 Reviewed-by: Sean Harmer --- src/quick3d/imports/animation/qt3dquick3danimationplugin.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/quick3d/imports/animation/qt3dquick3danimationplugin.cpp b/src/quick3d/imports/animation/qt3dquick3danimationplugin.cpp index e0addd6b0..9918e22b2 100644 --- a/src/quick3d/imports/animation/qt3dquick3danimationplugin.cpp +++ b/src/quick3d/imports/animation/qt3dquick3danimationplugin.cpp @@ -44,6 +44,7 @@ #include #include #include +#include #include #include #include @@ -65,6 +66,7 @@ void Qt3DQuick3DAnimationPlugin::registerTypes(const char *uri) qmlRegisterExtendedUncreatableType(uri, 2, 2, "AbstractClipBlendNode", QStringLiteral("QAbstractClipBlendNode is abstract")); qmlRegisterType(uri, 2, 2, "LerpBlend"); + qmlRegisterType(uri, 2, 2, "AddBlend"); } QT_END_NAMESPACE -- cgit v1.2.3 From 64172f28aea7d17ab4e12c87b677d6ac4591bdea Mon Sep 17 00:00:00 2001 From: Paul Lemire Date: Mon, 30 Jan 2017 15:23:00 +0100 Subject: Add AddBlend backend node Change-Id: I547ce2ffd7816fa905724df0ed0c417ecead1ce9 Reviewed-by: Sean Harmer --- src/animation/backend/addblend.cpp | 85 ++++++++++++++ src/animation/backend/addblend_p.h | 83 ++++++++++++++ src/animation/backend/backend.pri | 6 +- src/animation/backend/clipblendnode_p.h | 3 +- src/animation/frontend/qanimationaspect.cpp | 5 + tests/auto/animation/addblend/addblend.pro | 11 ++ tests/auto/animation/addblend/tst_addblend.cpp | 148 +++++++++++++++++++++++++ tests/auto/animation/animation.pro | 3 +- 8 files changed, 340 insertions(+), 4 deletions(-) create mode 100644 src/animation/backend/addblend.cpp create mode 100644 src/animation/backend/addblend_p.h create mode 100644 tests/auto/animation/addblend/addblend.pro create mode 100644 tests/auto/animation/addblend/tst_addblend.cpp diff --git a/src/animation/backend/addblend.cpp b/src/animation/backend/addblend.cpp new file mode 100644 index 000000000..497f66e4a --- /dev/null +++ b/src/animation/backend/addblend.cpp @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** 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 "addblend_p.h" +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { + +namespace Animation { + +AddBlend::AddBlend() + : ClipBlendNode(ClipBlendNode::AddBlendType) + , m_blendFactor(0.0f) +{ +} + +AddBlend::~AddBlend() +{ +} + +void AddBlend::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) +{ + if (e->type() == Qt3DCore::PropertyUpdated) { + Qt3DCore::QPropertyUpdatedChangePtr change = qSharedPointerCast(e); + if (change->propertyName() == QByteArrayLiteral("blendFactor")) + m_blendFactor = change->value().toFloat(); + } +} + +float AddBlend::blend(float value1, float value2) const +{ + return value1 + (m_blendFactor * value2); +} + +void AddBlend::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) +{ + ClipBlendNode::initializeFromPeer(change); + const auto creationChangeData = qSharedPointerCast>(change); + const Qt3DAnimation::QAddBlendData cloneData = creationChangeData->data; + m_blendFactor = cloneData.blendFactor; +} + +} // Animation + +} // Qt3DAnimation + +QT_END_NAMESPACE diff --git a/src/animation/backend/addblend_p.h b/src/animation/backend/addblend_p.h new file mode 100644 index 000000000..621f4e551 --- /dev/null +++ b/src/animation/backend/addblend_p.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** 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$ +** +****************************************************************************/ + +#ifndef QT3DANIMATION_ANIMATION_ADDBLEND_P_H +#define QT3DANIMATION_ANIMATION_ADDBLEND_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { + +namespace Animation { + +class Q_AUTOTEST_EXPORT AddBlend : public ClipBlendNode +{ +public: + AddBlend(); + ~AddBlend(); + + inline float blendFactor() const { return m_blendFactor; } + void setBlendFactor(float blendFactor) { m_blendFactor = blendFactor; } // For unit tests + + void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_FINAL; + float blend(float value1, float value2) const Q_DECL_FINAL; + +private: + void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL; + + float m_blendFactor; +}; + +} // Animation + +} // Qt3DAnimation + +QT_END_NAMESPACE + +#endif // QT3DANIMATION_ANIMATION_ADDBLEND_P_H diff --git a/src/animation/backend/backend.pri b/src/animation/backend/backend.pri index b0b0feaf0..35fdf5cfd 100644 --- a/src/animation/backend/backend.pri +++ b/src/animation/backend/backend.pri @@ -25,7 +25,8 @@ HEADERS += \ $$PWD/clipblendnodevisitor_p.h \ $$PWD/animationutils_p.h \ $$PWD/buildblendtreesjob_p.h \ - $$PWD/evaluateblendclipanimatorjob_p.h + $$PWD/evaluateblendclipanimatorjob_p.h \ + $$PWD/addblend_p.h SOURCES += \ $$PWD/animationclip.cpp \ @@ -48,4 +49,5 @@ SOURCES += \ $$PWD/clipblendnodevisitor.cpp \ $$PWD/animationutils.cpp \ $$PWD/buildblendtreesjob.cpp \ - $$PWD/evaluateblendclipanimatorjob.cpp + $$PWD/evaluateblendclipanimatorjob.cpp \ + $$PWD/addblend.cpp diff --git a/src/animation/backend/clipblendnode_p.h b/src/animation/backend/clipblendnode_p.h index a1d77d827..2ebe16ab7 100644 --- a/src/animation/backend/clipblendnode_p.h +++ b/src/animation/backend/clipblendnode_p.h @@ -67,7 +67,8 @@ public: enum BlendType { NoneBlendType, - LerpBlendType + LerpBlendType, + AddBlendType }; void setClipBlendNodeManager(ClipBlendNodeManager *manager); diff --git a/src/animation/frontend/qanimationaspect.cpp b/src/animation/frontend/qanimationaspect.cpp index 3310a8b77..6cf817ff8 100644 --- a/src/animation/frontend/qanimationaspect.cpp +++ b/src/animation/frontend/qanimationaspect.cpp @@ -46,10 +46,12 @@ #include #include #include +#include #include #include #include #include +#include QT_BEGIN_NAMESPACE @@ -111,6 +113,9 @@ QAnimationAspect::QAnimationAspect(QAnimationAspectPrivate &dd, QObject *parent) registerBackendType( QSharedPointer>::create(d->m_handler.data(), d->m_handler->clipBlendNodeManager())); + registerBackendType( + QSharedPointer>::create(d->m_handler.data(), + d->m_handler->clipBlendNodeManager())); } /*! \internal */ diff --git a/tests/auto/animation/addblend/addblend.pro b/tests/auto/animation/addblend/addblend.pro new file mode 100644 index 000000000..bfa9256f4 --- /dev/null +++ b/tests/auto/animation/addblend/addblend.pro @@ -0,0 +1,11 @@ +TEMPLATE = app + +TARGET = tst_addblend + +QT += 3dcore 3dcore-private 3danimation 3danimation-private testlib + +CONFIG += testcase + +SOURCES += tst_addblend.cpp + +include(../../core/common/common.pri) diff --git a/tests/auto/animation/addblend/tst_addblend.cpp b/tests/auto/animation/addblend/tst_addblend.cpp new file mode 100644 index 000000000..961fb498e --- /dev/null +++ b/tests/auto/animation/addblend/tst_addblend.cpp @@ -0,0 +1,148 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Paul Lemire +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $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 +#include +#include +#include +#include +#include +#include "qbackendnodetester.h" + +class tst_AddBlend : public Qt3DCore::QBackendNodeTester +{ + Q_OBJECT + +private Q_SLOTS: + + void checkInitialState() + { + // GIVEN + Qt3DAnimation::Animation::AddBlend backendAddBlend; + + // THEN + QCOMPARE(backendAddBlend.isEnabled(), false); + QVERIFY(backendAddBlend.peerId().isNull()); + QCOMPARE(backendAddBlend.blendFactor(), 0.0f); + QCOMPARE(backendAddBlend.blendType(), Qt3DAnimation::Animation::ClipBlendNode::AddBlendType); + } + + void checkInitializeFromPeer() + { + // GIVEN + Qt3DAnimation::QAddBlend AddBlend; + Qt3DAnimation::QAnimationClip clip; + AddBlend.setBlendFactor(0.8f); + AddBlend.addClip(&clip); + + { + // WHEN + Qt3DAnimation::Animation::AddBlend backendAddBlend; + simulateInitialization(&AddBlend, &backendAddBlend); + + // THEN + QCOMPARE(backendAddBlend.isEnabled(), true); + QCOMPARE(backendAddBlend.peerId(), AddBlend.id()); + QCOMPARE(backendAddBlend.blendFactor(), 0.8f); + QCOMPARE(backendAddBlend.clipIds().size(), 1); + QCOMPARE(backendAddBlend.clipIds().first(), clip.id()); + } + { + // WHEN + Qt3DAnimation::Animation::AddBlend backendAddBlend; + AddBlend.setEnabled(false); + simulateInitialization(&AddBlend, &backendAddBlend); + + // THEN + QCOMPARE(backendAddBlend.peerId(), AddBlend.id()); + QCOMPARE(backendAddBlend.isEnabled(), false); + } + } + + void checkSceneChangeEvents() + { + // GIVEN + Qt3DAnimation::Animation::AddBlend backendAddBlend; + { + // WHEN + const bool newValue = false; + const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId()); + change->setPropertyName("enabled"); + change->setValue(newValue); + backendAddBlend.sceneChangeEvent(change); + + // THEN + QCOMPARE(backendAddBlend.isEnabled(), newValue); + } + { + // WHEN + const float newValue = 0.883f; + const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId()); + change->setPropertyName("blendFactor"); + change->setValue(QVariant::fromValue(newValue)); + backendAddBlend.sceneChangeEvent(change); + + // THEN + QCOMPARE(backendAddBlend.blendFactor(), newValue); + } + } + + void checkBlend_data() + { + QTest::addColumn("value1"); + QTest::addColumn("value2"); + QTest::addColumn("blendFactor"); + QTest::addColumn("result"); + + QTest::newRow("0_blending") << 8.0f << 5.0f << 0.0f << 8.0f; + QTest::newRow("0.5_blending") << 8.0f << 5.0f << 0.5f << 10.5f; + QTest::newRow("1_blending") << 8.0f << 5.0f << 1.0f << 13.0f; + } + + void checkBlend() + { + // GIVEN + QFETCH(float, value1); + QFETCH(float, value2); + QFETCH(float, blendFactor); + QFETCH(float, result); + Qt3DAnimation::Animation::AddBlend addBlend; + + // WHEN + addBlend.setBlendFactor(blendFactor); + const float computed = addBlend.blend(value1, value2); + + // THEN + QCOMPARE(computed, result); + } +}; + +QTEST_MAIN(tst_AddBlend) + +#include "tst_addblend.moc" diff --git a/tests/auto/animation/animation.pro b/tests/auto/animation/animation.pro index 6e255f6c0..4acf2fe3e 100644 --- a/tests/auto/animation/animation.pro +++ b/tests/auto/animation/animation.pro @@ -26,5 +26,6 @@ qtConfig(private_tests) { clipblendnode \ lerpblend \ clipblendnodevisitor \ - qaddblend + qaddblend \ + addblend } -- cgit v1.2.3 From fb4c4abbc4beb9673654c318135f096013272d87 Mon Sep 17 00:00:00 2001 From: Paul Lemire Date: Mon, 30 Jan 2017 15:51:48 +0100 Subject: Updated animation-keyframe-simple to use additive blending Change-Id: I7d1b134b7a6df3a1047fee0d17e6094842c542a4 Reviewed-by: Sean Harmer --- tests/manual/animation-keyframe-simple/main.qml | 56 +++++++++++++++ tests/manual/animation-keyframe-simple/main.qrc | 1 + .../pulsing-cube-additive.json | 84 ++++++++++++++++++++++ 3 files changed, 141 insertions(+) create mode 100644 tests/manual/animation-keyframe-simple/pulsing-cube-additive.json diff --git a/tests/manual/animation-keyframe-simple/main.qml b/tests/manual/animation-keyframe-simple/main.qml index 8546d8b34..e7db8b30b 100644 --- a/tests/manual/animation-keyframe-simple/main.qml +++ b/tests/manual/animation-keyframe-simple/main.qml @@ -119,6 +119,62 @@ DefaultSceneEntity { ] } + Entity { + id: cube2 + + components: [ + Transform { + id: cube2Transform + translation: Qt.vector3d(2.5, 0, 0) + onTranslationChanged: console.log("t = " + translation) + }, + CuboidMesh { + }, + PhongMaterial { + id: cube2Material + ambient: Qt.rgba(0.8, 0.8, 0.8, 1.0) + diffuse: Qt.rgba(0.7, 0.7, 0.7, 1.0) + shininess: 50 + }, + ObjectPicker { + onClicked: blendedAnimator2.running = true + }, + BlendedClipAnimator { + id: blendedAnimator2 + loops: 2 + + onRunningChanged: console.log("running = " + running) + + blendTree: AddBlend { + blendFactor: 0.5 + clips: [ + AnimationClip { + source: "pulsing-moving-cube.json" + onDurationChanged: console.log("duration = " + duration) + }, + AnimationClip { + source: "pulsing-cube-additive.json" + onDurationChanged: console.log("duration = " + duration) + }] + } + + // By default introspect parent Entity and try + // to map fcurve groups to properties of QTransform + // mapping: AutomaticAnimationMapping {} + + // To do more, we can be explicit + channelMapper: ChannelMapper { + mappings: [ + ChannelMapping { channelName: "Location"; target: cube2Transform; property: "translation" }, + ChannelMapping { channelName: "Rotation"; target: cube2Transform; property: "rotation" }, + ChannelMapping { channelName: "Scaling"; target: cube2Transform; property: "scale3D" }, + ChannelMapping { channelName: "Diffuse Color"; target: cube2Transform; property: "diffuse" } + ] + } + } + ] + } + camera: Camera { position: Qt.vector3d(10, 3, 15) diff --git a/tests/manual/animation-keyframe-simple/main.qrc b/tests/manual/animation-keyframe-simple/main.qrc index 323756a88..b59429895 100644 --- a/tests/manual/animation-keyframe-simple/main.qrc +++ b/tests/manual/animation-keyframe-simple/main.qrc @@ -4,5 +4,6 @@ DefaultSceneEntity.qml cubeanimation.json pulsing-moving-cube.json + pulsing-cube-additive.json diff --git a/tests/manual/animation-keyframe-simple/pulsing-cube-additive.json b/tests/manual/animation-keyframe-simple/pulsing-cube-additive.json new file mode 100644 index 000000000..1373a5002 --- /dev/null +++ b/tests/manual/animation-keyframe-simple/pulsing-cube-additive.json @@ -0,0 +1,84 @@ +{ + "animations": [ + { "object": "Cube", + "action": "CubeAction", + "range": [0.0, 60.0], + "groups": [ + { "group": "Scaling", + "channels": [ + { "name": "x", + "keyframes": [ + { "co": [0.0, 1.0], + "handle_left": [-0.1464043160279592, 1.0], + "handle_right": [0.14640430609385172, 1.0]} + ,{ "co": [0.375, 0.5], + "handle_left": [0.22859569390614828, 0.5], + "handle_right": [0.5376714468002319, 0.5]} + ,{ "co": [0.7916666666666666, 1.0], + "handle_left": [0.6289951801300049, 1.0], + "handle_right": [0.9543381532033285, 1.0]} + ,{ "co": [1.2083333333333333, 0.5], + "handle_left": [1.0456619262695312, 0.5], + "handle_right": [1.371035893758138, 0.5]} + ,{ "co": [1.625, 1.0], + "handle_left": [1.462328592936198, 1.0], + "handle_right": [1.787671407063802, 1.0]} + ,{ "co": [2.0416666666666665, 0.5], + "handle_left": [1.8789952596028645, 0.5], + "handle_right": [2.2043380737304688, 0.5]} + ,{ "co": [2.4583333333333335, 1.0], + "handle_left": [2.2956619262695312, 1.0], + "handle_right": [2.6210047403971353, 1.0]} + ]} + ,{ "name": "z", + "keyframes": [ + { "co": [0.0, 1.0], + "handle_left": [-0.1464043160279592, 1.0], + "handle_right": [0.14640430609385172, 1.0]} + ,{ "co": [0.375, 0.5], + "handle_left": [0.22859569390614828, 0.5], + "handle_right": [0.5376714468002319, 0.5]} + ,{ "co": [0.7916666666666666, 1.0], + "handle_left": [0.6289951801300049, 1.0], + "handle_right": [0.9543381532033285, 1.0]} + ,{ "co": [1.2083333333333333, 0.5], + "handle_left": [1.0456618467966716, 0.5], + "handle_right": [1.3710047403971355, 0.5]} + ,{ "co": [1.625, 1.0], + "handle_left": [1.462328592936198, 1.0], + "handle_right": [1.787671407063802, 1.0]} + ,{ "co": [2.0416666666666665, 0.5], + "handle_left": [1.8789952596028645, 0.5], + "handle_right": [2.2043380737304688, 0.5]} + ,{ "co": [2.4583333333333335, 1.0], + "handle_left": [2.2956619262695312, 1.0], + "handle_right": [2.6210047403971353, 1.0]} + ]} + ,{ "name": "y", + "keyframes": [ + { "co": [0.0, 1.0], + "handle_left": [-0.1464043160279592, 1.0], + "handle_right": [0.14640430609385172, 1.0]} + ,{ "co": [0.375, 0.5], + "handle_left": [0.22859569390614828, 0.5], + "handle_right": [0.5376714468002319, 0.5]} + ,{ "co": [0.7916666666666666, 1.0], + "handle_left": [0.6289951801300049, 1.0], + "handle_right": [0.9543381532033285, 1.0]} + ,{ "co": [1.2083333333333333, 0.5441937446594238], + "handle_left": [1.0456618467966716, 0.5441937446594238], + "handle_right": [1.3710047403971355, 0.5441937446594238]} + ,{ "co": [1.625, 1.0], + "handle_left": [1.462328592936198, 1.0], + "handle_right": [1.787671407063802, 1.0]} + ,{ "co": [2.0416666666666665, 0.5771476030349731], + "handle_left": [1.8789952596028645, 0.5771476030349731], + "handle_right": [2.2043380737304688, 0.5771476030349731]} + ,{ "co": [2.4583333333333335, 1.0], + "handle_left": [2.2956619262695312, 1.0], + "handle_right": [2.6210047403971353, 1.0]} + ]} + ]} + ]} + ] +} -- cgit v1.2.3 From 0010aa249244ff801af62e73a4b121fbd1491d73 Mon Sep 17 00:00:00 2001 From: Wieland Hagen Date: Mon, 12 Dec 2016 12:53:53 +0700 Subject: Add Qt3DExtras::QTextureAtlas class areallocator is copied from qtdeclarative/src/quick/scenegraph/util. We could link to QtQuick to use this allocator from the private headers, but this would introduce a hard dependency on QtQuick that Qt3DExtras doesn't yet have. Image data for texture atlasses are stored inside QTextureAtlasData structures, which are shared between 1. the frontend QTextureAtlas node, and 2. the texture generators that are updated each time something is added to the atlas If we didn't share this data, we would have to copy the current QImage that stores the current state of the texture atlas, each time that a new sub-image is added. This would result in considerable memory copying overhead. By sharing the data, we can just add new sub-images to the shared data structure, and update the texture generator. This may happen dozens of times within one frame. When the backend texture loading job is executed, it will copy all the new sub-images into the overall texture image, and create the texture data from that image. This way, exactly zero image copying overhead happens in the frontend thread. Change-Id: I8c418bf335afd1363ad7cefdf81778e4075038e8 Reviewed-by: Sean Harmer --- src/extras/extras.pro | 1 + src/extras/text/areaallocator.cpp | 296 +++++++++++++++++++++++++++++++ src/extras/text/areaallocator_p.h | 92 ++++++++++ src/extras/text/qtextureatlas.cpp | 303 ++++++++++++++++++++++++++++++++ src/extras/text/qtextureatlas.h | 84 +++++++++ src/extras/text/qtextureatlas_p.h | 139 +++++++++++++++ src/extras/text/text.pri | 10 ++ src/render/texture/qabstracttexture_p.h | 3 +- 8 files changed, 927 insertions(+), 1 deletion(-) create mode 100644 src/extras/text/areaallocator.cpp create mode 100644 src/extras/text/areaallocator_p.h create mode 100644 src/extras/text/qtextureatlas.cpp create mode 100644 src/extras/text/qtextureatlas.h create mode 100644 src/extras/text/qtextureatlas_p.h create mode 100644 src/extras/text/text.pri diff --git a/src/extras/extras.pro b/src/extras/extras.pro index d723554ca..22c9fcb93 100644 --- a/src/extras/extras.pro +++ b/src/extras/extras.pro @@ -12,6 +12,7 @@ load(qt_module) include (geometries/geometries.pri) include (3dtext/3dtext.pri) include (defaults/defaults.pri) +include (text/text.pri) HEADERS += \ qt3dextras_global.h diff --git a/src/extras/text/areaallocator.cpp b/src/extras/text/areaallocator.cpp new file mode 100644 index 000000000..61f1d5bc6 --- /dev/null +++ b/src/extras/text/areaallocator.cpp @@ -0,0 +1,296 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "areaallocator_p.h" + +#include +#include +#include + +// +// This file is copied from qtdeclarative/src/quick/scenegraph/util/qsgareaallocator.cpp +// + +QT_BEGIN_NAMESPACE + +namespace Qt3DExtras { + +namespace +{ + enum SplitType + { + VerticalSplit, + HorizontalSplit + }; + + static const int maxMargin = 2; +} + +struct AreaAllocatorNode +{ + AreaAllocatorNode(AreaAllocatorNode *parent); + ~AreaAllocatorNode(); + inline bool isLeaf(); + + AreaAllocatorNode *parent; + AreaAllocatorNode *left; + AreaAllocatorNode *right; + int split; // only valid for inner nodes. + SplitType splitType; + bool isOccupied; // only valid for leaf nodes. +}; + +AreaAllocatorNode::AreaAllocatorNode(AreaAllocatorNode *parent) + : parent(parent) + , left(0) + , right(0) + , isOccupied(false) +{ +} + +AreaAllocatorNode::~AreaAllocatorNode() +{ + delete left; + delete right; +} + +bool AreaAllocatorNode::isLeaf() +{ + Q_ASSERT((left != 0) == (right != 0)); + return !left; +} + + +AreaAllocator::AreaAllocator(const QSize &size) : m_size(size) +{ + m_root = new AreaAllocatorNode(0); +} + +AreaAllocator::~AreaAllocator() +{ + delete m_root; +} + +QRect AreaAllocator::allocate(const QSize &size) +{ + QPoint point; + bool result = allocateInNode(size, point, QRect(QPoint(0, 0), m_size), m_root); + return result ? QRect(point, size) : QRect(); +} + +bool AreaAllocator::deallocate(const QRect &rect) +{ + return deallocateInNode(rect.topLeft(), m_root); +} + +bool AreaAllocator::allocateInNode(const QSize &size, QPoint &result, const QRect ¤tRect, AreaAllocatorNode *node) +{ + if (size.width() > currentRect.width() || size.height() > currentRect.height()) + return false; + + if (node->isLeaf()) { + if (node->isOccupied) + return false; + if (size.width() + maxMargin >= currentRect.width() && size.height() + maxMargin >= currentRect.height()) { + //Snug fit, occupy entire rectangle. + node->isOccupied = true; + result = currentRect.topLeft(); + return true; + } + // TODO: Reuse nodes. + // Split node. + node->left = new AreaAllocatorNode(node); + node->right = new AreaAllocatorNode(node); + QRect splitRect = currentRect; + if ((currentRect.width() - size.width()) * currentRect.height() < (currentRect.height() - size.height()) * currentRect.width()) { + node->splitType = HorizontalSplit; + node->split = currentRect.top() + size.height(); + splitRect.setHeight(size.height()); + } else { + node->splitType = VerticalSplit; + node->split = currentRect.left() + size.width(); + splitRect.setWidth(size.width()); + } + return allocateInNode(size, result, splitRect, node->left); + } else { + // TODO: avoid unnecessary recursion. + // has been split. + QRect leftRect = currentRect; + QRect rightRect = currentRect; + if (node->splitType == HorizontalSplit) { + leftRect.setHeight(node->split - leftRect.top()); + rightRect.setTop(node->split); + } else { + leftRect.setWidth(node->split - leftRect.left()); + rightRect.setLeft(node->split); + } + if (allocateInNode(size, result, leftRect, node->left)) + return true; + if (allocateInNode(size, result, rightRect, node->right)) + return true; + return false; + } +} + +bool AreaAllocator::deallocateInNode(const QPoint &pos, AreaAllocatorNode *node) +{ + while (!node->isLeaf()) { + // has been split. + int cmp = node->splitType == HorizontalSplit ? pos.y() : pos.x(); + node = cmp < node->split ? node->left : node->right; + } + if (!node->isOccupied) + return false; + node->isOccupied = false; + mergeNodeWithNeighbors(node); + return true; +} + +void AreaAllocator::mergeNodeWithNeighbors(AreaAllocatorNode *node) +{ + bool done = false; + AreaAllocatorNode *parent = 0; + AreaAllocatorNode *current = 0; + AreaAllocatorNode *sibling; + while (!done) { + Q_ASSERT(node->isLeaf()); + Q_ASSERT(!node->isOccupied); + if (node->parent == 0) + return; // No neighbors. + + SplitType splitType = SplitType(node->parent->splitType); + done = true; + + /* Special case. Might be faster than going through the general code path. + // Merge with sibling. + parent = node->parent; + sibling = (node == parent->left ? parent->right : parent->left); + if (sibling->isLeaf() && !sibling->isOccupied) { + Q_ASSERT(!sibling->right); + node = parent; + parent->isOccupied = false; + delete parent->left; + delete parent->right; + parent->left = parent->right = 0; + done = false; + continue; + } + */ + + // Merge with left neighbor. + current = node; + parent = current->parent; + while (parent && current == parent->left && parent->splitType == splitType) { + current = parent; + parent = parent->parent; + } + + if (parent && parent->splitType == splitType) { + Q_ASSERT(current == parent->right); + Q_ASSERT(parent->left); + + AreaAllocatorNode *neighbor = parent->left; + while (neighbor->right && neighbor->splitType == splitType) + neighbor = neighbor->right; + + if (neighbor->isLeaf() && neighbor->parent->splitType == splitType && !neighbor->isOccupied) { + // Left neighbor can be merged. + parent->split = neighbor->parent->split; + + parent = neighbor->parent; + sibling = neighbor == parent->left ? parent->right : parent->left; + AreaAllocatorNode **nodeRef = &m_root; + if (parent->parent) { + if (parent == parent->parent->left) + nodeRef = &parent->parent->left; + else + nodeRef = &parent->parent->right; + } + sibling->parent = parent->parent; + *nodeRef = sibling; + parent->left = parent->right = 0; + delete parent; + delete neighbor; + done = false; + } + } + + // Merge with right neighbor. + current = node; + parent = current->parent; + while (parent && current == parent->right && parent->splitType == splitType) { + current = parent; + parent = parent->parent; + } + + if (parent && parent->splitType == splitType) { + Q_ASSERT(current == parent->left); + Q_ASSERT(parent->right); + + AreaAllocatorNode *neighbor = parent->right; + while (neighbor->left && neighbor->splitType == splitType) + neighbor = neighbor->left; + + if (neighbor->isLeaf() && neighbor->parent->splitType == splitType && !neighbor->isOccupied) { + // Right neighbor can be merged. + parent->split = neighbor->parent->split; + + parent = neighbor->parent; + sibling = neighbor == parent->left ? parent->right : parent->left; + AreaAllocatorNode **nodeRef = &m_root; + if (parent->parent) { + if (parent == parent->parent->left) + nodeRef = &parent->parent->left; + else + nodeRef = &parent->parent->right; + } + sibling->parent = parent->parent; + *nodeRef = sibling; + parent->left = parent->right = 0; + delete parent; + delete neighbor; + done = false; + } + } + } // end while (!done) +} + +} // namespace Qt3DExtras + +QT_END_NAMESPACE diff --git a/src/extras/text/areaallocator_p.h b/src/extras/text/areaallocator_p.h new file mode 100644 index 000000000..809c5c698 --- /dev/null +++ b/src/extras/text/areaallocator_p.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3DEXTRAS_AREAALLOCATOR_P_H +#define QT3DEXTRAS_AREAALLOCATOR_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +// +// This file is copied from qtdeclarative/src/quick/scenegraph/util/qsgareaallocator_p.h +// + +#include + +QT_BEGIN_NAMESPACE + +class QRect; +class QPoint; + +namespace Qt3DExtras { + +struct AreaAllocatorNode; + +class AreaAllocator +{ +public: + AreaAllocator(const QSize &size); + ~AreaAllocator(); + + QRect allocate(const QSize &size); + bool deallocate(const QRect &rect); + bool isEmpty() const { return m_root == 0; } + QSize size() const { return m_size; } +private: + bool allocateInNode(const QSize &size, QPoint &result, const QRect ¤tRect, AreaAllocatorNode *node); + bool deallocateInNode(const QPoint &pos, AreaAllocatorNode *node); + void mergeNodeWithNeighbors(AreaAllocatorNode *node); + + AreaAllocatorNode *m_root; + QSize m_size; +}; + +} // namespace Qt3DExtras + +QT_END_NAMESPACE + +#endif // QT3DEXTRAS_AREAALLOCATOR_P_H diff --git a/src/extras/text/qtextureatlas.cpp b/src/extras/text/qtextureatlas.cpp new file mode 100644 index 000000000..1a076a3ab --- /dev/null +++ b/src/extras/text/qtextureatlas.cpp @@ -0,0 +1,303 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtextureatlas.h" +#include "qtextureatlas_p.h" +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +using namespace Qt3DCore; + +namespace Qt3DExtras { + +QTextureAtlasData::QTextureAtlasData(int w, int h, QImage::Format fmt) + : m_image(w, h, fmt) +{ +} + +QTextureAtlasData::~QTextureAtlasData() +{ +} + +void QTextureAtlasData::addImage(const AtlasTexture &texture, const QImage &image) +{ + QMutexLocker lock(&m_mutex); + + Update update; + update.textureInfo = texture; + update.image = image; + m_updates << update; +} + +QByteArray QTextureAtlasData::createUpdatedImageData() +{ + m_mutex.lock(); + const QVector updates = std::move(m_updates); + m_mutex.unlock(); + + // copy sub-images into the actual texture image + for (const Update &update : updates) { + const QImage &image = update.image; + + const int padding = update.textureInfo.padding; + const QRect imgRect = update.textureInfo.position; + const QRect alloc = imgRect.adjusted(-padding, -padding, padding, padding); + + // bytes per pixel + if (image.depth() != m_image.depth()) { + qWarning() << "[QTextureAtlas] Image depth does not match. Original =" << m_image.depth() << ", Sub-Image =" << image.depth(); + continue; + } + int bpp = image.depth() / 8; + + // copy image contents into texture image + // use image border pixels to fill the padding region + for (int y = alloc.top(); y <= alloc.bottom(); y++) { + const int ySrc = qBound(0, y - imgRect.top(), image.height()-1); + + const uchar *srcLine = image.scanLine(ySrc); + const uchar *srcLastPx = &srcLine[bpp * (image.width()-1)]; + + uchar *dstLine = m_image.scanLine(y); + + uchar *dstPadL = &dstLine[bpp * alloc.left()]; + uchar *dstPadR = &dstLine[bpp * imgRect.right()]; + uchar *dstImg = &dstLine[bpp * imgRect.left()]; + + // copy left and right padding pixels + for (int pad = 0; pad < padding; pad++) { + for (int px = 0; px < bpp; px++) { + dstPadL[bpp * pad + px] = srcLine[px]; + dstPadR[bpp * pad + px] = srcLastPx[px]; + } + } + + // copy image scanline + memcpy(dstImg, srcLine, bpp * imgRect.width()); + } + } + + return QByteArray(reinterpret_cast(m_image.constBits()), m_image.byteCount()); +} + +QTextureAtlasPrivate::QTextureAtlasPrivate() + : Qt3DRender::QAbstractTexturePrivate() +{ + m_target = Qt3DRender::QAbstractTexture::TargetAutomatic; + m_format = Qt3DRender::QAbstractTexture::RGBA8_UNorm; + m_width = 256; + m_height = 256; + m_depth = 1; +} + +QTextureAtlasPrivate::~QTextureAtlasPrivate() +{ +} + +QTextureAtlasGenerator::QTextureAtlasGenerator(const QTextureAtlasPrivate *texAtlas) + : m_data(texAtlas->m_data) + , m_format(texAtlas->m_format) + , m_pixelFormat(texAtlas->m_pixelFormat) + , m_generation(texAtlas->m_currGen) + , m_atlasId(texAtlas->m_id) +{ +} + +QTextureAtlasGenerator::~QTextureAtlasGenerator() +{ +} + +Qt3DRender::QTextureDataPtr QTextureAtlasGenerator::operator()() +{ + Qt3DRender::QTextureImageDataPtr texImage = Qt3DRender::QTextureImageDataPtr::create(); + texImage->setTarget(QOpenGLTexture::Target2D); + texImage->setWidth(m_data->width()); + texImage->setHeight(m_data->height()); + texImage->setDepth(1); + texImage->setFaces(1); + texImage->setLayers(1); + texImage->setMipLevels(1); + texImage->setFormat(static_cast(m_format)); + texImage->setPixelFormat(m_pixelFormat); + texImage->setPixelType(QOpenGLTexture::UInt8); + + const QByteArray bytes = m_data->createUpdatedImageData(); + texImage->setData(bytes, 1); + + Qt3DRender::QTextureDataPtr generatedData = Qt3DRender::QTextureDataPtr::create(); + generatedData->setTarget(Qt3DRender::QAbstractTexture::Target2D); + generatedData->setFormat(m_format); + generatedData->setWidth(m_data->width()); + generatedData->setHeight(m_data->height()); + generatedData->setDepth(1); + generatedData->setLayers(1); + generatedData->addImageData(texImage); + + return generatedData; +} + +bool QTextureAtlasGenerator::operator==(const QTextureGenerator &other) const +{ + const QTextureAtlasGenerator *otherFunctor = functor_cast(&other); + return (otherFunctor != nullptr + && otherFunctor->m_data == m_data + && otherFunctor->m_atlasId == m_atlasId + && otherFunctor->m_generation == m_generation); +} + +QTextureAtlas::QTextureAtlas(Qt3DCore::QNode *parent) + : QAbstractTexture(*new QTextureAtlasPrivate(), parent) +{ +} + +QOpenGLTexture::PixelFormat QTextureAtlas::pixelFormat() const +{ + Q_D(const QTextureAtlas); + return d->m_pixelFormat; +} + +void QTextureAtlas::setPixelFormat(QOpenGLTexture::PixelFormat fmt) +{ + Q_D(QTextureAtlas); + d->m_pixelFormat = fmt; +} + +QTextureAtlas::~QTextureAtlas() +{ +} + +QTextureAtlas::TextureId QTextureAtlas::addImage(const QImage &image, int padding) +{ + Q_D(QTextureAtlas); + + // lazily create image and allocator to allow setWidth/setHeight after object construction + if (!d->m_allocator) { + Q_ASSERT(d->m_data.isNull()); + + d->m_allocator.reset(new AreaAllocator(QSize(width(), height()))); + d->m_data = QTextureAtlasDataPtr::create(width(), height(), image.format()); + } + + const QSize allocSz = image.size() + QSize(2 * padding, 2 * padding); + + // try to allocate space within image space + const QRect alloc = d->m_allocator->allocate(allocSz); + if (alloc.isEmpty()) + return InvalidTexture; + + const QRect imgRect = alloc.adjusted(padding, padding, -padding, -padding); + AtlasTexture tex; + tex.position = imgRect; + tex.padding = padding; + + // store texture + TextureId id = d->m_currId++; + d->m_textures[id] = tex; + d->m_data->addImage(tex, image); + + // update data functor + d->m_currGen++; + d->setDataFunctor(QTextureAtlasGeneratorPtr::create(d)); + + return id; +} + +void QTextureAtlas::removeImage(TextureId id) +{ + Q_D(QTextureAtlas); + auto it = d->m_textures.find(id); + if (it != d->m_textures.end()) { + QRect imgRect = it->position; + imgRect.adjust(-it->padding, -it->padding, 2*it->padding, 2*it->padding); + + if (d->m_allocator) + d->m_allocator->deallocate(imgRect); + d->m_textures.erase(it); + } +} + +bool QTextureAtlas::hasImage(TextureId id) const +{ + Q_D(const QTextureAtlas); + return d->m_textures.contains(id); +} + +int QTextureAtlas::imageCount() const +{ + Q_D(const QTextureAtlas); + return d->m_textures.size(); +} + +QRect QTextureAtlas::imagePosition(TextureId id) const +{ + Q_D(const QTextureAtlas); + const auto it = d->m_textures.find(id); + return (it != d->m_textures.cend()) ? it->position : QRect(); +} + +QRectF QTextureAtlas::imageTexCoords(TextureId id) const +{ + Q_D(const QTextureAtlas); + const auto it = d->m_textures.find(id); + if (it != d->m_textures.cend()) { + const float w = d->m_data->width(); + const float h = d->m_data->height(); + return QRectF(static_cast(it->position.x()) / w, + static_cast(it->position.y()) / h, + static_cast(it->position.width()) / w, + static_cast(it->position.height()) / h); + } + return QRectF(); +} + +int QTextureAtlas::imagePadding(TextureId id) const +{ + Q_D(const QTextureAtlas); + const auto it = d->m_textures.find(id); + return (it != d->m_textures.cend()) ? it->padding : -1; +} + +} // namespace Qt3DExtras + +QT_END_NAMESPACE diff --git a/src/extras/text/qtextureatlas.h b/src/extras/text/qtextureatlas.h new file mode 100644 index 000000000..c70f9dfd3 --- /dev/null +++ b/src/extras/text/qtextureatlas.h @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3DEXTRAS_QTEXTUREATLAS_H +#define QT3DEXTRAS_QTEXTUREATLAS_H + +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DExtras { + +class QTextureAtlasPrivate; + +class QT3DEXTRASSHARED_EXPORT QTextureAtlas : public Qt3DRender::QAbstractTexture +{ + Q_OBJECT + +public: + typedef int TextureId; + static Q_CONSTEXPR TextureId InvalidTexture = -1; + + QTextureAtlas(Qt3DCore::QNode *parent = nullptr); + ~QTextureAtlas(); + + QOpenGLTexture::PixelFormat pixelFormat() const; + void setPixelFormat(QOpenGLTexture::PixelFormat fmt); + + TextureId addImage(const QImage &image, int padding); + void removeImage(TextureId id); + + int imageCount() const; + + bool hasImage(TextureId id) const; + QRect imagePosition(TextureId id) const; + QRectF imageTexCoords(TextureId id) const; + int imagePadding(TextureId id) const; + +private: + Q_DECLARE_PRIVATE(QTextureAtlas) +}; + +} // namespace Qt3DExtras + +QT_END_NAMESPACE + +#endif // QT3DEXTRAS_QTEXTUREATLAS_H diff --git a/src/extras/text/qtextureatlas_p.h b/src/extras/text/qtextureatlas_p.h new file mode 100644 index 000000000..34386a87a --- /dev/null +++ b/src/extras/text/qtextureatlas_p.h @@ -0,0 +1,139 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3DEXTRAS_QTEXTUREATLAS_P_H +#define QT3DEXTRAS_QTEXTUREATLAS_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DExtras { + +// Used to store texture info within atlas +struct AtlasTexture +{ + QRect position; + int padding = 0; +}; + +// data shared between QTextureAtlasPrivate and the QTextureGenerators +// we use this extra indirection so we can lazily copy the sub-images +// into the actual texture image in the backend texture loader thread. +class QTextureAtlasData +{ +public: + QTextureAtlasData(int w, int h, QImage::Format fmt); + ~QTextureAtlasData(); + + int width() const { return m_image.width(); } + int height() const { return m_image.height(); } + + void addImage(const AtlasTexture &texture, const QImage &image); + QByteArray createUpdatedImageData(); + +private: + struct Update { + AtlasTexture textureInfo; + QImage image; + }; + + QMutex m_mutex; + QImage m_image; + QVector m_updates; +}; + +typedef QSharedPointer QTextureAtlasDataPtr; + +class QTextureAtlasPrivate : public Qt3DRender::QAbstractTexturePrivate +{ +public: + QTextureAtlasPrivate(); + ~QTextureAtlasPrivate(); + + Q_DECLARE_PUBLIC(QTextureAtlas) + + QTextureAtlas::TextureId m_currId = 1; // IDs for new sub-textures + int m_currGen = 0; + + QTextureAtlasDataPtr m_data; + QScopedPointer m_allocator; + QOpenGLTexture::PixelFormat m_pixelFormat; + QHash m_textures; +}; + +class QTextureAtlasGenerator : public Qt3DRender::QTextureGenerator +{ +public: + QTextureAtlasGenerator(const QTextureAtlasPrivate *texAtlas); + ~QTextureAtlasGenerator(); + Qt3DRender::QTextureDataPtr operator()() Q_DECL_OVERRIDE; + bool operator==(const QTextureGenerator &other) const Q_DECL_OVERRIDE; + + QT3D_FUNCTOR(QTextureAtlasGenerator) + +private: + QTextureAtlasDataPtr m_data; + Qt3DRender::QAbstractTexture::TextureFormat m_format; + QOpenGLTexture::PixelFormat m_pixelFormat; + int m_generation; + Qt3DCore::QNodeId m_atlasId; +}; +typedef QSharedPointer QTextureAtlasGeneratorPtr; + +} // namespace Qt3DExtras + +QT_END_NAMESPACE + +#endif // QT3DEXTRAS_QTEXTUREATLAS_P_H diff --git a/src/extras/text/text.pri b/src/extras/text/text.pri new file mode 100644 index 000000000..9ba6830e9 --- /dev/null +++ b/src/extras/text/text.pri @@ -0,0 +1,10 @@ +HEADERS += \ + $$PWD/qtextureatlas.h \ + $$PWD/qtextureatlas_p.h \ + $$PWD/areaallocator_p.h + +SOURCES += \ + $$PWD/qtextureatlas.cpp \ + $$PWD/areaallocator.cpp + +INCLUDEPATH += $$PWD diff --git a/src/render/texture/qabstracttexture_p.h b/src/render/texture/qabstracttexture_p.h index 7f5a32c94..c245a78af 100644 --- a/src/render/texture/qabstracttexture_p.h +++ b/src/render/texture/qabstracttexture_p.h @@ -56,12 +56,13 @@ #include #include #include +#include QT_BEGIN_NAMESPACE namespace Qt3DRender { -class Q_AUTOTEST_EXPORT QAbstractTexturePrivate : public Qt3DCore::QNodePrivate +class QT3DRENDERSHARED_PRIVATE_EXPORT QAbstractTexturePrivate : public Qt3DCore::QNodePrivate { public : QAbstractTexturePrivate(); -- cgit v1.2.3 From 6c94c0395d060b4f4e07da1b86348f3e0e7a9b65 Mon Sep 17 00:00:00 2001 From: Wieland Hagen Date: Wed, 28 Dec 2016 13:25:04 +0700 Subject: QDistanceFieldGlyphCache: stores distance field textures For text rendering via textures (independent of the technique used) we want to store font glyphs 1. in a texture atlas, in order to reduce the number of GL textures by orders of magnitude 2. reference-counted: so that we can delete glyphs that are no longer needed, i.e. that are no longer rendered by any text instantiation The QDistanceFieldGlyph cache is a node that has to be placed somewhere in the scene, and is then referenced by QDistanceFieldText nodes so it will be used for text rendering. It associates with each QRawFont (but independent of the font size) a DistanceFieldFont, which stores in one or more texture atlasses (one atlas will hold ~50 entries, so it will be sufficient for most font instantiations) the glyphs that are currently referenced. These texture atlasses will be children of the QDistanceFieldGlyphCache. The QDistanceFieldGlyphCache offers methods to ref and de-ref glyphs for a given QRawFont, and will return a struct that contains the texture the glyphs are stored in, and the associated texture coordinates within that texture. Change-Id: I3c9557ecad605e912f8ce3b92265b9fc39329f49 Reviewed-by: Sean Harmer --- src/extras/text/qdistancefieldglyphcache.cpp | 310 +++++++++++++++++++++++++++ src/extras/text/qdistancefieldglyphcache.h | 90 ++++++++ src/extras/text/qdistancefieldglyphcache_p.h | 136 ++++++++++++ src/extras/text/text.pri | 3 + 4 files changed, 539 insertions(+) create mode 100644 src/extras/text/qdistancefieldglyphcache.cpp create mode 100644 src/extras/text/qdistancefieldglyphcache.h create mode 100644 src/extras/text/qdistancefieldglyphcache_p.h diff --git a/src/extras/text/qdistancefieldglyphcache.cpp b/src/extras/text/qdistancefieldglyphcache.cpp new file mode 100644 index 000000000..dfe59883c --- /dev/null +++ b/src/extras/text/qdistancefieldglyphcache.cpp @@ -0,0 +1,310 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include + +#include "qdistancefieldglyphcache.h" +#include "qdistancefieldglyphcache_p.h" +#include "qtextureatlas.h" + +QT_BEGIN_NAMESPACE + +#define DEFAULT_IMAGE_PADDING 1 + +using namespace Qt3DCore; + +namespace Qt3DExtras { + +StoredGlyph::StoredGlyph(const QRawFont &font, quint32 glyph, bool doubleResolution) + : m_glyph(glyph) + , m_ref(1) + , m_atlas(nullptr) + , m_atlasEntry(QTextureAtlas::InvalidTexture) +{ + // create new single-channel distance field image for given glyph + const QPainterPath path = font.pathForGlyph(glyph); + const QDistanceField dfield(font, glyph, doubleResolution); + m_distanceFieldImage = dfield.toImage(QImage::Format_Alpha8); + + // scale bounding rect down (as in QSGDistanceFieldGlyphCache::glyphData()) + const QRectF pathBound = path.boundingRect(); + float f = 1.0f / QT_DISTANCEFIELD_SCALE(doubleResolution); + m_glyphPathBoundingRect = QRectF(pathBound.left() * f, -pathBound.top() * f, pathBound.width() * f, pathBound.height() * f); +} + +bool StoredGlyph::addToTextureAtlas(QTextureAtlas *atlas) +{ + if (m_atlas || m_distanceFieldImage.isNull()) + return false; + + const auto texId = atlas->addImage(m_distanceFieldImage, DEFAULT_IMAGE_PADDING); + if (texId != QTextureAtlas::InvalidTexture) { + m_atlas = atlas; + m_atlasEntry = texId; + m_distanceFieldImage = QImage(); // free glyph image data + return true; + } + + return false; +} + +void StoredGlyph::removeFromTextureAtlas() +{ + if (m_atlas) { + m_atlas->removeImage(m_atlasEntry); + m_atlas = nullptr; + m_atlasEntry = QTextureAtlas::InvalidTexture; + } +} + +QRectF StoredGlyph::texCoords() const +{ + return m_atlas ? m_atlas->imageTexCoords(m_atlasEntry) : QRectF(); +} + +DistanceFieldFont::DistanceFieldFont(const QRawFont &font, bool doubleRes, Qt3DCore::QNode *parent) + : m_font(font) + , m_doubleGlyphResolution(doubleRes) + , m_parentNode(parent) +{ +} + +DistanceFieldFont::~DistanceFieldFont() +{ + qDeleteAll(m_atlasses); +} + +StoredGlyph DistanceFieldFont::findGlyph(quint32 glyph) const +{ + const auto it = m_glyphs.find(glyph); + return (it != m_glyphs.cend()) ? it.value() : StoredGlyph(); +} + +StoredGlyph DistanceFieldFont::refGlyph(quint32 glyph) +{ + // if glyph already exists, just increase ref-count + auto it = m_glyphs.find(glyph); + if (it != m_glyphs.end()) { + it.value().ref(); + return it.value(); + } + + // need to create new glyph + StoredGlyph storedGlyph(m_font, glyph, m_doubleGlyphResolution); + + // see if one of the existing atlasses can hold the distance field image + for (int i = 0; i < m_atlasses.size(); i++) + if (storedGlyph.addToTextureAtlas(m_atlasses[i])) + break; + + // if no texture atlas is big enough (or no exists yet), allocate a new one + if (!storedGlyph.atlas()) { + // this should be enough to store 40-60 glyphs, which should be sufficient for most + // scenarios + const int size = m_doubleGlyphResolution ? 512 : 256; + + QTextureAtlas *atlas = new QTextureAtlas(m_parentNode); + atlas->setWidth(size); + atlas->setHeight(size); + atlas->setFormat(Qt3DRender::QAbstractTexture::R8_UNorm); + atlas->setPixelFormat(QOpenGLTexture::Red); + atlas->setMinificationFilter(Qt3DRender::QAbstractTexture::Linear); + atlas->setMagnificationFilter(Qt3DRender::QAbstractTexture::Linear); + m_atlasses << atlas; + + if (!storedGlyph.addToTextureAtlas(atlas)) + qWarning() << Q_FUNC_INFO << "Couldn't add glyph to newly allocated atlas. Glyph could be huge?"; + } + + m_glyphs.insert(glyph, storedGlyph); + return storedGlyph; +} + +void DistanceFieldFont::derefGlyph(quint32 glyph) +{ + auto it = m_glyphs.find(glyph); + if (it == m_glyphs.end()) + return; + + // TODO + // possible optimization: keep unreferenced glyphs as the texture atlas + // still has space. only if a new glyph needs to be allocated, and there + // is no more space within the atlas, then we can actually remove the glyphs + // from the atlasses. + + // remove glyph if no refs anymore + if (it.value().deref() <= 0) { + QTextureAtlas *atlas = it.value().atlas(); + it.value().removeFromTextureAtlas(); + + // remove atlas, if it contains no glyphs anymore + if (atlas && atlas->imageCount() == 0) { + Q_ASSERT(m_atlasses.contains(atlas)); + + m_atlasses.removeAll(atlas); + delete atlas; + } + + m_glyphs.erase(it); + } +} + +// copied from QSGDistanceFieldGlyphCacheManager::fontKey +// we use this function to compare QRawFonts, as QRawFont doesn't +// implement a stable comparison function +QString QDistanceFieldGlyphCachePrivate::fontKey(const QRawFont &font) +{ + QFontEngine *fe = QRawFontPrivate::get(font)->fontEngine; + if (!fe->faceId().filename.isEmpty()) { + QByteArray keyName = fe->faceId().filename; + if (font.style() != QFont::StyleNormal) + keyName += QByteArray(" I"); + if (font.weight() != QFont::Normal) + keyName += ' ' + QByteArray::number(font.weight()); + keyName += QByteArray(" DF"); + return QString::fromUtf8(keyName); + } else { + return QString::fromLatin1("%1_%2_%3_%4") + .arg(font.familyName()) + .arg(font.styleName()) + .arg(font.weight()) + .arg(font.style()); + } +} + +DistanceFieldFont* QDistanceFieldGlyphCachePrivate::getOrCreateDistanceFieldFont(const QRawFont &font) +{ + // return, if font already exists (make sure to only create one DistanceFieldFont for + // each unique QRawFont, by building a hash on the QRawFont that ignores the font size) + const QString key = fontKey(font); + const auto it = m_fonts.find(key); + if (it != m_fonts.cend()) + return it.value(); + + // logic taken from QSGDistanceFieldGlyphCache::QSGDistanceFieldGlyphCache + QRawFontPrivate *fontD = QRawFontPrivate::get(font); + const int glyphCount = fontD->fontEngine->glyphCount(); + const bool useDoubleRes = qt_fontHasNarrowOutlines(font) && glyphCount < QT_DISTANCEFIELD_HIGHGLYPHCOUNT(); + + // only keep one FontCache with a fixed pixel size for each distinct font type + QRawFont actualFont = font; + actualFont.setPixelSize(QT_DISTANCEFIELD_BASEFONTSIZE(useDoubleRes) * QT_DISTANCEFIELD_SCALE(useDoubleRes)); + + // create new font cache + DistanceFieldFont *dff = new DistanceFieldFont(actualFont, useDoubleRes, q_func()); + m_fonts.insert(key, dff); + return dff; +} + +QDistanceFieldGlyphCache::QDistanceFieldGlyphCache(QNode *parent) + : QNode(*new QDistanceFieldGlyphCachePrivate(), parent) +{ +} + +QDistanceFieldGlyphCache::~QDistanceFieldGlyphCache() +{ +} + +bool QDistanceFieldGlyphCache::doubleGlyphResolution(const QRawFont &font) +{ + Q_D(QDistanceFieldGlyphCache); + return d->getOrCreateDistanceFieldFont(font)->doubleGlyphResolution(); +} + +namespace { +QDistanceFieldGlyphCache::Glyph refAndGetGlyph(DistanceFieldFont *dff, quint32 glyph) +{ + QDistanceFieldGlyphCache::Glyph ret; + + if (dff) { + const auto entry = dff->refGlyph(glyph); + + if (entry.atlas()) { + ret.glyphPathBoundingRect = entry.glyphPathBoundingRect(); + ret.texCoords = entry.texCoords(); + ret.texture = entry.atlas(); + } + } + + return ret; +} +} + +QVector QDistanceFieldGlyphCache::refGlyphs(const QGlyphRun &run) +{ + Q_D(QDistanceFieldGlyphCache); + + DistanceFieldFont *dff = d->getOrCreateDistanceFieldFont(run.rawFont()); + QVector ret; + + const QVector glyphs = run.glyphIndexes(); + for (quint32 glyph : glyphs) + ret << refAndGetGlyph(dff, glyph); + + return ret; +} + +QDistanceFieldGlyphCache::Glyph QDistanceFieldGlyphCache::refGlyph(const QRawFont &font, quint32 glyph) +{ + Q_D(QDistanceFieldGlyphCache); + return refAndGetGlyph(d->getOrCreateDistanceFieldFont(font), glyph); +} + +void QDistanceFieldGlyphCache::derefGlyphs(const QGlyphRun &run) +{ + Q_D(QDistanceFieldGlyphCache); + + DistanceFieldFont *dff = d->getOrCreateDistanceFieldFont(run.rawFont()); + + const QVector glyphs = run.glyphIndexes(); + for (quint32 glyph : glyphs) + dff->derefGlyph(glyph); +} + +void QDistanceFieldGlyphCache::derefGlyph(const QRawFont &font, quint32 glyph) +{ + Q_D(QDistanceFieldGlyphCache); + d->getOrCreateDistanceFieldFont(font)->derefGlyph(glyph); +} + +} // namespace Qt3DExtras + +QT_END_NAMESPACE diff --git a/src/extras/text/qdistancefieldglyphcache.h b/src/extras/text/qdistancefieldglyphcache.h new file mode 100644 index 000000000..b02625b47 --- /dev/null +++ b/src/extras/text/qdistancefieldglyphcache.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3DEXTRAS_QDISTANCEFIELDGLYPHCACHE_H +#define QT3DEXTRAS_QDISTANCEFIELDGLYPHCACHE_H + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QRawFont; +class QGlyphRun; + +namespace Qt3DRender { +class QAbstractTexture; +} + +namespace Qt3DExtras { + +class QDistanceFieldGlyphCachePrivate; + +class QT3DEXTRASSHARED_EXPORT QDistanceFieldGlyphCache : public Qt3DCore::QNode +{ + Q_OBJECT + +public: + QDistanceFieldGlyphCache(Qt3DCore::QNode *parent = nullptr); + ~QDistanceFieldGlyphCache(); + + struct Glyph { + Qt3DRender::QAbstractTexture *texture = nullptr; + QRectF glyphPathBoundingRect; // bounding rect of the QPainterPath used to draw the glyph + QRectF texCoords; // texture coordinates within texture + }; + + bool doubleGlyphResolution(const QRawFont &font); + + QVector refGlyphs(const QGlyphRun &run); + Glyph refGlyph(const QRawFont &font, quint32 glyph); + + void derefGlyphs(const QGlyphRun &run); + void derefGlyph(const QRawFont &font, quint32 glyph); + +private: + Q_DECLARE_PRIVATE(QDistanceFieldGlyphCache) +}; + +} // namespace Qt3DExtras + +QT_END_NAMESPACE + +#endif // QT3DEXTRAS_QDISTANCEFIELDGLYPHCACHE_H diff --git a/src/extras/text/qdistancefieldglyphcache_p.h b/src/extras/text/qdistancefieldglyphcache_p.h new file mode 100644 index 000000000..90164cd39 --- /dev/null +++ b/src/extras/text/qdistancefieldglyphcache_p.h @@ -0,0 +1,136 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3DEXTRAS_QDISTANCEFIELDGLYPHCACHE_P_H +#define QT3DEXTRAS_QDISTANCEFIELDGLYPHCACHE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DExtras { + +// ref-count glyphs and keep track of where they are stored +class StoredGlyph { +public: + StoredGlyph() = default; + StoredGlyph(const StoredGlyph &other) = default; + StoredGlyph(const QRawFont &font, quint32 glyph, bool doubleResolution); + + int refCount() const { return m_ref; } + void ref() { ++m_ref; } + int deref() { return m_ref = std::max(m_ref - 1, (quint32) 0); } + + bool addToTextureAtlas(QTextureAtlas *atlas); + void removeFromTextureAtlas(); + + QTextureAtlas *atlas() const { return m_atlas; } + QRectF glyphPathBoundingRect() const { return m_glyphPathBoundingRect; } + QRectF texCoords() const; + +private: + quint32 m_glyph = (quint32) -1; + quint32 m_ref = 0; + QTextureAtlas *m_atlas = nullptr; + QTextureAtlas::TextureId m_atlasEntry = QTextureAtlas::InvalidTexture; + QRectF m_glyphPathBoundingRect; + QImage m_distanceFieldImage; // only used until added to texture atlas +}; + +// A DistanceFieldFont stores all glyphs for a given QRawFont. +// it will use multiple QTextureAtlasess to store the distance +// fields and uses ref-counting for each glyph to ensure that +// unused glyphs are removed from the texture atlasses. +class DistanceFieldFont +{ +public: + DistanceFieldFont(const QRawFont &font, bool doubleRes, Qt3DCore::QNode *parent); + ~DistanceFieldFont(); + + StoredGlyph findGlyph(quint32 glyph) const; + StoredGlyph refGlyph(quint32 glyph); + void derefGlyph(quint32 glyph); + + bool doubleGlyphResolution() const { return m_doubleGlyphResolution; } + +private: + QRawFont m_font; + bool m_doubleGlyphResolution; + Qt3DCore::QNode *m_parentNode; // parent node for the QTextureAtlasses + + QHash m_glyphs; + + QVector m_atlasses; +}; + +class QDistanceFieldGlyphCachePrivate : public Qt3DCore::QNodePrivate +{ +public: + Q_DECLARE_PUBLIC(QDistanceFieldGlyphCache) + + DistanceFieldFont* getOrCreateDistanceFieldFont(const QRawFont &font); + +private: + static QString fontKey(const QRawFont &font); + + QHash m_fonts; +}; + +} // namespace Qt3DExtras + +QT_END_NAMESPACE + +#endif // QT3DEXTRAS_QDISTANCEFIELDGLYPHCACHE_P_H diff --git a/src/extras/text/text.pri b/src/extras/text/text.pri index 9ba6830e9..3cb6c5627 100644 --- a/src/extras/text/text.pri +++ b/src/extras/text/text.pri @@ -1,10 +1,13 @@ HEADERS += \ $$PWD/qtextureatlas.h \ $$PWD/qtextureatlas_p.h \ + $$PWD/qdistancefieldglyphcache.h \ + $$PWD/qdistancefieldglyphcache_p.h \ $$PWD/areaallocator_p.h SOURCES += \ $$PWD/qtextureatlas.cpp \ + $$PWD/qdistancefieldglyphcache.cpp \ $$PWD/areaallocator.cpp INCLUDEPATH += $$PWD -- cgit v1.2.3 From 18ad771187f3d9a7d14d1a98d71ce64ed8ff15d4 Mon Sep 17 00:00:00 2001 From: Wieland Hagen Date: Wed, 28 Dec 2016 13:25:38 +0700 Subject: QDistanceFieldMaterial: distance field text rendering shaders One QDistanceFieldMaterial will have to be created for each distinct texture atlas that is used to store the glyphs of fonts. The smaller the glyphs are in pixel space (i.e. the more texels per pixel), the smoother we render the threshold between inside-glyph and outside-glyph. We measure the size of the glyph by taking the per-fragment delta of the texture coordinates. This is to reduce aiasing as much as possible without resorting to screen-space AA techniques. The same method is used in the QtQuick renderer, but here in this case we allow a much smoother threshold for small glyphs. Change-Id: I6632e7e1da31126c84f5bd2b4a4498377bdad79e Reviewed-by: Sean Harmer --- src/extras/extras.qrc | 4 + src/extras/shaders/es2/distancefieldtext.frag | 36 ++++++ src/extras/shaders/es2/distancefieldtext.vert | 17 +++ src/extras/shaders/gl3/distancefieldtext.frag | 38 ++++++ src/extras/shaders/gl3/distancefieldtext.vert | 19 +++ src/extras/text/qdistancefieldmaterial.cpp | 179 ++++++++++++++++++++++++++ src/extras/text/qdistancefieldmaterial.h | 72 +++++++++++ src/extras/text/qdistancefieldmaterial_p.h | 106 +++++++++++++++ src/extras/text/text.pri | 3 + 9 files changed, 474 insertions(+) create mode 100644 src/extras/shaders/es2/distancefieldtext.frag create mode 100644 src/extras/shaders/es2/distancefieldtext.vert create mode 100644 src/extras/shaders/gl3/distancefieldtext.frag create mode 100644 src/extras/shaders/gl3/distancefieldtext.vert create mode 100644 src/extras/text/qdistancefieldmaterial.cpp create mode 100644 src/extras/text/qdistancefieldmaterial.h create mode 100644 src/extras/text/qdistancefieldmaterial_p.h diff --git a/src/extras/extras.qrc b/src/extras/extras.qrc index 1319b10a5..04437d599 100644 --- a/src/extras/extras.qrc +++ b/src/extras/extras.qrc @@ -41,5 +41,9 @@ shaders/es2/unlittexture.vert shaders/gl3/metalrough.vert shaders/gl3/metalrough.frag + shaders/gl3/distancefieldtext.vert + shaders/gl3/distancefieldtext.frag + shaders/es2/distancefieldtext.frag + shaders/es2/distancefieldtext.vert diff --git a/src/extras/shaders/es2/distancefieldtext.frag b/src/extras/shaders/es2/distancefieldtext.frag new file mode 100644 index 000000000..88ead1f68 --- /dev/null +++ b/src/extras/shaders/es2/distancefieldtext.frag @@ -0,0 +1,36 @@ +#define FP highp + +uniform FP sampler2D distanceFieldTexture; +uniform FP float minAlpha; +uniform FP float maxAlpha; +uniform FP float textureSize; +uniform FP vec4 color; + +varying FP vec3 position; +varying FP vec2 texCoord; + +void main() +{ + // determine the scale of the glyph texture within pixel-space coordinates + // (that is, how many pixels are drawn for each texel) + FP vec2 texelDeltaX = abs(dFdx(texCoord)); + FP vec2 texelDeltaY = abs(dFdy(texCoord)); + FP float avgTexelDelta = textureSize * 0.5 * (texelDeltaX.x + texelDeltaX.y + texelDeltaY.x + texelDeltaY.y); + FP float texScale = 1.0 / avgTexelDelta; + + // scaled to interval [0.0, 0.15] + FP float devScaleMin = 0.00; + FP float devScaleMax = 0.15; + FP float scaled = (clamp(texScale, devScaleMin, devScaleMax) - devScaleMin) / (devScaleMax - devScaleMin); + + // thickness of glyphs should increase a lot for very small glyphs to make them readable + FP float base = 0.5; + FP float threshold = base * scaled; + FP float range = 0.06 / texScale; + + FP float minAlpha = threshold - range; + FP float maxAlpha = threshold + range; + + FP float distVal = texture2D(distanceFieldTexture, texCoord).r; + gl_FragColor = color * smoothstep(minAlpha, maxAlpha, distVal); +} diff --git a/src/extras/shaders/es2/distancefieldtext.vert b/src/extras/shaders/es2/distancefieldtext.vert new file mode 100644 index 000000000..f7fc5327b --- /dev/null +++ b/src/extras/shaders/es2/distancefieldtext.vert @@ -0,0 +1,17 @@ +attribute vec3 vertexPosition; +attribute vec2 vertexTexCoord; + +varying vec3 position; +varying vec2 texCoord; + +uniform mat4 modelView; +uniform mat4 mvp; + +void main() +{ + texCoord = vertexTexCoord; + position = vec3(modelView * vec4(vertexPosition, 1.0)); + + gl_Position = mvp * vec4(vertexPosition, 1.0); +} + diff --git a/src/extras/shaders/gl3/distancefieldtext.frag b/src/extras/shaders/gl3/distancefieldtext.frag new file mode 100644 index 000000000..4f0c9cac0 --- /dev/null +++ b/src/extras/shaders/gl3/distancefieldtext.frag @@ -0,0 +1,38 @@ +#version 150 core + +uniform sampler2D distanceFieldTexture; +uniform float minAlpha; +uniform float maxAlpha; +uniform float textureSize; +uniform vec4 color; + +in vec3 position; +in vec2 texCoord; + +out vec4 fragColor; + +void main() +{ + // determine the scale of the glyph texture within pixel-space coordinates + // (that is, how many pixels are drawn for each texel) + vec2 texelDeltaX = abs(dFdx(texCoord)); + vec2 texelDeltaY = abs(dFdy(texCoord)); + float avgTexelDelta = textureSize * 0.5 * (texelDeltaX.x + texelDeltaX.y + texelDeltaY.x + texelDeltaY.y); + float texScale = 1.0 / avgTexelDelta; + + // scaled to interval [0.0, 0.15] + float devScaleMin = 0.00; + float devScaleMax = 0.15; + float scaled = (clamp(texScale, devScaleMin, devScaleMax) - devScaleMin) / (devScaleMax - devScaleMin); + + // thickness of glyphs should increase a lot for very small glyphs to make them readable + float base = 0.5; + float threshold = base * scaled; + float range = 0.06 / texScale; + + float minAlpha = threshold - range; + float maxAlpha = threshold + range; + + float distVal = texture(distanceFieldTexture, texCoord).r; + fragColor = color * smoothstep(minAlpha, maxAlpha, distVal); +} diff --git a/src/extras/shaders/gl3/distancefieldtext.vert b/src/extras/shaders/gl3/distancefieldtext.vert new file mode 100644 index 000000000..9bd2a0a90 --- /dev/null +++ b/src/extras/shaders/gl3/distancefieldtext.vert @@ -0,0 +1,19 @@ +#version 150 core + +in vec3 vertexPosition; +in vec2 vertexTexCoord; + +out vec3 position; +out vec2 texCoord; + +uniform mat4 modelView; +uniform mat4 mvp; + +void main() +{ + texCoord = vertexTexCoord; + position = vec3(modelView * vec4(vertexPosition, 1.0)); + + gl_Position = mvp * vec4(vertexPosition, 1.0); +} + diff --git a/src/extras/text/qdistancefieldmaterial.cpp b/src/extras/text/qdistancefieldmaterial.cpp new file mode 100644 index 000000000..d1c4a493c --- /dev/null +++ b/src/extras/text/qdistancefieldmaterial.cpp @@ -0,0 +1,179 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdistancefieldmaterial.h" +#include "qdistancefieldmaterial_p.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DExtras { + +QDistanceFieldMaterialPrivate::QDistanceFieldMaterialPrivate() + : QMaterialPrivate() + , m_effect(new Qt3DRender::QEffect()) + , m_distanceFieldTexture(nullptr) + , m_textureParameter(new Qt3DRender::QParameter(QStringLiteral("distanceFieldTexture"), QVariant(0))) + , m_textureSizeParameter(new Qt3DRender::QParameter(QStringLiteral("textureSize"), QVariant(256.f))) + , m_colorParameter(new Qt3DRender::QParameter(QStringLiteral("color"), QVariant(QColor(255, 255, 255, 255)))) + , m_gl3Technique(new Qt3DRender::QTechnique()) + , m_gl2Technique(new Qt3DRender::QTechnique()) + , m_es2Technique(new Qt3DRender::QTechnique()) + , m_gl3RenderPass(new Qt3DRender::QRenderPass()) + , m_gl2RenderPass(new Qt3DRender::QRenderPass()) + , m_es2RenderPass(new Qt3DRender::QRenderPass()) + , m_gl3ShaderProgram(new Qt3DRender::QShaderProgram()) + , m_gl2es2ShaderProgram(new Qt3DRender::QShaderProgram()) + , m_blend(new Qt3DRender::QBlendEquation()) + , m_blendArgs(new Qt3DRender::QBlendEquationArguments()) + , m_depthTest(new Qt3DRender::QDepthTest()) +{ +} + +void QDistanceFieldMaterialPrivate::init() +{ + m_gl3ShaderProgram->setVertexShaderCode(Qt3DRender::QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/gl3/distancefieldtext.vert")))); + m_gl3ShaderProgram->setFragmentShaderCode(Qt3DRender::QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/gl3/distancefieldtext.frag")))); + + m_gl2es2ShaderProgram->setVertexShaderCode(Qt3DRender::QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/es2/distancefieldtext.vert")))); + m_gl2es2ShaderProgram->setFragmentShaderCode(Qt3DRender::QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/es2/distancefieldtext.frag")))); + + m_blend->setBlendFunction(Qt3DRender::QBlendEquation::Add); + m_blendArgs->setSourceRgba(Qt3DRender::QBlendEquationArguments::SourceAlpha); + m_blendArgs->setDestinationRgba(Qt3DRender::QBlendEquationArguments::OneMinusSourceAlpha); + m_depthTest->setDepthFunction(Qt3DRender::QDepthTest::LessOrEqual); + + m_gl3RenderPass->setShaderProgram(m_gl3ShaderProgram); + m_gl3RenderPass->addRenderState(m_blend); + m_gl3RenderPass->addRenderState(m_blendArgs); + m_gl3RenderPass->addRenderState(m_depthTest); + + m_gl2RenderPass->setShaderProgram(m_gl2es2ShaderProgram); + m_gl2RenderPass->addRenderState(m_blend); + m_gl2RenderPass->addRenderState(m_blendArgs); + m_gl2RenderPass->addRenderState(m_depthTest); + + m_es2RenderPass->setShaderProgram(m_gl2es2ShaderProgram); + m_es2RenderPass->addRenderState(m_blend); + m_es2RenderPass->addRenderState(m_blendArgs); + m_es2RenderPass->addRenderState(m_depthTest); + + m_gl3Technique->graphicsApiFilter()->setApi(Qt3DRender::QGraphicsApiFilter::OpenGL); + m_gl3Technique->graphicsApiFilter()->setMajorVersion(3); + m_gl3Technique->graphicsApiFilter()->setMinorVersion(1); + m_gl3Technique->graphicsApiFilter()->setProfile(Qt3DRender::QGraphicsApiFilter::CoreProfile); + m_gl3Technique->addRenderPass(m_gl3RenderPass); + + m_gl2Technique->graphicsApiFilter()->setApi(Qt3DRender::QGraphicsApiFilter::OpenGL); + m_gl2Technique->graphicsApiFilter()->setMajorVersion(2); + m_gl2Technique->graphicsApiFilter()->setMinorVersion(0); + m_gl2Technique->graphicsApiFilter()->setProfile(Qt3DRender::QGraphicsApiFilter::NoProfile); + m_gl2Technique->addRenderPass(m_gl2RenderPass); + + m_es2Technique->graphicsApiFilter()->setApi(Qt3DRender::QGraphicsApiFilter::OpenGLES); + m_es2Technique->graphicsApiFilter()->setMajorVersion(2); + m_es2Technique->graphicsApiFilter()->setMinorVersion(0); + m_es2Technique->graphicsApiFilter()->setProfile(Qt3DRender::QGraphicsApiFilter::NoProfile); + m_es2Technique->addRenderPass(m_es2RenderPass); + + Qt3DRender::QFilterKey *filterKey = new Qt3DRender::QFilterKey(q_func()); + filterKey->setName(QStringLiteral("renderingStyle")); + filterKey->setValue(QStringLiteral("forward")); + m_gl3Technique->addFilterKey(filterKey); + m_gl2Technique->addFilterKey(filterKey); + m_es2Technique->addFilterKey(filterKey); + + m_effect->addTechnique(m_gl3Technique); + m_effect->addTechnique(m_gl2Technique); + m_effect->addTechnique(m_es2Technique); + m_effect->addParameter(m_textureParameter); + m_effect->addParameter(m_textureSizeParameter); + m_effect->addParameter(m_colorParameter); + + q_func()->setEffect(m_effect); +} + +QDistanceFieldMaterial::QDistanceFieldMaterial(Qt3DCore::QNode *parent) + : QMaterial(*new QDistanceFieldMaterialPrivate(), parent) +{ + Q_D(QDistanceFieldMaterial); + d->init(); +} + +QDistanceFieldMaterial::~QDistanceFieldMaterial() +{ +} + +void QDistanceFieldMaterial::setColor(const QColor &color) +{ + Q_D(QDistanceFieldMaterial); + d->m_colorParameter->setValue(QVariant::fromValue(color)); +} + +void QDistanceFieldMaterial::setDistanceFieldTexture(Qt3DRender::QAbstractTexture *tex) +{ + Q_D(QDistanceFieldMaterial); + d->m_distanceFieldTexture = tex; + + if (tex) { + d->m_textureParameter->setValue(QVariant::fromValue(tex)); + d->m_textureSizeParameter->setValue(QVariant::fromValue(static_cast(tex->width()))); + } else { + d->m_textureParameter->setValue(0); + d->m_textureSizeParameter->setValue(QVariant::fromValue(1.f)); + } +} + +} // namespace Qt3DExtras + +QT_END_NAMESPACE diff --git a/src/extras/text/qdistancefieldmaterial.h b/src/extras/text/qdistancefieldmaterial.h new file mode 100644 index 000000000..ebecbbcf2 --- /dev/null +++ b/src/extras/text/qdistancefieldmaterial.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3DEXTRAS_QDISTANCEFIELDMATERIAL_H +#define QT3DEXTRAS_QDISTANCEFIELDMATERIAL_H + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DExtras { + +class QDistanceFieldMaterialPrivate; + +class QDistanceFieldMaterial : public Qt3DRender::QMaterial +{ + Q_OBJECT + +public: + explicit QDistanceFieldMaterial(Qt3DCore::QNode *parent = nullptr); + ~QDistanceFieldMaterial(); + + void setColor(const QColor &color); + void setDistanceFieldTexture(Qt3DRender::QAbstractTexture *tex); + +private: + Q_DECLARE_PRIVATE(QDistanceFieldMaterial) +}; + +} // namespace Qt3DExtras + +QT_END_NAMESPACE + +#endif // QT3DEXTRAS_QDISTANCEFIELDMATERIAL_H diff --git a/src/extras/text/qdistancefieldmaterial_p.h b/src/extras/text/qdistancefieldmaterial_p.h new file mode 100644 index 000000000..00e3ac93a --- /dev/null +++ b/src/extras/text/qdistancefieldmaterial_p.h @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3DEXTRAS_QDISTANCEFIELDMATERIAL_P_H +#define QT3DEXTRAS_QDISTANCEFIELDMATERIAL_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { +class QAbstractTexture; +class QEffect; +class QTechnique; +class QParameter; +class QRenderPass; +class QShaderProgram; +class QBlendEquation; +class QBlendEquationArguments; +class QDepthTest; + +} // namespace Qt3DRender + +namespace Qt3DExtras { + +class QDistanceFieldMaterial; + +class QDistanceFieldMaterialPrivate : public Qt3DRender::QMaterialPrivate +{ +public: + QDistanceFieldMaterialPrivate(); + + Qt3DRender::QEffect *m_effect; + Qt3DRender::QAbstractTexture *m_distanceFieldTexture; + Qt3DRender::QParameter *m_textureParameter; + Qt3DRender::QParameter *m_textureSizeParameter; + Qt3DRender::QParameter *m_colorParameter; + Qt3DRender::QTechnique *m_gl3Technique; + Qt3DRender::QTechnique *m_gl2Technique; + Qt3DRender::QTechnique *m_es2Technique; + Qt3DRender::QRenderPass *m_gl3RenderPass; + Qt3DRender::QRenderPass *m_gl2RenderPass; + Qt3DRender::QRenderPass *m_es2RenderPass; + Qt3DRender::QShaderProgram *m_gl3ShaderProgram; + Qt3DRender::QShaderProgram *m_gl2es2ShaderProgram; + Qt3DRender::QBlendEquation *m_blend; + Qt3DRender::QBlendEquationArguments *m_blendArgs; + Qt3DRender::QDepthTest *m_depthTest; + + void init(); + + Q_DECLARE_PUBLIC(QDistanceFieldMaterial) +}; + +} // Qt3DExtras + +QT_END_NAMESPACE + +#endif // QT3DEXTRAS_QDISTANCEFIELDMATERIAL_P_H diff --git a/src/extras/text/text.pri b/src/extras/text/text.pri index 3cb6c5627..dd2eb0992 100644 --- a/src/extras/text/text.pri +++ b/src/extras/text/text.pri @@ -3,11 +3,14 @@ HEADERS += \ $$PWD/qtextureatlas_p.h \ $$PWD/qdistancefieldglyphcache.h \ $$PWD/qdistancefieldglyphcache_p.h \ + $$PWD/qdistancefieldmaterial.h \ + $$PWD/qdistancefieldmaterial_p.h \ $$PWD/areaallocator_p.h SOURCES += \ $$PWD/qtextureatlas.cpp \ $$PWD/qdistancefieldglyphcache.cpp \ + $$PWD/qdistancefieldmaterial.cpp \ $$PWD/areaallocator.cpp INCLUDEPATH += $$PWD -- cgit v1.2.3 From 5cb4d3951662369bb20e2890ac901070af8ce480 Mon Sep 17 00:00:00 2001 From: Wieland Hagen Date: Wed, 28 Dec 2016 13:26:34 +0700 Subject: QDistanceFieldText: QEntity that renders text A QDistanceFieldText has a text position (within the x/y-plane), a color, a text (QString), a QFont, and a QDistanceGlyphCache that is used to retrieve the glyph textures needed for rendering. To render a given string, we use a QTextLayout to generate GlyphRuns, which are associated with a given QRawFont. Now the following may happen: 1. there may be multiple QRawFonts generated by the QTextLayout. this is because some glyphs may not be available in one font, so another font has to be used for these glyphs. 2. for the same QRawFont, multiple QTextureAtlasses may be needed for all glyphs. This is because the the QDistanceFieldGlyphCache grows lazily by allocating more QTextureAtlasses on demand. So, for any given QDistanceFieldText, we might need to use multiple textures for rendering. Because of this, we might need to create multiple QEntities, each with a separate QDistanceFieldMaterial. These QEntities are the DistanceFieldTextRenderers, which encapsulate all QComponents needed to render the glyphs taken from one texture. When something changes, QDistanceFieldText::update() uses a QTextLayout to generate a number of QGlyphRuns, each associated with a QRawFont. These QGlyphRuns are then given to QDistanceFieldTextPrivate::setCurrentGlyphRuns(). There, for each distinct texture, all glyph positions are gathered, and according vertex and index buffers are built. These index buffers are then given to the DistanceFieldTextRenderer nodes. We make sure to properly ref-count the glyphs within the QDistanceFieldGlyphCache. Change-Id: Icf332b87541a6426abd4fbb12e2968a6d8ec5c4c Reviewed-by: Sean Harmer --- src/extras/text/distancefieldtextrenderer.cpp | 156 ++++++++++ src/extras/text/distancefieldtextrenderer_p.h | 90 ++++++ src/extras/text/distancefieldtextrenderer_p_p.h | 96 +++++++ src/extras/text/qdistancefieldtext.cpp | 362 ++++++++++++++++++++++++ src/extras/text/qdistancefieldtext.h | 104 +++++++ src/extras/text/qdistancefieldtext_p.h | 109 +++++++ src/extras/text/text.pri | 6 + 7 files changed, 923 insertions(+) create mode 100644 src/extras/text/distancefieldtextrenderer.cpp create mode 100644 src/extras/text/distancefieldtextrenderer_p.h create mode 100644 src/extras/text/distancefieldtextrenderer_p_p.h create mode 100644 src/extras/text/qdistancefieldtext.cpp create mode 100644 src/extras/text/qdistancefieldtext.h create mode 100644 src/extras/text/qdistancefieldtext_p.h diff --git a/src/extras/text/distancefieldtextrenderer.cpp b/src/extras/text/distancefieldtextrenderer.cpp new file mode 100644 index 000000000..76d9cf50e --- /dev/null +++ b/src/extras/text/distancefieldtextrenderer.cpp @@ -0,0 +1,156 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include +#include + +#include + +#include "distancefieldtextrenderer_p.h" +#include "distancefieldtextrenderer_p_p.h" + +QT_BEGIN_NAMESPACE + +namespace Qt3DExtras { + +using namespace Qt3DCore; + +DistanceFieldTextRendererPrivate::DistanceFieldTextRendererPrivate() + : m_renderer(nullptr) + , m_geometry(nullptr) + , m_positionAttr(nullptr) + , m_texCoordAttr(nullptr) + , m_indexAttr(nullptr) + , m_vertexBuffer(nullptr) + , m_indexBuffer(nullptr) + , m_material(nullptr) +{ +} + +DistanceFieldTextRendererPrivate::~DistanceFieldTextRendererPrivate() +{ +} + +void DistanceFieldTextRendererPrivate::init() +{ + Q_Q(DistanceFieldTextRenderer); + + m_renderer = new Qt3DRender::QGeometryRenderer(q); + m_renderer->setPrimitiveType(Qt3DRender::QGeometryRenderer::Triangles); + + m_geometry = new Qt3DRender::QGeometry(m_renderer); + m_renderer->setGeometry(m_geometry); + + m_vertexBuffer = new Qt3DRender::QBuffer(Qt3DRender::QBuffer::VertexBuffer, m_geometry); + m_indexBuffer = new Qt3DRender::QBuffer(Qt3DRender::QBuffer::IndexBuffer, m_geometry); + + m_positionAttr = new Qt3DRender::QAttribute(m_geometry); + m_positionAttr->setName(Qt3DRender::QAttribute::defaultPositionAttributeName()); + m_positionAttr->setVertexBaseType(Qt3DRender::QAttribute::Float); + m_positionAttr->setAttributeType(Qt3DRender::QAttribute::VertexAttribute); + m_positionAttr->setVertexSize(3); + m_positionAttr->setByteStride(5 * sizeof(float)); + m_positionAttr->setByteOffset(0); + m_positionAttr->setBuffer(m_vertexBuffer); + + m_texCoordAttr = new Qt3DRender::QAttribute(m_geometry); + m_texCoordAttr->setName(Qt3DRender::QAttribute::defaultTextureCoordinateAttributeName()); + m_texCoordAttr->setVertexBaseType(Qt3DRender::QAttribute::Float); + m_texCoordAttr->setAttributeType(Qt3DRender::QAttribute::VertexAttribute); + m_texCoordAttr->setVertexSize(2); + m_texCoordAttr->setByteStride(5 * sizeof(float)); + m_texCoordAttr->setByteOffset(3 * sizeof(float)); + m_texCoordAttr->setBuffer(m_vertexBuffer); + + m_indexAttr = new Qt3DRender::QAttribute(m_geometry); + m_indexAttr->setAttributeType(Qt3DRender::QAttribute::IndexAttribute); + m_indexAttr->setVertexBaseType(Qt3DRender::QAttribute::UnsignedShort); + m_indexAttr->setBuffer(m_indexBuffer); + + m_geometry->addAttribute(m_positionAttr); + m_geometry->setBoundingVolumePositionAttribute(m_positionAttr); + m_geometry->addAttribute(m_texCoordAttr); + m_geometry->addAttribute(m_indexAttr); + + m_material = new QDistanceFieldMaterial(q); + + q->addComponent(m_renderer); + q->addComponent(m_material); +} + +DistanceFieldTextRenderer::DistanceFieldTextRenderer(QNode *parent) + : QEntity(*new DistanceFieldTextRendererPrivate(), parent) +{ + Q_D(DistanceFieldTextRenderer); + d->init(); +} + +DistanceFieldTextRenderer::~DistanceFieldTextRenderer() +{ +} + +void DistanceFieldTextRenderer::setGlyphData(Qt3DRender::QAbstractTexture *glyphTexture, + const QVector &vertexData, + const QVector &indexData) +{ + Q_D(DistanceFieldTextRenderer); + + const int vertexCount = vertexData.size() / 5; + + d->m_vertexBuffer->setData(QByteArray((char*) vertexData.data(), vertexData.size() * sizeof(float))); + d->m_indexBuffer->setData(QByteArray((char*) indexData.data(), indexData.size() * sizeof(quint16))); + d->m_positionAttr->setCount(vertexCount); + d->m_texCoordAttr->setCount(vertexCount); + d->m_indexAttr->setCount(indexData.size()); + + d->m_material->setDistanceFieldTexture(glyphTexture); +} + +void DistanceFieldTextRenderer::setColor(const QColor &color) +{ + Q_D(DistanceFieldTextRenderer); + d->m_material->setColor(color); +} + +} // namespace Qt3DExtras + +QT_END_NAMESPACE diff --git a/src/extras/text/distancefieldtextrenderer_p.h b/src/extras/text/distancefieldtextrenderer_p.h new file mode 100644 index 000000000..fdb9a836f --- /dev/null +++ b/src/extras/text/distancefieldtextrenderer_p.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3DEXTRAS_DISTANCEFIELDTEXTRENDERER_P_H +#define QT3DEXTRAS_DISTANCEFIELDTEXTRENDERER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { +class QAbstractTexture; +} + +namespace Qt3DExtras { + +class DistanceFieldTextRendererPrivate; + +class DistanceFieldTextRenderer : public Qt3DCore::QEntity +{ + Q_OBJECT + +public: + DistanceFieldTextRenderer(Qt3DCore::QNode *parent = nullptr); + ~DistanceFieldTextRenderer(); + + void setGlyphData(Qt3DRender::QAbstractTexture *glyphTexture, + const QVector &vertexData, + const QVector &indexData); + + void setColor(const QColor &color); + + Q_DECLARE_PRIVATE(DistanceFieldTextRenderer) +}; + +} // namespace Qt3DExtras + +QT_END_NAMESPACE + +#endif // QT3DEXTRAS_DISTANCEFIELDTEXTRENDERER_P_H diff --git a/src/extras/text/distancefieldtextrenderer_p_p.h b/src/extras/text/distancefieldtextrenderer_p_p.h new file mode 100644 index 000000000..fd2e76167 --- /dev/null +++ b/src/extras/text/distancefieldtextrenderer_p_p.h @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3DEXTRAS_DISTANCEFIELDTEXTRENDERER_P_P_H +#define QT3DEXTRAS_DISTANCEFIELDTEXTRENDERER_P_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { +class QGeometryRenderer; +class QGeometry; +class QMaterial; +class QAttribute; +class QBuffer; +} + +namespace Qt3DExtras { + +class QDistanceFieldMaterial; + +class DistanceFieldTextRendererPrivate : public Qt3DCore::QEntityPrivate +{ +public: + DistanceFieldTextRendererPrivate(); + ~DistanceFieldTextRendererPrivate(); + + Q_DECLARE_PUBLIC(DistanceFieldTextRenderer) + + void init(); + + Qt3DRender::QGeometryRenderer *m_renderer; + Qt3DRender::QGeometry *m_geometry; + Qt3DRender::QAttribute *m_positionAttr; + Qt3DRender::QAttribute *m_texCoordAttr; + Qt3DRender::QAttribute *m_indexAttr; + Qt3DRender::QBuffer *m_vertexBuffer; + Qt3DRender::QBuffer *m_indexBuffer; + QDistanceFieldMaterial *m_material; +}; + +} // namespace Qt3DExtras + +QT_END_NAMESPACE + +#endif // QT3DEXTRAS_DISTANCEFIELDTEXTRENDERER_P_P_H diff --git a/src/extras/text/qdistancefieldtext.cpp b/src/extras/text/qdistancefieldtext.cpp new file mode 100644 index 000000000..fdd40fc5a --- /dev/null +++ b/src/extras/text/qdistancefieldtext.cpp @@ -0,0 +1,362 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdistancefieldtext.h" +#include "qdistancefieldtext_p.h" +#include "qdistancefieldmaterial.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace { + +inline Q_DECL_CONSTEXPR QRectF scaleRectF(const QRectF &rect, float scale) +{ + return QRectF(rect.left() * scale, rect.top() * scale, rect.width() * scale, rect.height() * scale); +} + +} // anonymous + +namespace Qt3DExtras { + +QDistanceFieldTextPrivate::QDistanceFieldTextPrivate() + : m_font(QLatin1String("Times"), 10) + , m_scaledFont(QLatin1String("Times"), 10) + , m_color(QColor(255, 255, 255, 255)) +{ +} + +QDistanceFieldTextPrivate::~QDistanceFieldTextPrivate() +{ +} + +QDistanceFieldText::QDistanceFieldText(QNode *parent) + : Qt3DCore::QEntity(*new QDistanceFieldTextPrivate(), parent) +{ +} + +QDistanceFieldText::~QDistanceFieldText() +{ +} + +float QDistanceFieldTextPrivate::computeActualScale() const +{ + // scale font based on fontScale property and given QFont + float scale = m_fontScale; + if (m_font.pointSizeF() > 0) + scale *= m_font.pointSizeF() / m_scaledFont.pointSizeF(); + return scale; +} + +struct RenderData { + int vertexCount = 0; + QVector vertex; + QVector index; +}; + +void QDistanceFieldTextPrivate::setCurrentGlyphRuns(const QVector &runs) +{ + Q_ASSERT(m_glyphCache || runs.isEmpty()); + + // For each distinct texture, we need a separate DistanceFieldTextRenderer, + // for which we need vertex and index data + QHash renderData; + + const float scale = computeActualScale(); + + // process glyph runs + for (const QGlyphRun &run : runs) { + const QVector glyphs = run.glyphIndexes(); + const QVector pos = run.positions(); + + Q_ASSERT(glyphs.size() == pos.size()); + + const bool doubleGlyphResolution = m_glyphCache->doubleGlyphResolution(run.rawFont()); + + // faithfully copied from QSGDistanceFieldGlyphNode::updateGeometry() + const float pixelSize = run.rawFont().pixelSize(); + const float fontScale = pixelSize / QT_DISTANCEFIELD_BASEFONTSIZE(doubleGlyphResolution); + const float margin = QT_DISTANCEFIELD_RADIUS(doubleGlyphResolution) / QT_DISTANCEFIELD_SCALE(doubleGlyphResolution) * fontScale; + + for (int i = 0; i < glyphs.size(); i++) { + const QDistanceFieldGlyphCache::Glyph &dfield = m_glyphCache->refGlyph(run.rawFont(), glyphs[i]); + + if (!dfield.texture) + continue; + + RenderData &data = renderData[dfield.texture]; + + // faithfully copied from QSGDistanceFieldGlyphNode::updateGeometry() + QRectF metrics = scaleRectF(dfield.glyphPathBoundingRect, fontScale); + metrics.adjust(-margin, margin, margin, 3*margin); + + float x1 = m_position.left() + scale * (pos[i].x() + metrics.left()); + float y2 = m_position.bottom() - scale * (pos[i].y() - metrics.top()); + float x2 = x1 + scale * metrics.width(); + float y1 = y2 - scale * metrics.height(); + + // only draw glyphs that are at least partly visible + if (y2 < m_position.top() || x1 > m_position.right()) + continue; + + QRectF texCoords = dfield.texCoords; + + // if a glyph is only partly visible within the given rectangle, + // cut it in half and adjust tex coords + if (y1 < m_position.top()) { + const float insideRatio = (m_position.top() - y2) / (y1 - y2); + y1 = m_position.top(); + texCoords.setHeight(texCoords.height() * insideRatio); + } + + // do the same thing horizontally + if (x2 > m_position.right()) { + const float insideRatio = (m_position.right() - x1) / (x2 - x1); + x2 = m_position.right(); + texCoords.setWidth(texCoords.width() * insideRatio); + } + + data.vertex << x1 << y1 << 0.f << texCoords.left() << texCoords.bottom(); + data.vertex << x1 << y2 << 0.f << texCoords.left() << texCoords.top(); + data.vertex << x2 << y1 << 0.f << texCoords.right() << texCoords.bottom(); + data.vertex << x2 << y2 << 0.f << texCoords.right() << texCoords.top(); + + data.index << data.vertexCount << data.vertexCount+3 << data.vertexCount+1; + data.index << data.vertexCount << data.vertexCount+2 << data.vertexCount+3; + + data.vertexCount += 4; + } + } + + // make sure we have the correct number of DistanceFieldTextRenderers + // TODO: we might keep one renderer at all times, so we won't delete and + // re-allocate one every time the text changes from an empty to a non-empty string + // and vice-versa + while (m_renderers.size() > renderData.size()) + delete m_renderers.takeLast(); + + while (m_renderers.size() < renderData.size()) { + DistanceFieldTextRenderer *renderer = new DistanceFieldTextRenderer(q_func()); + renderer->setColor(m_color); + m_renderers << renderer; + } + + Q_ASSERT(m_renderers.size() == renderData.size()); + + // assign vertex data for all textures to the renderers + int rendererIdx = 0; + for (auto it = renderData.begin(); it != renderData.end(); ++it) { + m_renderers[rendererIdx++]->setGlyphData(it.key(), it.value().vertex, it.value().index); + } + + // de-ref all glyphs for previous QGlyphRuns + if (m_glyphCache) { + for (int i = 0; i < m_currentGlyphRuns.size(); i++) + m_glyphCache->derefGlyphs(m_currentGlyphRuns[i]); + } + m_currentGlyphRuns = runs; +} + +void QDistanceFieldTextPrivate::update() +{ + QVector glyphRuns; + + // collect all GlyphRuns generated by the QTextLayout + if (m_glyphCache && !m_position.isEmpty() && !m_text.isEmpty() && m_fontScale > 0.f) { + QTextLayout layout(m_text, m_scaledFont); + const float lineWidth = m_position.width() / computeActualScale(); + float height = 0; + layout.beginLayout(); + + while (true) { + QTextLine line = layout.createLine(); + if (!line.isValid()) + break; + + // position current line + line.setLineWidth(lineWidth); + line.setPosition(QPointF(0, height)); + height += line.height(); + + // add glyph runs created by line + const QList runs = line.glyphRuns(); + for (const QGlyphRun &run : runs) + glyphRuns << run; + } + + layout.endLayout(); + } + + setCurrentGlyphRuns(glyphRuns); +} + +QFont QDistanceFieldText::font() const +{ + Q_D(const QDistanceFieldText); + return d->m_font; +} + +void QDistanceFieldText::setFont(const QFont &font) +{ + Q_D(QDistanceFieldText); + if (d->m_font != font) { + // ignore the point size of the font, just make it a default value. + // still we want to make sure that font() returns the same value + // that was passed to setFont(), so we store it nevertheless + d->m_font = font; + d->m_scaledFont = font; + d->m_scaledFont.setPointSize(10); + + emit fontChanged(font); + + if (!d->m_text.isEmpty() && d->m_glyphCache) + d->update(); + } +} + +QColor QDistanceFieldText::color() const +{ + Q_D(const QDistanceFieldText); + return d->m_color; +} + +void QDistanceFieldText::setColor(const QColor &color) +{ + Q_D(QDistanceFieldText); + if (d->m_color != color) { + d->m_color = color; + + emit colorChanged(color); + + for (DistanceFieldTextRenderer *renderer : qAsConst(d->m_renderers)) + renderer->setColor(color); + } +} + +QString QDistanceFieldText::text() const +{ + Q_D(const QDistanceFieldText); + return d->m_text; +} + +void QDistanceFieldText::setText(const QString &text) +{ + Q_D(QDistanceFieldText); + if (d->m_text != text) { + d->m_text = text; + emit textChanged(text); + + if (d->m_glyphCache) + d->update(); + } +} + +QRectF QDistanceFieldText::position() const +{ + Q_D(const QDistanceFieldText); + return d->m_position; +} + +void QDistanceFieldText::setPosition(const QRectF &pos) +{ + Q_D(QDistanceFieldText); + if (d->m_position != pos) { + d->m_position = pos; + emit positionChanged(pos); + + if (!d->m_text.isEmpty() && d->m_glyphCache) + d->update(); + } +} + +float QDistanceFieldText::fontScale() const +{ + Q_D(const QDistanceFieldText); + return d->m_fontScale; +} + +void QDistanceFieldText::setFontScale(float scale) +{ + Q_D(QDistanceFieldText); + if (d->m_fontScale != scale) { + d->m_fontScale = scale; + emit fontScaleChanged(scale); + + if (!d->m_text.isEmpty() && d->m_glyphCache) + d->update(); + } +} + +QDistanceFieldGlyphCache *QDistanceFieldText::glyphCache() const +{ + Q_D(const QDistanceFieldText); + return d->m_glyphCache; +} + +void QDistanceFieldText::setGlyphCache(QDistanceFieldGlyphCache *glyphCache) +{ + Q_D(QDistanceFieldText); + if (d->m_glyphCache != glyphCache) { + // make sure all glyphs that we still reference in our old glyph cache + // will be de-reffed + d->setCurrentGlyphRuns(QVector()); + + d->m_glyphCache = glyphCache; + emit glyphCacheChanged(glyphCache); + + if (!d->m_text.isEmpty()) + d->update(); + } +} + +} // namespace Qt3DExtras + +QT_END_NAMESPACE diff --git a/src/extras/text/qdistancefieldtext.h b/src/extras/text/qdistancefieldtext.h new file mode 100644 index 000000000..2eaafda63 --- /dev/null +++ b/src/extras/text/qdistancefieldtext.h @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3DEXTRAS_QDISTANCEFIELDTEXT_H +#define QT3DEXTRAS_QDISTANCEFIELDTEXT_H + +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DExtras { + +class QDistanceFieldGlyphCache; +class QDistanceFieldTextPrivate; + +class QT3DEXTRASSHARED_EXPORT QDistanceFieldText : public Qt3DCore::QEntity +{ + Q_OBJECT + Q_PROPERTY(QFont font READ font WRITE setFont NOTIFY fontChanged) + Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged) + Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged) + Q_PROPERTY(QRectF position READ position WRITE setPosition NOTIFY positionChanged) + Q_PROPERTY(float fontScale READ fontScale WRITE setFontScale NOTIFY fontScaleChanged) + Q_PROPERTY(Qt3DExtras::QDistanceFieldGlyphCache* glyphCache READ glyphCache WRITE setGlyphCache NOTIFY glyphCacheChanged) + +public: + explicit QDistanceFieldText(Qt3DCore::QNode *parent = nullptr); + ~QDistanceFieldText(); + + QFont font() const; + void setFont(const QFont &font); + + QColor color() const; + void setColor(const QColor &color); + + QString text() const; + void setText(const QString &text); + + QRectF position() const; + void setPosition(const QRectF &position); + + float fontScale() const; + void setFontScale(float scale); + + QDistanceFieldGlyphCache *glyphCache() const; + void setGlyphCache(QDistanceFieldGlyphCache *glyphCache); + +Q_SIGNALS: + void fontChanged(const QFont &font); + void colorChanged(const QColor &color); + void textChanged(const QString &text); + void positionChanged(const QRectF &position); + void fontScaleChanged(float scale); + void glyphCacheChanged(QDistanceFieldGlyphCache *glyphCache); + +private: + Q_DECLARE_PRIVATE(QDistanceFieldText) +}; + +} // namespace Qt3DExtras + +QT_END_NAMESPACE + +#endif // QT3DEXTRAS_QDISTANCEFIELDTEXT_H diff --git a/src/extras/text/qdistancefieldtext_p.h b/src/extras/text/qdistancefieldtext_p.h new file mode 100644 index 000000000..578ed7f98 --- /dev/null +++ b/src/extras/text/qdistancefieldtext_p.h @@ -0,0 +1,109 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3DEXTRAS_QDISTANCEFIELDTEXT_P_H +#define QT3DEXTRAS_QDISTANCEFIELDTEXT_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { +class QGeometryRenderer; +class QGeometry; +class QMaterial; +class QAttribute; +class QBuffer; +} + +namespace Qt3DExtras { + +class QDistanceFieldMaterial; +class QDistanceFieldText; + +class QDistanceFieldTextPrivate : public Qt3DCore::QEntityPrivate +{ +public: + QDistanceFieldTextPrivate(); + ~QDistanceFieldTextPrivate(); + + Q_DECLARE_PUBLIC(QDistanceFieldText) + + QDistanceFieldGlyphCache *m_glyphCache = nullptr; + + // keep track of the glyphs currently being displayed, + // to guarantee proper glyph ref-counting in the + // QDistanceFieldGlyphCache + QVector m_currentGlyphRuns; + + QFont m_font; + QFont m_scaledFont; // ignore point or pixel size, set to default value + + QColor m_color; + QRectF m_position; + QString m_text; + float m_fontScale = 1.0f; + + QVector m_renderers; + + float computeActualScale() const; + + void setCurrentGlyphRuns(const QVector &runs); + void update(); +}; + +} // namespace Qt3DExtras + +QT_END_NAMESPACE + +#endif // QT3DEXTRAS_QDISTANCEFIELDTEXT_P_H diff --git a/src/extras/text/text.pri b/src/extras/text/text.pri index dd2eb0992..24ab40cc2 100644 --- a/src/extras/text/text.pri +++ b/src/extras/text/text.pri @@ -5,12 +5,18 @@ HEADERS += \ $$PWD/qdistancefieldglyphcache_p.h \ $$PWD/qdistancefieldmaterial.h \ $$PWD/qdistancefieldmaterial_p.h \ + $$PWD/distancefieldtextrenderer_p.h \ + $$PWD/distancefieldtextrenderer_p_p.h \ + $$PWD/qdistancefieldtext.h \ + $$PWD/qdistancefieldtext_p.h \ $$PWD/areaallocator_p.h SOURCES += \ $$PWD/qtextureatlas.cpp \ $$PWD/qdistancefieldglyphcache.cpp \ $$PWD/qdistancefieldmaterial.cpp \ + $$PWD/qdistancefieldtext.cpp \ + $$PWD/distancefieldtextrenderer.cpp \ $$PWD/areaallocator.cpp INCLUDEPATH += $$PWD -- cgit v1.2.3 From 157a60f4879b2df53c652b259990ece26a528b60 Mon Sep 17 00:00:00 2001 From: Paul Lemire Date: Thu, 12 Jan 2017 08:26:36 +0100 Subject: QDistanceFieldText: export to QML Change-Id: I538a4552435609073e846a6ec4b34f266b11446e Reviewed-by: Sean Harmer --- src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp | 8 ++++++-- src/quick3d/imports/render/importsrender.pro | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp b/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp index 2f3763c06..ffa6be945 100644 --- a/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp +++ b/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp @@ -67,9 +67,10 @@ #include #include #include - +#include +#include +#include #include - #include QT_BEGIN_NAMESPACE @@ -117,6 +118,9 @@ void Qt3DQuick3DExtrasPlugin::registerTypes(const char *uri) // 3D Text qmlRegisterType(uri, 2, 2, "Text3DGeometry"); qmlRegisterType(uri, 2, 2, "Text3DMesh"); + + qmlRegisterType(uri, 2, 2, "DistanceFieldGlyphCache"); + qmlRegisterType(uri, 2, 2, "DistanceFieldText"); } diff --git a/src/quick3d/imports/render/importsrender.pro b/src/quick3d/imports/render/importsrender.pro index 442068fe7..cc34ff3df 100644 --- a/src/quick3d/imports/render/importsrender.pro +++ b/src/quick3d/imports/render/importsrender.pro @@ -3,7 +3,7 @@ TARGET = quick3drenderplugin TARGETPATH = Qt3D/Render IMPORT_VERSION = 2.0 -QT += core-private qml qml-private 3dcore 3drender 3dquick 3dquick-private 3dquickrender-private +QT += core-private qml qml-private 3dcore 3drender 3drender-private 3dquick 3dquick-private 3dquickrender-private # Qt3D is free of Q_FOREACH - make sure it stays that way: DEFINES += QT_NO_FOREACH -- cgit v1.2.3 From 38a284dce96b14f695a27879119e7a28b20756e1 Mon Sep 17 00:00:00 2001 From: Wieland Hagen Date: Mon, 19 Dec 2016 21:36:10 +0700 Subject: Add DistanceFieldText test This test also covers the gradual updating of the QTextureAtlas, and thus the correct working of QAbstractTexture::setDataGenerator() Change-Id: Ic3a989ff3e109136e8be2b560ee51c520366c3be Reviewed-by: Sean Harmer --- tests/manual/distancefieldtext/TextScene.qml | 156 +++++++++++++++++++++ .../manual/distancefieldtext/distancefieldtext.pro | 15 ++ .../manual/distancefieldtext/distancefieldtext.qrc | 6 + tests/manual/distancefieldtext/main.cpp | 75 ++++++++++ tests/manual/distancefieldtext/main.qml | 155 ++++++++++++++++++++ tests/manual/manual.pro | 3 +- 6 files changed, 409 insertions(+), 1 deletion(-) create mode 100644 tests/manual/distancefieldtext/TextScene.qml create mode 100644 tests/manual/distancefieldtext/distancefieldtext.pro create mode 100644 tests/manual/distancefieldtext/distancefieldtext.qrc create mode 100644 tests/manual/distancefieldtext/main.cpp create mode 100644 tests/manual/distancefieldtext/main.qml diff --git a/tests/manual/distancefieldtext/TextScene.qml b/tests/manual/distancefieldtext/TextScene.qml new file mode 100644 index 000000000..75fcf0e20 --- /dev/null +++ b/tests/manual/distancefieldtext/TextScene.qml @@ -0,0 +1,156 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import Qt3D.Core 2.0 +import Qt3D.Render 2.0 +import Qt3D.Input 2.0 +import Qt3D.Extras 2.2 +import QtQuick 2.0 as QQ2; + +Entity { + id: sceneRoot + + property alias fontFamily : text.font.family + property alias fontBold : text.font.bold + property alias fontItalic : text.font.italic + + signal clicked() + + Camera { + id: camera + projectionType: CameraLens.PerspectiveProjection + fieldOfView: 45 + aspectRatio: 16/9 + nearPlane : 0.1 + farPlane : 1000.0 + position: Qt.vector3d( 0.0, 0.0, 20.0 ) + upVector: Qt.vector3d( 0.0, 1.0, 0.0 ) + viewCenter: Qt.vector3d( 0.0, 0.0, 0.0 ) + } + + FirstPersonCameraController { + camera: camera + linearSpeed: 0.1 + camera.position.z + } + + components: [ + RenderSettings { + activeFrameGraph : ForwardRenderer { + camera: camera + clearColor: "black" + } + }, + InputSettings { + } + ] + + DistanceFieldGlyphCache { + id: glyphCache + } + + function getChars(n) { + var s = ""; + for (var i = 0; i < n; i++) { + s += String.fromCharCode(32+i); + if (i % 16 == 15) + s += "\n"; + } + return s; + } + + property int strLen : 28 + + onClicked: { + strLen += 1 + if (strLen > 96) + strLen = 10 + } + + Entity { + components: [ + Transform { + id: rot + } + ] + + QQ2.SequentialAnimation { + loops: QQ2.Animation.Infinite + running: true + QQ2.NumberAnimation { + target: rot + property: "rotationY" + from: 0; to: -80; + duration: 2000 + } + QQ2.NumberAnimation { + target: rot + property: "rotationY" + from: -80; to: 80; + duration: 4000 + } + QQ2.NumberAnimation { + target: rot + property: "rotationY" + from: 80; to: 0; + duration: 2000 + } + } + + DistanceFieldText { + id: text + + font.pointSize: 10 + text: getChars(strLen) + glyphCache: glyphCache + position: Qt.rect(-10, -5, 20, 10) + fontScale: 0.1 + } + } +} diff --git a/tests/manual/distancefieldtext/distancefieldtext.pro b/tests/manual/distancefieldtext/distancefieldtext.pro new file mode 100644 index 000000000..01f080917 --- /dev/null +++ b/tests/manual/distancefieldtext/distancefieldtext.pro @@ -0,0 +1,15 @@ +!include( ../manual.pri ) { + error( "Couldn't find the manual.pri file!" ) +} + +QT += 3dcore 3drender 3dinput 3dquick qml quick 3dquickextras + +SOURCES += \ + main.cpp + +OTHER_FILES += \ + TextScene.qml \ + main.qml + +RESOURCES += \ + distancefieldtext.qrc diff --git a/tests/manual/distancefieldtext/distancefieldtext.qrc b/tests/manual/distancefieldtext/distancefieldtext.qrc new file mode 100644 index 000000000..5a60978c0 --- /dev/null +++ b/tests/manual/distancefieldtext/distancefieldtext.qrc @@ -0,0 +1,6 @@ + + + main.qml + TextScene.qml + + diff --git a/tests/manual/distancefieldtext/main.cpp b/tests/manual/distancefieldtext/main.cpp new file mode 100644 index 000000000..28ba977d8 --- /dev/null +++ b/tests/manual/distancefieldtext/main.cpp @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include + +int main(int argc, char **argv) +{ + QGuiApplication app(argc, argv); + + QSurfaceFormat format; + if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGL) { + format.setVersion(3, 2); + format.setProfile(QSurfaceFormat::CoreProfile); + format.setDepthBufferSize(24); + format.setStencilBufferSize(8); + } + + QQuickView view; + view.setFormat(format); + view.resize(1200, 600); + view.setResizeMode(QQuickView::SizeRootObjectToView); + view.setSource(QUrl("qrc:/main.qml")); + view.show(); + + return app.exec(); +} diff --git a/tests/manual/distancefieldtext/main.qml b/tests/manual/distancefieldtext/main.qml new file mode 100644 index 000000000..69c76bb8f --- /dev/null +++ b/tests/manual/distancefieldtext/main.qml @@ -0,0 +1,155 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import QtQuick.Scene3D 2.0 + +Item { + id: root + property string currentFont + property bool bold : false + property bool italic : false + + Scene3D { + id: scene3d + anchors.left: parent.left + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.right: settingsPane.left + focus: true + aspects: ["input", "logic", "render"] + cameraAspectRatioMode: Scene3D.AutomaticAspectRatio + + TextScene { + id: textScene + fontFamily: root.currentFont + fontBold: bold + fontItalic: italic + } + } + + MouseArea { + anchors.fill: parent + onClicked: { + textScene.clicked() + } + } + + Item { + id: settingsPane + + anchors.right: parent.right + anchors.top: parent.top + anchors.bottom: parent.bottom + width: 400 + + Rectangle { + width: parent.width/2 + height:50 + color: root.bold ? "#000066" : "#222222" + Text { + anchors.centerIn: parent + text: "Bold" + font.pointSize: 20 + color: "#ffffff" + } + MouseArea { + anchors.fill: parent + onClicked: root.bold = !root.bold + } + } + + Rectangle { + x: parent.width/2 + width: parent.width/2 + height:50 + color: root.italic ? "#000066" : "#222222" + Text { + anchors.centerIn: parent + text: "Italic" + font.pointSize: 20 + color: "#ffffff" + } + MouseArea { + anchors.fill: parent + onClicked: root.italic = !root.italic + } + } + + ListView { + anchors.fill: parent + anchors.topMargin: 50 + model: Qt.fontFamilies() + + delegate: Rectangle { + height: fontFamilyText.height + 10 + width: parent.width + color: (modelData == root.currentFont) ? "#000066" : "#222222" + + Text { + id: fontFamilyText + anchors.centerIn: parent + font.pointSize: 14 + font.family: modelData + text: modelData + color: "#ffffff" + } + + MouseArea { + anchors.fill: parent + onClicked: { + root.currentFont = modelData; + + } + } + } + } + } +} diff --git a/tests/manual/manual.pro b/tests/manual/manual.pro index 708b49bea..c5a218ead 100644 --- a/tests/manual/manual.pro +++ b/tests/manual/manual.pro @@ -41,7 +41,8 @@ SUBDIRS += \ render-qml-to-texture \ render-qml-to-texture-qml \ video-texture-qml \ - animation-keyframe-simple + animation-keyframe-simple \ + distancefieldtext qtHaveModule(widgets): { SUBDIRS += \ -- cgit v1.2.3 From 1025ec92da6360a516a34e4fb483f82505f656ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Jos=C3=A9=20Casafranca?= Date: Tue, 20 Dec 2016 10:12:55 +0200 Subject: Transfers gpu buffer data to cpu Added some code to retrieve the data in the gpu back to a cpu pointer in the opengl helpers. Added a framegraph node which specifies if any data must be downloaded from the gpu Added a flag in the buffer object to specify if the data from that buffer must be downloaded. Added a job to send the data back to the frontend. Added a path in the renderer to download the gpu data. Task number: QTBUG-57727 Change-Id: I315a9221e5116c7d07f818e00c654fe1901144f4 Reviewed-by: Sean Harmer --- .../imports/render/qt3dquick3drenderplugin.cpp | 2 + src/render/backend/renderer.cpp | 29 ++++++ src/render/backend/renderer_p.h | 6 ++ src/render/backend/renderview.cpp | 12 +++ src/render/backend/renderview_p.h | 4 + src/render/framegraph/buffercapture.cpp | 61 +++++++++++ src/render/framegraph/buffercapture_p.h | 75 ++++++++++++++ src/render/framegraph/framegraph.pri | 5 + src/render/framegraph/framegraphnode_p.h | 1 + src/render/framegraph/qbuffercapture.cpp | 69 +++++++++++++ src/render/framegraph/qbuffercapture.h | 68 ++++++++++++ src/render/framegraph/qbuffercapture_p.h | 74 +++++++++++++ src/render/frontend/qrenderaspect.cpp | 4 + src/render/geometry/buffer.cpp | 18 ++++ src/render/geometry/buffer_p.h | 3 + src/render/geometry/qbuffer.cpp | 36 ++++++- src/render/geometry/qbuffer.h | 12 +++ src/render/geometry/qbuffer_p.h | 2 + src/render/graphicshelpers/graphicscontext.cpp | 29 ++++++ src/render/graphicshelpers/graphicscontext_p.h | 4 + src/render/graphicshelpers/graphicshelperes2.cpp | 14 +++ src/render/graphicshelpers/graphicshelperes2_p.h | 2 + src/render/graphicshelpers/graphicshelpergl2.cpp | 10 ++ src/render/graphicshelpers/graphicshelpergl2_p.h | 2 + src/render/graphicshelpers/graphicshelpergl3_2.cpp | 42 +++++--- src/render/graphicshelpers/graphicshelpergl3_2_p.h | 2 + src/render/graphicshelpers/graphicshelpergl3_3.cpp | 10 ++ src/render/graphicshelpers/graphicshelpergl3_3_p.h | 2 + src/render/graphicshelpers/graphicshelpergl4.cpp | 10 ++ src/render/graphicshelpers/graphicshelpergl4_p.h | 2 + .../graphicshelpers/graphicshelperinterface_p.h | 5 +- src/render/io/glbuffer.cpp | 12 +++ src/render/io/glbuffer_p.h | 2 + src/render/jobs/job_common_p.h | 1 + src/render/jobs/jobs.pri | 7 +- src/render/jobs/renderviewjobutils.cpp | 9 ++ src/render/jobs/sendbuffercapturejob.cpp | 90 ++++++++++++++++ src/render/jobs/sendbuffercapturejob_p.h | 100 ++++++++++++++++++ .../manual/buffercapture-qml/BufferSetterScene.qml | 114 +++++++++++++++++++++ .../manual/buffercapture-qml/ComputeFrameGraph.qml | 74 +++++++++++++ tests/manual/buffercapture-qml/ComputeMaterial.qml | 91 ++++++++++++++++ tests/manual/buffercapture-qml/bufferSetter.comp | 66 ++++++++++++ .../manual/buffercapture-qml/buffercapture-qml.pro | 16 +++ tests/manual/buffercapture-qml/main.cpp | 86 ++++++++++++++++ tests/manual/buffercapture-qml/main.qml | 63 ++++++++++++ tests/manual/buffercapture-qml/resources.qrc | 9 ++ tests/manual/manual.pro | 1 + 47 files changed, 1332 insertions(+), 24 deletions(-) create mode 100644 src/render/framegraph/buffercapture.cpp create mode 100644 src/render/framegraph/buffercapture_p.h create mode 100644 src/render/framegraph/qbuffercapture.cpp create mode 100644 src/render/framegraph/qbuffercapture.h create mode 100644 src/render/framegraph/qbuffercapture_p.h create mode 100644 src/render/jobs/sendbuffercapturejob.cpp create mode 100644 src/render/jobs/sendbuffercapturejob_p.h create mode 100644 tests/manual/buffercapture-qml/BufferSetterScene.qml create mode 100644 tests/manual/buffercapture-qml/ComputeFrameGraph.qml create mode 100644 tests/manual/buffercapture-qml/ComputeMaterial.qml create mode 100755 tests/manual/buffercapture-qml/bufferSetter.comp create mode 100644 tests/manual/buffercapture-qml/buffercapture-qml.pro create mode 100644 tests/manual/buffercapture-qml/main.cpp create mode 100644 tests/manual/buffercapture-qml/main.qml create mode 100644 tests/manual/buffercapture-qml/resources.qrc diff --git a/src/quick3d/imports/render/qt3dquick3drenderplugin.cpp b/src/quick3d/imports/render/qt3dquick3drenderplugin.cpp index bb0ac249c..903e7ae08 100644 --- a/src/quick3d/imports/render/qt3dquick3drenderplugin.cpp +++ b/src/quick3d/imports/render/qt3dquick3drenderplugin.cpp @@ -105,6 +105,7 @@ #include #include #include +#include #include #include @@ -238,6 +239,7 @@ void Qt3DQuick3DRenderPlugin::registerTypes(const char *uri) qmlRegisterType(uri, 2, 0, "DispatchCompute"); qmlRegisterType(uri, 2, 1, "RenderCapture"); qmlRegisterUncreatableType(uri, 2, 1, "RenderCaptureReply", QStringLiteral("RenderCaptureReply is only instantiated by RenderCapture")); + qmlRegisterType(uri, 2, 0, "BufferCapture"); Qt3DRender::Quick::registerExtendedType("QMemoryBarrier", "Qt3D.Render/MemoryBarrier", uri, 2, 0, "MemoryBarrier"); // RenderTarget diff --git a/src/render/backend/renderer.cpp b/src/render/backend/renderer.cpp index 6dafb1b10..9e579b870 100644 --- a/src/render/backend/renderer.cpp +++ b/src/render/backend/renderer.cpp @@ -84,6 +84,7 @@ #include #include #include +#include #include #include @@ -170,6 +171,7 @@ Renderer::Renderer(QRenderAspect::RenderType type) , m_updateTreeEnabledJob(Render::UpdateTreeEnabledJobPtr::create()) , m_sendRenderCaptureJob(Render::SendRenderCaptureJobPtr::create(this)) , m_updateLevelOfDetailJob(Render::UpdateLevelOfDetailJobPtr::create()) + , m_sendBufferCaptureJob(Render::SendBufferCaptureJobPtr::create(this)) , m_updateMeshTriangleListJob(Render::UpdateMeshTriangleListJobPtr::create()) , m_filterCompatibleTechniqueJob(Render::FilterCompatibleTechniqueJobPtr::create()) , m_bufferGathererJob(Render::GenericLambdaJobPtr>::create([this] { lookForDirtyBuffers(); }, JobTypes::DirtyBufferGathering)) @@ -264,6 +266,7 @@ void Renderer::setNodeManagers(NodeManagers *managers) m_pickBoundingVolumeJob->setManagers(m_nodesManager); m_updateWorldBoundingVolumeJob->setManager(m_nodesManager->renderNodesManager()); m_sendRenderCaptureJob->setManagers(m_nodesManager); + m_sendBufferCaptureJob->setManagers(m_nodesManager); m_updateLevelOfDetailJob->setManagers(m_nodesManager); m_updateMeshTriangleListJob->setManagers(m_nodesManager); m_filterCompatibleTechniqueJob->setManager(m_nodesManager->techniqueManager()); @@ -927,6 +930,17 @@ void Renderer::lookForDirtyBuffers() } } +void Renderer::lookForDownloadableBuffers() +{ + m_downloadableBuffers.clear(); + const QVector activeBufferHandles = m_nodesManager->bufferManager()->activeHandles(); + for (HBuffer handle : activeBufferHandles) { + Buffer *buffer = m_nodesManager->bufferManager()->data(handle); + if (buffer->access() & QBuffer::Read) + m_downloadableBuffers.push_back(handle); + } +} + // Executed in a job void Renderer::lookForDirtyTextures() { @@ -1109,6 +1123,17 @@ void Renderer::cleanupTexture(const Texture *texture) glTextureManager->abandon(glTexture, texture); } +void Renderer::downloadGLBuffers() +{ + lookForDownloadableBuffers(); + const QVector downloadableHandles = std::move(m_downloadableBuffers); + for (HBuffer handle : downloadableHandles) { + Buffer *buffer = m_nodesManager->bufferManager()->data(handle); + QByteArray content = m_graphicsContext->downloadBufferContent(buffer); + m_sendBufferCaptureJob->addRequest(QPair(buffer, content)); + } +} + // Happens in RenderThread context when all RenderViewJobs are done // Returns the id of the last bound FBO @@ -1247,6 +1272,9 @@ Renderer::ViewSubmissionResultData Renderer::submitRenderViews(const QVectorrenderCaptureNodeId()); } + if (renderView->isDownloadBuffersEnable()) + downloadGLBuffers(); + frameElapsed = timer.elapsed() - frameElapsed; qCDebug(Rendering) << Q_FUNC_INFO << "Submitted Renderview " << i + 1 << "/" << renderViewsCount << "in " << frameElapsed << "ms"; frameElapsed = timer.elapsed(); @@ -1357,6 +1385,7 @@ QVector Renderer::renderBinJobs() renderBinJobs.push_back(m_worldTransformJob); renderBinJobs.push_back(m_cleanupJob); renderBinJobs.push_back(m_sendRenderCaptureJob); + renderBinJobs.push_back(m_sendBufferCaptureJob); renderBinJobs.push_back(m_filterCompatibleTechniqueJob); renderBinJobs.append(bufferJobs); diff --git a/src/render/backend/renderer_p.h b/src/render/backend/renderer_p.h index 079d30e23..a2b13892c 100644 --- a/src/render/backend/renderer_p.h +++ b/src/render/backend/renderer_p.h @@ -71,6 +71,7 @@ #include #include #include +#include #include #include #include @@ -214,6 +215,7 @@ public: void updateGLResources(); void updateTexture(Texture *texture); void cleanupTexture(const Texture *texture); + void downloadGLBuffers(); void prepareCommandsSubmission(const QVector &renderViews); bool executeCommandsSubmission(const RenderView *rv); @@ -263,6 +265,7 @@ public: #ifdef QT3D_RENDER_UNIT_TESTS public: #else + private: #endif bool canRender() const; @@ -316,6 +319,7 @@ private: UpdateWorldBoundingVolumeJobPtr m_updateWorldBoundingVolumeJob; UpdateTreeEnabledJobPtr m_updateTreeEnabledJob; SendRenderCaptureJobPtr m_sendRenderCaptureJob; + SendBufferCaptureJobPtr m_sendBufferCaptureJob; UpdateLevelOfDetailJobPtr m_updateLevelOfDetailJob; UpdateMeshTriangleListJobPtr m_updateMeshTriangleListJob; FilterCompatibleTechniqueJobPtr m_filterCompatibleTechniqueJob; @@ -335,10 +339,12 @@ private: SynchronizerJobPtr m_syncTextureLoadingJob; void lookForDirtyBuffers(); + void lookForDownloadableBuffers(); void lookForDirtyTextures(); void lookForDirtyShaders(); QVector m_dirtyBuffers; + QVector m_downloadableBuffers; QVector m_dirtyShaders; QVector m_dirtyTextures; diff --git a/src/render/backend/renderview.cpp b/src/render/backend/renderview.cpp index bfdb68eb1..edd19622a 100644 --- a/src/render/backend/renderview.cpp +++ b/src/render/backend/renderview.cpp @@ -66,6 +66,7 @@ #include #include #include +#include #include #include #include @@ -209,6 +210,7 @@ RenderView::RenderView() , m_stateSet(nullptr) , m_noDraw(false) , m_compute(false) + , m_isDownloadBuffersEnable(false) , m_frustumCulling(false) , m_memoryBarrier(QMemoryBarrier::None) { @@ -830,6 +832,16 @@ void RenderView::setShaderAndUniforms(RenderCommand *command, RenderPass *rPass, } } +bool RenderView::isDownloadBuffersEnable() const +{ + return m_isDownloadBuffersEnable; +} + +void RenderView::setIsDownloadBuffersEnable(bool isDownloadBuffersEnable) +{ + m_isDownloadBuffersEnable = isDownloadBuffersEnable; +} + } // namespace Render } // namespace Qt3DRender diff --git a/src/render/backend/renderview_p.h b/src/render/backend/renderview_p.h index 1f00e2aae..ec56e7ff2 100644 --- a/src/render/backend/renderview_p.h +++ b/src/render/backend/renderview_p.h @@ -245,6 +245,9 @@ public: QVector3D m_eyePos; }; + bool isDownloadBuffersEnable() const; + void setIsDownloadBuffersEnable(bool isDownloadBuffersEnable); + private: void setShaderAndUniforms(RenderCommand *command, RenderPass *pass, ParameterInfoList ¶meters, const QMatrix4x4 &worldTransform, const QVector &activeLightSources) const; @@ -252,6 +255,7 @@ private: mutable QThreadStorage m_localData; Qt3DCore::QNodeId m_renderCaptureNodeId; + bool m_isDownloadBuffersEnable; Renderer *m_renderer; NodeManagers *m_manager; diff --git a/src/render/framegraph/buffercapture.cpp b/src/render/framegraph/buffercapture.cpp new file mode 100644 index 000000000..4e89150df --- /dev/null +++ b/src/render/framegraph/buffercapture.cpp @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Juan JosĂ© Casafranca +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +namespace Render { + +BufferCapture::BufferCapture() + : FrameGraphNode(FrameGraphNode::BufferCapture, QBackendNode::ReadWrite) +{ + +} + +} //Render + +} //Qt3DRender + +QT_END_NAMESPACE diff --git a/src/render/framegraph/buffercapture_p.h b/src/render/framegraph/buffercapture_p.h new file mode 100644 index 000000000..d638f35d5 --- /dev/null +++ b/src/render/framegraph/buffercapture_p.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Juan JosĂ© Casafranca +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef BUFFERCAPTURE_P_H +#define BUFFERCAPTURE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +namespace Render { + +class Q_AUTOTEST_EXPORT BufferCapture : public FrameGraphNode +{ +public: + BufferCapture(); +}; + +} //Render + +} //Qt3DRender + +QT_END_NAMESPACE + +#endif // BUFFERCAPTURE_P_H diff --git a/src/render/framegraph/framegraph.pri b/src/render/framegraph/framegraph.pri index 77d7dbc71..5e9ce68bf 100644 --- a/src/render/framegraph/framegraph.pri +++ b/src/render/framegraph/framegraph.pri @@ -45,6 +45,9 @@ HEADERS += \ $$PWD/qrendercapture.h \ $$PWD/qrendercapture_p.h \ $$PWD/rendercapture_p.h \ + $$PWD/qbuffercapture.h \ + $$PWD/qbuffercapture_p.h \ + $$PWD/buffercapture_p.h \ $$PWD/qframegraphnodecreatedchange.h \ $$PWD/qframegraphnodecreatedchange_p.h \ $$PWD/qmemorybarrier.h \ @@ -83,6 +86,8 @@ SOURCES += \ $$PWD/rendersurfaceselector.cpp \ $$PWD/qrendercapture.cpp \ $$PWD/rendercapture.cpp \ + $$PWD/qbuffercapture.cpp \ + $$PWD/buffercapture.cpp \ $$PWD/qframegraphnodecreatedchange.cpp \ $$PWD/qmemorybarrier.cpp \ $$PWD/memorybarrier.cpp diff --git a/src/render/framegraph/framegraphnode_p.h b/src/render/framegraph/framegraphnode_p.h index ccdc47f12..c7b399f89 100644 --- a/src/render/framegraph/framegraphnode_p.h +++ b/src/render/framegraph/framegraphnode_p.h @@ -98,6 +98,7 @@ public: ComputeDispatch, Surface, RenderCapture, + BufferCapture, MemoryBarrier }; FrameGraphNodeType nodeType() const { return m_nodeType; } diff --git a/src/render/framegraph/qbuffercapture.cpp b/src/render/framegraph/qbuffercapture.cpp new file mode 100644 index 000000000..e7c287d6b --- /dev/null +++ b/src/render/framegraph/qbuffercapture.cpp @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Juan JosĂ© Casafranca +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender +{ +//Documentation here + +/*! + * \internal + */ +QBufferCapturePrivate::QBufferCapturePrivate() + : QFrameGraphNodePrivate() +{ + +} + +QBufferCapture::QBufferCapture(Qt3DCore::QNode *parent) + : QFrameGraphNode(*new QBufferCapturePrivate, parent) +{ + +} + +} //Qt3DRender + +QT_END_NAMESPACE diff --git a/src/render/framegraph/qbuffercapture.h b/src/render/framegraph/qbuffercapture.h new file mode 100644 index 000000000..3a251f7a5 --- /dev/null +++ b/src/render/framegraph/qbuffercapture.h @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Juan JosĂ© Casafranca +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3DRENDER_QBUFFERCAPTURE_H +#define QT3DRENDER_QBUFFERCAPTURE_H + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender +{ + +class QBufferCapturePrivate; + +class QT3DRENDERSHARED_EXPORT QBufferCapture : public QFrameGraphNode +{ + Q_OBJECT +public: + explicit QBufferCapture(Qt3DCore::QNode *parent = nullptr); + +private: + Q_DECLARE_PRIVATE(QBufferCapture) +}; + +} //Qt3DRender + +QT_END_NAMESPACE + +#endif // QT3DRENDER_QBUFFERCAPTURE_H diff --git a/src/render/framegraph/qbuffercapture_p.h b/src/render/framegraph/qbuffercapture_p.h new file mode 100644 index 000000000..5e642aca3 --- /dev/null +++ b/src/render/framegraph/qbuffercapture_p.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Juan JosĂ© Casafranca +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3DRENDER_QBUFFERCAPTURE_P_H +#define QT3DRENDER_QBUFFERCAPTURE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender +{ + +class QBufferCapturePrivate : public QFrameGraphNodePrivate +{ +public: + QBufferCapturePrivate(); + + Q_DECLARE_PUBLIC(QBufferCapture) +}; + +} //Qt3DRender + +QT_END_NAMESPACE + +#endif // QT3DRENDER_QBUFFERCAPTURE_P_H diff --git a/src/render/frontend/qrenderaspect.cpp b/src/render/frontend/qrenderaspect.cpp index 0eb180650..5a5498ed9 100644 --- a/src/render/frontend/qrenderaspect.cpp +++ b/src/render/frontend/qrenderaspect.cpp @@ -80,6 +80,7 @@ #include #include #include +#include #include #include @@ -126,6 +127,7 @@ #include #include #include +#include #include #include #include @@ -244,6 +246,7 @@ void QRenderAspectPrivate::registerBackendTypes() q->registerBackendType(QSharedPointer >::create(m_renderer)); q->registerBackendType(QSharedPointer >::create(m_renderer)); q->registerBackendType(QSharedPointer >::create(m_renderer)); + q->registerBackendType(QSharedPointer >::create(m_renderer)); q->registerBackendType(QSharedPointer >::create(m_renderer)); // Picking @@ -307,6 +310,7 @@ void QRenderAspectPrivate::unregisterBackendTypes() unregisterBackendType(); unregisterBackendType(); unregisterBackendType(); + unregisterBackendType(); unregisterBackendType(); // Picking diff --git a/src/render/geometry/buffer.cpp b/src/render/geometry/buffer.cpp index df0bc3c92..7fefcfbbb 100644 --- a/src/render/geometry/buffer.cpp +++ b/src/render/geometry/buffer.cpp @@ -56,6 +56,7 @@ Buffer::Buffer() , m_usage(QBuffer::StaticDraw) , m_bufferDirty(false) , m_syncData(false) + , m_access(QBuffer::Write) , m_manager(nullptr) { // Maybe it could become read write if we want to inform @@ -75,6 +76,7 @@ void Buffer::cleanup() m_functor.reset(); m_bufferDirty = false; m_syncData = false; + m_access = QBuffer::Write; } @@ -98,6 +100,19 @@ void Buffer::executeFunctor() } } +//Called from th sendBufferJob +void Buffer::updateDataFromGPUToCPU(QByteArray data) +{ + m_data = data; + // Send data back to the frontend + auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId()); + e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll); + e->setPropertyName("downloadedData"); + e->setValue(QVariant::fromValue(m_data)); + Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(e.data())->m_isFinal = true; + notifyObservers(e); +} + void Buffer::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) { const auto typedChange = qSharedPointerCast>(change); @@ -106,6 +121,7 @@ void Buffer::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &chang m_type = data.type; m_usage = data.usage; m_syncData = data.syncData; + m_access = data.access; m_bufferDirty = true; m_functor = data.functor; @@ -133,6 +149,8 @@ void Buffer::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) } else if (propertyName == QByteArrayLiteral("usage")) { m_usage = static_cast(propertyChange->value().value()); m_bufferDirty = true; + } else if (propertyName == QByteArrayLiteral("access")) { + m_access = static_cast(propertyChange->value().value()); } else if (propertyName == QByteArrayLiteral("dataGenerator")) { QBufferDataGeneratorPtr newGenerator = propertyChange->value().value(); m_bufferDirty |= !(newGenerator && m_functor && *newGenerator == *m_functor); diff --git a/src/render/geometry/buffer_p.h b/src/render/geometry/buffer_p.h index d474c1720..8f6600f7a 100644 --- a/src/render/geometry/buffer_p.h +++ b/src/render/geometry/buffer_p.h @@ -77,6 +77,7 @@ public: void setManager(BufferManager *manager); void executeFunctor(); + void updateDataFromGPUToCPU(QByteArray data); inline QBuffer::BufferType type() const { return m_type; } inline QBuffer::UsageType usage() const { return m_usage; } inline QByteArray data() const { return m_data; } @@ -84,6 +85,7 @@ public: inline bool isDirty() const { return m_bufferDirty; } inline QBufferDataGeneratorPtr dataGenerator() const { return m_functor; } inline bool isSyncData() const { return m_syncData; } + inline QBuffer::AccessType access() const { return m_access; } void unsetDirty(); private: @@ -95,6 +97,7 @@ private: QVector m_bufferUpdates; bool m_bufferDirty; bool m_syncData; + QBuffer::AccessType m_access; QBufferDataGeneratorPtr m_functor; BufferManager *m_manager; }; diff --git a/src/render/geometry/qbuffer.cpp b/src/render/geometry/qbuffer.cpp index 98109a589..250ba7829 100644 --- a/src/render/geometry/qbuffer.cpp +++ b/src/render/geometry/qbuffer.cpp @@ -42,6 +42,7 @@ #include #include + QT_BEGIN_NAMESPACE using namespace Qt3DCore; @@ -52,6 +53,7 @@ QBufferPrivate::QBufferPrivate() : QNodePrivate() , m_usage(QBuffer::StaticDraw) , m_syncData(false) + , m_access(QBuffer::Write) { } @@ -271,11 +273,19 @@ QBuffer::~QBuffer() */ void QBuffer::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) { - QPropertyUpdatedChangePtr e = qSharedPointerCast(change); - if (e->type() == PropertyUpdated && e->propertyName() == QByteArrayLiteral("data")) { - const bool blocked = blockNotifications(true); - setData(e->value().toByteArray()); - blockNotifications(blocked); + if (change->type() == PropertyUpdated) { + QPropertyUpdatedChangePtr e = qSharedPointerCast(change); + const QByteArray propertyName = e->propertyName(); + if (propertyName == QByteArrayLiteral("data")) { + const bool blocked = blockNotifications(true); + setData(e->value().toByteArray()); + blockNotifications(blocked); + } else if (propertyName == QByteArrayLiteral("downloadedData")) { + const bool blocked = blockNotifications(true); + setData(e->value().toByteArray()); + blockNotifications(blocked); + Q_EMIT dataAvailable(); + } } } @@ -401,12 +411,27 @@ void QBuffer::setSyncData(bool syncData) } } +void QBuffer::setAccess(QBuffer::AccessType access) +{ + Q_D(QBuffer); + if (d->m_access != access) { + d->m_access = access; + Q_EMIT accessChanged(access); + } +} + bool QBuffer::isSyncData() const { Q_D(const QBuffer); return d->m_syncData; } +QBuffer::AccessType QBuffer::access() const +{ + Q_D(const QBuffer); + return d->m_access; +} + void QBuffer::setType(QBuffer::BufferType type) { Q_D(QBuffer); @@ -426,6 +451,7 @@ Qt3DCore::QNodeCreatedChangeBasePtr QBuffer::createNodeCreationChange() const data.usage = d->m_usage; data.functor = d->m_functor; data.syncData = d->m_syncData; + data.access = d->m_access; return creationChange; } diff --git a/src/render/geometry/qbuffer.h b/src/render/geometry/qbuffer.h index 8b47de918..a3facba39 100644 --- a/src/render/geometry/qbuffer.h +++ b/src/render/geometry/qbuffer.h @@ -59,6 +59,7 @@ class QT3DRENDERSHARED_EXPORT QBuffer : public Qt3DCore::QNode Q_PROPERTY(BufferType type READ type WRITE setType NOTIFY typeChanged) Q_PROPERTY(UsageType usage READ usage WRITE setUsage NOTIFY usageChanged) Q_PROPERTY(bool syncData READ isSyncData WRITE setSyncData NOTIFY syncDataChanged) + Q_PROPERTY(AccessType access READ access WRITE setAccess NOTIFY accessChanged) public: enum BufferType @@ -87,12 +88,20 @@ public: }; Q_ENUM(UsageType) // LCOV_EXCL_LINE + enum AccessType { + Write = 0x0, + Read = 0x1, + ReadWrite = 0x2 + }; + Q_ENUM(AccessType) // LCOV_EXCL_LINE + explicit QBuffer(BufferType ty = QBuffer::VertexBuffer, Qt3DCore::QNode *parent = nullptr); ~QBuffer(); UsageType usage() const; BufferType type() const; bool isSyncData() const; + AccessType access() const; void setData(const QByteArray &bytes); QByteArray data() const; @@ -106,6 +115,7 @@ public Q_SLOTS: void setType(BufferType type); void setUsage(UsageType usage); void setSyncData(bool syncData); + void setAccess(AccessType access); protected: void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) Q_DECL_OVERRIDE; @@ -115,6 +125,8 @@ Q_SIGNALS: void typeChanged(BufferType type); void usageChanged(UsageType usage); void syncDataChanged(bool syncData); + void accessChanged(AccessType access); + void dataAvailable(); private: Q_DECLARE_PRIVATE(QBuffer) diff --git a/src/render/geometry/qbuffer_p.h b/src/render/geometry/qbuffer_p.h index eb69730b8..a722675ab 100644 --- a/src/render/geometry/qbuffer_p.h +++ b/src/render/geometry/qbuffer_p.h @@ -74,6 +74,7 @@ public: QBuffer::UsageType m_usage; QBufferDataGeneratorPtr m_functor; bool m_syncData; + QBuffer::AccessType m_access; }; struct QBufferData @@ -83,6 +84,7 @@ struct QBufferData QBuffer::UsageType usage; QBufferDataGeneratorPtr functor; bool syncData; + QBuffer::AccessType access; }; struct QBufferUpdate diff --git a/src/render/graphicshelpers/graphicscontext.cpp b/src/render/graphicshelpers/graphicscontext.cpp index 8a2919a96..d27b7cd06 100644 --- a/src/render/graphicshelpers/graphicscontext.cpp +++ b/src/render/graphicshelpers/graphicscontext.cpp @@ -1073,6 +1073,16 @@ void GraphicsContext::dispatchCompute(int x, int y, int z) m_glHelper->dispatchCompute(x, y, z); } +GLboolean GraphicsContext::unmapBuffer(GLenum target) +{ + return m_glHelper->unmapBuffer(target); +} + +char *GraphicsContext::mapBuffer(GLenum target) +{ + return m_glHelper->mapBuffer(target); +} + void GraphicsContext::enablei(GLenum cap, GLuint index) { m_glHelper->enablei(cap, index); @@ -1426,6 +1436,16 @@ void GraphicsContext::updateBuffer(Buffer *buffer) uploadDataToGLBuffer(buffer, m_renderer->nodeManagers()->glBufferManager()->data(it.value())); } +QByteArray GraphicsContext::downloadBufferContent(Buffer *buffer) +{ + const QHash::iterator it = m_renderBufferHash.find(buffer->peerId()); + if (it != m_renderBufferHash.end()) + return downloadDataFromGLBuffer(buffer, m_renderer->nodeManagers()->glBufferManager()->data(it.value())); + return QByteArray(); +} + + + void GraphicsContext::releaseBuffer(Qt3DCore::QNodeId bufferId) { auto it = m_renderBufferHash.find(bufferId); @@ -1522,6 +1542,15 @@ void GraphicsContext::uploadDataToGLBuffer(Buffer *buffer, GLBuffer *b, bool rel qCDebug(Render::Io) << "uploaded buffer size=" << buffer->data().size(); } +QByteArray GraphicsContext::downloadDataFromGLBuffer(Buffer *buffer, GLBuffer *b) +{ + if (!bindGLBuffer(b, bufferTypeToGLBufferType(buffer->type()))) + qCWarning(Render::Io) << Q_FUNC_INFO << "buffer bind failed"; + + QByteArray data = b->download(this, buffer->data().size()); + return data; +} + GLint GraphicsContext::elementType(GLint type) { switch (type) { diff --git a/src/render/graphicshelpers/graphicscontext_p.h b/src/render/graphicshelpers/graphicscontext_p.h index 02de636ff..0d9b24b6e 100644 --- a/src/render/graphicshelpers/graphicscontext_p.h +++ b/src/render/graphicshelpers/graphicscontext_p.h @@ -159,6 +159,7 @@ public: void specifyAttribute(const Attribute *attribute, Buffer *buffer, int attributeLocation); void specifyIndices(Buffer *buffer); void updateBuffer(Buffer *buffer); + QByteArray downloadBufferContent(Buffer *buffer); void releaseBuffer(Qt3DCore::QNodeId bufferId); bool hasGLBufferForBuffer(Buffer *buffer); @@ -210,6 +211,8 @@ public: void disablei(GLenum cap, GLuint index); void disablePrimitiveRestart(); void dispatchCompute(int x, int y, int z); + char * mapBuffer(GLenum target); + GLboolean unmapBuffer(GLenum target); void drawArrays(GLenum primitiveType, GLint first, GLsizei count); void drawArraysIndirect(GLenum mode,void *indirect); void drawArraysInstanced(GLenum primitiveType, GLint first, GLsizei count, GLsizei instances); @@ -254,6 +257,7 @@ private: void activateDrawBuffers(const AttachmentPack &attachments); HGLBuffer createGLBufferFor(Buffer *buffer); void uploadDataToGLBuffer(Buffer *buffer, GLBuffer *b, bool releaseBuffer = false); + QByteArray downloadDataFromGLBuffer(Buffer *buffer, GLBuffer *b); bool bindGLBuffer(GLBuffer *buffer, GLBuffer::Type type); void resolveRenderTargetFormat(); diff --git a/src/render/graphicshelpers/graphicshelperes2.cpp b/src/render/graphicshelpers/graphicshelperes2.cpp index a89f0ff8b..97bfe4c7a 100644 --- a/src/render/graphicshelpers/graphicshelperes2.cpp +++ b/src/render/graphicshelpers/graphicshelperes2.cpp @@ -575,6 +575,20 @@ void GraphicsHelperES2::dispatchCompute(GLuint wx, GLuint wy, GLuint wz) qWarning() << "Compute Shaders are not supported by ES 2.0 (since ES 3.1)"; } +char *GraphicsHelperES2::mapBuffer(GLenum target) +{ + Q_UNUSED(target); + qWarning() << "Map buffer is not a core requirement for ES 2.0"; + return nullptr; +} + +GLboolean GraphicsHelperES2::unmapBuffer(GLenum target) +{ + Q_UNUSED(target); + qWarning() << "unMap buffer is not a core requirement for ES 2.0"; + return false; +} + void GraphicsHelperES2::glUniform1fv(GLint location, GLsizei count, const GLfloat *values) { m_funcs->glUniform1fv(location, count, values); diff --git a/src/render/graphicshelpers/graphicshelperes2_p.h b/src/render/graphicshelpers/graphicshelperes2_p.h index 2a1f3cf05..3ed963c7f 100644 --- a/src/render/graphicshelpers/graphicshelperes2_p.h +++ b/src/render/graphicshelpers/graphicshelperes2_p.h @@ -89,6 +89,8 @@ public: void disablei(GLenum cap, GLuint index) Q_DECL_OVERRIDE; void disablePrimitiveRestart() Q_DECL_OVERRIDE; void dispatchCompute(GLuint wx, GLuint wy, GLuint wz) Q_DECL_OVERRIDE; + char *mapBuffer(GLenum target) Q_DECL_OVERRIDE; + GLboolean unmapBuffer(GLenum target) Q_DECL_OVERRIDE; void drawArrays(GLenum primitiveType, GLint first, GLsizei count) Q_DECL_OVERRIDE; void drawArraysIndirect(GLenum mode,void *indirect) Q_DECL_OVERRIDE; void drawArraysInstanced(GLenum primitiveType, GLint first, GLsizei count, GLsizei instances) Q_DECL_OVERRIDE; diff --git a/src/render/graphicshelpers/graphicshelpergl2.cpp b/src/render/graphicshelpers/graphicshelpergl2.cpp index 765a12f42..9935ccccf 100644 --- a/src/render/graphicshelpers/graphicshelpergl2.cpp +++ b/src/render/graphicshelpers/graphicshelpergl2.cpp @@ -600,6 +600,16 @@ void GraphicsHelperGL2::dispatchCompute(GLuint wx, GLuint wy, GLuint wz) qWarning() << "Compute Shaders are not supported by OpenGL 2.0 (since OpenGL 4.3)"; } +char *GraphicsHelperGL2::mapBuffer(GLenum target) +{ + return static_cast(m_funcs->glMapBuffer(target, GL_READ_WRITE)); +} + +GLboolean GraphicsHelperGL2::unmapBuffer(GLenum target) +{ + return m_funcs->glUnmapBuffer(target); +} + void GraphicsHelperGL2::glUniform1fv(GLint location, GLsizei count, const GLfloat *values) { m_funcs->glUniform1fv(location, count, values); diff --git a/src/render/graphicshelpers/graphicshelpergl2_p.h b/src/render/graphicshelpers/graphicshelpergl2_p.h index a6fa6dba5..8652b2bef 100644 --- a/src/render/graphicshelpers/graphicshelpergl2_p.h +++ b/src/render/graphicshelpers/graphicshelpergl2_p.h @@ -91,6 +91,8 @@ public: void disablei(GLenum cap, GLuint index) Q_DECL_OVERRIDE; void disablePrimitiveRestart() Q_DECL_OVERRIDE; void dispatchCompute(GLuint wx, GLuint wy, GLuint wz) Q_DECL_OVERRIDE; + char *mapBuffer(GLenum target) Q_DECL_OVERRIDE; + GLboolean unmapBuffer(GLenum target) Q_DECL_OVERRIDE; void drawArrays(GLenum primitiveType, GLint first, GLsizei count) Q_DECL_OVERRIDE; void drawArraysIndirect(GLenum mode,void *indirect) Q_DECL_OVERRIDE; void drawArraysInstanced(GLenum primitiveType, GLint first, GLsizei count, GLsizei instances) Q_DECL_OVERRIDE; diff --git a/src/render/graphicshelpers/graphicshelpergl3_2.cpp b/src/render/graphicshelpers/graphicshelpergl3_2.cpp index 382078ac6..7599513fa 100644 --- a/src/render/graphicshelpers/graphicshelpergl3_2.cpp +++ b/src/render/graphicshelpers/graphicshelpergl3_2.cpp @@ -82,7 +82,7 @@ GraphicsHelperGL3_2::~GraphicsHelperGL3_2() } void GraphicsHelperGL3_2::initializeHelper(QOpenGLContext *context, - QAbstractOpenGLFunctions *functions) + QAbstractOpenGLFunctions *functions) { m_funcs = static_cast(functions); const bool ok = m_funcs->initializeOpenGLFunctions(); @@ -96,12 +96,12 @@ void GraphicsHelperGL3_2::initializeHelper(QOpenGLContext *context, } void GraphicsHelperGL3_2::drawElementsInstancedBaseVertexBaseInstance(GLenum primitiveType, - GLsizei primitiveCount, - GLint indexType, - void *indices, - GLsizei instances, - GLint baseVertex, - GLint baseInstance) + GLsizei primitiveCount, + GLint indexType, + void *indices, + GLsizei instances, + GLint baseVertex, + GLint baseInstance) { if (baseInstance != 0) qWarning() << "glDrawElementsInstancedBaseVertexBaseInstance is not supported with OpenGL ES 2"; @@ -116,9 +116,9 @@ void GraphicsHelperGL3_2::drawElementsInstancedBaseVertexBaseInstance(GLenum pri } void GraphicsHelperGL3_2::drawArraysInstanced(GLenum primitiveType, - GLint first, - GLsizei count, - GLsizei instances) + GLint first, + GLsizei count, + GLsizei instances) { // glDrawArraysInstanced OpenGL 3.1 or greater m_funcs->glDrawArraysInstanced(primitiveType, @@ -138,10 +138,10 @@ void GraphicsHelperGL3_2::drawArraysInstancedBaseInstance(GLenum primitiveType, } void GraphicsHelperGL3_2::drawElements(GLenum primitiveType, - GLsizei primitiveCount, - GLint indexType, - void *indices, - GLint baseVertex) + GLsizei primitiveCount, + GLint indexType, + void *indices, + GLint baseVertex) { m_funcs->glDrawElementsBaseVertex(primitiveType, primitiveCount, @@ -151,8 +151,8 @@ void GraphicsHelperGL3_2::drawElements(GLenum primitiveType, } void GraphicsHelperGL3_2::drawArrays(GLenum primitiveType, - GLint first, - GLsizei count) + GLint first, + GLsizei count) { m_funcs->glDrawArrays(primitiveType, first, @@ -882,6 +882,16 @@ void GraphicsHelperGL3_2::dispatchCompute(GLuint wx, GLuint wy, GLuint wz) qWarning() << "Compute Shaders are not supported by OpenGL 3.2 (since OpenGL 4.3)"; } +char *GraphicsHelperGL3_2::mapBuffer(GLenum target) +{ + return static_cast(m_funcs->glMapBuffer(target, GL_READ_WRITE)); +} + +GLboolean GraphicsHelperGL3_2::unmapBuffer(GLenum target) +{ + return m_funcs->glUnmapBuffer(target); +} + void GraphicsHelperGL3_2::glUniform1fv(GLint location, GLsizei count, const GLfloat *values) { m_funcs->glUniform1fv(location, count, values); diff --git a/src/render/graphicshelpers/graphicshelpergl3_2_p.h b/src/render/graphicshelpers/graphicshelpergl3_2_p.h index d10bda40b..e12a65801 100644 --- a/src/render/graphicshelpers/graphicshelpergl3_2_p.h +++ b/src/render/graphicshelpers/graphicshelpergl3_2_p.h @@ -93,6 +93,8 @@ public: void disablei(GLenum cap, GLuint index) Q_DECL_OVERRIDE; void disablePrimitiveRestart() Q_DECL_OVERRIDE; void dispatchCompute(GLuint wx, GLuint wy, GLuint wz) Q_DECL_OVERRIDE; + char *mapBuffer(GLenum target) Q_DECL_OVERRIDE; + GLboolean unmapBuffer(GLenum target) Q_DECL_OVERRIDE; void drawArrays(GLenum primitiveType, GLint first, GLsizei count) Q_DECL_OVERRIDE; void drawArraysIndirect(GLenum mode,void *indirect) Q_DECL_OVERRIDE; void drawArraysInstanced(GLenum primitiveType, GLint first, GLsizei count, GLsizei instances) Q_DECL_OVERRIDE; diff --git a/src/render/graphicshelpers/graphicshelpergl3_3.cpp b/src/render/graphicshelpers/graphicshelpergl3_3.cpp index 023e90965..4f6e38bf4 100644 --- a/src/render/graphicshelpers/graphicshelpergl3_3.cpp +++ b/src/render/graphicshelpers/graphicshelpergl3_3.cpp @@ -879,6 +879,16 @@ void GraphicsHelperGL3_3::dispatchCompute(GLuint wx, GLuint wy, GLuint wz) qWarning() << "Compute Shaders are not supported by OpenGL 3.3 (since OpenGL 4.3)"; } +char *GraphicsHelperGL3_3::mapBuffer(GLenum target) +{ + return static_cast(m_funcs->glMapBuffer(target, GL_READ_WRITE)); +} + +GLboolean GraphicsHelperGL3_3::unmapBuffer(GLenum target) +{ + return m_funcs->glUnmapBuffer(target); +} + void GraphicsHelperGL3_3::glUniform1fv(GLint location, GLsizei count, const GLfloat *values) { m_funcs->glUniform1fv(location, count, values); diff --git a/src/render/graphicshelpers/graphicshelpergl3_3_p.h b/src/render/graphicshelpers/graphicshelpergl3_3_p.h index 9e97f3dc4..6d87c99b7 100644 --- a/src/render/graphicshelpers/graphicshelpergl3_3_p.h +++ b/src/render/graphicshelpers/graphicshelpergl3_3_p.h @@ -93,6 +93,8 @@ public: void disablei(GLenum cap, GLuint index) Q_DECL_OVERRIDE; void disablePrimitiveRestart() Q_DECL_OVERRIDE; void dispatchCompute(GLuint wx, GLuint wy, GLuint wz) Q_DECL_OVERRIDE; + char *mapBuffer(GLenum target) Q_DECL_OVERRIDE; + GLboolean unmapBuffer(GLenum target) Q_DECL_OVERRIDE; void drawArrays(GLenum primitiveType, GLint first, GLsizei count) Q_DECL_OVERRIDE; void drawArraysIndirect(GLenum mode,void *indirect) Q_DECL_OVERRIDE; void drawArraysInstanced(GLenum primitiveType, GLint first, GLsizei count, GLsizei instances) Q_DECL_OVERRIDE; diff --git a/src/render/graphicshelpers/graphicshelpergl4.cpp b/src/render/graphicshelpers/graphicshelpergl4.cpp index 6972864cf..682b3ac3b 100644 --- a/src/render/graphicshelpers/graphicshelpergl4.cpp +++ b/src/render/graphicshelpers/graphicshelpergl4.cpp @@ -1128,6 +1128,16 @@ void GraphicsHelperGL4::dispatchCompute(GLuint wx, GLuint wy, GLuint wz) m_funcs->glDispatchCompute(wx, wy, wz); } +char *GraphicsHelperGL4::mapBuffer(GLenum target) +{ + return static_cast(m_funcs->glMapBuffer(target, GL_READ_WRITE)); +} + +GLboolean GraphicsHelperGL4::unmapBuffer(GLenum target) +{ + return m_funcs->glUnmapBuffer(target); +} + void GraphicsHelperGL4::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) { m_funcs->glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); diff --git a/src/render/graphicshelpers/graphicshelpergl4_p.h b/src/render/graphicshelpers/graphicshelpergl4_p.h index df4cf5dd9..5d464e116 100644 --- a/src/render/graphicshelpers/graphicshelpergl4_p.h +++ b/src/render/graphicshelpers/graphicshelpergl4_p.h @@ -91,6 +91,8 @@ public: void disablei(GLenum cap, GLuint index) Q_DECL_OVERRIDE; void disablePrimitiveRestart() Q_DECL_OVERRIDE; void dispatchCompute(GLuint wx, GLuint wy, GLuint wz) Q_DECL_OVERRIDE; + char *mapBuffer(GLenum target) Q_DECL_OVERRIDE; + GLboolean unmapBuffer(GLenum target) Q_DECL_OVERRIDE; void drawArrays(GLenum primitiveType, GLint first, GLsizei count) Q_DECL_OVERRIDE; void drawArraysIndirect(GLenum mode,void *indirect) Q_DECL_OVERRIDE; void drawArraysInstanced(GLenum primitiveType, GLint first, GLsizei count, GLsizei instances) Q_DECL_OVERRIDE; diff --git a/src/render/graphicshelpers/graphicshelperinterface_p.h b/src/render/graphicshelpers/graphicshelperinterface_p.h index 847b2fc9e..1048e1b26 100644 --- a/src/render/graphicshelpers/graphicshelperinterface_p.h +++ b/src/render/graphicshelpers/graphicshelperinterface_p.h @@ -80,7 +80,8 @@ public: Compute, DrawBuffersBlend, BlitFramebuffer, - IndirectDrawing + IndirectDrawing, + MapBuffer }; virtual ~GraphicsHelperInterface() {} @@ -106,6 +107,8 @@ public: virtual void disablei(GLenum cap, GLuint index) = 0; virtual void disablePrimitiveRestart() = 0; virtual void dispatchCompute(GLuint wx, GLuint wy, GLuint wz) = 0; + virtual char *mapBuffer(GLenum target) = 0; + virtual GLboolean unmapBuffer(GLenum target) = 0; virtual void drawArrays(GLenum primitiveType, GLint first, GLsizei count) = 0; virtual void drawArraysIndirect(GLenum mode,void *indirect) = 0; virtual void drawArraysInstanced(GLenum primitiveType, GLint first, GLsizei count, GLsizei instances) = 0; diff --git a/src/render/io/glbuffer.cpp b/src/render/io/glbuffer.cpp index 074868528..4918f9a56 100644 --- a/src/render/io/glbuffer.cpp +++ b/src/render/io/glbuffer.cpp @@ -140,6 +140,18 @@ void GLBuffer::update(GraphicsContext *ctx, const void *data, uint size, int off ctx->openGLContext()->functions()->glBufferSubData(m_lastTarget, offset, size, data); } +QByteArray GLBuffer::download(GraphicsContext *ctx, uint size) +{ + char *gpu_ptr = ctx->mapBuffer(m_lastTarget); + QByteArray data; + if (gpu_ptr != nullptr) { + data.resize(size); + std::copy(gpu_ptr, gpu_ptr+size, data.data()); + } + ctx->unmapBuffer(m_lastTarget); + return data; +} + void GLBuffer::bindBufferBase(GraphicsContext *ctx, int bindingPoint, GLBuffer::Type t) { ctx->bindBufferBase(glBufferTypes[t], bindingPoint, m_bufferId); diff --git a/src/render/io/glbuffer_p.h b/src/render/io/glbuffer_p.h index e800d2bc4..731634b6b 100644 --- a/src/render/io/glbuffer_p.h +++ b/src/render/io/glbuffer_p.h @@ -53,6 +53,7 @@ #include #include +#include QT_BEGIN_NAMESPACE @@ -85,6 +86,7 @@ public: void allocate(GraphicsContext *ctx, uint size, bool dynamic = true); void allocate(GraphicsContext *ctx, const void *data, uint size, bool dynamic = true); void update(GraphicsContext *ctx, const void *data, uint size, int offset = 0); + QByteArray download(GraphicsContext *ctx, uint size); void bindBufferBase(GraphicsContext *ctx, int bindingPoint, Type t); void bindBufferBase(GraphicsContext *ctx, int bindingPoint); diff --git a/src/render/jobs/job_common_p.h b/src/render/jobs/job_common_p.h index 90e29d0dc..eb6df9b93 100644 --- a/src/render/jobs/job_common_p.h +++ b/src/render/jobs/job_common_p.h @@ -89,6 +89,7 @@ namespace JobTypes { DirtyTextureGathering, DirtyShaderGathering, SendRenderCapture, + SendBufferCapture, SyncRenderViewCommandBuilding, SyncRenderViewInitialization, SyncRenderViewCommandBuilder, diff --git a/src/render/jobs/jobs.pri b/src/render/jobs/jobs.pri index d7f05ec4c..010914f88 100644 --- a/src/render/jobs/jobs.pri +++ b/src/render/jobs/jobs.pri @@ -28,7 +28,8 @@ HEADERS += \ $$PWD/updatemeshtrianglelistjob_p.h \ $$PWD/pickboundingvolumeutils_p.h \ $$PWD/filtercompatibletechniquejob_p.h \ - $$PWD/updatetreeenabledjob_p.h + $$PWD/updatetreeenabledjob_p.h \ + $$PWD/sendbuffercapturejob_p.h SOURCES += \ $$PWD/updateworldtransformjob.cpp \ @@ -55,4 +56,6 @@ SOURCES += \ $$PWD/updatelevelofdetailjob.cpp \ $$PWD/pickboundingvolumeutils.cpp \ $$PWD/filtercompatibletechniquejob.cpp \ - $$PWD/updatetreeenabledjob.cpp + $$PWD/updatetreeenabledjob.cpp \ + $$PWD/sendbuffercapturejob.cpp + diff --git a/src/render/jobs/renderviewjobutils.cpp b/src/render/jobs/renderviewjobutils.cpp index e587dd828..f2f0f8388 100644 --- a/src/render/jobs/renderviewjobutils.cpp +++ b/src/render/jobs/renderviewjobutils.cpp @@ -63,6 +63,7 @@ #include #include #include +#include #include #include #include @@ -242,6 +243,14 @@ void setRenderViewConfigFromFrameGraphLeafNode(RenderView *rv, const FrameGraphN break; } + case FrameGraphNode::BufferCapture: { + auto *bufferCapture = const_cast( + static_cast(node)); + if (bufferCapture != nullptr) + rv->setIsDownloadBuffersEnable(bufferCapture->isEnabled()); + break; + } + default: // Should never get here qCWarning(Backend) << "Unhandled FrameGraphNode type"; diff --git a/src/render/jobs/sendbuffercapturejob.cpp b/src/render/jobs/sendbuffercapturejob.cpp new file mode 100644 index 000000000..90d328b96 --- /dev/null +++ b/src/render/jobs/sendbuffercapturejob.cpp @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Juan JosĂ© Casafranca +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "sendbuffercapturejob_p.h" + + +#include "Qt3DRender/private/renderer_p.h" +#include "Qt3DRender/private/nodemanagers_p.h" +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +namespace Render { + +SendBufferCaptureJob::SendBufferCaptureJob(Renderer *renderer) + : Qt3DCore::QAspectJob() + , m_renderer(renderer) +{ + SET_JOB_RUN_STAT_TYPE(this, JobTypes::SendBufferCapture, 0); +} + +SendBufferCaptureJob::~SendBufferCaptureJob() +{ +} + +void SendBufferCaptureJob::setManagers(NodeManagers *managers) +{ + m_managers = managers; +} + +void SendBufferCaptureJob::addRequest(QPair request) +{ + QMutexLocker locker(&m_mutex); + m_pendingSendBufferCaptures.push_back(request); +} + +void SendBufferCaptureJob::run() +{ + QMutexLocker locker(&m_mutex); + for (QPair pendingCapture : m_pendingSendBufferCaptures) { + pendingCapture.first->updateDataFromGPUToCPU(pendingCapture.second); + } + + m_pendingSendBufferCaptures.clear(); +} + +} // Render + +} // Qt3DRender + +QT_END_NAMESPACE diff --git a/src/render/jobs/sendbuffercapturejob_p.h b/src/render/jobs/sendbuffercapturejob_p.h new file mode 100644 index 000000000..9a7f839c7 --- /dev/null +++ b/src/render/jobs/sendbuffercapturejob_p.h @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Juan JosĂ© Casafranca +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3DRENDER_SENDBUFFERCAPTUREJOB_P_H +#define QT3DRENDER_SENDBUFFERCAPTUREJOB_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include +#include + + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +namespace Render { + +class NodeManagers; +class Entity; +class Renderer; +class Buffer; + +class QT3DRENDERSHARED_PRIVATE_EXPORT SendBufferCaptureJob : public Qt3DCore::QAspectJob +{ +public: + explicit SendBufferCaptureJob(Renderer *renderer); + ~SendBufferCaptureJob(); + + void setManagers(NodeManagers *managers); + + void addRequest(QPair request); + + void run() Q_DECL_FINAL; + +private: + Renderer *m_renderer; + NodeManagers *m_managers; + QMutex m_mutex; + + QVector > m_pendingSendBufferCaptures; +}; + +typedef QSharedPointer SendBufferCaptureJobPtr; + +} //Render + +} //Qt3DRender + +QT_END_NAMESPACE + + +#endif // QT3DRENDER_SENDBUFFERCAPTUREJOB_P_H diff --git a/tests/manual/buffercapture-qml/BufferSetterScene.qml b/tests/manual/buffercapture-qml/BufferSetterScene.qml new file mode 100644 index 000000000..37f2858d6 --- /dev/null +++ b/tests/manual/buffercapture-qml/BufferSetterScene.qml @@ -0,0 +1,114 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Juan JosĂ© Casafranca. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.2 as QQ2 +import Qt3D.Core 2.0 +import Qt3D.Render 2.1 +import Qt3D.Input 2.0 +import Qt3D.Extras 2.0 + +Entity { + id: sceneRoot + + Camera { + id: sceneCamera + projectionType: CameraLens.PerspectiveProjection + viewCenter: Qt.vector3d(0, 0, 0) + position: Qt.vector3d(0, 0, -800) + nearPlane: 0.1 + farPlane: 1000 + fieldOfView: 25 + aspectRatio: 1.33 + } + + components: [ + RenderSettings { + ComputeFrameGraph { + } + // explicitly set RenderingPolicy to AlwaysRender, as changes in the + // scene won't be reflected in actual Qt scene-graph changes (due to + // GPU compute calls) + renderPolicy: RenderSettings.Always + } + ] + + function initGraphBuffer() { + var bufferData = new Uint32Array(1024); + for (var i = 0; i < 1024; ++i) { + bufferData[i] = 1; + } + return bufferData + } + + + Buffer { + id: graphBuffer + objectName: "buffer" + type: Buffer.VertexBuffer + data: initGraphBuffer() + access: Buffer.Read + onDataAvailable: access = Buffer.Write + } + + ComputeMaterial { + id: computeMaterial + dataBuffer: graphBuffer + inputSize: 1024 + } + + Entity { + id: particleComputeEntity + readonly property ComputeCommand particlesComputeJob: ComputeCommand {} + components: [ + particlesComputeJob, + computeMaterial + ] + } +} diff --git a/tests/manual/buffercapture-qml/ComputeFrameGraph.qml b/tests/manual/buffercapture-qml/ComputeFrameGraph.qml new file mode 100644 index 000000000..6c510598b --- /dev/null +++ b/tests/manual/buffercapture-qml/ComputeFrameGraph.qml @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Juan JosĂ© Casafranca. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import Qt3D.Core 2.0 +import Qt3D.Render 2.0 + +Viewport { + RenderSurfaceSelector { + id: surfaceSelector + + // Compute Pass + DispatchCompute { + workGroupX: 50; workGroupY: 1; workGroupZ: 1 + BufferCapture { + TechniqueFilter { + matchAll: [ + FilterKey { name: "type"; value: "compute"} + ] + } + } + } + + NoDraw { } + } +} + + diff --git a/tests/manual/buffercapture-qml/ComputeMaterial.qml b/tests/manual/buffercapture-qml/ComputeMaterial.qml new file mode 100644 index 000000000..05c56901c --- /dev/null +++ b/tests/manual/buffercapture-qml/ComputeMaterial.qml @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Juan JosĂ© Casafranca. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import Qt3D.Core 2.0 +import Qt3D.Render 2.0 + +Material { + property Buffer dataBuffer; + property int inputSize; + + parameters: [ + Parameter { name: "inputSize"; value: inputSize} + ] + + ShaderProgram { + id: computeShader + computeShaderCode: loadSource("qrc:/bufferSetter.comp") + } + + effect: Effect { + techniques: [ + Technique { + renderPasses: [ + RenderPass { + shaderProgram: computeShader + // We set the buffer as the parameter data + parameters: [ + Parameter { name: "input"; value: dataBuffer } + ] + } + ] + filterKeys: [ + FilterKey { name: "type"; value: "compute" } + ] + graphicsApiFilter { + api: GraphicsApiFilter.OpenGL + profile: GraphicsApiFilter.CoreProfile + majorVersion: 4 + minorVersion: 3 + } + } + ] // techniques + } +} diff --git a/tests/manual/buffercapture-qml/bufferSetter.comp b/tests/manual/buffercapture-qml/bufferSetter.comp new file mode 100755 index 000000000..4fd99bf33 --- /dev/null +++ b/tests/manual/buffercapture-qml/bufferSetter.comp @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Juan JosĂ© Casafranca. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#version 430 core + +layout (local_size_x=32) in; + +layout (std430, binding = 1) buffer input +{ + uint d[]; +}; + +layout (location=1) uniform int inputSize; + +void main() +{ + if (gl_GlobalInvocationID.x < inputSize) + d[gl_GlobalInvocationID.x] = gl_GlobalInvocationID.x; +} diff --git a/tests/manual/buffercapture-qml/buffercapture-qml.pro b/tests/manual/buffercapture-qml/buffercapture-qml.pro new file mode 100644 index 000000000..32b79a36e --- /dev/null +++ b/tests/manual/buffercapture-qml/buffercapture-qml.pro @@ -0,0 +1,16 @@ +!include( ../manual.pri ) { + error( "Couldn't find the manual.pri file!" ) +} + +QT += 3dcore 3drender 3dinput 3dextras 3dquick 3dlogic qml quick 3dquickextras + +SOURCES += \ + main.cpp + +DISTFILES += \ + main.qml \ + main.qml + +RESOURCES += \ + resources.qrc + diff --git a/tests/manual/buffercapture-qml/main.cpp b/tests/manual/buffercapture-qml/main.cpp new file mode 100644 index 000000000..cb6d6a489 --- /dev/null +++ b/tests/manual/buffercapture-qml/main.cpp @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Juan JosĂ© Casafranca. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include +#include +#include + +#include +#include + + +int main(int argc, char* argv[]) +{ + QGuiApplication app(argc, argv); + QQuickView view; + + view.setSource(QUrl("qrc:/main.qml")); + + + QObject *rootObject = view.rootObject(); + Qt3DRender::QBuffer *buffer = rootObject->findChild("buffer"); + + QObject::connect(buffer, &Qt3DRender::QBuffer::dataChanged, + [=](const QByteArray &bytes) { + //I know I'm receiving int data + const uint *data = reinterpret_cast(bytes.data()); + std::cout << "Data received" << std::endl; + for (uint i = 0; i < 1024; ++i) + std::cout << data[i] << std::endl; + } + ); + + view.show(); + + return app.exec(); +} diff --git a/tests/manual/buffercapture-qml/main.qml b/tests/manual/buffercapture-qml/main.qml new file mode 100644 index 000000000..95859b576 --- /dev/null +++ b/tests/manual/buffercapture-qml/main.qml @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Juan JosĂ© Casafranca. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import Qt3D.Core 2.0 +import Qt3D.Render 2.0 +import QtQuick.Scene3D 2.0 + +Item { + Scene3D { + anchors.fill: parent + BufferSetterScene { + id: scene + } + } +} diff --git a/tests/manual/buffercapture-qml/resources.qrc b/tests/manual/buffercapture-qml/resources.qrc new file mode 100644 index 000000000..167957feb --- /dev/null +++ b/tests/manual/buffercapture-qml/resources.qrc @@ -0,0 +1,9 @@ + + + BufferSetterScene.qml + bufferSetter.comp + main.qml + ComputeFrameGraph.qml + ComputeMaterial.qml + + diff --git a/tests/manual/manual.pro b/tests/manual/manual.pro index c5a218ead..562daa511 100644 --- a/tests/manual/manual.pro +++ b/tests/manual/manual.pro @@ -38,6 +38,7 @@ SUBDIRS += \ rendercapture-qml \ additional-attributes-qml \ dynamic-model-loader-qml \ + buffercapture-qml \ render-qml-to-texture \ render-qml-to-texture-qml \ video-texture-qml \ -- cgit v1.2.3 From ae1a3bee761c29edffc5fdbe7b77140f1620a04a Mon Sep 17 00:00:00 2001 From: Kevin Ottens Date: Mon, 30 Jan 2017 10:31:44 +0100 Subject: QTexturedMetalRoughMaterial: albedo really is baseColor Change-Id: I0e46976e2fa03eb1ad2f77b8c672bcc31c4da973 Reviewed-by: Sean Harmer --- .../defaults/qtexturedmetalroughmaterial.cpp | 38 +++++++++++----------- src/extras/defaults/qtexturedmetalroughmaterial.h | 8 ++--- .../defaults/qtexturedmetalroughmaterial_p.h | 6 ++-- src/extras/shaders/gl3/metalrough.frag | 4 +-- 4 files changed, 28 insertions(+), 28 deletions(-) diff --git a/src/extras/defaults/qtexturedmetalroughmaterial.cpp b/src/extras/defaults/qtexturedmetalroughmaterial.cpp index 25fe5e344..20c54f1c6 100644 --- a/src/extras/defaults/qtexturedmetalroughmaterial.cpp +++ b/src/extras/defaults/qtexturedmetalroughmaterial.cpp @@ -60,14 +60,14 @@ namespace Qt3DExtras { QTexturedMetalRoughMaterialPrivate::QTexturedMetalRoughMaterialPrivate() : QMaterialPrivate() - , m_albedoTexture(new QTexture2D()) + , m_baseColorTexture(new QTexture2D()) , m_metallicTexture(new QTexture2D()) , m_roughnessTexture(new QTexture2D()) , m_ambientOcclusionTexture(new QTexture2D()) , m_normalTexture(new QTexture2D()) , m_environmentIrradianceTexture(new QTexture2D()) , m_environmentSpecularTexture(new QTexture2D()) - , m_albedoParameter(new QParameter(QStringLiteral("albedoMap"), m_albedoTexture)) + , m_baseColorParameter(new QParameter(QStringLiteral("baseColorMap"), m_baseColorTexture)) , m_metallicParameter(new QParameter(QStringLiteral("metallicMap"), m_metallicTexture)) , m_roughnessParameter(new QParameter(QStringLiteral("roughnessMap"), m_roughnessTexture)) , m_ambientOcclusionParameter(new QParameter(QStringLiteral("ambientOcclusionMap"), m_ambientOcclusionTexture)) @@ -81,11 +81,11 @@ QTexturedMetalRoughMaterialPrivate::QTexturedMetalRoughMaterialPrivate() , m_metalRoughGL3Shader(new QShaderProgram()) , m_filterKey(new QFilterKey) { - m_albedoTexture->setMagnificationFilter(QAbstractTexture::Linear); - m_albedoTexture->setMinificationFilter(QAbstractTexture::LinearMipMapLinear); - m_albedoTexture->setWrapMode(QTextureWrapMode(QTextureWrapMode::Repeat)); - m_albedoTexture->setGenerateMipMaps(true); - m_albedoTexture->setMaximumAnisotropy(16.0f); + m_baseColorTexture->setMagnificationFilter(QAbstractTexture::Linear); + m_baseColorTexture->setMinificationFilter(QAbstractTexture::LinearMipMapLinear); + m_baseColorTexture->setWrapMode(QTextureWrapMode(QTextureWrapMode::Repeat)); + m_baseColorTexture->setGenerateMipMaps(true); + m_baseColorTexture->setMaximumAnisotropy(16.0f); m_metallicTexture->setMagnificationFilter(QAbstractTexture::Linear); m_metallicTexture->setMinificationFilter(QAbstractTexture::LinearMipMapLinear); @@ -126,8 +126,8 @@ QTexturedMetalRoughMaterialPrivate::QTexturedMetalRoughMaterialPrivate() void QTexturedMetalRoughMaterialPrivate::init() { - connect(m_albedoParameter, &Qt3DRender::QParameter::valueChanged, - this, &QTexturedMetalRoughMaterialPrivate::handleAlbedoChanged); + connect(m_baseColorParameter, &Qt3DRender::QParameter::valueChanged, + this, &QTexturedMetalRoughMaterialPrivate::handleBaseColorChanged); connect(m_metallicParameter, &Qt3DRender::QParameter::valueChanged, this, &QTexturedMetalRoughMaterialPrivate::handleMetallicChanged); connect(m_roughnessParameter, &Qt3DRender::QParameter::valueChanged, @@ -161,7 +161,7 @@ void QTexturedMetalRoughMaterialPrivate::init() m_metalRoughGL3Technique->addRenderPass(m_metalRoughGL3RenderPass); m_metalRoughEffect->addTechnique(m_metalRoughGL3Technique); - m_metalRoughEffect->addParameter(m_albedoParameter); + m_metalRoughEffect->addParameter(m_baseColorParameter); m_metalRoughEffect->addParameter(m_metallicParameter); m_metalRoughEffect->addParameter(m_roughnessParameter); m_metalRoughEffect->addParameter(m_ambientOcclusionParameter); @@ -173,10 +173,10 @@ void QTexturedMetalRoughMaterialPrivate::init() q->setEffect(m_metalRoughEffect); } -void QTexturedMetalRoughMaterialPrivate::handleAlbedoChanged(const QVariant &var) +void QTexturedMetalRoughMaterialPrivate::handleBaseColorChanged(const QVariant &var) { Q_Q(QTexturedMetalRoughMaterial); - emit q->albedoChanged(var.value()); + emit q->baseColorChanged(var.value()); } void QTexturedMetalRoughMaterialPrivate::handleMetallicChanged(const QVariant &var) @@ -258,11 +258,11 @@ QTexturedMetalRoughMaterial::~QTexturedMetalRoughMaterial() } /*! - \property QTexturedMetalRoughMaterial::albedo + \property QTexturedMetalRoughMaterial::baseColor - Holds the current albedo map texture. + Holds the current base color map texture. - By default, the albedo texture has the following properties: + By default, the base color texture has the following properties: \list \li Linear minification and magnification filters @@ -271,10 +271,10 @@ QTexturedMetalRoughMaterial::~QTexturedMetalRoughMaterial() \li Maximum anisotropy of 16.0 \endlist */ -QAbstractTexture *QTexturedMetalRoughMaterial::albedo() const +QAbstractTexture *QTexturedMetalRoughMaterial::baseColor() const { Q_D(const QTexturedMetalRoughMaterial); - return d->m_albedoParameter->value().value(); + return d->m_baseColorParameter->value().value(); } /*! @@ -407,10 +407,10 @@ float QTexturedMetalRoughMaterial::exposure() const return d->m_exposureParameter->value().toFloat(); } -void QTexturedMetalRoughMaterial::setAlbedo(QAbstractTexture *albedo) +void QTexturedMetalRoughMaterial::setBaseColor(QAbstractTexture *baseColor) { Q_D(QTexturedMetalRoughMaterial); - d->m_albedoParameter->setValue(QVariant::fromValue(albedo)); + d->m_baseColorParameter->setValue(QVariant::fromValue(baseColor)); } void QTexturedMetalRoughMaterial::setMetallic(QAbstractTexture *metallic) diff --git a/src/extras/defaults/qtexturedmetalroughmaterial.h b/src/extras/defaults/qtexturedmetalroughmaterial.h index 755dd3e5a..39a01d960 100644 --- a/src/extras/defaults/qtexturedmetalroughmaterial.h +++ b/src/extras/defaults/qtexturedmetalroughmaterial.h @@ -52,7 +52,7 @@ class QTexturedMetalRoughMaterialPrivate; class QT3DEXTRASSHARED_EXPORT QTexturedMetalRoughMaterial : public Qt3DRender::QMaterial { Q_OBJECT - Q_PROPERTY(Qt3DRender::QAbstractTexture *albedo READ albedo WRITE setAlbedo NOTIFY albedoChanged) + Q_PROPERTY(Qt3DRender::QAbstractTexture *baseColor READ baseColor WRITE setBaseColor NOTIFY baseColorChanged) Q_PROPERTY(Qt3DRender::QAbstractTexture *metallic READ metallic WRITE setMetallic NOTIFY metallicChanged) Q_PROPERTY(Qt3DRender::QAbstractTexture *roughness READ roughness WRITE setRoughness NOTIFY roughnessChanged) Q_PROPERTY(Qt3DRender::QAbstractTexture *ambientOcclusion READ ambientOcclusion WRITE setAmbientOcclusion NOTIFY ambientOcclusionChanged) @@ -65,7 +65,7 @@ public: explicit QTexturedMetalRoughMaterial(Qt3DCore::QNode *parent = nullptr); ~QTexturedMetalRoughMaterial(); - Qt3DRender::QAbstractTexture *albedo() const; + Qt3DRender::QAbstractTexture *baseColor() const; Qt3DRender::QAbstractTexture *metallic() const; Qt3DRender::QAbstractTexture *roughness() const; Qt3DRender::QAbstractTexture *ambientOcclusion() const; @@ -75,7 +75,7 @@ public: float exposure() const; public Q_SLOTS: - void setAlbedo(Qt3DRender::QAbstractTexture *albedo); + void setBaseColor(Qt3DRender::QAbstractTexture *baseColor); void setMetallic(Qt3DRender::QAbstractTexture *metallic); void setRoughness(Qt3DRender::QAbstractTexture *roughness); void setAmbientOcclusion(Qt3DRender::QAbstractTexture *ambientOcclusion); @@ -85,7 +85,7 @@ public Q_SLOTS: void setExposure(float exposure); Q_SIGNALS: - void albedoChanged(Qt3DRender::QAbstractTexture *albedo); + void baseColorChanged(Qt3DRender::QAbstractTexture *baseColor); void metallicChanged(Qt3DRender::QAbstractTexture *metallic); void roughnessChanged(Qt3DRender::QAbstractTexture *roughness); void ambientOcclusionChanged(Qt3DRender::QAbstractTexture *ambientOcclusion); diff --git a/src/extras/defaults/qtexturedmetalroughmaterial_p.h b/src/extras/defaults/qtexturedmetalroughmaterial_p.h index 9a5825efa..84b0e7d77 100644 --- a/src/extras/defaults/qtexturedmetalroughmaterial_p.h +++ b/src/extras/defaults/qtexturedmetalroughmaterial_p.h @@ -78,7 +78,7 @@ public: void init(); - void handleAlbedoChanged(const QVariant &var); + void handleBaseColorChanged(const QVariant &var); void handleMetallicChanged(const QVariant &var); void handleRoughnessChanged(const QVariant &var); void handleAmbientOcclusionChanged(const QVariant &var); @@ -87,14 +87,14 @@ public: void handleEnvironmentSpecularChanged(const QVariant &var); void handleExposureChanged(const QVariant &var); - Qt3DRender::QAbstractTexture *m_albedoTexture; + Qt3DRender::QAbstractTexture *m_baseColorTexture; Qt3DRender::QAbstractTexture *m_metallicTexture; Qt3DRender::QAbstractTexture *m_roughnessTexture; Qt3DRender::QAbstractTexture *m_ambientOcclusionTexture; Qt3DRender::QAbstractTexture *m_normalTexture; Qt3DRender::QAbstractTexture *m_environmentIrradianceTexture; Qt3DRender::QAbstractTexture *m_environmentSpecularTexture; - Qt3DRender::QParameter *m_albedoParameter; + Qt3DRender::QParameter *m_baseColorParameter; Qt3DRender::QParameter *m_metallicParameter; Qt3DRender::QParameter *m_roughnessParameter; Qt3DRender::QParameter *m_ambientOcclusionParameter; diff --git a/src/extras/shaders/gl3/metalrough.frag b/src/extras/shaders/gl3/metalrough.frag index 385bb2db9..ccb1f8297 100644 --- a/src/extras/shaders/gl3/metalrough.frag +++ b/src/extras/shaders/gl3/metalrough.frag @@ -66,7 +66,7 @@ uniform samplerCube skyIrradiance; // For diffuse contribution uniform samplerCube skySpecular; // For specular contribution // PBR Material maps -uniform sampler2D albedoMap; +uniform sampler2D baseColorMap; uniform sampler2D metallicMap; uniform sampler2D roughnessMap; uniform sampler2D normalMap; @@ -216,7 +216,7 @@ void main() vec3 tView = worldToTangentMatrix * wView; // Sample the inputs needed for the metal-roughness PBR BRDF - vec3 baseColor = texture(albedoMap, texCoord).rgb; + vec3 baseColor = texture(baseColorMap, texCoord).rgb; float metallic = texture(metallicMap, texCoord).r * metalFactor; float roughness = texture(roughnessMap, texCoord).r; float ambientOcclusion = texture(ambientOcclusionMap, texCoord).r; -- cgit v1.2.3 From cfb6bf0c53d9f70f12802cb25a1c14327615b756 Mon Sep 17 00:00:00 2001 From: Kevin Ottens Date: Mon, 30 Jan 2017 16:04:06 +0100 Subject: Uniform color PBR lighting to Qt3DExtras Second material using PBR. Still uses environment maps and ignores regular lights but provide a plain color variant of the material. Change-Id: Ica2045826f6efdc804240709154b6822b89f4417 Reviewed-by: Sean Harmer --- src/extras/defaults/defaults.pri | 3 + src/extras/defaults/qmetalroughmaterial.cpp | 328 +++++++++++++++++++++ src/extras/defaults/qmetalroughmaterial.h | 105 +++++++ src/extras/defaults/qmetalroughmaterial_p.h | 110 +++++++ src/extras/extras.qrc | 1 + src/extras/shaders/gl3/metalroughuniform.frag | 217 ++++++++++++++ .../imports/extras/qt3dquick3dextrasplugin.cpp | 2 + 7 files changed, 766 insertions(+) create mode 100644 src/extras/defaults/qmetalroughmaterial.cpp create mode 100644 src/extras/defaults/qmetalroughmaterial.h create mode 100644 src/extras/defaults/qmetalroughmaterial_p.h create mode 100644 src/extras/shaders/gl3/metalroughuniform.frag diff --git a/src/extras/defaults/defaults.pri b/src/extras/defaults/defaults.pri index 58204bd71..cab26cafd 100644 --- a/src/extras/defaults/defaults.pri +++ b/src/extras/defaults/defaults.pri @@ -30,6 +30,8 @@ HEADERS += \ $$PWD/qorbitcameracontroller_p.h \ $$PWD/qtexturematerial.h \ $$PWD/qtexturematerial_p.h \ + $$PWD/qmetalroughmaterial.h \ + $$PWD/qmetalroughmaterial_p.h \ $$PWD/qtexturedmetalroughmaterial.h \ $$PWD/qtexturedmetalroughmaterial_p.h @@ -50,5 +52,6 @@ SOURCES += \ $$PWD/qfirstpersoncameracontroller.cpp \ $$PWD/qorbitcameracontroller.cpp \ $$PWD/qtexturematerial.cpp \ + $$PWD/qmetalroughmaterial.cpp \ $$PWD/qtexturedmetalroughmaterial.cpp diff --git a/src/extras/defaults/qmetalroughmaterial.cpp b/src/extras/defaults/qmetalroughmaterial.cpp new file mode 100644 index 000000000..e895da639 --- /dev/null +++ b/src/extras/defaults/qmetalroughmaterial.cpp @@ -0,0 +1,328 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmetalroughmaterial.h" +#include "qmetalroughmaterial_p.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +using namespace Qt3DRender; + +namespace Qt3DExtras { + +QMetalRoughMaterialPrivate::QMetalRoughMaterialPrivate() + : QMaterialPrivate() + , m_environmentIrradianceTexture(new QTexture2D()) + , m_environmentSpecularTexture(new QTexture2D()) + , m_baseColorParameter(new QParameter(QStringLiteral("baseColor"), QColor("grey"))) + , m_metallicParameter(new QParameter(QStringLiteral("metallic"), 0.0f)) + , m_roughnessParameter(new QParameter(QStringLiteral("roughness"), 0.0f)) + , m_environmentIrradianceParameter(new QParameter(QStringLiteral("skyIrradiance"), m_environmentIrradianceTexture)) + , m_environmentSpecularParameter(new QParameter(QStringLiteral("skySpecular"), m_environmentSpecularTexture)) + , m_exposureParameter(new QParameter(QStringLiteral("exposure"), 0.0f)) + , m_metalRoughEffect(new QEffect()) + , m_metalRoughGL3Technique(new QTechnique()) + , m_metalRoughGL3RenderPass(new QRenderPass()) + , m_metalRoughGL3Shader(new QShaderProgram()) + , m_filterKey(new QFilterKey) +{ + m_environmentIrradianceTexture->setMagnificationFilter(QAbstractTexture::Linear); + m_environmentIrradianceTexture->setMinificationFilter(QAbstractTexture::LinearMipMapLinear); + m_environmentIrradianceTexture->setWrapMode(QTextureWrapMode(QTextureWrapMode::Repeat)); + m_environmentIrradianceTexture->setGenerateMipMaps(true); + m_environmentIrradianceTexture->setMaximumAnisotropy(16.0f); + + m_environmentSpecularTexture->setMagnificationFilter(QAbstractTexture::Linear); + m_environmentSpecularTexture->setMinificationFilter(QAbstractTexture::LinearMipMapLinear); + m_environmentSpecularTexture->setWrapMode(QTextureWrapMode(QTextureWrapMode::Repeat)); + m_environmentSpecularTexture->setGenerateMipMaps(true); + m_environmentSpecularTexture->setMaximumAnisotropy(16.0f); +} + +void QMetalRoughMaterialPrivate::init() +{ + connect(m_baseColorParameter, &Qt3DRender::QParameter::valueChanged, + this, &QMetalRoughMaterialPrivate::handleBaseColorChanged); + connect(m_metallicParameter, &Qt3DRender::QParameter::valueChanged, + this, &QMetalRoughMaterialPrivate::handleMetallicChanged); + connect(m_roughnessParameter, &Qt3DRender::QParameter::valueChanged, + this, &QMetalRoughMaterialPrivate::handleRoughnessChanged); + connect(m_environmentIrradianceParameter, &Qt3DRender::QParameter::valueChanged, + this, &QMetalRoughMaterialPrivate::handleEnvironmentIrradianceChanged); + connect(m_environmentSpecularParameter, &Qt3DRender::QParameter::valueChanged, + this, &QMetalRoughMaterialPrivate::handleEnvironmentSpecularChanged); + connect(m_exposureParameter, &Qt3DRender::QParameter::valueChanged, + this, &QMetalRoughMaterialPrivate::handleExposureChanged); + + m_metalRoughGL3Shader->setVertexShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/gl3/metalrough.vert")))); + m_metalRoughGL3Shader->setFragmentShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/gl3/metalroughuniform.frag")))); + + m_metalRoughGL3Technique->graphicsApiFilter()->setApi(QGraphicsApiFilter::OpenGL); + m_metalRoughGL3Technique->graphicsApiFilter()->setMajorVersion(3); + m_metalRoughGL3Technique->graphicsApiFilter()->setMinorVersion(1); + m_metalRoughGL3Technique->graphicsApiFilter()->setProfile(QGraphicsApiFilter::CoreProfile); + + Q_Q(QMetalRoughMaterial); + m_filterKey->setParent(q); + m_filterKey->setName(QStringLiteral("renderingStyle")); + m_filterKey->setValue(QStringLiteral("forward")); + + m_metalRoughGL3Technique->addFilterKey(m_filterKey); + m_metalRoughGL3RenderPass->setShaderProgram(m_metalRoughGL3Shader); + m_metalRoughGL3Technique->addRenderPass(m_metalRoughGL3RenderPass); + m_metalRoughEffect->addTechnique(m_metalRoughGL3Technique); + + m_metalRoughEffect->addParameter(m_baseColorParameter); + m_metalRoughEffect->addParameter(m_metallicParameter); + m_metalRoughEffect->addParameter(m_roughnessParameter); + m_metalRoughEffect->addParameter(m_environmentIrradianceParameter); + m_metalRoughEffect->addParameter(m_environmentSpecularParameter); + m_metalRoughEffect->addParameter(m_exposureParameter); + + q->setEffect(m_metalRoughEffect); +} + +void QMetalRoughMaterialPrivate::handleBaseColorChanged(const QVariant &var) +{ + Q_Q(QMetalRoughMaterial); + emit q->baseColorChanged(var.value()); +} + +void QMetalRoughMaterialPrivate::handleMetallicChanged(const QVariant &var) +{ + Q_Q(QMetalRoughMaterial); + emit q->metallicChanged(var.toFloat()); +} +void QMetalRoughMaterialPrivate::handleRoughnessChanged(const QVariant &var) +{ + Q_Q(QMetalRoughMaterial); + emit q->roughnessChanged(var.toFloat()); +} + +void QMetalRoughMaterialPrivate::handleEnvironmentIrradianceChanged(const QVariant &var) +{ + Q_Q(QMetalRoughMaterial); + emit q->environmentIrradianceChanged(var.value()); +} + +void QMetalRoughMaterialPrivate::handleEnvironmentSpecularChanged(const QVariant &var) +{ + Q_Q(QMetalRoughMaterial); + emit q->environmentSpecularChanged(var.value()); +} + +void QMetalRoughMaterialPrivate::handleExposureChanged(const QVariant &var) +{ + Q_Q(QMetalRoughMaterial); + emit q->exposureChanged(var.toFloat()); +} + +/*! + \class Qt3DExtras::QMetalRoughMaterial + \brief The QMetalRoughMaterial provides a default implementation of PBR + lighting. + \inmodule Qt3DExtras + \since 5.9 + \inherits Qt3DRender::QMaterial + + This material uses an effect with a single render pass approach and performs per fragment + lighting. Techniques are provided for OpenGL 3 only. +*/ + +/*! + Constructs a new QMetalRoughMaterial instance with parent object \a parent. +*/ +QMetalRoughMaterial::QMetalRoughMaterial(QNode *parent) + : QMaterial(*new QMetalRoughMaterialPrivate, parent) +{ + Q_D(QMetalRoughMaterial); + d->init(); +} + +/*! \internal */ +QMetalRoughMaterial::QMetalRoughMaterial(QMetalRoughMaterialPrivate &dd, QNode *parent) + : QMaterial(dd, parent) +{ + Q_D(QMetalRoughMaterial); + d->init(); +} + +/*! + Destroys the QMetalRoughMaterial instance. +*/ +QMetalRoughMaterial::~QMetalRoughMaterial() +{ +} + +/*! + \property QMetalRoughMaterial::baseColor + + Holds the current base color of the material. +*/ +QColor QMetalRoughMaterial::baseColor() const +{ + Q_D(const QMetalRoughMaterial); + return d->m_baseColorParameter->value().value(); +} + +/*! + \property QMetalRoughMaterial::metallic + + Holds the current metallic level of the material, since is a value between 0 (purely dielectric, the default) + and 1 (purely metallic). +*/ +float QMetalRoughMaterial::metallic() const +{ + Q_D(const QMetalRoughMaterial); + return d->m_metallicParameter->value().toFloat(); +} + +/*! + \property QMetalRoughMaterial::roughness + + Holds the current roughness level of the material. +*/ +float QMetalRoughMaterial::roughness() const +{ + Q_D(const QMetalRoughMaterial); + return d->m_roughnessParameter->value().toFloat(); +} + +/*! + \property QMetalRoughMaterial::environmentIrradiance + + Holds the current environment irradiance map texture. + + By default, the environment irradiance texture has the following properties: + + \list + \li Linear minification and magnification filters + \li Linear mipmap with mipmapping enabled + \li Repeat wrap mode + \li Maximum anisotropy of 16.0 + \endlist +*/ +QAbstractTexture *QMetalRoughMaterial::environmentIrradiance() const +{ + Q_D(const QMetalRoughMaterial); + return d->m_environmentIrradianceParameter->value().value(); +} + +/*! + \property QMetalRoughMaterial::environmentSpecular + + Holds the current environment specular map texture. + + By default, the environment specular texture has the following properties: + + \list + \li Linear minification and magnification filters + \li Linear mipmap with mipmapping enabled + \li Repeat wrap mode + \li Maximum anisotropy of 16.0 + \endlist +*/ +QAbstractTexture *QMetalRoughMaterial::environmentSpecular() const +{ + Q_D(const QMetalRoughMaterial); + return d->m_environmentSpecularParameter->value().value(); +} + +/*! + \property QMetalRoughMaterial::exposure + + Holds the current exposure as a float value. +*/ +float QMetalRoughMaterial::exposure() const +{ + Q_D(const QMetalRoughMaterial); + return d->m_exposureParameter->value().toFloat(); +} + +void QMetalRoughMaterial::setBaseColor(const QColor &baseColor) +{ + Q_D(QMetalRoughMaterial); + d->m_baseColorParameter->setValue(QVariant::fromValue(baseColor)); +} + +void QMetalRoughMaterial::setMetallic(float metallic) +{ + Q_D(QMetalRoughMaterial); + d->m_metallicParameter->setValue(QVariant::fromValue(metallic)); +} + +void QMetalRoughMaterial::setRoughness(float roughness) +{ + Q_D(QMetalRoughMaterial); + d->m_roughnessParameter->setValue(QVariant::fromValue(roughness)); +} + +void QMetalRoughMaterial::setEnvironmentIrradiance(QAbstractTexture *environmentIrradiance) +{ + Q_D(QMetalRoughMaterial); + d->m_environmentIrradianceParameter->setValue(QVariant::fromValue(environmentIrradiance)); +} + +void QMetalRoughMaterial::setEnvironmentSpecular(QAbstractTexture *environmentSpecular) +{ + Q_D(QMetalRoughMaterial); + d->m_environmentSpecularParameter->setValue(QVariant::fromValue(environmentSpecular)); +} + +void QMetalRoughMaterial::setExposure(float exposure) +{ + Q_D(QMetalRoughMaterial); + d->m_exposureParameter->setValue(exposure); +} + +} // namespace Qt3DExtras + +QT_END_NAMESPACE diff --git a/src/extras/defaults/qmetalroughmaterial.h b/src/extras/defaults/qmetalroughmaterial.h new file mode 100644 index 000000000..914cef6ca --- /dev/null +++ b/src/extras/defaults/qmetalroughmaterial.h @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3DEXTRAS_QMETALROUGHMATERIAL_H +#define QT3DEXTRAS_QMETALROUGHMATERIAL_H + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { +class QAbstractTexture; +} + +namespace Qt3DExtras { + +class QMetalRoughMaterialPrivate; + +class QT3DEXTRASSHARED_EXPORT QMetalRoughMaterial : public Qt3DRender::QMaterial +{ + Q_OBJECT + Q_PROPERTY(QColor baseColor READ baseColor WRITE setBaseColor NOTIFY baseColorChanged) + Q_PROPERTY(float metallic READ metallic WRITE setMetallic NOTIFY metallicChanged) + Q_PROPERTY(float roughness READ roughness WRITE setRoughness NOTIFY roughnessChanged) + Q_PROPERTY(Qt3DRender::QAbstractTexture *environmentIrradiance READ environmentIrradiance WRITE setEnvironmentIrradiance NOTIFY environmentIrradianceChanged) + Q_PROPERTY(Qt3DRender::QAbstractTexture *environmentSpecular READ environmentSpecular WRITE setEnvironmentSpecular NOTIFY environmentSpecularChanged) + Q_PROPERTY(float exposure READ exposure WRITE setExposure NOTIFY exposureChanged) + +public: + explicit QMetalRoughMaterial(Qt3DCore::QNode *parent = nullptr); + ~QMetalRoughMaterial(); + + QColor baseColor() const; + float metallic() const; + float roughness() const; + Qt3DRender::QAbstractTexture *environmentIrradiance() const; + Qt3DRender::QAbstractTexture *environmentSpecular() const; + float exposure() const; + +public Q_SLOTS: + void setBaseColor(const QColor &baseColor); + void setMetallic(float metallic); + void setRoughness(float roughness); + void setEnvironmentIrradiance(Qt3DRender::QAbstractTexture *environmentIrradiance); + void setEnvironmentSpecular(Qt3DRender::QAbstractTexture *environmentSpecular); + void setExposure(float exposure); + +Q_SIGNALS: + void baseColorChanged(const QColor &baseColor); + void metallicChanged(float metallic); + void roughnessChanged(float roughness); + void environmentIrradianceChanged(Qt3DRender::QAbstractTexture *environmentIrradiance); + void environmentSpecularChanged(Qt3DRender::QAbstractTexture *environmentSpecular); + void exposureChanged(float exposure); + +protected: + QMetalRoughMaterial(QMetalRoughMaterialPrivate &dd, Qt3DCore::QNode *parent = nullptr); + +private: + Q_DECLARE_PRIVATE(QMetalRoughMaterial) +}; + +} // namespace Qt3DExtras + +QT_END_NAMESPACE + +#endif // QT3DEXTRAS_QMETALROUGHMATERIAL_H diff --git a/src/extras/defaults/qmetalroughmaterial_p.h b/src/extras/defaults/qmetalroughmaterial_p.h new file mode 100644 index 000000000..d287f0093 --- /dev/null +++ b/src/extras/defaults/qmetalroughmaterial_p.h @@ -0,0 +1,110 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3DEXTRAS_QMETALROUGHMATERIAL_P_H +#define QT3DEXTRAS_QMETALROUGHMATERIAL_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +class QFilterKey; +class QEffect; +class QAbstractTexture; +class QTechnique; +class QParameter; +class QShaderProgram; +class QRenderPass; + +} // namespace Qt3DRender + +namespace Qt3DExtras { + +class QMetalRoughMaterial; + +class QMetalRoughMaterialPrivate : public Qt3DRender::QMaterialPrivate +{ +public: + QMetalRoughMaterialPrivate(); + + void init(); + + void handleBaseColorChanged(const QVariant &var); + void handleMetallicChanged(const QVariant &var); + void handleRoughnessChanged(const QVariant &var); + void handleEnvironmentIrradianceChanged(const QVariant &var); + void handleEnvironmentSpecularChanged(const QVariant &var); + void handleExposureChanged(const QVariant &var); + + Qt3DRender::QAbstractTexture *m_environmentIrradianceTexture; + Qt3DRender::QAbstractTexture *m_environmentSpecularTexture; + Qt3DRender::QParameter *m_baseColorParameter; + Qt3DRender::QParameter *m_metallicParameter; + Qt3DRender::QParameter *m_roughnessParameter; + Qt3DRender::QParameter *m_environmentIrradianceParameter; + Qt3DRender::QParameter *m_environmentSpecularParameter; + Qt3DRender::QParameter *m_exposureParameter; + Qt3DRender::QEffect *m_metalRoughEffect; + Qt3DRender::QTechnique *m_metalRoughGL3Technique; + Qt3DRender::QRenderPass *m_metalRoughGL3RenderPass; + Qt3DRender::QShaderProgram *m_metalRoughGL3Shader; + Qt3DRender::QFilterKey *m_filterKey; + + Q_DECLARE_PUBLIC(QMetalRoughMaterial) +}; + +} // Qt3DExtras + +QT_END_NAMESPACE + +#endif // QT3DEXTRAS_QMETALROUGHMATERIAL_P_H + diff --git a/src/extras/extras.qrc b/src/extras/extras.qrc index 04437d599..133955e7d 100644 --- a/src/extras/extras.qrc +++ b/src/extras/extras.qrc @@ -41,6 +41,7 @@ shaders/es2/unlittexture.vert shaders/gl3/metalrough.vert shaders/gl3/metalrough.frag + shaders/gl3/metalroughuniform.frag shaders/gl3/distancefieldtext.vert shaders/gl3/distancefieldtext.frag shaders/es2/distancefieldtext.frag diff --git a/src/extras/shaders/gl3/metalroughuniform.frag b/src/extras/shaders/gl3/metalroughuniform.frag new file mode 100644 index 000000000..dfc174e8b --- /dev/null +++ b/src/extras/shaders/gl3/metalroughuniform.frag @@ -0,0 +1,217 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#version 150 + +in vec2 texCoord; +in vec3 worldPosition; +in vec3 worldNormal; +in vec4 worldTangent; + +out vec4 fragColor; + +// Qt 3D built in uniforms +uniform vec3 eyePosition; // World space eye position +uniform float time; // Time in seconds + +// Pre-convolved environment maps +uniform samplerCube skyIrradiance; // For diffuse contribution +uniform samplerCube skySpecular; // For specular contribution + +// PBR Material maps +uniform vec4 baseColor; +uniform float metallic; +uniform float roughness; + +// Roughness -> mip level mapping +uniform float maxT = 0.939824; +uniform float mipLevels = 11.0; +uniform float mipOffset = 5.0; + +// Exposure correction +uniform float exposure = 0.0; + +mat3 calcWorldSpaceToTangentSpaceMatrix(const in vec3 wNormal, const in vec4 wTangent) +{ + // Make the tangent truly orthogonal to the normal by using Gram-Schmidt. + // This allows to build the tangentMatrix below by simply transposing the + // tangent -> eyespace matrix (which would now be orthogonal) + vec3 wFixedTangent = normalize(wTangent.xyz - dot(wTangent.xyz, wNormal) * wNormal); + + // Calculate binormal vector. No "real" need to renormalize it, + // as built by crossing two normal vectors. + // To orient the binormal correctly, use the fourth coordinate of the tangent, + // which is +1 for a right hand system, and -1 for a left hand system. + vec3 wBinormal = cross(wNormal, wFixedTangent.xyz) * wTangent.w; + + // Construct matrix to transform from world space to tangent space + // This is the transpose of the tangentToWorld transformation matrix + mat3 tangentToWorldMatrix = mat3(wFixedTangent, wBinormal, wNormal); + mat3 worldToTangentMatrix = transpose(tangentToWorldMatrix); + return worldToTangentMatrix; +} + +float roughnessToMipLevel(float roughness) +{ + // HACK: Improve the roughness -> mip level mapping for roughness map from substace painter + // TODO: Use mathematica or similar to improve this mapping more generally + roughness = 0.75 + (1.7 * (roughness - 0.5)); + return (mipLevels - 1.0 - mipOffset) * (1.0 - (1.0 - roughness) / maxT); +} + +vec3 fresnelFactor(const in vec3 color, const in float cosineFactor) +{ + // Calculate the Fresnel effect value + vec3 f = color; + vec3 F = f + (1.0 - f) * pow(1.0 - cosineFactor, 5.0); + return clamp(F, f, vec3(1.0)); +} + +float geometricModel(const in float lDotN, + const in float vDotN, + const in vec3 h) +{ + // Implicit geometric model (equal to denominator in specular model). + // This currently assumes that there is no attenuation by geometric shadowing or + // masking according to the microfacet theory. + return 1.0; +} + +vec3 specularModel(const in vec3 F0, + const in float lDotH, + const in float lDotN, + const in float vDotN, + const in vec3 n, + const in vec3 h) +{ + // Clamp lDotN and vDotN to small positive value to prevent the + // denominator in the reflection equation going to infinity. Balance this + // by using the clamped values in the geometric factor function to + // avoid ugly seams in the specular lighting. + float sDotNPrime = max(lDotN, 0.001); + float vDotNPrime = max(vDotN, 0.001); + + vec3 F = fresnelFactor(F0, lDotH); + float G = geometricModel(sDotNPrime, vDotNPrime, h); + + // TODO: Verify which parts of the BRDF Lys is preconvolving and multiply + // by the remaining factors here. + vec3 cSpec = F * G / (4.0 * sDotNPrime * vDotNPrime); + return clamp(cSpec, vec3(0.0), vec3(1.0)); +} + +vec3 pbrIblModel(const in vec3 wNormal, + const in vec3 wView, + const in vec3 baseColor, + const in float metallic, + const in float roughness) +{ + // Calculate reflection direction of view vector about surface normal + // vector in world space. This is used in the fragment shader to sample + // from the environment textures for a light source. This is equivalent + // to the l vector for punctual light sources. Armed with this, calculate + // the usual factors needed + vec3 n = wNormal; + vec3 l = reflect(-wView, n); + vec3 v = wView; + vec3 h = normalize(l + v); + float vDotN = dot(v, n); + float lDotN = dot(l, n); + float lDotH = dot(l, h); + + // Calculate diffuse component + vec3 diffuseColor = (1.0 - metallic) * baseColor; + vec3 diffuse = diffuseColor * texture(skyIrradiance, l).rgb; + + // Calculate specular component + vec3 dielectricColor = vec3(0.04); + vec3 F0 = mix(dielectricColor, baseColor, metallic); + vec3 specularFactor = specularModel(F0, lDotH, lDotN, vDotN, n, h); + + float lod = roughnessToMipLevel(roughness); + vec3 specularSkyColor = textureLod(skySpecular, l, lod).rgb; + vec3 specular = specularSkyColor * specularFactor; + + // Blend between diffuse and specular to conserve energy + vec3 iblColor = specular + diffuse * (vec3(1.0) - specularFactor); + + // Apply exposure correction + iblColor *= pow(2.0, exposure); + + return iblColor; +} + +vec3 toneMap(const in vec3 c) +{ + return c / (c + vec3(1.0)); +} + +vec3 gammaCorrect(const in vec3 color) +{ + const float gamma = 1.0 / 2.2; + return pow(color, vec3(gamma)); +} + +void main() +{ + vec3 worldView = normalize(eyePosition - worldPosition); + vec3 cLinear = pbrIblModel(worldNormal, + worldView, + baseColor.rgb, + metallic, + roughness); + + // Apply simple (Reinhard) tonemap transform to get into LDR range [0, 1] + vec3 cToneMapped = toneMap(cLinear); + + // Apply gamma correction prior to display + vec3 cGamma = gammaCorrect(cToneMapped); + fragColor = vec4(cGamma, 1.0); +} diff --git a/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp b/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp index ffa6be945..1edde1e19 100644 --- a/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp +++ b/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp @@ -46,6 +46,7 @@ #include #include #include +#include #include #include #include @@ -99,6 +100,7 @@ void Qt3DQuick3DExtrasPlugin::registerTypes(const char *uri) qmlRegisterType(uri, 2, 0, "PerVertexColorMaterial"); qmlRegisterType(uri, 2, 0, "GoochMaterial"); qmlRegisterType(uri, 2, 0, "TextureMaterial"); + qmlRegisterType(uri, 2, 2, "MetalRoughMaterial"); qmlRegisterType(uri, 2, 2, "TexturedMetalRoughMaterial"); // Meshes -- cgit v1.2.3 From 90f1063a1e090a03bb45826d1229fc9179484f9b Mon Sep 17 00:00:00 2001 From: Kevin Ottens Date: Mon, 30 Jan 2017 16:25:04 +0100 Subject: Updating Qt3D.Extras qmltypes Change-Id: I2adc3e518ce9c6e5cdaac26638f8f9164f505e34 Reviewed-by: Sean Harmer --- src/quick3d/imports/extras/plugins.qmltypes | 162 ++++++++++++++++++++++++++++ 1 file changed, 162 insertions(+) diff --git a/src/quick3d/imports/extras/plugins.qmltypes b/src/quick3d/imports/extras/plugins.qmltypes index e6cff3ab8..843c9802b 100644 --- a/src/quick3d/imports/extras/plugins.qmltypes +++ b/src/quick3d/imports/extras/plugins.qmltypes @@ -730,6 +730,78 @@ Module { Parameter { name: "shininess"; type: "float" } } } + Component { + name: "Qt3DExtras::QMetalRoughMaterial" + prototype: "Qt3DRender::QMaterial" + exports: ["Qt3D.Extras/MetalRoughMaterial 2.2"] + exportMetaObjectRevisions: [0] + Property { name: "baseColor"; type: "QColor" } + Property { name: "metallic"; type: "float" } + Property { name: "roughness"; type: "float" } + Property { + name: "environmentIrradiance" + type: "Qt3DRender::QAbstractTexture" + isPointer: true + } + Property { name: "environmentSpecular"; type: "Qt3DRender::QAbstractTexture"; isPointer: true } + Property { name: "exposure"; type: "float" } + Signal { + name: "baseColorChanged" + Parameter { name: "baseColor"; type: "QColor" } + } + Signal { + name: "metallicChanged" + Parameter { name: "metallic"; type: "float" } + } + Signal { + name: "roughnessChanged" + Parameter { name: "roughness"; type: "float" } + } + Signal { + name: "environmentIrradianceChanged" + Parameter { + name: "environmentIrradiance" + type: "Qt3DRender::QAbstractTexture" + isPointer: true + } + } + Signal { + name: "environmentSpecularChanged" + Parameter { name: "environmentSpecular"; type: "Qt3DRender::QAbstractTexture"; isPointer: true } + } + Signal { + name: "exposureChanged" + Parameter { name: "exposure"; type: "float" } + } + Method { + name: "setBaseColor" + Parameter { name: "baseColor"; type: "QColor" } + } + Method { + name: "setMetallic" + Parameter { name: "metallic"; type: "float" } + } + Method { + name: "setRoughness" + Parameter { name: "roughness"; type: "float" } + } + Method { + name: "setEnvironmentIrradiance" + Parameter { + name: "environmentIrradiance" + type: "Qt3DRender::QAbstractTexture" + isPointer: true + } + } + Method { + name: "setEnvironmentSpecular" + Parameter { name: "environmentSpecular"; type: "Qt3DRender::QAbstractTexture"; isPointer: true } + } + Method { + name: "setExposure" + Parameter { name: "exposure"; type: "float" } + } + } Component { name: "Qt3DExtras::QNormalDiffuseMapAlphaMaterial" prototype: "Qt3DExtras::QNormalDiffuseMapMaterial" @@ -1371,6 +1443,96 @@ Module { Parameter { name: "textureOffset"; type: "QVector2D" } } } + Component { + name: "Qt3DExtras::QTexturedMetalRoughMaterial" + prototype: "Qt3DRender::QMaterial" + exports: ["Qt3D.Extras/TexturedMetalRoughMaterial 2.2"] + exportMetaObjectRevisions: [0] + Property { name: "baseColor"; type: "Qt3DRender::QAbstractTexture"; isPointer: true } + Property { name: "metallic"; type: "Qt3DRender::QAbstractTexture"; isPointer: true } + Property { name: "roughness"; type: "Qt3DRender::QAbstractTexture"; isPointer: true } + Property { name: "ambientOcclusion"; type: "Qt3DRender::QAbstractTexture"; isPointer: true } + Property { name: "normal"; type: "Qt3DRender::QAbstractTexture"; isPointer: true } + Property { + name: "environmentIrradiance" + type: "Qt3DRender::QAbstractTexture" + isPointer: true + } + Property { name: "environmentSpecular"; type: "Qt3DRender::QAbstractTexture"; isPointer: true } + Property { name: "exposure"; type: "float" } + Signal { + name: "baseColorChanged" + Parameter { name: "baseColor"; type: "Qt3DRender::QAbstractTexture"; isPointer: true } + } + Signal { + name: "metallicChanged" + Parameter { name: "metallic"; type: "Qt3DRender::QAbstractTexture"; isPointer: true } + } + Signal { + name: "roughnessChanged" + Parameter { name: "roughness"; type: "Qt3DRender::QAbstractTexture"; isPointer: true } + } + Signal { + name: "ambientOcclusionChanged" + Parameter { name: "ambientOcclusion"; type: "Qt3DRender::QAbstractTexture"; isPointer: true } + } + Signal { + name: "normalChanged" + Parameter { name: "normal"; type: "Qt3DRender::QAbstractTexture"; isPointer: true } + } + Signal { + name: "environmentIrradianceChanged" + Parameter { + name: "environmentIrradiance" + type: "Qt3DRender::QAbstractTexture" + isPointer: true + } + } + Signal { + name: "environmentSpecularChanged" + Parameter { name: "environmentSpecular"; type: "Qt3DRender::QAbstractTexture"; isPointer: true } + } + Signal { + name: "exposureChanged" + Parameter { name: "exposure"; type: "float" } + } + Method { + name: "setBaseColor" + Parameter { name: "baseColor"; type: "Qt3DRender::QAbstractTexture"; isPointer: true } + } + Method { + name: "setMetallic" + Parameter { name: "metallic"; type: "Qt3DRender::QAbstractTexture"; isPointer: true } + } + Method { + name: "setRoughness" + Parameter { name: "roughness"; type: "Qt3DRender::QAbstractTexture"; isPointer: true } + } + Method { + name: "setAmbientOcclusion" + Parameter { name: "ambientOcclusion"; type: "Qt3DRender::QAbstractTexture"; isPointer: true } + } + Method { + name: "setNormal" + Parameter { name: "normal"; type: "Qt3DRender::QAbstractTexture"; isPointer: true } + } + Method { + name: "setEnvironmentIrradiance" + Parameter { + name: "environmentIrradiance" + type: "Qt3DRender::QAbstractTexture" + isPointer: true + } + } + Method { + name: "setEnvironmentSpecular" + Parameter { name: "environmentSpecular"; type: "Qt3DRender::QAbstractTexture"; isPointer: true } + } + Method { + name: "setExposure" + Parameter { name: "exposure"; type: "float" } + } + } Component { name: "Qt3DExtras::QTorusGeometry" prototype: "Qt3DRender::QGeometry" -- cgit v1.2.3 From 26b1dd88d374b17314218584487a383e3d558018 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Tue, 31 Jan 2017 11:05:10 +0200 Subject: Remove renderOnce from video-texture test Vestiges of renderPolicy change. Change-Id: Ic42efda4d541ebc72b6abb55a9746fae8c41eff3 Reviewed-by: Sean Harmer --- tests/manual/video-texture-qml/main.qml | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/manual/video-texture-qml/main.qml b/tests/manual/video-texture-qml/main.qml index 55b2329eb..4e72ab45f 100644 --- a/tests/manual/video-texture-qml/main.qml +++ b/tests/manual/video-texture-qml/main.qml @@ -59,7 +59,6 @@ Entity { } Scene2D { - renderOnce: false output: RenderTargetOutput { attachmentPoint: RenderTargetOutput.Color0 texture: Texture2D { -- cgit v1.2.3 From c35f8e7c5f573fcc89b3042157d5843d9322ac90 Mon Sep 17 00:00:00 2001 From: Paul Lemire Date: Tue, 31 Jan 2017 11:57:02 +0100 Subject: BlendedAnimations: allow nested blending nodes evaluation Change-Id: Ic6a70ee57f56dff7406b5917d620ea15b74ecb44 Reviewed-by: Sean Harmer --- src/animation/backend/animationutils_p.h | 9 +- src/animation/backend/blendedclipanimator.cpp | 7 +- src/animation/backend/blendedclipanimator_p.h | 21 ++- src/animation/backend/buildblendtreesjob.cpp | 200 ++++++++++++++------- src/animation/backend/clipblendnodevisitor.cpp | 3 +- .../backend/evaluateblendclipanimatorjob.cpp | 175 ++++++++++++------ .../backend/evaluateblendclipanimatorjob_p.h | 11 ++ src/animation/backend/handler.cpp | 2 + src/animation/backend/handler_p.h | 7 +- src/animation/frontend/qblendedclipanimator.cpp | 25 +++ .../tst_blendedclipanimator.cpp | 5 - .../tst_clipblendnodevisitor.cpp | 11 +- 12 files changed, 337 insertions(+), 139 deletions(-) diff --git a/src/animation/backend/animationutils_p.h b/src/animation/backend/animationutils_p.h index e89dd5d6f..061d09261 100644 --- a/src/animation/backend/animationutils_p.h +++ b/src/animation/backend/animationutils_p.h @@ -65,7 +65,8 @@ class ChannelMapper; class Q_AUTOTEST_EXPORT AnimationUtils { public: - struct MappingData { + struct MappingData + { Qt3DCore::QNodeId targetId; const char *propertyName; int type; @@ -73,10 +74,8 @@ public: QVector channelIndices; }; - struct BlendingMappingData { - Qt3DCore::QNodeId targetId; - const char *propertyName; - int type; + struct BlendingMappingData : public MappingData + { QVector channelIndicesClip1; QVector channelIndicesClip2; diff --git a/src/animation/backend/blendedclipanimator.cpp b/src/animation/backend/blendedclipanimator.cpp index 1cb774f72..e2e58c8de 100644 --- a/src/animation/backend/blendedclipanimator.cpp +++ b/src/animation/backend/blendedclipanimator.cpp @@ -74,7 +74,7 @@ void BlendedClipAnimator::cleanup() m_startGlobalTime = 0; m_currentLoop = 0; m_loops = 1; - m_mappingData.clear(); + m_blendTreeTable.clear(); } void BlendedClipAnimator::setBlendTreeRootId(Qt3DCore::QNodeId blendTreeId) @@ -95,11 +95,6 @@ void BlendedClipAnimator::setRunning(bool running) setDirty(Handler::BlendedClipAnimatorDirty); } -void BlendedClipAnimator::setMappingData(const QVector mappingData) -{ - m_mappingData = mappingData; -} - void BlendedClipAnimator::sendPropertyChanges(const QVector &changes) { for (const Qt3DCore::QSceneChangePtr &change : changes) diff --git a/src/animation/backend/blendedclipanimator_p.h b/src/animation/backend/blendedclipanimator_p.h index d0db13e53..d83f8458e 100644 --- a/src/animation/backend/blendedclipanimator_p.h +++ b/src/animation/backend/blendedclipanimator_p.h @@ -77,9 +77,6 @@ public: void setMapperId(Qt3DCore::QNodeId mapperId); void setRunning(bool running); - void setMappingData(const QVector mappingData); - QVector mappingData() const { return m_mappingData; } - void setStartTime(qint64 globalTime) { m_startGlobalTime = globalTime; } qint64 startTime() const { return m_startGlobalTime; } @@ -90,6 +87,22 @@ public: void sendPropertyChanges(const QVector &changes); + struct BlendNodeData + { + Qt3DCore::QNodeId blendNodeId; + enum ChildType { + ClipType, + BlendNodeType + }; + ChildType type; + Qt3DCore::QNodeId left; + Qt3DCore::QNodeId right; + QVector mappingData; + }; + + void setBlendTreeTable(const QHash &blendTreeTable) { m_blendTreeTable = blendTreeTable; } + QHash blendTreeTable() const { return m_blendTreeTable; } + private: void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL; Qt3DCore::QNodeId m_blendTreeRootId; @@ -97,9 +110,9 @@ private: bool m_running; qint64 m_startGlobalTime; - QVector m_mappingData; int m_currentLoop; int m_loops; + QHash m_blendTreeTable; }; } // namespace Animation diff --git a/src/animation/backend/buildblendtreesjob.cpp b/src/animation/backend/buildblendtreesjob.cpp index a8e969a39..e1c3dd701 100644 --- a/src/animation/backend/buildblendtreesjob.cpp +++ b/src/animation/backend/buildblendtreesjob.cpp @@ -57,16 +57,125 @@ void BuildBlendTreesJob::setBlendedClipAnimators(const QVector +QVector buildBlendMappingDataForNode(const QVector &mappingInNode1, + const QVector &mappingInNode2) +{ + // We can only blend channels that are in both clips + // If a channel is present in one clip and not the other, we use 100% of its value (no blending) + QVector blendingMappingData; + const int mappingInNode1Size = mappingInNode1.size(); + blendingMappingData.reserve(mappingInNode1Size); + + // Find mappings that are in both vectors and build mappingData out of that + for (const MappingDataType &mappingDataInNode1 : mappingInNode1) { + AnimationUtils::BlendingMappingData mappingData; + mappingData.channelIndicesClip1 = mappingDataInNode1.channelIndices; + mappingData.propertyName = mappingDataInNode1.propertyName; + mappingData.targetId = mappingDataInNode1.targetId; + mappingData.type = mappingDataInNode1.type; + mappingData.blendAction = AnimationUtils::BlendingMappingData::NoBlending; + blendingMappingData.push_back(mappingData); + } + + for (const MappingDataType &mappingDataInNode2 : mappingInNode2) { + bool sharedChannel = false; + for (int i = 0; i < mappingInNode1Size; ++i) { + AnimationUtils::BlendingMappingData &mappingDataInNode1 = blendingMappingData[i]; + if ((strcmp(mappingDataInNode1.propertyName, mappingDataInNode2.propertyName) == 0) && + mappingDataInNode1.targetId == mappingDataInNode2.targetId && + mappingDataInNode1.type == mappingDataInNode2.type) { + // We have a channel shared in both clips + mappingDataInNode1.channelIndicesClip2 = mappingDataInNode2.channelIndices; + mappingDataInNode1.blendAction = AnimationUtils::BlendingMappingData::ClipBlending; + sharedChannel = true; + break; + } + } + if (!sharedChannel) { // We have a channel defined in only one of the clips + AnimationUtils::BlendingMappingData mappingData; + mappingData.channelIndicesClip2 = mappingDataInNode2.channelIndices; + mappingData.propertyName = mappingDataInNode2.propertyName; + mappingData.targetId = mappingDataInNode2.targetId; + mappingData.type = mappingDataInNode2.type; + mappingData.blendAction = AnimationUtils::BlendingMappingData::NoBlending; + blendingMappingData.push_back(mappingData); + } + } + + // Final indices (indices into the final blended result vector of floats for the node) + int idx = 0; + for (AnimationUtils::BlendingMappingData &mapping : blendingMappingData) { + switch (mapping.blendAction) { + case AnimationUtils::BlendingMappingData::ClipBlending: { + Q_ASSERT(mapping.channelIndicesClip1.size() == mapping.channelIndicesClip2.size()); + for (int i = 0, m = mapping.channelIndicesClip1.size(); i < m; ++i) + mapping.channelIndices.push_back(idx++); + break; + } + case AnimationUtils::BlendingMappingData::NoBlending: { + const bool useClip1 = !mapping.channelIndicesClip1.empty(); + const QVector channelIndices = useClip1 ? mapping.channelIndicesClip1 : mapping.channelIndicesClip2; + for (int i = 0, m = channelIndices.size(); i < m; ++i) { + mapping.channelIndices.push_back(idx++); + } + break; + } + default: + Q_UNREACHABLE(); + break; + } + } + + return blendingMappingData; +} + +void buildEntryForBlendClipNode(Handler *handler, const ChannelMapper *mapper, BlendedClipAnimator::BlendNodeData &nodeData) +{ + // Retrieve Animation clips + const AnimationClip *clip1 = handler->animationClipManager()->lookupResource(nodeData.left); + const AnimationClip *clip2 = handler->animationClipManager()->lookupResource(nodeData.right); + + Q_ASSERT(clip1 && clip2); + + // Build mappings for the 2 clips + const QVector mappingDataClip1 = AnimationUtils::buildPropertyMappings(handler, clip1, mapper); + const QVector mappingDataClip2 = AnimationUtils::buildPropertyMappings(handler, clip2, mapper); + + // We can only blend channels that are in both clips + // If a channel is present in one clip and not the other, we use 100% of its value (no blending) + const QVector blendingMappingData = buildBlendMappingDataForNode(mappingDataClip1, mappingDataClip2); + nodeData.mappingData = blendingMappingData; +} + +void buildEntryForBlendNodeNode(BlendedClipAnimator::BlendNodeData &nodeData, const QHash &blendingNodeTable) +{ + const BlendedClipAnimator::BlendNodeData &node1Data = blendingNodeTable.value(nodeData.left); + const BlendedClipAnimator::BlendNodeData &node2Data = blendingNodeTable.value(nodeData.right); + + // Build mappings for the 2 nodes + const QVector mappingDataNode1 = node1Data.mappingData; + const QVector mappingDataNode2 = node2Data.mappingData; + + // We can only blend channels that are in both clips + // If a channel is present in one clip and not the other, we use 100% of its value (no blending) + const QVector blendingMappingData = buildBlendMappingDataForNode(mappingDataNode1, mappingDataNode2); + nodeData.mappingData = blendingMappingData; +} + +} // anonymous + +// Note this job is run once for all stopped blended animators that have been marked dirty +// We assume that the structure of blend node tree does not change once a BlendClipAnimator has been set to running void BuildBlendTreesJob::run() { for (const HBlendedClipAnimator blendedClipAnimatorHandle : m_blendedClipAnimatorHandles) { - // Retrive BlendTree node + // Retrieve BlendTree node BlendedClipAnimator *blendClipAnimator = m_handler->blendedClipAnimatorManager()->data(blendedClipAnimatorHandle); Q_ASSERT(blendClipAnimator); - // TO DO: Add support for tree of blend nodes - // For now assumes only one - const bool canRun = blendClipAnimator->canRun(); m_handler->setBlendedClipAnimatorRunning(blendedClipAnimatorHandle, canRun); @@ -74,66 +183,35 @@ void BuildBlendTreesJob::run() if (canRun) { const ChannelMapper *mapper = m_handler->channelMapperManager()->lookupResource(blendClipAnimator->mapperId()); Q_ASSERT(mapper); - ClipBlendNode *node = m_handler->clipBlendNodeManager()->lookupNode(blendClipAnimator->blendTreeRootId()); - const Qt3DCore::QNodeIdVector clipIds = node->clipIds(); - // There must be 2 clips - if (clipIds.size() != 2) { - qWarning() << "A Blend Tree requires exactly 2 clips"; - return; - } - - // Retrieve Animation clips - const AnimationClip *clip1 = m_handler->animationClipManager()->lookupResource(clipIds.first()); - const AnimationClip *clip2 = m_handler->animationClipManager()->lookupResource(clipIds.last()); - - // Build mappings for the 2 clips - const QVector mappingDataClip1 = AnimationUtils::buildPropertyMappings(m_handler, clip1, mapper); - const QVector mappingDataClip2 = AnimationUtils::buildPropertyMappings(m_handler, clip2, mapper); - - // We can only blend channels that are in both clips - // If a channel is present in one clip and not the other, we use 100% of its value (no blending) - QVector blendingMappingData; - const int mappingInClip1Size = mappingDataClip1.size(); - blendingMappingData.reserve(mappingInClip1Size); - - // Find mappings that are in both vectors and build mappingData out of that - for (const AnimationUtils::MappingData &mappingDataInClip1 : mappingDataClip1) { - AnimationUtils::BlendingMappingData mappingData; - mappingData.channelIndicesClip1 = mappingDataInClip1.channelIndices; - mappingData.propertyName = mappingDataInClip1.propertyName; - mappingData.targetId = mappingDataInClip1.targetId; - mappingData.type = mappingDataInClip1.type; - mappingData.blendAction = AnimationUtils::BlendingMappingData::NoBlending; - blendingMappingData.push_back(mappingData); - } - - for (const AnimationUtils::MappingData &mappingDataInClip2 : mappingDataClip2) { - bool sharedChannel = false; - for (int i = 0; i < mappingInClip1Size; ++i) { - AnimationUtils::BlendingMappingData &mappingDataInClip1 = blendingMappingData[i]; - if ((strcmp(mappingDataInClip1.propertyName, mappingDataInClip2.propertyName) == 0) && - mappingDataInClip1.targetId == mappingDataInClip2.targetId && - mappingDataInClip1.type == mappingDataInClip2.type) { - // We have a channel shared in both clips - mappingDataInClip1.channelIndicesClip2 = mappingDataInClip2.channelIndices; - mappingDataInClip1.blendAction = AnimationUtils::BlendingMappingData::ClipBlending; - sharedChannel = true; - break; - } - } - if (!sharedChannel) { // We have a channel defined in only one of the clips - AnimationUtils::BlendingMappingData mappingData; - mappingData.channelIndicesClip2 = mappingDataInClip2.channelIndices; - mappingData.propertyName = mappingDataInClip2.propertyName; - mappingData.targetId = mappingDataInClip2.targetId; - mappingData.type = mappingDataInClip2.type; - mappingData.blendAction = AnimationUtils::BlendingMappingData::NoBlending; - blendingMappingData.push_back(mappingData); + ClipBlendNodeVisitor visitor(m_handler->clipBlendNodeManager()); + QHash blendingNodeTable; + // Build a Binary Tree of BlendNodeData + Handler *handler = m_handler; // For lambda capture + visitor.traverse(blendClipAnimator->blendTreeRootId(), [&] (ClipBlendNode *node) { + BlendedClipAnimator::BlendNodeData nodeData; + nodeData.blendNodeId = node->peerId(); + nodeData.type = (node->childrenIds().size() > 0) ? BlendedClipAnimator::BlendNodeData::BlendNodeType : BlendedClipAnimator::BlendNodeData::ClipType; + + if (nodeData.type == BlendedClipAnimator::BlendNodeData::BlendNodeType) { + Q_ASSERT(node->childrenIds().size() == 2); + nodeData.left = node->childrenIds().first(); + nodeData.right = node->childrenIds().last(); + buildEntryForBlendNodeNode(nodeData, blendingNodeTable); + } else { // ClipType + Q_ASSERT(node->clipIds().size() == 2); + nodeData.left = node->clipIds().first(); + nodeData.right = node->clipIds().last(); + buildEntryForBlendClipNode(handler, mapper, nodeData); } - } - blendClipAnimator->setMappingData(blendingMappingData); + // Note: we assume that ClipType are always leave nodes + // We will therefore perform blending on all the ClipType nodes + // Then traverse the tree of BlendNodeType and merge the values + blendingNodeTable.insert(nodeData.blendNodeId, nodeData); + }); + + blendClipAnimator->setBlendTreeTable(blendingNodeTable); } } } diff --git a/src/animation/backend/clipblendnodevisitor.cpp b/src/animation/backend/clipblendnodevisitor.cpp index 9940bd1f8..12533d2ca 100644 --- a/src/animation/backend/clipblendnodevisitor.cpp +++ b/src/animation/backend/clipblendnodevisitor.cpp @@ -56,15 +56,16 @@ void ClipBlendNodeVisitor::traverse(Qt3DCore::QNodeId rootId, const VisitFunctio visit(node, visitFunction); } +// Leaf to root traversal (Post-order traversal) void ClipBlendNodeVisitor::visit(ClipBlendNode *node, const VisitFunction &visitFunction) const { - visitFunction(node); const Qt3DCore::QNodeIdVector childIds = node->childrenIds(); for (const Qt3DCore::QNodeId childId: childIds) { ClipBlendNode *childNode = m_manager->lookupNode(childId); if (childNode != nullptr) visit(childNode, visitFunction); } + visitFunction(node); } } // Animation diff --git a/src/animation/backend/evaluateblendclipanimatorjob.cpp b/src/animation/backend/evaluateblendclipanimatorjob.cpp index 349156f39..0f79edbe6 100644 --- a/src/animation/backend/evaluateblendclipanimatorjob.cpp +++ b/src/animation/backend/evaluateblendclipanimatorjob.cpp @@ -40,6 +40,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE @@ -48,63 +49,32 @@ namespace Animation { EvaluateBlendClipAnimatorJob::EvaluateBlendClipAnimatorJob() : Qt3DCore::QAspectJob() + , m_currentLoop(std::numeric_limits::max()) + , m_isFinalFrame(true) { // TO DO: Add Profiler ID } -void EvaluateBlendClipAnimatorJob::run() -{ - const qint64 globalTime = m_handler->simulationTime(); - - BlendedClipAnimator *blendedClipAnimator = m_handler->blendedClipAnimatorManager()->data(m_blendClipAnimatorHandle); - Q_ASSERT(blendedClipAnimator); - - // TO DO: Right now we are doing LERP but refactor to handle other types - ClipBlendNode *blendNode = m_handler->clipBlendNodeManager()->lookupNode(blendedClipAnimator->blendTreeRootId()); - - const Qt3DCore::QNodeIdVector clipIds = blendNode->clipIds(); - - // Evaluate the fcurves for both clip - AnimationClip *clip1 = m_handler->animationClipManager()->lookupResource(clipIds.first()); - AnimationClip *clip2 = m_handler->animationClipManager()->lookupResource(clipIds.last()); - Q_ASSERT(clip1 && clip2); - - // Prepare for evaluation (convert global time to local time ....) - const AnimationUtils::AnimatorEvaluationData animatorEvaluationData = AnimationUtils::animatorEvaluationDataForAnimator(blendedClipAnimator, globalTime); - const AnimationUtils::ClipPreEvaluationData preEvaluationDataForClip1 = AnimationUtils::evaluationDataForClip(clip1, animatorEvaluationData); - const AnimationUtils::ClipPreEvaluationData preEvaluationDataForClip2 = AnimationUtils::evaluationDataForClip(clip2, animatorEvaluationData); - - // Evaluate the clips - const QVector channelResultsClip1 = AnimationUtils::evaluateClipAtLocalTime(clip1, preEvaluationDataForClip1.localTime); - const QVector channelResultsClip2 = AnimationUtils::evaluateClipAtLocalTime(clip2, preEvaluationDataForClip2.localTime); +namespace { - // Update loops and running of the animator - blendedClipAnimator->setCurrentLoop(std::min(preEvaluationDataForClip1.currentLoop, preEvaluationDataForClip2.currentLoop)); - const bool isFinalFrame = preEvaluationDataForClip1.isFinalFrame && preEvaluationDataForClip2.isFinalFrame; - if (isFinalFrame) - blendedClipAnimator->setRunning(false); - - // Perform blending between the two clips - QVector blendedMappingData; +QVector blendValuesBasedOnMappings(ClipBlendNode *node, + const QVector &channelResults1, + const QVector &channelResults2, + const QVector &blendingMappingData) +{ QVector blendedValues; + blendedValues.reserve(blendingMappingData.size()); // Build a combined vector of blended value - const QVector blendingMappingData = blendedClipAnimator->mappingData(); for (const AnimationUtils::BlendingMappingData &mapping : blendingMappingData) { - AnimationUtils::MappingData finalMapping; - finalMapping.type = mapping.type; - finalMapping.targetId = mapping.targetId; - finalMapping.propertyName = mapping.propertyName; - switch (mapping.blendAction) { case AnimationUtils::BlendingMappingData::ClipBlending: { Q_ASSERT(mapping.channelIndicesClip1.size() == mapping.channelIndicesClip2.size()); for (int i = 0, m = mapping.channelIndicesClip1.size(); i < m; ++i) { - const float value1 = channelResultsClip1.at(mapping.channelIndicesClip1[i]); - const float value2 = channelResultsClip2.at(mapping.channelIndicesClip2[i]); - const float blendedValue = blendNode->blend(value1, value2); - finalMapping.channelIndices.push_back(blendedValues.size()); + const float value1 = channelResults1.at(mapping.channelIndicesClip1[i]); + const float value2 = channelResults2.at(mapping.channelIndicesClip2[i]); + const float blendedValue = node->blend(value1, value2); blendedValues.push_back(blendedValue); } break; @@ -112,10 +82,9 @@ void EvaluateBlendClipAnimatorJob::run() case AnimationUtils::BlendingMappingData::NoBlending: { const bool useClip1 = !mapping.channelIndicesClip1.empty(); const QVector channelIndices = useClip1 ? mapping.channelIndicesClip1 : mapping.channelIndicesClip2; - const QVector values = useClip1 ? channelResultsClip1 : channelResultsClip2; + const QVector values = useClip1 ? channelResults1 : channelResults2; for (int i = 0, m = channelIndices.size(); i < m; ++i) { const float value = values.at(channelIndices[i]); - finalMapping.channelIndices.push_back(blendedValues.size()); blendedValues.push_back(value); } break; @@ -124,21 +93,127 @@ void EvaluateBlendClipAnimatorJob::run() Q_UNREACHABLE(); break; } + } + return blendedValues; +} - blendedMappingData.push_back(finalMapping); +QVector fromBlendingMappingData(const QVector &blendingMappingData) +{ + const int blendingMappingDataSize = blendingMappingData.size(); + QVector mappingData(blendingMappingDataSize); + for (int i = 0; i < blendingMappingDataSize; ++i) { + mappingData[i] = blendingMappingData[i]; } + return mappingData; +} + +} // anonymous + +void EvaluateBlendClipAnimatorJob::blendClips(ClipBlendNode *node, const BlendedClipAnimator::BlendNodeData &nodeData, + const AnimationUtils::AnimatorEvaluationData &animatorEvaluationData) +{ + AnimationClip *clip1 = m_handler->animationClipManager()->lookupResource(nodeData.left); + AnimationClip *clip2 = m_handler->animationClipManager()->lookupResource(nodeData.right); + Q_ASSERT(clip1 && clip2); + + // Prepare for evaluation (convert global time to local time ....) + const AnimationUtils::ClipPreEvaluationData preEvaluationDataForClip1 = AnimationUtils::evaluationDataForClip(clip1, animatorEvaluationData); + const AnimationUtils::ClipPreEvaluationData preEvaluationDataForClip2 = AnimationUtils::evaluationDataForClip(clip2, animatorEvaluationData); + + // Evaluate the fcurves for both clip + const QVector channelResultsClip1 = AnimationUtils::evaluateClipAtLocalTime(clip1, preEvaluationDataForClip1.localTime); + const QVector channelResultsClip2 = AnimationUtils::evaluateClipAtLocalTime(clip2, preEvaluationDataForClip2.localTime); + + // Update loops and running of the animator + m_currentLoop = std::min(m_currentLoop, std::min(preEvaluationDataForClip1.currentLoop, preEvaluationDataForClip2.currentLoop)); + // isFinalFrame remains true only if all the clips have reached their final frame + m_isFinalFrame &= (preEvaluationDataForClip1.isFinalFrame && preEvaluationDataForClip2.isFinalFrame); + + const QVector blendingMappingData = nodeData.mappingData; + // Perform blending between the two clips + const QVector blendedValues = blendValuesBasedOnMappings(node, channelResultsClip1, + channelResultsClip2, blendingMappingData); + + m_clipBlendResultsTable.insert(node, blendedValues); +} + +void EvaluateBlendClipAnimatorJob::blendNodes(ClipBlendNode *node, const BlendedClipAnimator::BlendNodeData &nodeData) +{ + ClipBlendNode *node1 = m_handler->clipBlendNodeManager()->lookupNode(nodeData.left); + ClipBlendNode *node2 = m_handler->clipBlendNodeManager()->lookupNode(nodeData.right); + Q_ASSERT(node1 && node2); + + // Retrieve results for the childNodes + const QVector channelResultsNode1 = m_clipBlendResultsTable.take(node1); + const QVector channelResultsNode2 = m_clipBlendResultsTable.take(node2); + + // Build a combined vector of blended value + const QVector blendingMappingData = nodeData.mappingData; + // Perform blending between the two nodes + const QVector blendedValues = blendValuesBasedOnMappings(node, channelResultsNode1, + channelResultsNode2, blendingMappingData); + + m_clipBlendResultsTable.insert(node, blendedValues); +} + +void EvaluateBlendClipAnimatorJob::run() +{ + const qint64 globalTime = m_handler->simulationTime(); + + BlendedClipAnimator *blendedClipAnimator = m_handler->blendedClipAnimatorManager()->data(m_blendClipAnimatorHandle); + Q_ASSERT(blendedClipAnimator); + + const AnimationUtils::AnimatorEvaluationData animatorEvaluationData = AnimationUtils::animatorEvaluationDataForAnimator(blendedClipAnimator, globalTime); + const QHash blendindNodeTable = blendedClipAnimator->blendTreeTable(); + + // Reset globals + m_currentLoop = std::numeric_limits::max(); + m_isFinalFrame = true; + + // Perform blending of the tree (Post-order traversal) + ClipBlendNodeVisitor visitor(m_handler->clipBlendNodeManager()); + visitor.traverse(blendedClipAnimator->blendTreeRootId(), [&, this] (ClipBlendNode *blendNode) { + // Retrieve BlendingData for the not + const BlendedClipAnimator::BlendNodeData &nodeData = blendindNodeTable.value(blendNode->peerId()); + + switch (nodeData.type) { + case BlendedClipAnimator::BlendNodeData::BlendNodeType: + // Blend two ClipBlendNode + blendNodes(blendNode, nodeData); + break; + case BlendedClipAnimator::BlendNodeData::ClipType: // Leaf + // Blend two clips + blendClips(blendNode, nodeData, animatorEvaluationData); + break; + default: + Q_UNREACHABLE(); + break; + } + }); + + + // Set current loop and running if need + if (m_isFinalFrame) + blendedClipAnimator->setRunning(false); + blendedClipAnimator->setCurrentLoop(m_currentLoop); + + // Prepare property changes using the root node which should now be filled with correct values + ClipBlendNode *rootBlendNode = m_handler->clipBlendNodeManager()->lookupNode(blendedClipAnimator->blendTreeRootId()); + Q_ASSERT(m_clipBlendResultsTable.size() == 1 && m_clipBlendResultsTable.contains(rootBlendNode)); + + const QVector blendedValues = m_clipBlendResultsTable.take(rootBlendNode); + const BlendedClipAnimator::BlendNodeData &rootNodeData = blendindNodeTable.value(rootBlendNode->peerId()); + const QVector mappingData = fromBlendingMappingData(rootNodeData.mappingData); // Prepare property changes (if finalFrame it also prepares the change for the running property for the frontend) const QVector changes = AnimationUtils::preparePropertyChanges(blendedClipAnimator->peerId(), - blendedMappingData, + mappingData, blendedValues, - isFinalFrame); - + m_isFinalFrame); // Send the property changes blendedClipAnimator->sendPropertyChanges(changes); } - } // Animation } // Qt3DAnimation diff --git a/src/animation/backend/evaluateblendclipanimatorjob_p.h b/src/animation/backend/evaluateblendclipanimatorjob_p.h index 07db68fdc..8090a025a 100644 --- a/src/animation/backend/evaluateblendclipanimatorjob_p.h +++ b/src/animation/backend/evaluateblendclipanimatorjob_p.h @@ -50,6 +50,8 @@ #include #include +#include +#include QT_BEGIN_NAMESPACE @@ -57,6 +59,7 @@ namespace Qt3DAnimation { namespace Animation { class Handler; +class ClipBlendNode; class EvaluateBlendClipAnimatorJob : public Qt3DCore::QAspectJob { @@ -75,6 +78,14 @@ protected: private: HBlendedClipAnimator m_blendClipAnimatorHandle; Handler *m_handler; + + void blendClips(ClipBlendNode *node, const BlendedClipAnimator::BlendNodeData &nodeData, + const AnimationUtils::AnimatorEvaluationData &animatorEvaluationData); + void blendNodes(ClipBlendNode *node, const BlendedClipAnimator::BlendNodeData &nodeData); + + QHash> m_clipBlendResultsTable; + int m_currentLoop; + bool m_isFinalFrame; }; typedef QSharedPointer EvaluateBlendClipAnimatorJobPtr; diff --git a/src/animation/backend/handler.cpp b/src/animation/backend/handler.cpp index 6dea5d6f3..e17227431 100644 --- a/src/animation/backend/handler.cpp +++ b/src/animation/backend/handler.cpp @@ -42,6 +42,8 @@ #include #include #include +#include +#include QT_BEGIN_NAMESPACE diff --git a/src/animation/backend/handler_p.h b/src/animation/backend/handler_p.h index 3abaae215..25286fb45 100644 --- a/src/animation/backend/handler_p.h +++ b/src/animation/backend/handler_p.h @@ -50,8 +50,6 @@ #include #include -#include -#include #include #include #include @@ -82,6 +80,11 @@ class ClipBlendNodeManager; class FindRunningClipAnimatorsJob; class LoadAnimationClipJob; class EvaluateClipAnimatorJob; +class BuildBlendTreesJob; +class EvaluateBlendClipAnimatorJob; + +using BuildBlendTreesJobPtr = QSharedPointer; +using EvaluateBlendClipAnimatorJobPtr = QSharedPointer; class Q_AUTOTEST_EXPORT Handler { diff --git a/src/animation/frontend/qblendedclipanimator.cpp b/src/animation/frontend/qblendedclipanimator.cpp index 8e0897b5c..9d3bf5ba2 100644 --- a/src/animation/frontend/qblendedclipanimator.cpp +++ b/src/animation/frontend/qblendedclipanimator.cpp @@ -54,6 +54,31 @@ QBlendedClipAnimatorPrivate::QBlendedClipAnimatorPrivate() { } +/*! + \qmltype BlendedClipAnimator + \instantiates Qt3DAnimation::QBlendedClipAnimator + \inqmlmodule Qt3D.Animation + + \brief Performs an animation based on a tree of blend nodes + + \note The blend node tree should only be edited when the clip is not + running + + \since 5.9 +*/ + +/*! + \class Qt3DAnimation::QBlendedClipAnimator + \inmodule Qt3DAnimation + \inherits Qt3DCore::QComponent + + \brief Performs an animation based on a tree of blend nodes + + \note The blend node tree should only be edited when the clip is not + running + + \since 5.9 +*/ QBlendedClipAnimator::QBlendedClipAnimator(Qt3DCore::QNode *parent) : Qt3DCore::QComponent(*new QBlendedClipAnimatorPrivate, parent) { diff --git a/tests/auto/animation/blendedclipanimator/tst_blendedclipanimator.cpp b/tests/auto/animation/blendedclipanimator/tst_blendedclipanimator.cpp index c53f6ec62..04cc1026e 100644 --- a/tests/auto/animation/blendedclipanimator/tst_blendedclipanimator.cpp +++ b/tests/auto/animation/blendedclipanimator/tst_blendedclipanimator.cpp @@ -65,7 +65,6 @@ private Q_SLOTS: QCOMPARE(backendBlendedClipAnimator.isRunning(), false); QCOMPARE(backendBlendedClipAnimator.startTime(), 0); QCOMPARE(backendBlendedClipAnimator.currentLoop(), 0); - QCOMPARE(backendBlendedClipAnimator.mappingData().size(), 0); QCOMPARE(backendBlendedClipAnimator.loops(), 1); } @@ -83,9 +82,6 @@ private Q_SLOTS: backendBlendedClipAnimator.setMapperId(Qt3DCore::QNodeId::createId()); backendBlendedClipAnimator.setRunning(true); backendBlendedClipAnimator.setStartTime(28); - QVector mappingData; - mappingData.resize(5); - backendBlendedClipAnimator.setMappingData(mappingData); backendBlendedClipAnimator.cleanup(); // THEN @@ -95,7 +91,6 @@ private Q_SLOTS: QCOMPARE(backendBlendedClipAnimator.isRunning(), false); QCOMPARE(backendBlendedClipAnimator.startTime(), 0); QCOMPARE(backendBlendedClipAnimator.currentLoop(), 0); - QCOMPARE(backendBlendedClipAnimator.mappingData().size(), 0); QCOMPARE(backendBlendedClipAnimator.loops(), 1); } diff --git a/tests/auto/animation/clipblendnodevisitor/tst_clipblendnodevisitor.cpp b/tests/auto/animation/clipblendnodevisitor/tst_clipblendnodevisitor.cpp index 6c6723920..78f0f1202 100644 --- a/tests/auto/animation/clipblendnodevisitor/tst_clipblendnodevisitor.cpp +++ b/tests/auto/animation/clipblendnodevisitor/tst_clipblendnodevisitor.cpp @@ -89,17 +89,18 @@ private Q_SLOTS: // WHEN int i = 0; + // Note: post-order traversal auto childCounter = [&] (Qt3DAnimation::Animation::ClipBlendNode *node) { if (i == 0) - QCOMPARE(node, backendRootBlendNode); + QCOMPARE(node, backendChildBlendNode11); else if (i == 1) - QCOMPARE(node, backendChildBlendNode1); + QCOMPARE(node, backendChildBlendNode12); else if (i == 2) - QCOMPARE(node, backendChildBlendNode11); + QCOMPARE(node, backendChildBlendNode1); else if (i == 3) - QCOMPARE(node, backendChildBlendNode12); - else if (i == 4) QCOMPARE(node, backendChildBlendNode2); + else if (i == 4) + QCOMPARE(node, backendRootBlendNode); ++i; }; -- cgit v1.2.3 From 7416cf5ecff88cff4ab312271322d8fb281cf68f Mon Sep 17 00:00:00 2001 From: Paul Lemire Date: Tue, 31 Jan 2017 11:58:04 +0100 Subject: animation-keyframe-simple updated to use a nested blending tree Change-Id: I4db83a3f9c3e867269147298d204bb90c1193631 Reviewed-by: Sean Harmer --- tests/manual/animation-keyframe-simple/main.qml | 71 +++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/tests/manual/animation-keyframe-simple/main.qml b/tests/manual/animation-keyframe-simple/main.qml index e7db8b30b..328d8c7b2 100644 --- a/tests/manual/animation-keyframe-simple/main.qml +++ b/tests/manual/animation-keyframe-simple/main.qml @@ -175,6 +175,77 @@ DefaultSceneEntity { ] } + Entity { + id: cube3 + + components: [ + Transform { + id: cube3Transform + translation: Qt.vector3d(2.5, 0, 2) + onTranslationChanged: console.log("t = " + translation) + }, + CuboidMesh { + }, + PhongMaterial { + id: cube3Material + ambient: Qt.rgba(0.8, 0.8, 0.8, 1.0) + diffuse: "green" + shininess: 50 + }, + ObjectPicker { + onClicked: blendedAnimator3.running = true + }, + BlendedClipAnimator { + id: blendedAnimator3 + loops: 2 + + onRunningChanged: console.log("running = " + running) + + blendTree: LerpBlend { + blendFactor: 0.5 + AddBlend { + blendFactor: 0.5 + clips: [ + AnimationClip { + source: "pulsing-moving-cube.json" + onDurationChanged: console.log("duration = " + duration) + }, + AnimationClip { + source: "pulsing-cube-additive.json" + onDurationChanged: console.log("duration = " + duration) + }] + } + LerpBlend { + blendFactor: 0.5 + clips: [ + AnimationClip { + source: "cubeanimation.json" + onDurationChanged: console.log("duration = " + duration) + }, + AnimationClip { + source: "pulsing-moving-cube.json" + onDurationChanged: console.log("duration = " + duration) + }] + } + } + + // By default introspect parent Entity and try + // to map fcurve groups to properties of QTransform + // mapping: AutomaticAnimationMapping {} + + // To do more, we can be explicit + channelMapper: ChannelMapper { + mappings: [ + ChannelMapping { channelName: "Location"; target: cube3Transform; property: "translation" }, + ChannelMapping { channelName: "Rotation"; target: cube3Transform; property: "rotation" }, + ChannelMapping { channelName: "Scaling"; target: cube3Transform; property: "scale3D" }, + ChannelMapping { channelName: "Diffuse Color"; target: cube3Transform; property: "diffuse" } + ] + } + } + ] + } + camera: Camera { position: Qt.vector3d(10, 3, 15) -- cgit v1.2.3 From 68606da9f12482a7bd910dccc53daf2899082526 Mon Sep 17 00:00:00 2001 From: Paul Lemire Date: Tue, 31 Jan 2017 12:26:27 +0100 Subject: Renamed QAddBlend to QAdditiveBlend Change-Id: I1a2737c335790507c3b598e274f8dc5f8f82d1a1 Reviewed-by: Sean Harmer --- src/animation/backend/addblend.cpp | 85 ---------- src/animation/backend/addblend_p.h | 83 --------- src/animation/backend/additiveblend.cpp | 85 ++++++++++ src/animation/backend/additiveblend_p.h | 83 +++++++++ src/animation/backend/backend.pri | 4 +- src/animation/backend/clipblendnode_p.h | 2 +- src/animation/frontend/frontend.pri | 6 +- src/animation/frontend/qaddblend.cpp | 175 ------------------- src/animation/frontend/qaddblend.h | 76 --------- src/animation/frontend/qaddblend_p.h | 78 --------- src/animation/frontend/qadditiveblend.cpp | 175 +++++++++++++++++++ src/animation/frontend/qadditiveblend.h | 76 +++++++++ src/animation/frontend/qadditiveblend_p.h | 78 +++++++++ src/animation/frontend/qanimationaspect.cpp | 8 +- .../animation/qt3dquick3danimationplugin.cpp | 4 +- tests/auto/animation/addblend/addblend.pro | 11 -- tests/auto/animation/addblend/tst_addblend.cpp | 148 ----------------- .../auto/animation/additiveblend/additiveblend.pro | 12 ++ .../animation/additiveblend/tst_additiveblend.cpp | 148 +++++++++++++++++ tests/auto/animation/animation.pro | 4 +- tests/auto/animation/qaddblend/qaddblend.pro | 11 -- tests/auto/animation/qaddblend/tst_qaddblend.cpp | 185 --------------------- .../animation/qadditiveblend/qadditiveblend.pro | 12 ++ .../qadditiveblend/tst_qadditiveblend.cpp | 185 +++++++++++++++++++++ tests/manual/animation-keyframe-simple/main.qml | 4 +- 25 files changed, 870 insertions(+), 868 deletions(-) delete mode 100644 src/animation/backend/addblend.cpp delete mode 100644 src/animation/backend/addblend_p.h create mode 100644 src/animation/backend/additiveblend.cpp create mode 100644 src/animation/backend/additiveblend_p.h delete mode 100644 src/animation/frontend/qaddblend.cpp delete mode 100644 src/animation/frontend/qaddblend.h delete mode 100644 src/animation/frontend/qaddblend_p.h create mode 100644 src/animation/frontend/qadditiveblend.cpp create mode 100644 src/animation/frontend/qadditiveblend.h create mode 100644 src/animation/frontend/qadditiveblend_p.h delete mode 100644 tests/auto/animation/addblend/addblend.pro delete mode 100644 tests/auto/animation/addblend/tst_addblend.cpp create mode 100644 tests/auto/animation/additiveblend/additiveblend.pro create mode 100644 tests/auto/animation/additiveblend/tst_additiveblend.cpp delete mode 100644 tests/auto/animation/qaddblend/qaddblend.pro delete mode 100644 tests/auto/animation/qaddblend/tst_qaddblend.cpp create mode 100644 tests/auto/animation/qadditiveblend/qadditiveblend.pro create mode 100644 tests/auto/animation/qadditiveblend/tst_qadditiveblend.cpp diff --git a/src/animation/backend/addblend.cpp b/src/animation/backend/addblend.cpp deleted file mode 100644 index 497f66e4a..000000000 --- a/src/animation/backend/addblend.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). -** Contact: http://www.qt-project.org/legal -** -** 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 "addblend_p.h" -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE - -namespace Qt3DAnimation { - -namespace Animation { - -AddBlend::AddBlend() - : ClipBlendNode(ClipBlendNode::AddBlendType) - , m_blendFactor(0.0f) -{ -} - -AddBlend::~AddBlend() -{ -} - -void AddBlend::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) -{ - if (e->type() == Qt3DCore::PropertyUpdated) { - Qt3DCore::QPropertyUpdatedChangePtr change = qSharedPointerCast(e); - if (change->propertyName() == QByteArrayLiteral("blendFactor")) - m_blendFactor = change->value().toFloat(); - } -} - -float AddBlend::blend(float value1, float value2) const -{ - return value1 + (m_blendFactor * value2); -} - -void AddBlend::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) -{ - ClipBlendNode::initializeFromPeer(change); - const auto creationChangeData = qSharedPointerCast>(change); - const Qt3DAnimation::QAddBlendData cloneData = creationChangeData->data; - m_blendFactor = cloneData.blendFactor; -} - -} // Animation - -} // Qt3DAnimation - -QT_END_NAMESPACE diff --git a/src/animation/backend/addblend_p.h b/src/animation/backend/addblend_p.h deleted file mode 100644 index 621f4e551..000000000 --- a/src/animation/backend/addblend_p.h +++ /dev/null @@ -1,83 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). -** Contact: http://www.qt-project.org/legal -** -** 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$ -** -****************************************************************************/ - -#ifndef QT3DANIMATION_ANIMATION_ADDBLEND_P_H -#define QT3DANIMATION_ANIMATION_ADDBLEND_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of other Qt classes. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include - -QT_BEGIN_NAMESPACE - -namespace Qt3DAnimation { - -namespace Animation { - -class Q_AUTOTEST_EXPORT AddBlend : public ClipBlendNode -{ -public: - AddBlend(); - ~AddBlend(); - - inline float blendFactor() const { return m_blendFactor; } - void setBlendFactor(float blendFactor) { m_blendFactor = blendFactor; } // For unit tests - - void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_FINAL; - float blend(float value1, float value2) const Q_DECL_FINAL; - -private: - void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL; - - float m_blendFactor; -}; - -} // Animation - -} // Qt3DAnimation - -QT_END_NAMESPACE - -#endif // QT3DANIMATION_ANIMATION_ADDBLEND_P_H diff --git a/src/animation/backend/additiveblend.cpp b/src/animation/backend/additiveblend.cpp new file mode 100644 index 000000000..6364e54a7 --- /dev/null +++ b/src/animation/backend/additiveblend.cpp @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** 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 "additiveblend_p.h" +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { + +namespace Animation { + +AdditiveBlend::AdditiveBlend() + : ClipBlendNode(ClipBlendNode::AdditiveBlendType) + , m_blendFactor(0.0f) +{ +} + +AdditiveBlend::~AdditiveBlend() +{ +} + +void AdditiveBlend::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) +{ + if (e->type() == Qt3DCore::PropertyUpdated) { + Qt3DCore::QPropertyUpdatedChangePtr change = qSharedPointerCast(e); + if (change->propertyName() == QByteArrayLiteral("blendFactor")) + m_blendFactor = change->value().toFloat(); + } +} + +float AdditiveBlend::blend(float value1, float value2) const +{ + return value1 + (m_blendFactor * value2); +} + +void AdditiveBlend::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) +{ + ClipBlendNode::initializeFromPeer(change); + const auto creationChangeData = qSharedPointerCast>(change); + const Qt3DAnimation::QAdditiveBlendData cloneData = creationChangeData->data; + m_blendFactor = cloneData.blendFactor; +} + +} // Animation + +} // Qt3DAnimation + +QT_END_NAMESPACE diff --git a/src/animation/backend/additiveblend_p.h b/src/animation/backend/additiveblend_p.h new file mode 100644 index 000000000..d67e95b51 --- /dev/null +++ b/src/animation/backend/additiveblend_p.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** 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$ +** +****************************************************************************/ + +#ifndef QT3DANIMATION_ANIMATION_ADDITIVEBLEND_P_H +#define QT3DANIMATION_ANIMATION_ADDITIVEBLEND_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { + +namespace Animation { + +class Q_AUTOTEST_EXPORT AdditiveBlend : public ClipBlendNode +{ +public: + AdditiveBlend(); + ~AdditiveBlend(); + + inline float blendFactor() const { return m_blendFactor; } + void setBlendFactor(float blendFactor) { m_blendFactor = blendFactor; } // For unit tests + + void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_FINAL; + float blend(float value1, float value2) const Q_DECL_FINAL; + +private: + void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL; + + float m_blendFactor; +}; + +} // Animation + +} // Qt3DAnimation + +QT_END_NAMESPACE + +#endif // QT3DANIMATION_ANIMATION_ADDITIVEBLEND_P_H diff --git a/src/animation/backend/backend.pri b/src/animation/backend/backend.pri index 35fdf5cfd..cc405fd79 100644 --- a/src/animation/backend/backend.pri +++ b/src/animation/backend/backend.pri @@ -26,7 +26,7 @@ HEADERS += \ $$PWD/animationutils_p.h \ $$PWD/buildblendtreesjob_p.h \ $$PWD/evaluateblendclipanimatorjob_p.h \ - $$PWD/addblend_p.h + $$PWD/additiveblend_p.h SOURCES += \ $$PWD/animationclip.cpp \ @@ -50,4 +50,4 @@ SOURCES += \ $$PWD/animationutils.cpp \ $$PWD/buildblendtreesjob.cpp \ $$PWD/evaluateblendclipanimatorjob.cpp \ - $$PWD/addblend.cpp + $$PWD/additiveblend.cpp diff --git a/src/animation/backend/clipblendnode_p.h b/src/animation/backend/clipblendnode_p.h index 2ebe16ab7..4ce1816b9 100644 --- a/src/animation/backend/clipblendnode_p.h +++ b/src/animation/backend/clipblendnode_p.h @@ -68,7 +68,7 @@ public: enum BlendType { NoneBlendType, LerpBlendType, - AddBlendType + AdditiveBlendType }; void setClipBlendNodeManager(ClipBlendNodeManager *manager); diff --git a/src/animation/frontend/frontend.pri b/src/animation/frontend/frontend.pri index f41de531e..2716c3d39 100644 --- a/src/animation/frontend/frontend.pri +++ b/src/animation/frontend/frontend.pri @@ -19,8 +19,8 @@ HEADERS += \ $$PWD/qlerpblend_p.h \ $$PWD/qclipblendnodecreatedchange.h \ $$PWD/qclipblendnodecreatedchange_p.h \ - $$PWD/qaddblend.h \ - $$PWD/qaddblend_p.h + $$PWD/qadditiveblend.h \ + $$PWD/qadditiveblend_p.h SOURCES += \ $$PWD/qanimationaspect.cpp \ @@ -33,6 +33,6 @@ SOURCES += \ $$PWD/qchannelmapping.cpp \ $$PWD/qlerpblend.cpp \ $$PWD/qclipblendnodecreatedchange.cpp \ - $$PWD/qaddblend.cpp + $$PWD/qadditiveblend.cpp INCLUDEPATH += $$PWD diff --git a/src/animation/frontend/qaddblend.cpp b/src/animation/frontend/qaddblend.cpp deleted file mode 100644 index fdf99f2c0..000000000 --- a/src/animation/frontend/qaddblend.cpp +++ /dev/null @@ -1,175 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). -** Contact: http://www.qt-project.org/legal -** -** 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 "qaddblend.h" -#include "qaddblend_p.h" -#include -#include - -QT_BEGIN_NAMESPACE - -namespace Qt3DAnimation { - - -/*! - \qmltype AddBlend - \instantiates Qt3DAnimation::QAddBlend - \inqmlmodule Qt3D.Animation - - \brief Performs an addition of two animation clips based on a - normalized factor - - \since 5.9 - - AddBlend can be useful to create advanced animation effects based on - individual animation clips. For instance, given a player character, additive - blending could be used to combine a walking animation clip with an injured - animation clip based on a blend factor that increases the more the player - gets injured. This would then allow with blend factor == 0 to have a non - injured walking player, with blend factor == 1 a fully injured player, with - blend factor == 0.5 a partially walking and injured player. - - \sa BlendedClipAnimator -*/ - -/*! - \class Qt3DAnimation::QAddBlend - \inmodule Qt3DAnimation - \inherits Qt3DAnimation::QAbstractClipBlendNode - - \brief Performs an addition of two animation clips based on a - normalized factor - - \since 5.9 - - QAddBlend can be useful to create advanced animation effects based on - individual animation clips. For instance, given a player character, additive - blending could be used to combine a walking animation clip with an injured - animation clip based on a blend factor that increases the more the player - gets injured. This would then allow with blend factor == 0 to have a non - injured walking player, with blend factor == 1 a fully injured player, with - blend factor == 0.5 a partially walking and injured player. - - \sa QBlendedClipAnimator -*/ - -QAddBlendPrivate::QAddBlendPrivate() - : QAbstractClipBlendNodePrivate() - , m_blendFactor(0.0f) -{ -} - -QAddBlend::QAddBlend(Qt3DCore::QNode *parent) - : QAbstractClipBlendNode(*new QAddBlendPrivate(), parent) -{ -} - -QAddBlend::QAddBlend(QAddBlendPrivate &dd, Qt3DCore::QNode *parent) - : QAbstractClipBlendNode(dd, parent) -{ -} - -QAddBlend::~QAddBlend() -{ -} - -Qt3DCore::QNodeCreatedChangeBasePtr QAddBlend::createNodeCreationChange() const -{ - Q_D(const QAddBlend); - auto creationChange = QClipBlendNodeCreatedChangePtr::create(this); - QAddBlendData &data = creationChange->data; - data.blendFactor = d->m_blendFactor; - return creationChange; -} - -/*! - \qmlproperty real AddBlend::blendFactor - - Specifies the blending factor between 0 and 1 to control the blending of - two animation clips. -*/ -/*! - \property QAddBlend::blendFactor - - Specifies the blending factor between 0 and 1 to control the blending of - two animation clips. - */ -float QAddBlend::blendFactor() const -{ - Q_D(const QAddBlend); - return d->m_blendFactor; -} - -void QAddBlend::setBlendFactor(float blendFactor) -{ - Q_D(QAddBlend); - if (d->m_blendFactor == blendFactor) - return; - - d->m_blendFactor = blendFactor; - emit blendFactorChanged(blendFactor); -} - -/*! - \qmlproperty list AddBlend::clips - - Holds the list of AnimationClip nodes against which the blending is performed. - - \note Only the two first AnimationClip are used, subsequent ones are ignored -*/ - - -/*! - \fn void QAddBlend::addClip(QAnimationClip *clip); - Adds a \a clip to the blending node's clips list. - - \note Only the two first AnimationClip are used, subsequent ones are ignored - */ - -/*! - \fn void QAddBlend::removeClip(QAnimationClip *clip); - Removes a \a clip from the blending node's clips list. - */ - -/*! - \fn QVector QAddBlend::clips() const; - Returns the list of QAnimationClip against which the blending is performed. - */ - - -} // Qt3DAnimation - -QT_END_NAMESPACE diff --git a/src/animation/frontend/qaddblend.h b/src/animation/frontend/qaddblend.h deleted file mode 100644 index 034bc7ee0..000000000 --- a/src/animation/frontend/qaddblend.h +++ /dev/null @@ -1,76 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). -** Contact: http://www.qt-project.org/legal -** -** 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$ -** -****************************************************************************/ - -#ifndef QT3DANIMATION_QADDBLEND_H -#define QT3DANIMATION_QADDBLEND_H - -#include - -QT_BEGIN_NAMESPACE - -namespace Qt3DAnimation { - -class QAddBlendPrivate; - -class QT3DANIMATIONSHARED_EXPORT QAddBlend : public QAbstractClipBlendNode -{ - Q_OBJECT - Q_PROPERTY(float blendFactor READ blendFactor WRITE setBlendFactor NOTIFY blendFactorChanged) -public: - explicit QAddBlend(Qt3DCore::QNode *parent = nullptr); - ~QAddBlend(); - - float blendFactor() const; - -public Q_SLOTS: - void setBlendFactor(float blendFactor); - -Q_SIGNALS: - void blendFactorChanged(float blendFactor); - -protected: - explicit QAddBlend(QAddBlendPrivate &dd, Qt3DCore::QNode *parent = nullptr); - -private: - Q_DECLARE_PRIVATE(QAddBlend) - Qt3DCore::QNodeCreatedChangeBasePtr createNodeCreationChange() const Q_DECL_OVERRIDE; -}; - -} // Qt3DAnimation - -QT_END_NAMESPACE - -#endif // QT3DANIMATION_QADDBLEND_H diff --git a/src/animation/frontend/qaddblend_p.h b/src/animation/frontend/qaddblend_p.h deleted file mode 100644 index 002747045..000000000 --- a/src/animation/frontend/qaddblend_p.h +++ /dev/null @@ -1,78 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). -** Contact: http://www.qt-project.org/legal -** -** 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$ -** -****************************************************************************/ - -#ifndef QT3DANIMATION_QADDBLEND_P_H -#define QT3DANIMATION_QADDBLEND_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of other Qt classes. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include -#include - -QT_BEGIN_NAMESPACE - -namespace Qt3DAnimation { - -class QAddBlend; - -class QAddBlendPrivate : public QAbstractClipBlendNodePrivate -{ -public: - QAddBlendPrivate(); - - Q_DECLARE_PUBLIC(QAddBlend) - float m_blendFactor; -}; - -struct QAddBlendData -{ - float blendFactor; -}; - -} // Qt3DAnimation - -QT_END_NAMESPACE - -#endif // QT3DANIMATION_QADDBLEND_P_H diff --git a/src/animation/frontend/qadditiveblend.cpp b/src/animation/frontend/qadditiveblend.cpp new file mode 100644 index 000000000..7b181848a --- /dev/null +++ b/src/animation/frontend/qadditiveblend.cpp @@ -0,0 +1,175 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** 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 "qadditiveblend.h" +#include "qadditiveblend_p.h" +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { + + +/*! + \qmltype AdditiveBlend + \instantiates Qt3DAnimation::QAdditiveBlend + \inqmlmodule Qt3D.Animation + + \brief Performs an addition of two animation clips based on a + normalized factor + + \since 5.9 + + AdditiveBlend can be useful to create advanced animation effects based on + individual animation clips. For instance, given a player character, additive + blending could be used to combine a walking animation clip with an injured + animation clip based on a blend factor that increases the more the player + gets injured. This would then allow with blend factor == 0 to have a non + injured walking player, with blend factor == 1 a fully injured player, with + blend factor == 0.5 a partially walking and injured player. + + \sa BlendedClipAnimator +*/ + +/*! + \class Qt3DAnimation::QAdditiveBlend + \inmodule Qt3DAnimation + \inherits Qt3DAnimation::QAbstractClipBlendNode + + \brief Performs an addition of two animation clips based on a + normalized factor + + \since 5.9 + + QAdditiveBlend can be useful to create advanced animation effects based on + individual animation clips. For instance, given a player character, additive + blending could be used to combine a walking animation clip with an injured + animation clip based on a blend factor that increases the more the player + gets injured. This would then allow with blend factor == 0 to have a non + injured walking player, with blend factor == 1 a fully injured player, with + blend factor == 0.5 a partially walking and injured player. + + \sa QBlendedClipAnimator +*/ + +QAdditiveBlendPrivate::QAdditiveBlendPrivate() + : QAbstractClipBlendNodePrivate() + , m_blendFactor(0.0f) +{ +} + +QAdditiveBlend::QAdditiveBlend(Qt3DCore::QNode *parent) + : QAbstractClipBlendNode(*new QAdditiveBlendPrivate(), parent) +{ +} + +QAdditiveBlend::QAdditiveBlend(QAdditiveBlendPrivate &dd, Qt3DCore::QNode *parent) + : QAbstractClipBlendNode(dd, parent) +{ +} + +QAdditiveBlend::~QAdditiveBlend() +{ +} + +Qt3DCore::QNodeCreatedChangeBasePtr QAdditiveBlend::createNodeCreationChange() const +{ + Q_D(const QAdditiveBlend); + auto creationChange = QClipBlendNodeCreatedChangePtr::create(this); + QAdditiveBlendData &data = creationChange->data; + data.blendFactor = d->m_blendFactor; + return creationChange; +} + +/*! + \qmlproperty real AdditiveBlend::blendFactor + + Specifies the blending factor between 0 and 1 to control the blending of + two animation clips. +*/ +/*! + \property QAdditiveBlend::blendFactor + + Specifies the blending factor between 0 and 1 to control the blending of + two animation clips. + */ +float QAdditiveBlend::blendFactor() const +{ + Q_D(const QAdditiveBlend); + return d->m_blendFactor; +} + +void QAdditiveBlend::setBlendFactor(float blendFactor) +{ + Q_D(QAdditiveBlend); + if (d->m_blendFactor == blendFactor) + return; + + d->m_blendFactor = blendFactor; + emit blendFactorChanged(blendFactor); +} + +/*! + \qmlproperty list AdditiveBlend::clips + + Holds the list of AnimationClip nodes against which the blending is performed. + + \note Only the two first AnimationClip are used, subsequent ones are ignored +*/ + + +/*! + \fn void QAdditiveBlend::addClip(QAnimationClip *clip); + Adds a \a clip to the blending node's clips list. + + \note Only the two first AnimationClip are used, subsequent ones are ignored + */ + +/*! + \fn void QAdditiveBlend::removeClip(QAnimationClip *clip); + Removes a \a clip from the blending node's clips list. + */ + +/*! + \fn QVector QAdditiveBlend::clips() const; + Returns the list of QAnimationClip against which the blending is performed. + */ + + +} // Qt3DAnimation + +QT_END_NAMESPACE diff --git a/src/animation/frontend/qadditiveblend.h b/src/animation/frontend/qadditiveblend.h new file mode 100644 index 000000000..76075988b --- /dev/null +++ b/src/animation/frontend/qadditiveblend.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** 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$ +** +****************************************************************************/ + +#ifndef QT3DANIMATION_QADDITIVEBLEND_H +#define QT3DANIMATION_QADDITIVEBLEND_H + +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { + +class QAdditiveBlendPrivate; + +class QT3DANIMATIONSHARED_EXPORT QAdditiveBlend : public QAbstractClipBlendNode +{ + Q_OBJECT + Q_PROPERTY(float blendFactor READ blendFactor WRITE setBlendFactor NOTIFY blendFactorChanged) +public: + explicit QAdditiveBlend(Qt3DCore::QNode *parent = nullptr); + ~QAdditiveBlend(); + + float blendFactor() const; + +public Q_SLOTS: + void setBlendFactor(float blendFactor); + +Q_SIGNALS: + void blendFactorChanged(float blendFactor); + +protected: + explicit QAdditiveBlend(QAdditiveBlendPrivate &dd, Qt3DCore::QNode *parent = nullptr); + +private: + Q_DECLARE_PRIVATE(QAdditiveBlend) + Qt3DCore::QNodeCreatedChangeBasePtr createNodeCreationChange() const Q_DECL_OVERRIDE; +}; + +} // Qt3DAnimation + +QT_END_NAMESPACE + +#endif // QT3DANIMATION_QADDITIVEBLEND_H diff --git a/src/animation/frontend/qadditiveblend_p.h b/src/animation/frontend/qadditiveblend_p.h new file mode 100644 index 000000000..e21872098 --- /dev/null +++ b/src/animation/frontend/qadditiveblend_p.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** 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$ +** +****************************************************************************/ + +#ifndef QT3DANIMATION_QADDITIVEBLEND_P_H +#define QT3DANIMATION_QADDITIVEBLEND_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { + +class QAdditiveBlend; + +class QAdditiveBlendPrivate : public QAbstractClipBlendNodePrivate +{ +public: + QAdditiveBlendPrivate(); + + Q_DECLARE_PUBLIC(QAdditiveBlend) + float m_blendFactor; +}; + +struct QAdditiveBlendData +{ + float blendFactor; +}; + +} // Qt3DAnimation + +QT_END_NAMESPACE + +#endif // QT3DANIMATION_QADDITIVEBLEND_P_H diff --git a/src/animation/frontend/qanimationaspect.cpp b/src/animation/frontend/qanimationaspect.cpp index 6cf817ff8..b40077fd4 100644 --- a/src/animation/frontend/qanimationaspect.cpp +++ b/src/animation/frontend/qanimationaspect.cpp @@ -46,12 +46,12 @@ #include #include #include -#include +#include #include #include #include #include -#include +#include QT_BEGIN_NAMESPACE @@ -113,8 +113,8 @@ QAnimationAspect::QAnimationAspect(QAnimationAspectPrivate &dd, QObject *parent) registerBackendType( QSharedPointer>::create(d->m_handler.data(), d->m_handler->clipBlendNodeManager())); - registerBackendType( - QSharedPointer>::create(d->m_handler.data(), + registerBackendType( + QSharedPointer>::create(d->m_handler.data(), d->m_handler->clipBlendNodeManager())); } diff --git a/src/quick3d/imports/animation/qt3dquick3danimationplugin.cpp b/src/quick3d/imports/animation/qt3dquick3danimationplugin.cpp index 9918e22b2..85c2afee9 100644 --- a/src/quick3d/imports/animation/qt3dquick3danimationplugin.cpp +++ b/src/quick3d/imports/animation/qt3dquick3danimationplugin.cpp @@ -44,7 +44,7 @@ #include #include #include -#include +#include #include #include #include @@ -66,7 +66,7 @@ void Qt3DQuick3DAnimationPlugin::registerTypes(const char *uri) qmlRegisterExtendedUncreatableType(uri, 2, 2, "AbstractClipBlendNode", QStringLiteral("QAbstractClipBlendNode is abstract")); qmlRegisterType(uri, 2, 2, "LerpBlend"); - qmlRegisterType(uri, 2, 2, "AddBlend"); + qmlRegisterType(uri, 2, 2, "AdditiveBlend"); } QT_END_NAMESPACE diff --git a/tests/auto/animation/addblend/addblend.pro b/tests/auto/animation/addblend/addblend.pro deleted file mode 100644 index bfa9256f4..000000000 --- a/tests/auto/animation/addblend/addblend.pro +++ /dev/null @@ -1,11 +0,0 @@ -TEMPLATE = app - -TARGET = tst_addblend - -QT += 3dcore 3dcore-private 3danimation 3danimation-private testlib - -CONFIG += testcase - -SOURCES += tst_addblend.cpp - -include(../../core/common/common.pri) diff --git a/tests/auto/animation/addblend/tst_addblend.cpp b/tests/auto/animation/addblend/tst_addblend.cpp deleted file mode 100644 index 961fb498e..000000000 --- a/tests/auto/animation/addblend/tst_addblend.cpp +++ /dev/null @@ -1,148 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 Paul Lemire -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt3D module of the Qt Toolkit. -** -** $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 -#include -#include -#include -#include -#include -#include "qbackendnodetester.h" - -class tst_AddBlend : public Qt3DCore::QBackendNodeTester -{ - Q_OBJECT - -private Q_SLOTS: - - void checkInitialState() - { - // GIVEN - Qt3DAnimation::Animation::AddBlend backendAddBlend; - - // THEN - QCOMPARE(backendAddBlend.isEnabled(), false); - QVERIFY(backendAddBlend.peerId().isNull()); - QCOMPARE(backendAddBlend.blendFactor(), 0.0f); - QCOMPARE(backendAddBlend.blendType(), Qt3DAnimation::Animation::ClipBlendNode::AddBlendType); - } - - void checkInitializeFromPeer() - { - // GIVEN - Qt3DAnimation::QAddBlend AddBlend; - Qt3DAnimation::QAnimationClip clip; - AddBlend.setBlendFactor(0.8f); - AddBlend.addClip(&clip); - - { - // WHEN - Qt3DAnimation::Animation::AddBlend backendAddBlend; - simulateInitialization(&AddBlend, &backendAddBlend); - - // THEN - QCOMPARE(backendAddBlend.isEnabled(), true); - QCOMPARE(backendAddBlend.peerId(), AddBlend.id()); - QCOMPARE(backendAddBlend.blendFactor(), 0.8f); - QCOMPARE(backendAddBlend.clipIds().size(), 1); - QCOMPARE(backendAddBlend.clipIds().first(), clip.id()); - } - { - // WHEN - Qt3DAnimation::Animation::AddBlend backendAddBlend; - AddBlend.setEnabled(false); - simulateInitialization(&AddBlend, &backendAddBlend); - - // THEN - QCOMPARE(backendAddBlend.peerId(), AddBlend.id()); - QCOMPARE(backendAddBlend.isEnabled(), false); - } - } - - void checkSceneChangeEvents() - { - // GIVEN - Qt3DAnimation::Animation::AddBlend backendAddBlend; - { - // WHEN - const bool newValue = false; - const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId()); - change->setPropertyName("enabled"); - change->setValue(newValue); - backendAddBlend.sceneChangeEvent(change); - - // THEN - QCOMPARE(backendAddBlend.isEnabled(), newValue); - } - { - // WHEN - const float newValue = 0.883f; - const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId()); - change->setPropertyName("blendFactor"); - change->setValue(QVariant::fromValue(newValue)); - backendAddBlend.sceneChangeEvent(change); - - // THEN - QCOMPARE(backendAddBlend.blendFactor(), newValue); - } - } - - void checkBlend_data() - { - QTest::addColumn("value1"); - QTest::addColumn("value2"); - QTest::addColumn("blendFactor"); - QTest::addColumn("result"); - - QTest::newRow("0_blending") << 8.0f << 5.0f << 0.0f << 8.0f; - QTest::newRow("0.5_blending") << 8.0f << 5.0f << 0.5f << 10.5f; - QTest::newRow("1_blending") << 8.0f << 5.0f << 1.0f << 13.0f; - } - - void checkBlend() - { - // GIVEN - QFETCH(float, value1); - QFETCH(float, value2); - QFETCH(float, blendFactor); - QFETCH(float, result); - Qt3DAnimation::Animation::AddBlend addBlend; - - // WHEN - addBlend.setBlendFactor(blendFactor); - const float computed = addBlend.blend(value1, value2); - - // THEN - QCOMPARE(computed, result); - } -}; - -QTEST_MAIN(tst_AddBlend) - -#include "tst_addblend.moc" diff --git a/tests/auto/animation/additiveblend/additiveblend.pro b/tests/auto/animation/additiveblend/additiveblend.pro new file mode 100644 index 000000000..e61417c73 --- /dev/null +++ b/tests/auto/animation/additiveblend/additiveblend.pro @@ -0,0 +1,12 @@ +TEMPLATE = app + +TARGET = tst_additiveblend + +QT += 3dcore 3dcore-private 3danimation 3danimation-private testlib + +CONFIG += testcase + +SOURCES += \ + tst_additiveblend.cpp + +include(../../core/common/common.pri) diff --git a/tests/auto/animation/additiveblend/tst_additiveblend.cpp b/tests/auto/animation/additiveblend/tst_additiveblend.cpp new file mode 100644 index 000000000..31c103166 --- /dev/null +++ b/tests/auto/animation/additiveblend/tst_additiveblend.cpp @@ -0,0 +1,148 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Paul Lemire +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $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 +#include +#include +#include +#include +#include +#include "qbackendnodetester.h" + +class tst_AdditiveBlend : public Qt3DCore::QBackendNodeTester +{ + Q_OBJECT + +private Q_SLOTS: + + void checkInitialState() + { + // GIVEN + Qt3DAnimation::Animation::AdditiveBlend backendAdditiveBlend; + + // THEN + QCOMPARE(backendAdditiveBlend.isEnabled(), false); + QVERIFY(backendAdditiveBlend.peerId().isNull()); + QCOMPARE(backendAdditiveBlend.blendFactor(), 0.0f); + QCOMPARE(backendAdditiveBlend.blendType(), Qt3DAnimation::Animation::ClipBlendNode::AdditiveBlendType); + } + + void checkInitializeFromPeer() + { + // GIVEN + Qt3DAnimation::QAdditiveBlend additiveBlend; + Qt3DAnimation::QAnimationClip clip; + additiveBlend.setBlendFactor(0.8f); + additiveBlend.addClip(&clip); + + { + // WHEN + Qt3DAnimation::Animation::AdditiveBlend backendAdditiveBlend; + simulateInitialization(&additiveBlend, &backendAdditiveBlend); + + // THEN + QCOMPARE(backendAdditiveBlend.isEnabled(), true); + QCOMPARE(backendAdditiveBlend.peerId(), additiveBlend.id()); + QCOMPARE(backendAdditiveBlend.blendFactor(), 0.8f); + QCOMPARE(backendAdditiveBlend.clipIds().size(), 1); + QCOMPARE(backendAdditiveBlend.clipIds().first(), clip.id()); + } + { + // WHEN + Qt3DAnimation::Animation::AdditiveBlend backendAdditiveBlend; + additiveBlend.setEnabled(false); + simulateInitialization(&additiveBlend, &backendAdditiveBlend); + + // THEN + QCOMPARE(backendAdditiveBlend.peerId(), additiveBlend.id()); + QCOMPARE(backendAdditiveBlend.isEnabled(), false); + } + } + + void checkSceneChangeEvents() + { + // GIVEN + Qt3DAnimation::Animation::AdditiveBlend backendAdditiveBlend; + { + // WHEN + const bool newValue = false; + const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId()); + change->setPropertyName("enabled"); + change->setValue(newValue); + backendAdditiveBlend.sceneChangeEvent(change); + + // THEN + QCOMPARE(backendAdditiveBlend.isEnabled(), newValue); + } + { + // WHEN + const float newValue = 0.883f; + const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId()); + change->setPropertyName("blendFactor"); + change->setValue(QVariant::fromValue(newValue)); + backendAdditiveBlend.sceneChangeEvent(change); + + // THEN + QCOMPARE(backendAdditiveBlend.blendFactor(), newValue); + } + } + + void checkBlend_data() + { + QTest::addColumn("value1"); + QTest::addColumn("value2"); + QTest::addColumn("blendFactor"); + QTest::addColumn("result"); + + QTest::newRow("0_blending") << 8.0f << 5.0f << 0.0f << 8.0f; + QTest::newRow("0.5_blending") << 8.0f << 5.0f << 0.5f << 10.5f; + QTest::newRow("1_blending") << 8.0f << 5.0f << 1.0f << 13.0f; + } + + void checkBlend() + { + // GIVEN + QFETCH(float, value1); + QFETCH(float, value2); + QFETCH(float, blendFactor); + QFETCH(float, result); + Qt3DAnimation::Animation::AdditiveBlend addBlend; + + // WHEN + addBlend.setBlendFactor(blendFactor); + const float computed = addBlend.blend(value1, value2); + + // THEN + QCOMPARE(computed, result); + } +}; + +QTEST_MAIN(tst_AdditiveBlend) + +#include "tst_additiveblend.moc" diff --git a/tests/auto/animation/animation.pro b/tests/auto/animation/animation.pro index 4acf2fe3e..43a00cd12 100644 --- a/tests/auto/animation/animation.pro +++ b/tests/auto/animation/animation.pro @@ -26,6 +26,6 @@ qtConfig(private_tests) { clipblendnode \ lerpblend \ clipblendnodevisitor \ - qaddblend \ - addblend + qadditiveblend \ + additiveblend } diff --git a/tests/auto/animation/qaddblend/qaddblend.pro b/tests/auto/animation/qaddblend/qaddblend.pro deleted file mode 100644 index e633576f6..000000000 --- a/tests/auto/animation/qaddblend/qaddblend.pro +++ /dev/null @@ -1,11 +0,0 @@ -TEMPLATE = app - -TARGET = tst_qaddblend - -QT += 3dcore 3dcore-private 3danimation 3danimation-private testlib - -CONFIG += testcase - -SOURCES += tst_qaddblend.cpp - -include(../../core/common/common.pri) diff --git a/tests/auto/animation/qaddblend/tst_qaddblend.cpp b/tests/auto/animation/qaddblend/tst_qaddblend.cpp deleted file mode 100644 index 57377b3c4..000000000 --- a/tests/auto/animation/qaddblend/tst_qaddblend.cpp +++ /dev/null @@ -1,185 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 Paul Lemire -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt3D module of the Qt Toolkit. -** -** $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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "testpostmanarbiter.h" - -class tst_QAddBlend : public QObject -{ - Q_OBJECT - -private Q_SLOTS: - - void checkDefaultConstruction() - { - // GIVEN - Qt3DAnimation::QAddBlend addBlend; - - // THEN - QCOMPARE(addBlend.blendFactor(), 0.0f); - } - - void checkPropertyChanges() - { - // GIVEN - Qt3DAnimation::QAddBlend addBlend; - - { - // WHEN - QSignalSpy spy(&addBlend, SIGNAL(blendFactorChanged(float))); - const float newValue = 0.5f; - addBlend.setBlendFactor(newValue); - - // THEN - QVERIFY(spy.isValid()); - QCOMPARE(addBlend.blendFactor(), newValue); - QCOMPARE(spy.count(), 1); - - // WHEN - spy.clear(); - addBlend.setBlendFactor(newValue); - - // THEN - QCOMPARE(addBlend.blendFactor(), newValue); - QCOMPARE(spy.count(), 0); - } - } - - void checkCreationData() - { - // GIVEN - Qt3DAnimation::QAddBlend addBlend; - Qt3DAnimation::QAnimationClip clip1; - Qt3DAnimation::QAnimationClip clip2; - - addBlend.addClip(&clip1); - addBlend.addClip(&clip2); - addBlend.setBlendFactor(0.8f); - - - // WHEN - QVector creationChanges; - - { - Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&addBlend); - creationChanges = creationChangeGenerator.creationChanges(); - } - - // THEN - { - QCOMPARE(creationChanges.size(), 3); // 1 + 2 clips - - const auto creationChangeData = qSharedPointerCast>(creationChanges.first()); - const Qt3DAnimation::QAddBlendData cloneData = creationChangeData->data; - - QCOMPARE(addBlend.blendFactor(), cloneData.blendFactor); - QCOMPARE(addBlend.id(), creationChangeData->subjectId()); - QCOMPARE(addBlend.isEnabled(), true); - QCOMPARE(addBlend.isEnabled(), creationChangeData->isNodeEnabled()); - QCOMPARE(addBlend.metaObject(), creationChangeData->metaObject()); - QCOMPARE(creationChangeData->clips().size(), 2); - QCOMPARE(creationChangeData->clips().first(), clip1.id()); - QCOMPARE(creationChangeData->clips().last(), clip2.id()); - QCOMPARE(creationChangeData->parentClipBlendNodeId(), Qt3DCore::QNodeId()); - } - - // WHEN - addBlend.setEnabled(false); - - { - Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&addBlend); - creationChanges = creationChangeGenerator.creationChanges(); - } - - // THEN - { - QCOMPARE(creationChanges.size(), 3); // 1 + 2 clips - - const auto creationChangeData = qSharedPointerCast>(creationChanges.first()); - const Qt3DAnimation::QAddBlendData cloneData = creationChangeData->data; - - QCOMPARE(addBlend.blendFactor(), cloneData.blendFactor); - QCOMPARE(addBlend.id(), creationChangeData->subjectId()); - QCOMPARE(addBlend.isEnabled(), false); - QCOMPARE(addBlend.isEnabled(), creationChangeData->isNodeEnabled()); - QCOMPARE(addBlend.metaObject(), creationChangeData->metaObject()); - QCOMPARE(creationChangeData->clips().size(), 2); - QCOMPARE(creationChangeData->clips().first(), clip1.id()); - QCOMPARE(creationChangeData->clips().last(), clip2.id()); - QCOMPARE(creationChangeData->parentClipBlendNodeId(), Qt3DCore::QNodeId()); - } - } - - void checkBlendFactorUpdate() - { - // GIVEN - TestArbiter arbiter; - Qt3DAnimation::QAddBlend addBlend; - arbiter.setArbiterOnNode(&addBlend); - - { - // WHEN - addBlend.setBlendFactor(0.4f); - QCoreApplication::processEvents(); - - // THEN - QCOMPARE(arbiter.events.size(), 1); - auto change = arbiter.events.first().staticCast(); - QCOMPARE(change->propertyName(), "blendFactor"); - QCOMPARE(change->value().value(), addBlend.blendFactor()); - QCOMPARE(change->type(), Qt3DCore::PropertyUpdated); - - arbiter.events.clear(); - } - - { - // WHEN - addBlend.setBlendFactor(0.4f); - QCoreApplication::processEvents(); - - // THEN - QCOMPARE(arbiter.events.size(), 0); - } - - } - -}; - -QTEST_MAIN(tst_QAddBlend) - -#include "tst_qaddblend.moc" diff --git a/tests/auto/animation/qadditiveblend/qadditiveblend.pro b/tests/auto/animation/qadditiveblend/qadditiveblend.pro new file mode 100644 index 000000000..b3f2a4599 --- /dev/null +++ b/tests/auto/animation/qadditiveblend/qadditiveblend.pro @@ -0,0 +1,12 @@ +TEMPLATE = app + +TARGET = tst_qadditiveblend + +QT += 3dcore 3dcore-private 3danimation 3danimation-private testlib + +CONFIG += testcase + +SOURCES += \ + tst_qadditiveblend.cpp + +include(../../core/common/common.pri) diff --git a/tests/auto/animation/qadditiveblend/tst_qadditiveblend.cpp b/tests/auto/animation/qadditiveblend/tst_qadditiveblend.cpp new file mode 100644 index 000000000..27acf2b47 --- /dev/null +++ b/tests/auto/animation/qadditiveblend/tst_qadditiveblend.cpp @@ -0,0 +1,185 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Paul Lemire +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "testpostmanarbiter.h" + +class tst_QAdditiveBlend : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + + void checkDefaultConstruction() + { + // GIVEN + Qt3DAnimation::QAdditiveBlend addBlend; + + // THEN + QCOMPARE(addBlend.blendFactor(), 0.0f); + } + + void checkPropertyChanges() + { + // GIVEN + Qt3DAnimation::QAdditiveBlend addBlend; + + { + // WHEN + QSignalSpy spy(&addBlend, SIGNAL(blendFactorChanged(float))); + const float newValue = 0.5f; + addBlend.setBlendFactor(newValue); + + // THEN + QVERIFY(spy.isValid()); + QCOMPARE(addBlend.blendFactor(), newValue); + QCOMPARE(spy.count(), 1); + + // WHEN + spy.clear(); + addBlend.setBlendFactor(newValue); + + // THEN + QCOMPARE(addBlend.blendFactor(), newValue); + QCOMPARE(spy.count(), 0); + } + } + + void checkCreationData() + { + // GIVEN + Qt3DAnimation::QAdditiveBlend addBlend; + Qt3DAnimation::QAnimationClip clip1; + Qt3DAnimation::QAnimationClip clip2; + + addBlend.addClip(&clip1); + addBlend.addClip(&clip2); + addBlend.setBlendFactor(0.8f); + + + // WHEN + QVector creationChanges; + + { + Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&addBlend); + creationChanges = creationChangeGenerator.creationChanges(); + } + + // THEN + { + QCOMPARE(creationChanges.size(), 3); // 1 + 2 clips + + const auto creationChangeData = qSharedPointerCast>(creationChanges.first()); + const Qt3DAnimation::QAdditiveBlendData cloneData = creationChangeData->data; + + QCOMPARE(addBlend.blendFactor(), cloneData.blendFactor); + QCOMPARE(addBlend.id(), creationChangeData->subjectId()); + QCOMPARE(addBlend.isEnabled(), true); + QCOMPARE(addBlend.isEnabled(), creationChangeData->isNodeEnabled()); + QCOMPARE(addBlend.metaObject(), creationChangeData->metaObject()); + QCOMPARE(creationChangeData->clips().size(), 2); + QCOMPARE(creationChangeData->clips().first(), clip1.id()); + QCOMPARE(creationChangeData->clips().last(), clip2.id()); + QCOMPARE(creationChangeData->parentClipBlendNodeId(), Qt3DCore::QNodeId()); + } + + // WHEN + addBlend.setEnabled(false); + + { + Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&addBlend); + creationChanges = creationChangeGenerator.creationChanges(); + } + + // THEN + { + QCOMPARE(creationChanges.size(), 3); // 1 + 2 clips + + const auto creationChangeData = qSharedPointerCast>(creationChanges.first()); + const Qt3DAnimation::QAdditiveBlendData cloneData = creationChangeData->data; + + QCOMPARE(addBlend.blendFactor(), cloneData.blendFactor); + QCOMPARE(addBlend.id(), creationChangeData->subjectId()); + QCOMPARE(addBlend.isEnabled(), false); + QCOMPARE(addBlend.isEnabled(), creationChangeData->isNodeEnabled()); + QCOMPARE(addBlend.metaObject(), creationChangeData->metaObject()); + QCOMPARE(creationChangeData->clips().size(), 2); + QCOMPARE(creationChangeData->clips().first(), clip1.id()); + QCOMPARE(creationChangeData->clips().last(), clip2.id()); + QCOMPARE(creationChangeData->parentClipBlendNodeId(), Qt3DCore::QNodeId()); + } + } + + void checkBlendFactorUpdate() + { + // GIVEN + TestArbiter arbiter; + Qt3DAnimation::QAdditiveBlend addBlend; + arbiter.setArbiterOnNode(&addBlend); + + { + // WHEN + addBlend.setBlendFactor(0.4f); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 1); + auto change = arbiter.events.first().staticCast(); + QCOMPARE(change->propertyName(), "blendFactor"); + QCOMPARE(change->value().value(), addBlend.blendFactor()); + QCOMPARE(change->type(), Qt3DCore::PropertyUpdated); + + arbiter.events.clear(); + } + + { + // WHEN + addBlend.setBlendFactor(0.4f); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 0); + } + + } + +}; + +QTEST_MAIN(tst_QAdditiveBlend) + +#include "tst_qadditiveblend.moc" diff --git a/tests/manual/animation-keyframe-simple/main.qml b/tests/manual/animation-keyframe-simple/main.qml index 328d8c7b2..69bccde7d 100644 --- a/tests/manual/animation-keyframe-simple/main.qml +++ b/tests/manual/animation-keyframe-simple/main.qml @@ -145,7 +145,7 @@ DefaultSceneEntity { onRunningChanged: console.log("running = " + running) - blendTree: AddBlend { + blendTree: AdditiveBlend { blendFactor: 0.5 clips: [ AnimationClip { @@ -203,7 +203,7 @@ DefaultSceneEntity { blendTree: LerpBlend { blendFactor: 0.5 - AddBlend { + AdditiveBlend { blendFactor: 0.5 clips: [ AnimationClip { -- cgit v1.2.3 From d7a8f157b78ab998b89e1ceb9cb321638f964e7f Mon Sep 17 00:00:00 2001 From: Kevin Ottens Date: Tue, 31 Jan 2017 16:23:06 +0100 Subject: Add exposure to QCameraLens API Change-Id: I2ad776ec6a7371c7d057d4d5f0feee715e9df188 Reviewed-by: Sean Harmer --- src/render/backend/cameralens.cpp | 8 ++++ src/render/backend/cameralens_p.h | 4 ++ src/render/frontend/qcameralens.cpp | 26 +++++++++++ src/render/frontend/qcameralens.h | 5 ++ src/render/frontend/qcameralens_p.h | 3 ++ tests/auto/render/qcameralens/tst_qcameralens.cpp | 56 +++++++++++++++++++++++ 6 files changed, 102 insertions(+) diff --git a/src/render/backend/cameralens.cpp b/src/render/backend/cameralens.cpp index e60a32422..da557ac76 100644 --- a/src/render/backend/cameralens.cpp +++ b/src/render/backend/cameralens.cpp @@ -54,6 +54,7 @@ namespace Render { CameraLens::CameraLens() : BackendNode() + , m_exposure(0.0f) { } @@ -79,6 +80,11 @@ void CameraLens::setProjection(const QMatrix4x4 &projection) m_projection = projection; } +void CameraLens::setExposure(float exposure) +{ + m_exposure = exposure; +} + void CameraLens::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) { switch (e->type()) { @@ -88,6 +94,8 @@ void CameraLens::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) if (propertyChange->propertyName() == QByteArrayLiteral("projectionMatrix")) { QMatrix4x4 projectionMatrix = propertyChange->value().value(); m_projection = projectionMatrix; + } else if (propertyChange->propertyName() == QByteArrayLiteral("exposure")) { + setExposure(propertyChange->value().toFloat()); } markDirty(AbstractRenderer::AllDirty); diff --git a/src/render/backend/cameralens_p.h b/src/render/backend/cameralens_p.h index e5268da53..72282a88b 100644 --- a/src/render/backend/cameralens_p.h +++ b/src/render/backend/cameralens_p.h @@ -73,12 +73,16 @@ public: void setProjection(const QMatrix4x4 &projection); inline QMatrix4x4 projection() const { return m_projection; } + void setExposure(float exposure); + inline float exposure() const { return m_exposure; } + void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_OVERRIDE; private: void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL; QMatrix4x4 m_projection; + float m_exposure; }; } // namespace Render diff --git a/src/render/frontend/qcameralens.cpp b/src/render/frontend/qcameralens.cpp index 269bc8d16..1b03a16ae 100644 --- a/src/render/frontend/qcameralens.cpp +++ b/src/render/frontend/qcameralens.cpp @@ -201,6 +201,11 @@ namespace Qt3DRender { * \readonly */ +/*! + * \property QCameraLens::exposure + * Holds the current exposure of the camera lens. + */ + /*! * \internal */ @@ -215,6 +220,7 @@ QCameraLensPrivate::QCameraLensPrivate() , m_right(0.5f) , m_bottom(-0.5f) , m_top(0.5f) + , m_exposure(0.0f) { } @@ -559,11 +565,31 @@ QMatrix4x4 QCameraLens::projectionMatrix() const return d->m_projectionMatrix; } +/*! + * Sets the camera lens' exposure + */ +void QCameraLens::setExposure(float exposure) +{ + Q_D(QCameraLens); + if (qFuzzyCompare(d->m_exposure, exposure)) + return; + d->m_exposure = exposure; + + emit exposureChanged(exposure); +} + +float QCameraLens::exposure() const +{ + Q_D(const QCameraLens); + return d->m_exposure; +} + Qt3DCore::QNodeCreatedChangeBasePtr QCameraLens::createNodeCreationChange() const { auto creationChange = Qt3DCore::QNodeCreatedChangePtr::create(this); auto &data = creationChange->data; data.projectionMatrix = d_func()->m_projectionMatrix; + data.exposure = d_func()->m_exposure; return creationChange; } diff --git a/src/render/frontend/qcameralens.h b/src/render/frontend/qcameralens.h index ad414cada..dc7cfa561 100644 --- a/src/render/frontend/qcameralens.h +++ b/src/render/frontend/qcameralens.h @@ -66,6 +66,7 @@ class QT3DRENDERSHARED_EXPORT QCameraLens : public Qt3DCore::QComponent Q_PROPERTY(float bottom READ bottom WRITE setBottom NOTIFY bottomChanged) Q_PROPERTY(float top READ top WRITE setTop NOTIFY topChanged) Q_PROPERTY(QMatrix4x4 projectionMatrix READ projectionMatrix WRITE setProjectionMatrix NOTIFY projectionMatrixChanged) + Q_PROPERTY(float exposure READ exposure WRITE setExposure NOTIFY exposureChanged) public: explicit QCameraLens(QNode *parent = nullptr); @@ -102,6 +103,8 @@ public: void setPerspectiveProjection(float fieldOfView, float aspect, float nearPlane, float farPlane); + float exposure() const; + public Q_SLOTS: void setProjectionType(ProjectionType projectionType); void setNearPlane(float nearPlane); @@ -113,6 +116,7 @@ public Q_SLOTS: void setBottom(float bottom); void setTop(float top); void setProjectionMatrix(const QMatrix4x4 &projectionMatrix); + void setExposure(float exposure); Q_SIGNALS: void projectionTypeChanged(QCameraLens::ProjectionType projectionType); @@ -125,6 +129,7 @@ Q_SIGNALS: void bottomChanged(float bottom); void topChanged(float top); void projectionMatrixChanged(const QMatrix4x4 &projectionMatrix); + void exposureChanged(float exposure); protected: explicit QCameraLens(QCameraLensPrivate &dd, QNode *parent = nullptr); diff --git a/src/render/frontend/qcameralens_p.h b/src/render/frontend/qcameralens_p.h index ecaa45b68..71759d5f8 100644 --- a/src/render/frontend/qcameralens_p.h +++ b/src/render/frontend/qcameralens_p.h @@ -101,6 +101,8 @@ public: mutable QMatrix4x4 m_projectionMatrix; + float m_exposure; + private: inline void updatePerpectiveProjection() { @@ -130,6 +132,7 @@ private: struct QCameraLensData { QMatrix4x4 projectionMatrix; + float exposure; }; } // namespace Qt3DRender diff --git a/tests/auto/render/qcameralens/tst_qcameralens.cpp b/tests/auto/render/qcameralens/tst_qcameralens.cpp index aab43d553..adff66dc5 100644 --- a/tests/auto/render/qcameralens/tst_qcameralens.cpp +++ b/tests/auto/render/qcameralens/tst_qcameralens.cpp @@ -63,6 +63,7 @@ private Q_SLOTS: QCOMPARE(cameraLens.right(), 0.5f); QCOMPARE(cameraLens.bottom(), -0.5f); QCOMPARE(cameraLens.top(), 0.5f); + QCOMPARE(cameraLens.exposure(), 0.0f); } void checkPropertyChanges() @@ -241,6 +242,26 @@ private Q_SLOTS: QCOMPARE(cameraLens.top(), newValue); QCOMPARE(spy.count(), 0); } + { + // WHEN + QSignalSpy spy(&cameraLens, SIGNAL(exposureChanged(float))); + const float newValue = -2.0f; + cameraLens.setExposure(newValue); + + // THEN + QVERIFY(spy.isValid()); + QCOMPARE(cameraLens.exposure(), newValue); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.takeFirst().first().toFloat(), -2.0f); + + // WHEN + spy.clear(); + cameraLens.setExposure(newValue); + + // THEN + QCOMPARE(cameraLens.exposure(), newValue); + QCOMPARE(spy.count(), 0); + } { // WHEN QSignalSpy spy(&cameraLens, SIGNAL(projectionMatrixChanged(QMatrix4x4))); @@ -340,6 +361,7 @@ private Q_SLOTS: cameraLens.setFarPlane(1005.0f); cameraLens.setFieldOfView(35.0f); cameraLens.setAspectRatio(16.0f/9.0f); + cameraLens.setExposure(1.0f); // WHEN QVector creationChanges; @@ -357,6 +379,7 @@ private Q_SLOTS: const Qt3DRender::QCameraLensData cloneData = creationChangeData->data; QCOMPARE(cameraLens.projectionMatrix(), cloneData.projectionMatrix); + QCOMPARE(cameraLens.exposure(), cloneData.exposure); QCOMPARE(cameraLens.id(), creationChangeData->subjectId()); QCOMPARE(cameraLens.isEnabled(), true); QCOMPARE(cameraLens.isEnabled(), creationChangeData->isNodeEnabled()); @@ -379,6 +402,7 @@ private Q_SLOTS: const Qt3DRender::QCameraLensData cloneData = creationChangeData->data; QCOMPARE(cameraLens.projectionMatrix(), cloneData.projectionMatrix); + QCOMPARE(cameraLens.exposure(), cloneData.exposure); QCOMPARE(cameraLens.id(), creationChangeData->subjectId()); QCOMPARE(cameraLens.isEnabled(), false); QCOMPARE(cameraLens.isEnabled(), creationChangeData->isNodeEnabled()); @@ -674,6 +698,38 @@ private Q_SLOTS: } + void checkExposureUpdate() + { + // GIVEN + TestArbiter arbiter; + Qt3DRender::QCameraLens cameraLens; + arbiter.setArbiterOnNode(&cameraLens); + + { + // WHEN + cameraLens.setExposure(2.0f); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 1); + auto change = arbiter.events.first().staticCast(); + QCOMPARE(change->propertyName(), "exposure"); + QCOMPARE(change->type(), Qt3DCore::PropertyUpdated); + + arbiter.events.clear(); + } + + { + // WHEN + cameraLens.setExposure(2.0f); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 0); + } + + } + void checkProjectionMatrixUpdate() { // GIVEN -- cgit v1.2.3 From ac4c450d7067ff176d7cd3d62d6d094f636d6bc6 Mon Sep 17 00:00:00 2001 From: Kevin Ottens Date: Tue, 31 Jan 2017 16:27:45 +0100 Subject: Add exposure to QCamera's API Change-Id: I10b8248f10dac510f7750a230cd9a66793ed26a0 Reviewed-by: Sean Harmer --- src/render/frontend/qcamera.cpp | 21 +++++++++++++++++++++ src/render/frontend/qcamera.h | 4 ++++ 2 files changed, 25 insertions(+) diff --git a/src/render/frontend/qcamera.cpp b/src/render/frontend/qcamera.cpp index b9e180b97..38fda277f 100644 --- a/src/render/frontend/qcamera.cpp +++ b/src/render/frontend/qcamera.cpp @@ -345,6 +345,11 @@ QCameraPrivate::QCameraPrivate() * Holds the current projection matrix of the camera. */ +/*! + * \property QCamera::exposure + * Holds the current exposure of the camera. + */ + /*! * \property QCamera::position * Holds the camera's position. @@ -387,6 +392,7 @@ QCamera::QCamera(Qt3DCore::QNode *parent) QObject::connect(d_func()->m_lens, SIGNAL(bottomChanged(float)), this, SIGNAL(bottomChanged(float))); QObject::connect(d_func()->m_lens, SIGNAL(topChanged(float)), this, SIGNAL(topChanged(float))); QObject::connect(d_func()->m_lens, SIGNAL(projectionMatrixChanged(const QMatrix4x4 &)), this, SIGNAL(projectionMatrixChanged(const QMatrix4x4 &))); + QObject::connect(d_func()->m_lens, SIGNAL(exposureChanged(float)), this, SIGNAL(exposureChanged(float))); QObject::connect(d_func()->m_transform, SIGNAL(matrixChanged()), this, SIGNAL(viewMatrixChanged())); addComponent(d_func()->m_lens); addComponent(d_func()->m_transform); @@ -773,12 +779,27 @@ void QCamera::setProjectionMatrix(const QMatrix4x4 &projectionMatrix) d->m_lens->setProjectionMatrix(projectionMatrix); } +/*! + * Sets the camera's exposure to \a exposure. + */ +void QCamera::setExposure(float exposure) +{ + Q_D(QCamera); + d->m_lens->setExposure(exposure); +} + QMatrix4x4 QCamera::projectionMatrix() const { Q_D(const QCamera); return d->m_lens->projectionMatrix(); } +float QCamera::exposure() const +{ + Q_D(const QCamera); + return d->m_lens->exposure(); +} + /*! * Sets the camera's position in 3D space to \a position. */ diff --git a/src/render/frontend/qcamera.h b/src/render/frontend/qcamera.h index f5bd49fa2..04e54d88c 100644 --- a/src/render/frontend/qcamera.h +++ b/src/render/frontend/qcamera.h @@ -72,6 +72,7 @@ class QT3DRENDERSHARED_EXPORT QCamera : public Qt3DCore::QEntity Q_PROPERTY(float bottom READ bottom WRITE setBottom NOTIFY bottomChanged) Q_PROPERTY(float top READ top WRITE setTop NOTIFY topChanged) Q_PROPERTY(QMatrix4x4 projectionMatrix READ projectionMatrix WRITE setProjectionMatrix NOTIFY projectionMatrixChanged) + Q_PROPERTY(float exposure READ exposure WRITE setExposure NOTIFY exposureChanged) // LookAt Q_PROPERTY(QVector3D position READ position WRITE setPosition NOTIFY positionChanged) Q_PROPERTY(QVector3D upVector READ upVector WRITE setUpVector NOTIFY upVectorChanged) @@ -126,6 +127,7 @@ public: float bottom() const; float top() const; QMatrix4x4 projectionMatrix() const; + float exposure() const; QVector3D position() const; QVector3D upVector() const; QVector3D viewCenter() const; @@ -143,6 +145,7 @@ public Q_SLOTS: void setBottom(float bottom); void setTop(float top); void setProjectionMatrix(const QMatrix4x4 &projectionMatrix); + void setExposure(float exposure); void setPosition(const QVector3D &position); void setUpVector(const QVector3D &upVector); void setViewCenter(const QVector3D &viewCenter); @@ -158,6 +161,7 @@ Q_SIGNALS: void bottomChanged(float bottom); void topChanged(float top); void projectionMatrixChanged(const QMatrix4x4 &projectionMatrix); + void exposureChanged(float exposure); void positionChanged(const QVector3D &position); void upVectorChanged(const QVector3D &upVector); void viewCenterChanged(const QVector3D &viewCenter); -- cgit v1.2.3 From 1b538c2311d43830d8a43cfa244c35e6fe77c0e7 Mon Sep 17 00:00:00 2001 From: Kevin Ottens Date: Tue, 31 Jan 2017 16:31:35 +0100 Subject: Expose QCameraLens' exposure to the shaders Change-Id: I31c6907ba2a596d2e359d85bf00263751f6e2586 Reviewed-by: Sean Harmer --- src/render/backend/renderview.cpp | 3 +++ src/render/backend/renderview_p.h | 1 + 2 files changed, 4 insertions(+) diff --git a/src/render/backend/renderview.cpp b/src/render/backend/renderview.cpp index edd19622a..c4e4a191e 100644 --- a/src/render/backend/renderview.cpp +++ b/src/render/backend/renderview.cpp @@ -129,6 +129,7 @@ RenderView::StandardUniformsNameToTypeHash RenderView::initializeStandardUniform setters.insert(StringToInt::lookupId(QLatin1String("modelViewNormal")), ModelViewNormalMatrix); setters.insert(StringToInt::lookupId(QLatin1String("viewportMatrix")), ViewportMatrix); setters.insert(StringToInt::lookupId(QLatin1String("inverseViewportMatrix")), InverseViewportMatrix); + setters.insert(StringToInt::lookupId(QLatin1String("exposure")), Exposure); setters.insert(StringToInt::lookupId(QLatin1String("time")), Time); setters.insert(StringToInt::lookupId(QLatin1String("eyePosition")), EyePosition); @@ -191,6 +192,8 @@ UniformValue RenderView::standardUniformValue(RenderView::StandardUniform standa viewportMatrix.viewport(resolveViewport(m_viewport, m_surfaceSize)); return UniformValue(viewportMatrix.inverted()); } + case Exposure: + return UniformValue(m_data.m_renderCameraLens->exposure()); case Time: return UniformValue(float(m_renderer->time() / 1000000000.0f)); case EyePosition: diff --git a/src/render/backend/renderview_p.h b/src/render/backend/renderview_p.h index ec56e7ff2..ac2733eaa 100644 --- a/src/render/backend/renderview_p.h +++ b/src/render/backend/renderview_p.h @@ -307,6 +307,7 @@ private: ViewportMatrix, InverseViewportMatrix, Time, + Exposure, EyePosition }; -- cgit v1.2.3 From 708720b8a1056aec2c62a3a2467a324d62a25ee1 Mon Sep 17 00:00:00 2001 From: Kevin Ottens Date: Tue, 31 Jan 2017 16:37:26 +0100 Subject: Remove exposure property from metal/rough materials This is now controlled on the camera lens as it should be. No need to have that per material instance anymore. Change-Id: I2e46a38f2cc2f2e2d670ed73a2be6d98464b21b1 Reviewed-by: Sean Harmer --- src/extras/defaults/qmetalroughmaterial.cpp | 27 ---------------------- src/extras/defaults/qmetalroughmaterial.h | 4 ---- src/extras/defaults/qmetalroughmaterial_p.h | 2 -- .../defaults/qtexturedmetalroughmaterial.cpp | 27 ---------------------- src/extras/defaults/qtexturedmetalroughmaterial.h | 4 ---- .../defaults/qtexturedmetalroughmaterial_p.h | 2 -- 6 files changed, 66 deletions(-) diff --git a/src/extras/defaults/qmetalroughmaterial.cpp b/src/extras/defaults/qmetalroughmaterial.cpp index e895da639..ee43993c9 100644 --- a/src/extras/defaults/qmetalroughmaterial.cpp +++ b/src/extras/defaults/qmetalroughmaterial.cpp @@ -67,7 +67,6 @@ QMetalRoughMaterialPrivate::QMetalRoughMaterialPrivate() , m_roughnessParameter(new QParameter(QStringLiteral("roughness"), 0.0f)) , m_environmentIrradianceParameter(new QParameter(QStringLiteral("skyIrradiance"), m_environmentIrradianceTexture)) , m_environmentSpecularParameter(new QParameter(QStringLiteral("skySpecular"), m_environmentSpecularTexture)) - , m_exposureParameter(new QParameter(QStringLiteral("exposure"), 0.0f)) , m_metalRoughEffect(new QEffect()) , m_metalRoughGL3Technique(new QTechnique()) , m_metalRoughGL3RenderPass(new QRenderPass()) @@ -99,8 +98,6 @@ void QMetalRoughMaterialPrivate::init() this, &QMetalRoughMaterialPrivate::handleEnvironmentIrradianceChanged); connect(m_environmentSpecularParameter, &Qt3DRender::QParameter::valueChanged, this, &QMetalRoughMaterialPrivate::handleEnvironmentSpecularChanged); - connect(m_exposureParameter, &Qt3DRender::QParameter::valueChanged, - this, &QMetalRoughMaterialPrivate::handleExposureChanged); m_metalRoughGL3Shader->setVertexShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/gl3/metalrough.vert")))); m_metalRoughGL3Shader->setFragmentShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/gl3/metalroughuniform.frag")))); @@ -125,7 +122,6 @@ void QMetalRoughMaterialPrivate::init() m_metalRoughEffect->addParameter(m_roughnessParameter); m_metalRoughEffect->addParameter(m_environmentIrradianceParameter); m_metalRoughEffect->addParameter(m_environmentSpecularParameter); - m_metalRoughEffect->addParameter(m_exposureParameter); q->setEffect(m_metalRoughEffect); } @@ -159,12 +155,6 @@ void QMetalRoughMaterialPrivate::handleEnvironmentSpecularChanged(const QVariant emit q->environmentSpecularChanged(var.value()); } -void QMetalRoughMaterialPrivate::handleExposureChanged(const QVariant &var) -{ - Q_Q(QMetalRoughMaterial); - emit q->exposureChanged(var.toFloat()); -} - /*! \class Qt3DExtras::QMetalRoughMaterial \brief The QMetalRoughMaterial provides a default implementation of PBR @@ -276,17 +266,6 @@ QAbstractTexture *QMetalRoughMaterial::environmentSpecular() const return d->m_environmentSpecularParameter->value().value(); } -/*! - \property QMetalRoughMaterial::exposure - - Holds the current exposure as a float value. -*/ -float QMetalRoughMaterial::exposure() const -{ - Q_D(const QMetalRoughMaterial); - return d->m_exposureParameter->value().toFloat(); -} - void QMetalRoughMaterial::setBaseColor(const QColor &baseColor) { Q_D(QMetalRoughMaterial); @@ -317,12 +296,6 @@ void QMetalRoughMaterial::setEnvironmentSpecular(QAbstractTexture *environmentSp d->m_environmentSpecularParameter->setValue(QVariant::fromValue(environmentSpecular)); } -void QMetalRoughMaterial::setExposure(float exposure) -{ - Q_D(QMetalRoughMaterial); - d->m_exposureParameter->setValue(exposure); -} - } // namespace Qt3DExtras QT_END_NAMESPACE diff --git a/src/extras/defaults/qmetalroughmaterial.h b/src/extras/defaults/qmetalroughmaterial.h index 914cef6ca..a7fbfba59 100644 --- a/src/extras/defaults/qmetalroughmaterial.h +++ b/src/extras/defaults/qmetalroughmaterial.h @@ -62,7 +62,6 @@ class QT3DEXTRASSHARED_EXPORT QMetalRoughMaterial : public Qt3DRender::QMaterial Q_PROPERTY(float roughness READ roughness WRITE setRoughness NOTIFY roughnessChanged) Q_PROPERTY(Qt3DRender::QAbstractTexture *environmentIrradiance READ environmentIrradiance WRITE setEnvironmentIrradiance NOTIFY environmentIrradianceChanged) Q_PROPERTY(Qt3DRender::QAbstractTexture *environmentSpecular READ environmentSpecular WRITE setEnvironmentSpecular NOTIFY environmentSpecularChanged) - Q_PROPERTY(float exposure READ exposure WRITE setExposure NOTIFY exposureChanged) public: explicit QMetalRoughMaterial(Qt3DCore::QNode *parent = nullptr); @@ -73,7 +72,6 @@ public: float roughness() const; Qt3DRender::QAbstractTexture *environmentIrradiance() const; Qt3DRender::QAbstractTexture *environmentSpecular() const; - float exposure() const; public Q_SLOTS: void setBaseColor(const QColor &baseColor); @@ -81,7 +79,6 @@ public Q_SLOTS: void setRoughness(float roughness); void setEnvironmentIrradiance(Qt3DRender::QAbstractTexture *environmentIrradiance); void setEnvironmentSpecular(Qt3DRender::QAbstractTexture *environmentSpecular); - void setExposure(float exposure); Q_SIGNALS: void baseColorChanged(const QColor &baseColor); @@ -89,7 +86,6 @@ Q_SIGNALS: void roughnessChanged(float roughness); void environmentIrradianceChanged(Qt3DRender::QAbstractTexture *environmentIrradiance); void environmentSpecularChanged(Qt3DRender::QAbstractTexture *environmentSpecular); - void exposureChanged(float exposure); protected: QMetalRoughMaterial(QMetalRoughMaterialPrivate &dd, Qt3DCore::QNode *parent = nullptr); diff --git a/src/extras/defaults/qmetalroughmaterial_p.h b/src/extras/defaults/qmetalroughmaterial_p.h index d287f0093..e501867e1 100644 --- a/src/extras/defaults/qmetalroughmaterial_p.h +++ b/src/extras/defaults/qmetalroughmaterial_p.h @@ -83,7 +83,6 @@ public: void handleRoughnessChanged(const QVariant &var); void handleEnvironmentIrradianceChanged(const QVariant &var); void handleEnvironmentSpecularChanged(const QVariant &var); - void handleExposureChanged(const QVariant &var); Qt3DRender::QAbstractTexture *m_environmentIrradianceTexture; Qt3DRender::QAbstractTexture *m_environmentSpecularTexture; @@ -92,7 +91,6 @@ public: Qt3DRender::QParameter *m_roughnessParameter; Qt3DRender::QParameter *m_environmentIrradianceParameter; Qt3DRender::QParameter *m_environmentSpecularParameter; - Qt3DRender::QParameter *m_exposureParameter; Qt3DRender::QEffect *m_metalRoughEffect; Qt3DRender::QTechnique *m_metalRoughGL3Technique; Qt3DRender::QRenderPass *m_metalRoughGL3RenderPass; diff --git a/src/extras/defaults/qtexturedmetalroughmaterial.cpp b/src/extras/defaults/qtexturedmetalroughmaterial.cpp index 20c54f1c6..f50bc8ab8 100644 --- a/src/extras/defaults/qtexturedmetalroughmaterial.cpp +++ b/src/extras/defaults/qtexturedmetalroughmaterial.cpp @@ -74,7 +74,6 @@ QTexturedMetalRoughMaterialPrivate::QTexturedMetalRoughMaterialPrivate() , m_normalParameter(new QParameter(QStringLiteral("normalMap"), m_normalTexture)) , m_environmentIrradianceParameter(new QParameter(QStringLiteral("skyIrradiance"), m_environmentIrradianceTexture)) , m_environmentSpecularParameter(new QParameter(QStringLiteral("skySpecular"), m_environmentSpecularTexture)) - , m_exposureParameter(new QParameter(QStringLiteral("exposure"), 0.0f)) , m_metalRoughEffect(new QEffect()) , m_metalRoughGL3Technique(new QTechnique()) , m_metalRoughGL3RenderPass(new QRenderPass()) @@ -140,8 +139,6 @@ void QTexturedMetalRoughMaterialPrivate::init() this, &QTexturedMetalRoughMaterialPrivate::handleEnvironmentIrradianceChanged); connect(m_environmentSpecularParameter, &Qt3DRender::QParameter::valueChanged, this, &QTexturedMetalRoughMaterialPrivate::handleEnvironmentSpecularChanged); - connect(m_exposureParameter, &Qt3DRender::QParameter::valueChanged, - this, &QTexturedMetalRoughMaterialPrivate::handleExposureChanged); m_metalRoughGL3Shader->setVertexShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/gl3/metalrough.vert")))); m_metalRoughGL3Shader->setFragmentShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/gl3/metalrough.frag")))); @@ -168,7 +165,6 @@ void QTexturedMetalRoughMaterialPrivate::init() m_metalRoughEffect->addParameter(m_normalParameter); m_metalRoughEffect->addParameter(m_environmentIrradianceParameter); m_metalRoughEffect->addParameter(m_environmentSpecularParameter); - m_metalRoughEffect->addParameter(m_exposureParameter); q->setEffect(m_metalRoughEffect); } @@ -213,12 +209,6 @@ void QTexturedMetalRoughMaterialPrivate::handleEnvironmentSpecularChanged(const emit q->environmentSpecularChanged(var.value()); } -void QTexturedMetalRoughMaterialPrivate::handleExposureChanged(const QVariant &var) -{ - Q_Q(QTexturedMetalRoughMaterial); - emit q->exposureChanged(var.toFloat()); -} - /*! \class Qt3DExtras::QTexturedMetalRoughMaterial \brief The QTexturedMetalRoughMaterial provides a default implementation of PBR @@ -396,17 +386,6 @@ QAbstractTexture *QTexturedMetalRoughMaterial::environmentSpecular() const return d->m_environmentSpecularParameter->value().value(); } -/*! - \property QTexturedMetalRoughMaterial::exposure - - Holds the current exposure as a float value. -*/ -float QTexturedMetalRoughMaterial::exposure() const -{ - Q_D(const QTexturedMetalRoughMaterial); - return d->m_exposureParameter->value().toFloat(); -} - void QTexturedMetalRoughMaterial::setBaseColor(QAbstractTexture *baseColor) { Q_D(QTexturedMetalRoughMaterial); @@ -449,12 +428,6 @@ void QTexturedMetalRoughMaterial::setEnvironmentSpecular(QAbstractTexture *envir d->m_environmentSpecularParameter->setValue(QVariant::fromValue(environmentSpecular)); } -void QTexturedMetalRoughMaterial::setExposure(float exposure) -{ - Q_D(QTexturedMetalRoughMaterial); - d->m_exposureParameter->setValue(exposure); -} - } // namespace Qt3DExtras QT_END_NAMESPACE diff --git a/src/extras/defaults/qtexturedmetalroughmaterial.h b/src/extras/defaults/qtexturedmetalroughmaterial.h index 39a01d960..2a667aea8 100644 --- a/src/extras/defaults/qtexturedmetalroughmaterial.h +++ b/src/extras/defaults/qtexturedmetalroughmaterial.h @@ -59,7 +59,6 @@ class QT3DEXTRASSHARED_EXPORT QTexturedMetalRoughMaterial : public Qt3DRender::Q Q_PROPERTY(Qt3DRender::QAbstractTexture *normal READ normal WRITE setNormal NOTIFY normalChanged) Q_PROPERTY(Qt3DRender::QAbstractTexture *environmentIrradiance READ environmentIrradiance WRITE setEnvironmentIrradiance NOTIFY environmentIrradianceChanged) Q_PROPERTY(Qt3DRender::QAbstractTexture *environmentSpecular READ environmentSpecular WRITE setEnvironmentSpecular NOTIFY environmentSpecularChanged) - Q_PROPERTY(float exposure READ exposure WRITE setExposure NOTIFY exposureChanged) public: explicit QTexturedMetalRoughMaterial(Qt3DCore::QNode *parent = nullptr); @@ -72,7 +71,6 @@ public: Qt3DRender::QAbstractTexture *normal() const; Qt3DRender::QAbstractTexture *environmentIrradiance() const; Qt3DRender::QAbstractTexture *environmentSpecular() const; - float exposure() const; public Q_SLOTS: void setBaseColor(Qt3DRender::QAbstractTexture *baseColor); @@ -82,7 +80,6 @@ public Q_SLOTS: void setNormal(Qt3DRender::QAbstractTexture *normal); void setEnvironmentIrradiance(Qt3DRender::QAbstractTexture *environmentIrradiance); void setEnvironmentSpecular(Qt3DRender::QAbstractTexture *environmentSpecular); - void setExposure(float exposure); Q_SIGNALS: void baseColorChanged(Qt3DRender::QAbstractTexture *baseColor); @@ -92,7 +89,6 @@ Q_SIGNALS: void normalChanged(Qt3DRender::QAbstractTexture *normal); void environmentIrradianceChanged(Qt3DRender::QAbstractTexture *environmentIrradiance); void environmentSpecularChanged(Qt3DRender::QAbstractTexture *environmentSpecular); - void exposureChanged(float exposure); protected: QTexturedMetalRoughMaterial(QTexturedMetalRoughMaterialPrivate &dd, Qt3DCore::QNode *parent = nullptr); diff --git a/src/extras/defaults/qtexturedmetalroughmaterial_p.h b/src/extras/defaults/qtexturedmetalroughmaterial_p.h index 84b0e7d77..54fdb73b2 100644 --- a/src/extras/defaults/qtexturedmetalroughmaterial_p.h +++ b/src/extras/defaults/qtexturedmetalroughmaterial_p.h @@ -85,7 +85,6 @@ public: void handleNormalChanged(const QVariant &var); void handleEnvironmentIrradianceChanged(const QVariant &var); void handleEnvironmentSpecularChanged(const QVariant &var); - void handleExposureChanged(const QVariant &var); Qt3DRender::QAbstractTexture *m_baseColorTexture; Qt3DRender::QAbstractTexture *m_metallicTexture; @@ -101,7 +100,6 @@ public: Qt3DRender::QParameter *m_normalParameter; Qt3DRender::QParameter *m_environmentIrradianceParameter; Qt3DRender::QParameter *m_environmentSpecularParameter; - Qt3DRender::QParameter *m_exposureParameter; Qt3DRender::QEffect *m_metalRoughEffect; Qt3DRender::QTechnique *m_metalRoughGL3Technique; Qt3DRender::QRenderPass *m_metalRoughGL3RenderPass; -- cgit v1.2.3 From 9ae12590ac965ca454b67c27f4411d71ad05ae86 Mon Sep 17 00:00:00 2001 From: Kevin Ottens Date: Tue, 31 Jan 2017 17:09:21 +0100 Subject: Add gamma to QViewport's API Change-Id: Ieced911cf1e51c0befc5ce91e8529a421b5c5a80 Reviewed-by: Sean Harmer --- src/render/framegraph/qviewport.cpp | 34 +++++++- src/render/framegraph/qviewport.h | 4 + src/render/framegraph/qviewport_p.h | 2 + src/render/framegraph/viewportnode.cpp | 14 ++++ src/render/framegraph/viewportnode_p.h | 4 + tests/auto/render/qviewport/tst_qviewport.cpp | 108 ++++++++++++++++++-------- 6 files changed, 131 insertions(+), 35 deletions(-) diff --git a/src/render/framegraph/qviewport.cpp b/src/render/framegraph/qviewport.cpp index a78e260a5..8c1ebe67c 100644 --- a/src/render/framegraph/qviewport.cpp +++ b/src/render/framegraph/qviewport.cpp @@ -50,6 +50,7 @@ namespace Qt3DRender { QViewportPrivate::QViewportPrivate() : QFrameGraphNodePrivate() , m_normalizedRect(QRectF(0.0f, 0.0f, 1.0f, 1.0f)) + , m_gamma(2.2f) { } @@ -62,7 +63,8 @@ QViewportPrivate::QViewportPrivate() \inherits Qt3DRender::QFrameGraphNode Qt3DRender::QViewport of the scene specifies at which portion of the render surface Qt3D - is rendering to. Area outside the viewport is left untouched. + is rendering to. Area outside the viewport is left untouched. It also controls global parameters + to the rendering in that viewport like gamma. */ /*! @@ -74,7 +76,8 @@ QViewportPrivate::QViewportPrivate() \brief A viewport on the Qt3D Scene Viewport of the scene specifies at which portion of the render surface Qt3D is - rendering to. Area outside the viewport is left untouched. + rendering to. Area outside the viewport is left untouched. It also controls global parameters + to the rendering in that viewport like gamma. */ /*! @@ -85,6 +88,12 @@ QViewportPrivate::QViewportPrivate() is specified as [0.0, 0.0, 1.0, 1.0], which is the default. */ +/*! + \qmlproperty rect Viewport::gamma + + Specifies the gamma factor for the viewport. The default is 2.2 which should give proper result on most screens. + */ + /*! Constructs QViewport with given \a parent. */ @@ -111,6 +120,12 @@ QRectF QViewport::normalizedRect() const return d->m_normalizedRect; } +float QViewport::gamma() const +{ + Q_D(const QViewport); + return d->m_gamma; +} + /*! \property QViewport::normalizedRect @@ -127,12 +142,27 @@ void QViewport::setNormalizedRect(const QRectF &normalizedRect) } } +/*! + \property QViewport::gamma + + Specifies the gamma factor for the viewport. The default is 2.2 which should give proper result on most screens. + */ +void QViewport::setGamma(float gamma) +{ + Q_D(QViewport); + if (gamma != d->m_gamma) { + d->m_gamma = gamma; + emit gammaChanged(gamma); + } +} + Qt3DCore::QNodeCreatedChangeBasePtr QViewport::createNodeCreationChange() const { auto creationChange = QFrameGraphNodeCreatedChangePtr::create(this); auto &data = creationChange->data; Q_D(const QViewport); data.normalizedRect = d->m_normalizedRect; + data.gamma = d->m_gamma; return creationChange; } diff --git a/src/render/framegraph/qviewport.h b/src/render/framegraph/qviewport.h index 5959ed791..abe423cf4 100644 --- a/src/render/framegraph/qviewport.h +++ b/src/render/framegraph/qviewport.h @@ -54,18 +54,22 @@ class QT3DRENDERSHARED_EXPORT QViewport : public QFrameGraphNode { Q_OBJECT Q_PROPERTY(QRectF normalizedRect READ normalizedRect WRITE setNormalizedRect NOTIFY normalizedRectChanged) + Q_PROPERTY(float gamma READ gamma WRITE setGamma NOTIFY gammaChanged) public: explicit QViewport(Qt3DCore::QNode *parent = nullptr); ~QViewport(); QRectF normalizedRect() const; + float gamma() const; public Q_SLOTS: void setNormalizedRect(const QRectF& normalizedRect); + void setGamma(float gamma); Q_SIGNALS: void normalizedRectChanged(const QRectF& normalizedRect); + void gammaChanged(float gamma); protected: explicit QViewport(QViewportPrivate &dd, Qt3DCore::QNode *parent = nullptr); diff --git a/src/render/framegraph/qviewport_p.h b/src/render/framegraph/qviewport_p.h index 790cd3d06..4c82f38b3 100644 --- a/src/render/framegraph/qviewport_p.h +++ b/src/render/framegraph/qviewport_p.h @@ -67,11 +67,13 @@ public : Q_DECLARE_PUBLIC(QViewport) QRectF m_normalizedRect; QColor m_clearColor; + float m_gamma; }; struct QViewportData { QRectF normalizedRect; + float gamma; }; } // namespace Qt3DRender diff --git a/src/render/framegraph/viewportnode.cpp b/src/render/framegraph/viewportnode.cpp index ccdb68918..c16a660b0 100644 --- a/src/render/framegraph/viewportnode.cpp +++ b/src/render/framegraph/viewportnode.cpp @@ -55,6 +55,7 @@ ViewportNode::ViewportNode() , m_yMin(0.0f) , m_xMax(1.0f) , m_yMax(1.0f) + , m_gamma(2.2f) { } @@ -67,6 +68,7 @@ void ViewportNode::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr m_xMax = data.normalizedRect.width(); m_yMin = data.normalizedRect.y(); m_yMax = data.normalizedRect.height(); + m_gamma = data.gamma; } float ViewportNode::xMin() const @@ -106,6 +108,16 @@ void ViewportNode::setYMax(float yMax) m_yMax = yMax; } +float ViewportNode::gamma() const +{ + return m_gamma; +} + +void ViewportNode::setGamma(float gamma) +{ + m_gamma = gamma; +} + void ViewportNode::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) { if (e->type() == PropertyUpdated) { @@ -116,6 +128,8 @@ void ViewportNode::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) setYMin(normalizedRect.y()); setXMax(normalizedRect.width()); setYMax(normalizedRect.height()); + } else if (propertyChange->propertyName() == QByteArrayLiteral("gamma")) { + setGamma(propertyChange->value().toFloat()); } markDirty(AbstractRenderer::AllDirty); } diff --git a/src/render/framegraph/viewportnode_p.h b/src/render/framegraph/viewportnode_p.h index 882aa4d86..85003ff36 100644 --- a/src/render/framegraph/viewportnode_p.h +++ b/src/render/framegraph/viewportnode_p.h @@ -81,6 +81,9 @@ public: float yMax() const; void setYMax(float yMax); + float gamma() const; + void setGamma(float gamma); + void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_OVERRIDE; private: @@ -90,6 +93,7 @@ private: float m_yMin; float m_xMax; float m_yMax; + float m_gamma; }; QRectF computeViewport(const QRectF &childViewport, const ViewportNode *parentViewport); diff --git a/tests/auto/render/qviewport/tst_qviewport.cpp b/tests/auto/render/qviewport/tst_qviewport.cpp index 87b22e22b..93a2735f2 100644 --- a/tests/auto/render/qviewport/tst_qviewport.cpp +++ b/tests/auto/render/qviewport/tst_qviewport.cpp @@ -46,14 +46,15 @@ private Q_SLOTS: { QTest::addColumn("viewport"); QTest::addColumn("normalizedRect"); + QTest::addColumn("gamma"); Qt3DRender::QViewport *defaultConstructed = new Qt3DRender::QViewport(); - QTest::newRow("defaultConstructed") << defaultConstructed << QRectF(0.0f, 0.0f, 1.0f, 1.0f); + QTest::newRow("defaultConstructed") << defaultConstructed << QRectF(0.0f, 0.0f, 1.0f, 1.0f) << 2.2f; Qt3DRender::QViewport *smallGreenViewport = new Qt3DRender::QViewport(); smallGreenViewport->setNormalizedRect(QRectF(0.2f, 0.2f, 0.6f, 0.6f)); - QTest::newRow("smallGreenViewport") << smallGreenViewport << QRectF(0.2f, 0.2f, 0.6f, 0.6f); - + smallGreenViewport->setGamma(1.8f); + QTest::newRow("smallGreenViewport") << smallGreenViewport << QRectF(0.2f, 0.2f, 0.6f, 0.6f) << 1.8f; } void checkCloning() @@ -61,9 +62,11 @@ private Q_SLOTS: // GIVEN QFETCH(Qt3DRender::QViewport *, viewport); QFETCH(QRectF, normalizedRect); + QFETCH(float, gamma); // THEN QCOMPARE(viewport->normalizedRect(), normalizedRect); + QCOMPARE(viewport->gamma(), gamma); // WHEN Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(viewport); @@ -80,6 +83,7 @@ private Q_SLOTS: QCOMPARE(viewport->isEnabled(), creationChangeData->isNodeEnabled()); QCOMPARE(viewport->metaObject(), creationChangeData->metaObject()); QCOMPARE(viewport->normalizedRect(), cloneData.normalizedRect); + QCOMPARE(viewport->gamma(), cloneData.gamma); delete viewport; } @@ -91,39 +95,77 @@ private Q_SLOTS: QScopedPointer viewport(new Qt3DRender::QViewport()); arbiter.setArbiterOnNode(viewport.data()); - // WHEN - viewport->setNormalizedRect(QRectF(0.5f, 0.5f, 1.0f, 1.0f)); - QCoreApplication::processEvents(); - - // THEN - QCOMPARE(arbiter.events.size(), 1); - Qt3DCore::QPropertyUpdatedChangePtr change = arbiter.events.first().staticCast(); - QCOMPARE(change->propertyName(), "normalizedRect"); - QCOMPARE(change->subjectId(), viewport->id()); - QCOMPARE(change->value().value(), QRectF(0.5f, 0.5f, 1.0f, 1.0f)); - QCOMPARE(change->type(), Qt3DCore::PropertyUpdated); + { + // WHEN + viewport->setNormalizedRect(QRectF(0.5f, 0.5f, 1.0f, 1.0f)); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 1); + Qt3DCore::QPropertyUpdatedChangePtr change = arbiter.events.first().staticCast(); + QCOMPARE(change->propertyName(), "normalizedRect"); + QCOMPARE(change->subjectId(), viewport->id()); + QCOMPARE(change->value().value(), QRectF(0.5f, 0.5f, 1.0f, 1.0f)); + QCOMPARE(change->type(), Qt3DCore::PropertyUpdated); + + arbiter.events.clear(); + + // WHEN + viewport->setNormalizedRect(QRectF(0.5f, 0.5f, 1.0f, 1.0f)); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 0); + + // WHEN + viewport->setNormalizedRect(QRectF(0.0f, 0.0f, 1.0f, 1.0f)); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 1); + change = arbiter.events.first().staticCast(); + QCOMPARE(change->propertyName(), "normalizedRect"); + QCOMPARE(change->subjectId(), viewport->id()); + QCOMPARE(change->value().value(), QRectF(0.0f, 0.0f, 1.0f, 1.0f)); + QCOMPARE(change->type(), Qt3DCore::PropertyUpdated); + } arbiter.events.clear(); - // WHEN - viewport->setNormalizedRect(QRectF(0.5f, 0.5f, 1.0f, 1.0f)); - QCoreApplication::processEvents(); - - // THEN - QCOMPARE(arbiter.events.size(), 0); - - // WHEN - viewport->setNormalizedRect(QRectF(0.0f, 0.0f, 1.0f, 1.0f)); - QCoreApplication::processEvents(); - - // THEN - QCOMPARE(arbiter.events.size(), 1); - change = arbiter.events.first().staticCast(); - QCOMPARE(change->propertyName(), "normalizedRect"); - QCOMPARE(change->subjectId(), viewport->id()); - QCOMPARE(change->value().value(), QRectF(0.0f, 0.0f, 1.0f, 1.0f)); - QCOMPARE(change->type(), Qt3DCore::PropertyUpdated); - + { + // WHEN + viewport->setGamma(1.8f); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 1); + Qt3DCore::QPropertyUpdatedChangePtr change = arbiter.events.first().staticCast(); + QCOMPARE(change->propertyName(), "gamma"); + QCOMPARE(change->subjectId(), viewport->id()); + QCOMPARE(change->value().toFloat(), 1.8f); + QCOMPARE(change->type(), Qt3DCore::PropertyUpdated); + + arbiter.events.clear(); + + // WHEN + viewport->setGamma(1.8f); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 0); + + // WHEN + viewport->setGamma(2.0f); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 1); + change = arbiter.events.first().staticCast(); + QCOMPARE(change->propertyName(), "gamma"); + QCOMPARE(change->subjectId(), viewport->id()); + QCOMPARE(change->value().toFloat(), 2.0f); + QCOMPARE(change->type(), Qt3DCore::PropertyUpdated); + } } }; -- cgit v1.2.3 From 4894683d18974a15d2e4c62c621c485cb42e0fbf Mon Sep 17 00:00:00 2001 From: Kevin Ottens Date: Tue, 31 Jan 2017 17:19:34 +0100 Subject: Expose QViewport's gamma property to the shaders Change-Id: I1f5b3f9a622b56dcb5459d067444559d40a25148 Reviewed-by: Sean Harmer --- src/render/backend/renderview.cpp | 4 ++++ src/render/backend/renderview_p.h | 5 +++++ src/render/jobs/renderviewjobutils.cpp | 1 + 3 files changed, 10 insertions(+) diff --git a/src/render/backend/renderview.cpp b/src/render/backend/renderview.cpp index c4e4a191e..e5e75aee9 100644 --- a/src/render/backend/renderview.cpp +++ b/src/render/backend/renderview.cpp @@ -130,6 +130,7 @@ RenderView::StandardUniformsNameToTypeHash RenderView::initializeStandardUniform setters.insert(StringToInt::lookupId(QLatin1String("viewportMatrix")), ViewportMatrix); setters.insert(StringToInt::lookupId(QLatin1String("inverseViewportMatrix")), InverseViewportMatrix); setters.insert(StringToInt::lookupId(QLatin1String("exposure")), Exposure); + setters.insert(StringToInt::lookupId(QLatin1String("gamma")), Gamma); setters.insert(StringToInt::lookupId(QLatin1String("time")), Time); setters.insert(StringToInt::lookupId(QLatin1String("eyePosition")), EyePosition); @@ -194,6 +195,8 @@ UniformValue RenderView::standardUniformValue(RenderView::StandardUniform standa } case Exposure: return UniformValue(m_data.m_renderCameraLens->exposure()); + case Gamma: + return UniformValue(m_gamma); case Time: return UniformValue(float(m_renderer->time() / 1000000000.0f)); case EyePosition: @@ -208,6 +211,7 @@ RenderView::RenderView() : m_renderer(nullptr) , m_devicePixelRatio(1.) , m_viewport(QRectF(0.0f, 0.0f, 1.0f, 1.0f)) + , m_gamma(2.2f) , m_surface(nullptr) , m_clearBuffer(QClearBuffers::None) , m_stateSet(nullptr) diff --git a/src/render/backend/renderview_p.h b/src/render/backend/renderview_p.h index ac2733eaa..92fb502d9 100644 --- a/src/render/backend/renderview_p.h +++ b/src/render/backend/renderview_p.h @@ -181,6 +181,9 @@ public: inline void setViewport(const QRectF &vp) Q_DECL_NOTHROW { m_viewport = vp; } inline QRectF viewport() const Q_DECL_NOTHROW { return m_viewport; } + inline float gamma() const Q_DECL_NOTHROW { return m_gamma; } + inline void setGamma(float gamma) Q_DECL_NOTHROW { m_gamma = gamma; } + // depth and stencil ClearBuffers are cached locally // color ClearBuffers are collected, as there may be multiple // color buffers to be cleared. we need to apply all these at rendering @@ -265,6 +268,7 @@ private: InnerData m_data; QRectF m_viewport; + float m_gamma; Qt3DCore::QNodeId m_renderTarget; QSurface *m_surface; AttachmentPack m_attachmentPack; @@ -308,6 +312,7 @@ private: InverseViewportMatrix, Time, Exposure, + Gamma, EyePosition }; diff --git a/src/render/jobs/renderviewjobutils.cpp b/src/render/jobs/renderviewjobutils.cpp index f2f0f8388..b2b995cfa 100644 --- a/src/render/jobs/renderviewjobutils.cpp +++ b/src/render/jobs/renderviewjobutils.cpp @@ -165,6 +165,7 @@ void setRenderViewConfigFromFrameGraphLeafNode(RenderView *rv, const FrameGraphN // a subregion relative to that of the parent viewport const ViewportNode *vpNode = static_cast(node); rv->setViewport(computeViewport(rv->viewport(), vpNode)); + rv->setGamma(vpNode->gamma()); break; } -- cgit v1.2.3 From a9965e7e984d519079e52a9672ba6116931c741a Mon Sep 17 00:00:00 2001 From: Kevin Ottens Date: Tue, 31 Jan 2017 17:35:24 +0100 Subject: Don't hardcode gamma in metal/rough materials Now that it is controllable via the frame graph and exposed as a uniform, let's use it. Change-Id: I0684fdb02a4e8aa867c865f3bf2ffe251a064f88 Reviewed-by: Sean Harmer --- src/extras/shaders/gl3/metalrough.frag | 5 +++-- src/extras/shaders/gl3/metalroughuniform.frag | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/extras/shaders/gl3/metalrough.frag b/src/extras/shaders/gl3/metalrough.frag index ccb1f8297..99624dd24 100644 --- a/src/extras/shaders/gl3/metalrough.frag +++ b/src/extras/shaders/gl3/metalrough.frag @@ -82,6 +82,8 @@ uniform float mipOffset = 5.0; // Exposure correction uniform float exposure = 0.0; +// Gamma correction +uniform float gamma = 2.2; mat3 calcWorldSpaceToTangentSpaceMatrix(const in vec3 wNormal, const in vec4 wTangent) { @@ -204,8 +206,7 @@ vec3 toneMap(const in vec3 c) vec3 gammaCorrect(const in vec3 color) { - const float gamma = 1.0 / 2.2; - return pow(color, vec3(gamma)); + return pow(color, vec3(1.0 / gamma)); } void main() diff --git a/src/extras/shaders/gl3/metalroughuniform.frag b/src/extras/shaders/gl3/metalroughuniform.frag index dfc174e8b..7ff061e12 100644 --- a/src/extras/shaders/gl3/metalroughuniform.frag +++ b/src/extras/shaders/gl3/metalroughuniform.frag @@ -77,6 +77,8 @@ uniform float mipOffset = 5.0; // Exposure correction uniform float exposure = 0.0; +// Gamma correction +uniform float gamma = 2.2; mat3 calcWorldSpaceToTangentSpaceMatrix(const in vec3 wNormal, const in vec4 wTangent) { @@ -195,8 +197,7 @@ vec3 toneMap(const in vec3 c) vec3 gammaCorrect(const in vec3 color) { - const float gamma = 1.0 / 2.2; - return pow(color, vec3(gamma)); + return pow(color, vec3(1.0 / gamma)); } void main() -- cgit v1.2.3 From 574fab140f3c389c59d955c092d30e0ad1d0bafb Mon Sep 17 00:00:00 2001 From: Kevin Ottens Date: Tue, 31 Jan 2017 17:27:32 +0100 Subject: QForwardRenderer exposes the gamma of its viewport Change-Id: I67d5d23bdec1c01ef3e31cfdd47f4e4dd8eeacf4 Reviewed-by: Sean Harmer --- src/extras/defaults/qforwardrenderer.cpp | 23 ++++++++++++++++++++++ src/extras/defaults/qforwardrenderer.h | 4 ++++ .../qforwardrenderer/tst_qforwardrenderer.cpp | 21 ++++++++++++++++++++ 3 files changed, 48 insertions(+) diff --git a/src/extras/defaults/qforwardrenderer.cpp b/src/extras/defaults/qforwardrenderer.cpp index 7790313e3..3a5c6803b 100644 --- a/src/extras/defaults/qforwardrenderer.cpp +++ b/src/extras/defaults/qforwardrenderer.cpp @@ -135,6 +135,7 @@ QForwardRenderer::QForwardRenderer(QNode *parent) QObject::connect(d->m_surfaceSelector, &QRenderSurfaceSelector::surfaceChanged, this, &QForwardRenderer::surfaceChanged); QObject::connect(d->m_surfaceSelector, &QRenderSurfaceSelector::externalRenderTargetSizeChanged, this, &QForwardRenderer::externalRenderTargetSizeChanged); QObject::connect(d->m_frustumCulling, &QFrustumCulling::enabledChanged, this, &QForwardRenderer::frustumCullingEnabledChanged); + QObject::connect(d->m_viewport, &QViewport::gammaChanged, this, &QForwardRenderer::gammaChanged); d->init(); } @@ -178,6 +179,12 @@ void QForwardRenderer::setFrustumCullingEnabled(bool enabled) d->m_frustumCulling->setEnabled(enabled); } +void QForwardRenderer::setGamma(float gamma) +{ + Q_D(QForwardRenderer); + d->m_viewport->setGamma(gamma); +} + /*! \qmlproperty rect ForwardRenderer::viewportRect @@ -285,6 +292,22 @@ bool QForwardRenderer::isFrustumCullingEnabled() const return d->m_frustumCulling->isEnabled(); } +/*! + \qmlproperty color ForwardRenderer::gamma + + Holds the gamma value the renderer applies to the scene. +*/ +/*! + \property QForwardRenderer::gamma + + Holds the gamma value the renderer applies to the scene. +*/ +float QForwardRenderer::gamma() const +{ + Q_D(const QForwardRenderer); + return d->m_viewport->gamma(); +} + } // namespace Qt3DExtras QT_END_NAMESPACE diff --git a/src/extras/defaults/qforwardrenderer.h b/src/extras/defaults/qforwardrenderer.h index 6a2773029..160236462 100644 --- a/src/extras/defaults/qforwardrenderer.h +++ b/src/extras/defaults/qforwardrenderer.h @@ -63,6 +63,7 @@ class QT3DEXTRASSHARED_EXPORT QForwardRenderer : public Qt3DRender::QTechniqueFi Q_PROPERTY(Qt3DCore::QEntity *camera READ camera WRITE setCamera NOTIFY cameraChanged) Q_PROPERTY(QSize externalRenderTargetSize READ externalRenderTargetSize WRITE setExternalRenderTargetSize NOTIFY externalRenderTargetSizeChanged) Q_PROPERTY(bool frustumCulling READ isFrustumCullingEnabled WRITE setFrustumCullingEnabled NOTIFY frustumCullingEnabledChanged) + Q_PROPERTY(float gamma READ gamma WRITE setGamma NOTIFY gammaChanged) public: explicit QForwardRenderer(Qt3DCore::QNode *parent = nullptr); ~QForwardRenderer(); @@ -73,6 +74,7 @@ public: QObject *surface() const; QSize externalRenderTargetSize() const; bool isFrustumCullingEnabled() const; + float gamma() const; public Q_SLOTS: void setViewportRect(const QRectF &viewportRect); @@ -81,6 +83,7 @@ public Q_SLOTS: void setSurface(QObject * surface); void setExternalRenderTargetSize(const QSize &size); void setFrustumCullingEnabled(bool enabled); + void setGamma(float gamma); Q_SIGNALS: void viewportRectChanged(const QRectF &viewportRect); @@ -89,6 +92,7 @@ Q_SIGNALS: void surfaceChanged(QObject *surface); void externalRenderTargetSizeChanged(const QSize &size); void frustumCullingEnabledChanged(bool enabled); + void gammaChanged(float gamma); private: Q_DECLARE_PRIVATE(QForwardRenderer) diff --git a/tests/auto/extras/qforwardrenderer/tst_qforwardrenderer.cpp b/tests/auto/extras/qforwardrenderer/tst_qforwardrenderer.cpp index 0d80f0e35..d4d856a7c 100644 --- a/tests/auto/extras/qforwardrenderer/tst_qforwardrenderer.cpp +++ b/tests/auto/extras/qforwardrenderer/tst_qforwardrenderer.cpp @@ -56,6 +56,7 @@ private Q_SLOTS: QVERIFY(forwardRenderer.camera() == nullptr); QCOMPARE(forwardRenderer.externalRenderTargetSize(), QSize()); QVERIFY(forwardRenderer.isFrustumCullingEnabled()); + QCOMPARE(forwardRenderer.gamma(), 2.2f); } void checkPropertyChanges() @@ -189,6 +190,26 @@ private Q_SLOTS: QCOMPARE(spy.count(), 1); QVERIFY(spy.takeFirst().takeFirst().toBool()); } + { + // WHEN + QSignalSpy spy(&forwardRenderer, SIGNAL(gammaChanged(float))); + const float newValue = 1.8f; + forwardRenderer.setGamma(newValue); + + // THEN + QCOMPARE(forwardRenderer.gamma(), newValue); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.takeFirst().first().toFloat(), 1.8f); + + // WHEN + spy.clear(); + forwardRenderer.setClearColor(newValue); + + // THEN + QCOMPARE(forwardRenderer.gamma(), newValue); + QCOMPARE(spy.count(), 0); + + } } }; -- cgit v1.2.3 From 1c6004383a2f26cc5ca8cacab49a3152414e110d Mon Sep 17 00:00:00 2001 From: Kevin Ottens Date: Tue, 31 Jan 2017 17:56:27 +0100 Subject: QSkyBoxEntity: use QTextureLoader for dds cubemaps This fixes a bug where dds cubemaps would simply display nothing. Change-Id: Ife3ad095effec0ede446ae124c7d2e024b25f550 Reviewed-by: Sean Harmer --- src/extras/defaults/qskyboxentity.cpp | 19 +++++++++++++------ src/extras/defaults/qskyboxentity_p.h | 2 ++ 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/extras/defaults/qskyboxentity.cpp b/src/extras/defaults/qskyboxentity.cpp index 46c1a4743..85899793c 100644 --- a/src/extras/defaults/qskyboxentity.cpp +++ b/src/extras/defaults/qskyboxentity.cpp @@ -65,6 +65,7 @@ QSkyboxEntityPrivate::QSkyboxEntityPrivate() , m_effect(new QEffect()) , m_material(new QMaterial()) , m_skyboxTexture(new QTextureCubeMap()) + , m_loadedTexture(new QTextureLoader()) , m_gl3Shader(new QShaderProgram()) , m_gl2es2Shader(new QShaderProgram()) , m_gl2Technique(new QTechnique()) @@ -184,12 +185,18 @@ void QSkyboxEntityPrivate::init() */ void QSkyboxEntityPrivate::reloadTexture() { - m_posXImage->setSource(QUrl(m_baseName + QStringLiteral("_posx") + m_extension)); - m_posYImage->setSource(QUrl(m_baseName + QStringLiteral("_posy") + m_extension)); - m_posZImage->setSource(QUrl(m_baseName + QStringLiteral("_posz") + m_extension)); - m_negXImage->setSource(QUrl(m_baseName + QStringLiteral("_negx") + m_extension)); - m_negYImage->setSource(QUrl(m_baseName + QStringLiteral("_negy") + m_extension)); - m_negZImage->setSource(QUrl(m_baseName + QStringLiteral("_negz") + m_extension)); + if (m_extension == QStringLiteral(".dds")) { + m_loadedTexture->setSource(QUrl(m_baseName + m_extension)); + m_textureParameter->setValue(QVariant::fromValue(m_loadedTexture)); + } else { + m_posXImage->setSource(QUrl(m_baseName + QStringLiteral("_posx") + m_extension)); + m_posYImage->setSource(QUrl(m_baseName + QStringLiteral("_posy") + m_extension)); + m_posZImage->setSource(QUrl(m_baseName + QStringLiteral("_posz") + m_extension)); + m_negXImage->setSource(QUrl(m_baseName + QStringLiteral("_negx") + m_extension)); + m_negYImage->setSource(QUrl(m_baseName + QStringLiteral("_negy") + m_extension)); + m_negZImage->setSource(QUrl(m_baseName + QStringLiteral("_negz") + m_extension)); + m_textureParameter->setValue(QVariant::fromValue(m_skyboxTexture)); + } } /*! diff --git a/src/extras/defaults/qskyboxentity_p.h b/src/extras/defaults/qskyboxentity_p.h index effe97fce..795d59ab2 100644 --- a/src/extras/defaults/qskyboxentity_p.h +++ b/src/extras/defaults/qskyboxentity_p.h @@ -60,6 +60,7 @@ namespace Qt3DRender { class QFilterKey; class QTextureCubeMap; +class QTextureLoader; class QShaderProgram; class QSkyboxEntity; class QTextureImage; @@ -87,6 +88,7 @@ class QSkyboxEntityPrivate : public Qt3DCore::QEntityPrivate Qt3DRender::QEffect *m_effect; Qt3DRender::QMaterial *m_material; Qt3DRender::QTextureCubeMap *m_skyboxTexture; + Qt3DRender::QTextureLoader *m_loadedTexture; Qt3DRender::QShaderProgram *m_gl3Shader; Qt3DRender::QShaderProgram *m_gl2es2Shader; Qt3DRender::QTechnique *m_gl2Technique; -- cgit v1.2.3 From 861e4d71e34c73e3bd5f550b02448df6fa6279ec Mon Sep 17 00:00:00 2001 From: Kevin Ottens Date: Tue, 31 Jan 2017 18:13:32 +0100 Subject: SkyboxEntity can gamma correct the fragments This is an opt-in feature, required because dds file tend to need gamma correction while png probably not. Change-Id: I9f32d8f23110fb2fd6b11f33a20018907355e986 Reviewed-by: Sean Harmer --- src/extras/defaults/qskyboxentity.cpp | 25 +++++++++++++++++++++++++ src/extras/defaults/qskyboxentity.h | 5 +++++ src/extras/defaults/qskyboxentity_p.h | 1 + src/extras/shaders/gl3/skybox.frag | 16 +++++++++++++++- 4 files changed, 46 insertions(+), 1 deletion(-) diff --git a/src/extras/defaults/qskyboxentity.cpp b/src/extras/defaults/qskyboxentity.cpp index 85899793c..f955cd5c5 100644 --- a/src/extras/defaults/qskyboxentity.cpp +++ b/src/extras/defaults/qskyboxentity.cpp @@ -76,6 +76,7 @@ QSkyboxEntityPrivate::QSkyboxEntityPrivate() , m_es2RenderPass(new QRenderPass()) , m_gl3RenderPass(new QRenderPass()) , m_mesh(new QCuboidMesh()) + , m_gammaStrengthParameter(new QParameter(QStringLiteral("gammaStrength"), 0.0f)) , m_textureParameter(new QParameter(QStringLiteral("skyboxTexture"), m_skyboxTexture)) , m_posXImage(new QTextureImage()) , m_posYImage(new QTextureImage()) @@ -145,6 +146,7 @@ void QSkyboxEntityPrivate::init() m_effect->addTechnique(m_es2Technique); m_material->setEffect(m_effect); + m_material->addParameter(m_gammaStrengthParameter); m_material->addParameter(m_textureParameter); m_mesh->setXYMeshResolution(QSize(2, 2)); @@ -280,6 +282,29 @@ QString QSkyboxEntity::extension() const return d->m_extension; } +/*! + * Sets the gamma correction enable state to \a enabled. + * \since 5.9 + */ +void QSkyboxEntity::setGammaCorrectEnabled(bool enabled) +{ + Q_D(QSkyboxEntity); + if (enabled != isGammaCorrectEnabled()) { + d->m_gammaStrengthParameter->setValue(enabled ? 1.0f : 0.0f); + emit gammaCorrectEnabledChanged(enabled); + } +} + +/*! + * Indicates if gamma correction is enabled for this skybox. + * \since 5.9 + */ +bool QSkyboxEntity::isGammaCorrectEnabled() const +{ + Q_D(const QSkyboxEntity); + return !qFuzzyIsNull(d->m_gammaStrengthParameter->value().toFloat()); +} + } // namespace Qt3DExtras QT_END_NAMESPACE diff --git a/src/extras/defaults/qskyboxentity.h b/src/extras/defaults/qskyboxentity.h index ca5cab6f2..cc01ff7bb 100644 --- a/src/extras/defaults/qskyboxentity.h +++ b/src/extras/defaults/qskyboxentity.h @@ -54,6 +54,7 @@ class QT3DEXTRASSHARED_EXPORT QSkyboxEntity : public Qt3DCore::QEntity Q_OBJECT Q_PROPERTY(QString baseName READ baseName WRITE setBaseName NOTIFY baseNameChanged) Q_PROPERTY(QString extension READ extension WRITE setExtension NOTIFY extensionChanged) + Q_PROPERTY(bool gammaCorrect READ isGammaCorrectEnabled WRITE setGammaCorrectEnabled NOTIFY gammaCorrectEnabledChanged) public: explicit QSkyboxEntity(Qt3DCore::QNode *parent = nullptr); ~QSkyboxEntity(); @@ -64,9 +65,13 @@ public: void setExtension(const QString &extension); QString extension() const; + void setGammaCorrectEnabled(bool enabled); + bool isGammaCorrectEnabled() const; + Q_SIGNALS: void baseNameChanged(const QString &path); void extensionChanged(const QString &extension); + void gammaCorrectEnabledChanged(bool enabled); private: Q_DECLARE_PRIVATE(QSkyboxEntity) diff --git a/src/extras/defaults/qskyboxentity_p.h b/src/extras/defaults/qskyboxentity_p.h index 795d59ab2..ebf89bdbc 100644 --- a/src/extras/defaults/qskyboxentity_p.h +++ b/src/extras/defaults/qskyboxentity_p.h @@ -99,6 +99,7 @@ class QSkyboxEntityPrivate : public Qt3DCore::QEntityPrivate Qt3DRender::QRenderPass *m_es2RenderPass; Qt3DRender::QRenderPass *m_gl3RenderPass; QCuboidMesh *m_mesh; + Qt3DRender::QParameter *m_gammaStrengthParameter; Qt3DRender::QParameter *m_textureParameter; Qt3DRender::QTextureImage *m_posXImage; Qt3DRender:: QTextureImage *m_posYImage; diff --git a/src/extras/shaders/gl3/skybox.frag b/src/extras/shaders/gl3/skybox.frag index 99c8f111b..931e20343 100644 --- a/src/extras/shaders/gl3/skybox.frag +++ b/src/extras/shaders/gl3/skybox.frag @@ -4,7 +4,21 @@ in vec3 texCoord0; out vec4 fragColor; uniform samplerCube skyboxTexture; +// Gamma correction +uniform float gamma = 2.2; + +uniform float gammaStrength; + +vec3 gammaCorrect(const in vec3 color) +{ + return pow(color, vec3(1.0 / gamma)); +} + void main() { - fragColor = texture(skyboxTexture, texCoord0); + vec4 baseColor = texture(skyboxTexture, texCoord0); + vec4 gammaColor = vec4(gammaCorrect(baseColor.rgb), 1.0); + // This is an odd way to enable or not gamma correction, + // but this is a way to avoid branching until we can generate shaders + fragColor = mix(baseColor, gammaColor, gammaStrength); } -- cgit v1.2.3 From b5f6c2b02c0fd359fb537f20f9bde8d50592eb1b Mon Sep 17 00:00:00 2001 From: Harald Vistnes Date: Mon, 30 Jan 2017 11:55:26 +0100 Subject: Enable point sprites for GL2 Call glEnable(GL_POINT_SPRITE) if PointSize renderstate is used with GL2. If the point size is programmable, also enable GL_VERTEX_PROGRAM_POINT_SIZE. If not, call glPointSize with the given value. Task-number: QTBUG-58346 Change-Id: Ic2fb33a45c0efb87d031838dd3141fa8ada7f63b Reviewed-by: Sean Harmer --- src/render/graphicshelpers/graphicshelpergl2.cpp | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/render/graphicshelpers/graphicshelpergl2.cpp b/src/render/graphicshelpers/graphicshelpergl2.cpp index 8ee0c020b..73969a322 100644 --- a/src/render/graphicshelpers/graphicshelpergl2.cpp +++ b/src/render/graphicshelpers/graphicshelpergl2.cpp @@ -525,15 +525,11 @@ void GraphicsHelperGL2::clearBufferf(GLint drawbuffer, const QVector4D &values) void GraphicsHelperGL2::pointSize(bool programmable, GLfloat value) { - // Print a warning once for trying to set GL_PROGRAM_POINT_SIZE - if (programmable) { - static bool warned = false; - if (!warned) { - qWarning() << "GL_PROGRAM_POINT_SIZE is not supported by OpenGL 2.0 (since 3.2)"; - warned = true; - } - } - m_funcs->glPointSize(value); + m_funcs->glEnable(GL_POINT_SPRITE); + if (programmable) + m_funcs->glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); + else + m_funcs->glPointSize(value); } void GraphicsHelperGL2::enablei(GLenum cap, GLuint index) -- cgit v1.2.3 From 9c39fd7915e6d23c27ceb21bb1aa3e4b9ae2aed1 Mon Sep 17 00:00:00 2001 From: Wieland Hagen Date: Mon, 9 Jan 2017 11:16:39 +0700 Subject: Free VAOs in Renderer::releaseGraphicsResources() Change-Id: I7dc349dc2b91078cda3cb97fa061a7362aa36ddc Task-number: QTBUG-55489 Reviewed-by: Paul Lemire --- src/render/backend/renderer.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/render/backend/renderer.cpp b/src/render/backend/renderer.cpp index c0b85c349..d38df13e2 100644 --- a/src/render/backend/renderer.cpp +++ b/src/render/backend/renderer.cpp @@ -401,6 +401,13 @@ void Renderer::releaseGraphicsResources() buffer->destroy(m_graphicsContext.data()); } + // Do the same thing with VAOs + const QVector activeVaos = m_nodesManager->vaoManager()->activeHandles(); + for (const HVao &vaoHandle : activeVaos) { + OpenGLVertexArrayObject *vao = m_nodesManager->vaoManager()->data(vaoHandle); + vao->destroy(); + } + context->doneCurrent(); } else { qWarning() << "Failed to make context current: OpenGL resources will not be destroyed"; -- cgit v1.2.3 From 0da1d0e6a93e9c1f745f5ff3b8d628a2de9b0fa3 Mon Sep 17 00:00:00 2001 From: Wieland Hagen Date: Wed, 1 Feb 2017 15:12:18 +0700 Subject: OpenGLVertexArrayObject: require cleanup Change-Id: I65d7e85abd707aea0554652694803bfdc52b8632 Reviewed-by: Paul Lemire --- src/render/backend/managers_p.h | 3 ++- src/render/backend/openglvertexarrayobject.cpp | 14 ++++++++++---- src/render/backend/openglvertexarrayobject_p.h | 3 +++ 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/render/backend/managers_p.h b/src/render/backend/managers_p.h index ed43fde13..15006fd6e 100644 --- a/src/render/backend/managers_p.h +++ b/src/render/backend/managers_p.h @@ -248,7 +248,7 @@ public: class VAOManager : public Qt3DCore::QResourceManager< OpenGLVertexArrayObject, - QPair, + VAOIdentifier, 16, Qt3DCore::ArrayAllocatingPolicy, Qt3DCore::NonLockingPolicy> @@ -410,6 +410,7 @@ Q_DECLARE_RESOURCE_INFO(Qt3DRender::Render::BoundingVolumeDebug, Q_REQUIRES_CLEA Q_DECLARE_RESOURCE_INFO(Qt3DRender::Render::ComputeCommand, Q_REQUIRES_CLEANUP) Q_DECLARE_RESOURCE_INFO(Qt3DRender::Render::Parameter, Q_REQUIRES_CLEANUP) Q_DECLARE_RESOURCE_INFO(Qt3DRender::Render::Transform, Q_REQUIRES_CLEANUP) +Q_DECLARE_RESOURCE_INFO(Qt3DRender::Render::OpenGLVertexArrayObject, Q_REQUIRES_CLEANUP) QT_END_NAMESPACE diff --git a/src/render/backend/openglvertexarrayobject.cpp b/src/render/backend/openglvertexarrayobject.cpp index 6120c7233..30f79c466 100644 --- a/src/render/backend/openglvertexarrayobject.cpp +++ b/src/render/backend/openglvertexarrayobject.cpp @@ -113,15 +113,21 @@ void OpenGLVertexArrayObject::create() void OpenGLVertexArrayObject::destroy() { Q_ASSERT(m_ctx); - if (m_supportsVao) { - Q_ASSERT(!m_vao.isNull()); - m_vao->destroy(); - } + cleanup(); +} + +void OpenGLVertexArrayObject::cleanup() +{ + m_vao.reset(); + m_ctx = nullptr; m_specified = false; + m_supportsVao = false; + m_createdEmulatedVAO = false; m_indexAttribute = GraphicsContext::VAOIndexAttribute(); m_vertexAttributes.clear(); } + bool OpenGLVertexArrayObject::isCreated() const { if (m_supportsVao) { diff --git a/src/render/backend/openglvertexarrayobject_p.h b/src/render/backend/openglvertexarrayobject_p.h index 4f21497f0..6d8eecec8 100644 --- a/src/render/backend/openglvertexarrayobject_p.h +++ b/src/render/backend/openglvertexarrayobject_p.h @@ -59,6 +59,8 @@ QT_BEGIN_NAMESPACE namespace Qt3DRender { namespace Render { +typedef QPair VAOIdentifier; + class OpenGLVertexArrayObject { public: @@ -69,6 +71,7 @@ public: void release(); void create(); void destroy(); + void cleanup(); bool isCreated() const; QOpenGLVertexArrayObject *vao() { return m_vao.data(); } -- cgit v1.2.3 From f1c21aaae49d0a356ecfab268994381932b6d327 Mon Sep 17 00:00:00 2001 From: Wieland Hagen Date: Wed, 1 Feb 2017 15:38:38 +0700 Subject: Delete abandoned VAOs after each frame Use a job to traverse all active VAO handles to check if the geometry and shader objects used to identify the VAO do stil exist. If not, let the renderer dispose the VAOs. Make sure to synchronize access to VAO state and hide state changes behind member functions. Change-Id: Ib77be67d55daa61885cd914af8d9cfc622cae940 Reviewed-by: Paul Lemire --- src/render/backend/openglvertexarrayobject.cpp | 49 +++++++++++++------------- src/render/backend/openglvertexarrayobject_p.h | 15 +++++--- src/render/backend/renderer.cpp | 46 +++++++++++++++++++----- src/render/backend/renderer_p.h | 5 +++ src/render/jobs/job_common_p.h | 1 + 5 files changed, 79 insertions(+), 37 deletions(-) diff --git a/src/render/backend/openglvertexarrayobject.cpp b/src/render/backend/openglvertexarrayobject.cpp index 30f79c466..b88ddfb7b 100644 --- a/src/render/backend/openglvertexarrayobject.cpp +++ b/src/render/backend/openglvertexarrayobject.cpp @@ -52,15 +52,8 @@ OpenGLVertexArrayObject::OpenGLVertexArrayObject() : m_ctx(nullptr) , m_specified(false) , m_supportsVao(false) - , m_createdEmulatedVAO(false) {} -void OpenGLVertexArrayObject::setGraphicsContext(GraphicsContext *ctx) -{ - m_ctx = ctx; - m_supportsVao = m_ctx->supportsVAO(); -} - void OpenGLVertexArrayObject::bind() { Q_ASSERT(m_ctx); @@ -99,19 +92,25 @@ void OpenGLVertexArrayObject::release() } } -void OpenGLVertexArrayObject::create() +// called from Render thread +void OpenGLVertexArrayObject::create(GraphicsContext *ctx, const VAOIdentifier &key) { - Q_ASSERT(m_ctx); - if (m_supportsVao) { - Q_ASSERT(!m_vao.isNull()); - m_vao->create(); - } else { - m_createdEmulatedVAO = true; - } + QMutexLocker lock(&m_mutex); + + Q_ASSERT(!m_ctx && !m_vao); + + m_ctx = ctx; + m_supportsVao = m_ctx->supportsVAO(); + m_vao.reset(m_supportsVao ? new QOpenGLVertexArrayObject() : nullptr); + m_vao->create(); + m_owners = key; } +// called from Render thread void OpenGLVertexArrayObject::destroy() { + QMutexLocker locker(&m_mutex); + Q_ASSERT(m_ctx); cleanup(); } @@ -122,20 +121,22 @@ void OpenGLVertexArrayObject::cleanup() m_ctx = nullptr; m_specified = false; m_supportsVao = false; - m_createdEmulatedVAO = false; m_indexAttribute = GraphicsContext::VAOIndexAttribute(); m_vertexAttributes.clear(); } - -bool OpenGLVertexArrayObject::isCreated() const +// called from job +bool OpenGLVertexArrayObject::isAbandoned(GeometryManager *geomMgr, ShaderManager *shaderMgr) { - if (m_supportsVao) { - Q_ASSERT(!m_vao.isNull()); - return m_vao->isCreated(); - } else { - return m_createdEmulatedVAO; - } + QMutexLocker lock(&m_mutex); + + if (!m_ctx) + return false; + + const bool geometryExists = (geomMgr->data(m_owners.first) != nullptr); + const bool shaderExists = (shaderMgr->data(m_owners.second) != nullptr); + + return !geometryExists || !shaderExists; } void OpenGLVertexArrayObject::saveVertexAttribute(const GraphicsContext::VAOVertexAttribute &attr) diff --git a/src/render/backend/openglvertexarrayobject_p.h b/src/render/backend/openglvertexarrayobject_p.h index 6d8eecec8..a564175f6 100644 --- a/src/render/backend/openglvertexarrayobject_p.h +++ b/src/render/backend/openglvertexarrayobject_p.h @@ -59,6 +59,9 @@ QT_BEGIN_NAMESPACE namespace Qt3DRender { namespace Render { +class GeometryManager; +class ShaderManager; + typedef QPair VAOIdentifier; class OpenGLVertexArrayObject @@ -66,27 +69,29 @@ class OpenGLVertexArrayObject public: OpenGLVertexArrayObject(); - void setGraphicsContext(GraphicsContext *ctx); void bind(); void release(); - void create(); + + void create(GraphicsContext *ctx, const VAOIdentifier &key); void destroy(); void cleanup(); - bool isCreated() const; + + bool isAbandoned(GeometryManager *geomMgr, ShaderManager *shaderMgr); QOpenGLVertexArrayObject *vao() { return m_vao.data(); } const QOpenGLVertexArrayObject *vao() const { return m_vao.data(); } - void setVao(QOpenGLVertexArrayObject *vao) { m_vao.reset(vao); } void setSpecified(bool b) { m_specified = b; } bool isSpecified() const { return m_specified; } + private: + QMutex m_mutex; GraphicsContext *m_ctx; QScopedPointer m_vao; bool m_specified; bool m_supportsVao; - bool m_createdEmulatedVAO; + VAOIdentifier m_owners; friend class GraphicsContext; diff --git a/src/render/backend/renderer.cpp b/src/render/backend/renderer.cpp index d38df13e2..100c4a33d 100644 --- a/src/render/backend/renderer.cpp +++ b/src/render/backend/renderer.cpp @@ -170,6 +170,7 @@ Renderer::Renderer(QRenderAspect::RenderType type) , m_updateMeshTriangleListJob(Render::UpdateMeshTriangleListJobPtr::create()) , m_filterCompatibleTechniqueJob(Render::FilterCompatibleTechniqueJobPtr::create()) , m_bufferGathererJob(Render::GenericLambdaJobPtr>::create([this] { lookForDirtyBuffers(); }, JobTypes::DirtyBufferGathering)) + , m_vaoGathererJob(Render::GenericLambdaJobPtr>::create([this] { lookForAbandonedVaos(); }, JobTypes::DirtyVaoGathering)) , m_textureGathererJob(Render::GenericLambdaJobPtr>::create([this] { lookForDirtyTextures(); }, JobTypes::DirtyTextureGathering)) , m_shaderGathererJob(Render::GenericLambdaJobPtr>::create([this] { lookForDirtyShaders(); }, JobTypes::DirtyShaderGathering)) , m_syncTextureLoadingJob(Render::GenericLambdaJobPtr>::create([] {}, JobTypes::SyncTextureLoading)) @@ -830,6 +831,23 @@ void Renderer::prepareCommandsSubmission(const QVector &renderView m_dirtyGeometry.clear(); } +// Executed in a job +void Renderer::lookForAbandonedVaos() +{ + const QVector activeVaos = m_nodesManager->vaoManager()->activeHandles(); + for (HVao handle : activeVaos) { + OpenGLVertexArrayObject *vao = m_nodesManager->vaoManager()->data(handle); + + // Make sure to only mark VAOs for deletion that were already created + // (ignore those that might be currently under construction in the render thread) + if (vao->isAbandoned(m_nodesManager->geometryManager(), m_nodesManager->shaderManager())) { + m_abandonedVaosMutex.lock(); + m_abandonedVaos.push_back(handle); + m_abandonedVaosMutex.unlock(); + } + } +} + // Executed in a job void Renderer::lookForDirtyBuffers() { @@ -923,8 +941,6 @@ void Renderer::updateGLResources() // We can really release the texture at this point m_nodesManager->textureManager()->releaseResource(textureCleanedUpId); } - - } // Render Thread @@ -1267,6 +1283,7 @@ QVector Renderer::renderBinJobs() // Jobs to prepare GL Resource upload renderBinJobs.push_back(m_syncTextureLoadingJob); + renderBinJobs.push_back(m_vaoGathererJob); renderBinJobs.push_back(m_bufferGathererJob); renderBinJobs.push_back(m_textureGathererJob); renderBinJobs.push_back(m_shaderGathererJob); @@ -1368,16 +1385,15 @@ void Renderer::createOrUpdateVAO(RenderCommand *command, HVao *previousVaoHandle, OpenGLVertexArrayObject **vao) { + const VAOIdentifier vaoKey(command->m_geometry, command->m_shader); + VAOManager *vaoManager = m_nodesManager->vaoManager(); - command->m_vao = vaoManager->lookupHandle(QPair(command->m_geometry, command->m_shader)); + command->m_vao = vaoManager->lookupHandle(vaoKey); if (command->m_vao.isNull()) { qCDebug(Rendering) << Q_FUNC_INFO << "Allocating new VAO"; - command->m_vao = vaoManager->getOrAcquireHandle(QPair(command->m_geometry, command->m_shader)); - vaoManager->data(command->m_vao)->setGraphicsContext(m_graphicsContext.data()); - if (m_graphicsContext->supportsVAO()) - vaoManager->data(command->m_vao)->setVao(new QOpenGLVertexArrayObject()); - vaoManager->data(command->m_vao)->create(); + command->m_vao = vaoManager->getOrAcquireHandle(vaoKey); + vaoManager->data(command->m_vao)->create(m_graphicsContext.data(), vaoKey); } if (*previousVaoHandle != command->m_vao) { @@ -1573,6 +1589,20 @@ void Renderer::cleanGraphicsResources() tex->destroyGLTexture(); delete tex; } + + // Delete abandoned VAOs + m_abandonedVaosMutex.lock(); + const QVector abandonedVaos = std::move(m_abandonedVaos); + m_abandonedVaosMutex.unlock(); + for (HVao vaoHandle : abandonedVaos) { + // might have already been destroyed last frame, but added by the cleanup job before, so + // check if the VAO is really still existent + OpenGLVertexArrayObject *vao = m_nodesManager->vaoManager()->data(vaoHandle); + if (vao) { + vao->destroy(); + m_nodesManager->vaoManager()->release(vaoHandle); + } + } } QList Renderer::pendingPickingEvents() const diff --git a/src/render/backend/renderer_p.h b/src/render/backend/renderer_p.h index 9f6e8d857..bd12ecec6 100644 --- a/src/render/backend/renderer_p.h +++ b/src/render/backend/renderer_p.h @@ -322,15 +322,20 @@ private: OpenGLVertexArrayObject **vao); GenericLambdaJobPtr> m_bufferGathererJob; + GenericLambdaJobPtr> m_vaoGathererJob; GenericLambdaJobPtr> m_textureGathererJob; GenericLambdaJobPtr> m_shaderGathererJob; SynchronizerJobPtr m_syncTextureLoadingJob; + void lookForAbandonedVaos(); void lookForDirtyBuffers(); void lookForDirtyTextures(); void lookForDirtyShaders(); + QMutex m_abandonedVaosMutex; + QVector m_abandonedVaos; + QVector m_dirtyBuffers; QVector m_dirtyShaders; QVector m_dirtyTextures; diff --git a/src/render/jobs/job_common_p.h b/src/render/jobs/job_common_p.h index f3be2e6b0..4c3a6a6c0 100644 --- a/src/render/jobs/job_common_p.h +++ b/src/render/jobs/job_common_p.h @@ -86,6 +86,7 @@ namespace JobTypes { UpdateWorldBoundingVolume, FrameSubmissionPart2, DirtyBufferGathering, + DirtyVaoGathering, DirtyTextureGathering, DirtyShaderGathering, SendRenderCapture, -- cgit v1.2.3 From f471bf3ac9ecf9d8149dd8916d057a31af51255f Mon Sep 17 00:00:00 2001 From: Wieland Hagen Date: Wed, 28 Dec 2016 19:56:38 +0700 Subject: Fix node de-registration from scene on deletion/reparenting QNodePrivate::unsetSceneHelper() used to be broken, in that it set the m_scene of the the item that the NodeVisitor functor was executed on. Subsequent calls for child nodes would then have a m_scene == nullptr, and could thus not be de-registered. This patch fixes this behavior by treating each node's m_scene separately Task-number: QTBUG-57571 Change-Id: I779caadd6957a97514fd105cd16935c3edc9f41f Reviewed-by: Paul Lemire --- src/core/nodes/qnode.cpp | 16 +++++---- tests/auto/core/qscene/tst_qscene.cpp | 64 +++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 7 deletions(-) diff --git a/src/core/nodes/qnode.cpp b/src/core/nodes/qnode.cpp index e4bb5d4a3..8e7261be0 100644 --- a/src/core/nodes/qnode.cpp +++ b/src/core/nodes/qnode.cpp @@ -392,20 +392,22 @@ void QNodePrivate::setSceneHelper(QNode *root) Recursively unsets and remove nodes in the subtree of base node \a root from the scene. Also takes care of removing Components and Entities connections. */ -void QNodePrivate::unsetSceneHelper(QNode *root) +void QNodePrivate::unsetSceneHelper(QNode *node) { + QNodePrivate *nodePrivate = QNodePrivate::get(node); + // We also need to handle QEntity <-> QComponent relationships removal - if (QComponent *c = qobject_cast(root)) { + if (QComponent *c = qobject_cast(node)) { const QVector entities = c->entities(); for (QEntity *entity : entities) { - if (m_scene) - m_scene->removeEntityForComponent(c->id(), entity->id()); + if (nodePrivate->m_scene) + nodePrivate->m_scene->removeEntityForComponent(c->id(), entity->id()); } } - if (m_scene != nullptr) - m_scene->removeObservable(root); - root->d_func()->setScene(nullptr); + if (nodePrivate->m_scene != nullptr) + nodePrivate->m_scene->removeObservable(node); + nodePrivate->setScene(nullptr); } /*! diff --git a/tests/auto/core/qscene/tst_qscene.cpp b/tests/auto/core/qscene/tst_qscene.cpp index eabcc96fb..561a67765 100644 --- a/tests/auto/core/qscene/tst_qscene.cpp +++ b/tests/auto/core/qscene/tst_qscene.cpp @@ -48,6 +48,7 @@ private slots: void removeObservable(); void removeNodeObservable(); void addChildNode(); + void deleteChildNode(); void removeChildNode(); void addEntityForComponent(); void removeEntityForComponent(); @@ -280,6 +281,69 @@ void tst_QScene::addChildNode() } } +void tst_QScene::deleteChildNode() +{ + // GIVEN + Qt3DCore::QScene *scene = new Qt3DCore::QScene; + + QList nodes1, nodes2; + + Qt3DCore::QNode *root1 = new tst_Node(); + Qt3DCore::QNode *root2 = new tst_Node(); + Qt3DCore::QNodePrivate::get(root1)->setScene(scene); + Qt3DCore::QNodePrivate::get(root2)->setScene(scene); + + // WHEN + scene->addObservable(root1); + scene->addObservable(root2); + // THEN + QVERIFY(scene->lookupNode(root1->id()) == root1); + QVERIFY(scene->lookupNode(root2->id()) == root2); + + // WHEN + for (int i = 0; i < 10; i++) { + Qt3DCore::QNode *child1 = new tst_Node(); + child1->setParent(nodes1.isEmpty() ? root1 : nodes1.last()); + nodes1.append(child1); + + Qt3DCore::QNode *child2 = new tst_Node(); + child2->setParent(nodes2.isEmpty() ? root2 : nodes2.last()); + nodes2.append(child2); + } + QCoreApplication::processEvents(); + + // THEN + for (Qt3DCore::QNode *n : qAsConst(nodes1)) { + QVERIFY(scene->lookupNode(n->id()) == n); + } + for (Qt3DCore::QNode *n : qAsConst(nodes2)) { + QVERIFY(scene->lookupNode(n->id()) == n); + } + + // gather node IDs + Qt3DCore::QNodeIdVector root1ChildIds; + for (Qt3DCore::QNode *n : qAsConst(nodes1)) + root1ChildIds << n->id(); + + // WHEN + delete root1; + QCoreApplication::processEvents(); + + // THEN + for (Qt3DCore::QNodeId id : qAsConst(root1ChildIds)) { + QVERIFY(scene->lookupNode(id) == nullptr); + } + + // WHEN + nodes2.first()->setParent(static_cast(nullptr)); + QCoreApplication::processEvents(); + + // THEN + for (Qt3DCore::QNode *n : qAsConst(nodes2)) { + QVERIFY(scene->lookupNode(n->id()) == nullptr); + } +} + void tst_QScene::removeChildNode() { // GIVEN -- cgit v1.2.3 From 20780b747f36f9cf206774271d983106a1ab5f3b Mon Sep 17 00:00:00 2001 From: Wieland Hagen Date: Wed, 1 Feb 2017 19:37:26 +0700 Subject: Remove unneeded setAspectRatio will get updated in Qt3DWindow::resizeEvent() Task-number: QTBUG-58327 Change-Id: I9464ba193a225af17cc4638902d0c68e82640d41 Reviewed-by: Guillermo A. Amaral Reviewed-by: Sean Harmer --- examples/qt3d/materials-cpp/main.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/qt3d/materials-cpp/main.cpp b/examples/qt3d/materials-cpp/main.cpp index 5ca6998e0..b788bff30 100644 --- a/examples/qt3d/materials-cpp/main.cpp +++ b/examples/qt3d/materials-cpp/main.cpp @@ -81,7 +81,6 @@ int main(int argc, char* argv[]) // Scene Camera Qt3DRender::QCamera *basicCamera = view.camera(); basicCamera->setProjectionType(Qt3DRender::QCameraLens::PerspectiveProjection); - basicCamera->setAspectRatio(view.width() / view.height()); basicCamera->setUpVector(QVector3D(0.0f, 1.0f, 0.0f)); basicCamera->setViewCenter(QVector3D(0.0f, 3.5f, 0.0f)); basicCamera->setPosition(QVector3D(0.0f, 3.5f, 25.0f)); -- cgit v1.2.3 From 5cdfef0be44d12bf340b5640e458a73631a4a6f3 Mon Sep 17 00:00:00 2001 From: Wieland Hagen Date: Thu, 2 Feb 2017 13:02:47 +0700 Subject: Make sure not to reference already deleted VAOs Change-Id: I112100da22885b8f3868f235b44ea649e35755e9 Reviewed-by: Paul Lemire --- src/render/backend/renderer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/render/backend/renderer.cpp b/src/render/backend/renderer.cpp index 100c4a33d..cfa495356 100644 --- a/src/render/backend/renderer.cpp +++ b/src/render/backend/renderer.cpp @@ -840,7 +840,7 @@ void Renderer::lookForAbandonedVaos() // Make sure to only mark VAOs for deletion that were already created // (ignore those that might be currently under construction in the render thread) - if (vao->isAbandoned(m_nodesManager->geometryManager(), m_nodesManager->shaderManager())) { + if (vao && vao->isAbandoned(m_nodesManager->geometryManager(), m_nodesManager->shaderManager())) { m_abandonedVaosMutex.lock(); m_abandonedVaos.push_back(handle); m_abandonedVaosMutex.unlock(); -- cgit v1.2.3 From 1171898369e8ef73fde5e81cdcf44d9f3ffe33a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Thu, 2 Feb 2017 12:10:50 +0200 Subject: Fix build warnings in animations Fix type name first seen using 'class' now seen using 'struct' warnings Change-Id: I5ff27e56216d22290de6c104f04eeec8d7389137 Reviewed-by: Sean Harmer --- src/animation/backend/animationutils_p.h | 2 +- src/animation/backend/clipanimator_p.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/animation/backend/animationutils_p.h b/src/animation/backend/animationutils_p.h index 061d09261..b662ec445 100644 --- a/src/animation/backend/animationutils_p.h +++ b/src/animation/backend/animationutils_p.h @@ -57,7 +57,7 @@ QT_BEGIN_NAMESPACE namespace Qt3DAnimation { namespace Animation { -class ChannelGroup; +struct ChannelGroup; class Handler; class AnimationClip; class ChannelMapper; diff --git a/src/animation/backend/clipanimator_p.h b/src/animation/backend/clipanimator_p.h index 577d18d7b..f182920b1 100644 --- a/src/animation/backend/clipanimator_p.h +++ b/src/animation/backend/clipanimator_p.h @@ -57,7 +57,7 @@ QT_BEGIN_NAMESPACE namespace Qt3DAnimation { namespace Animation { -class ChannelGroup; +struct ChannelGroup; class Handler; class Q_AUTOTEST_EXPORT ClipAnimator : public BackendNode -- cgit v1.2.3 From a79d8643753080c20d815f46091f3867f074ec6e Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Thu, 2 Feb 2017 15:30:21 +0100 Subject: Bump version Change-Id: If8caa3205feef820c23f2703d57632ecdcb5664a --- .qmake.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.qmake.conf b/.qmake.conf index b1c22d3b7..138038d54 100644 --- a/.qmake.conf +++ b/.qmake.conf @@ -1,3 +1,3 @@ load(qt_build_config) -MODULE_VERSION = 5.9.0 +MODULE_VERSION = 5.10.0 -- cgit v1.2.3 From f05c59f14409b9b448e6445f0f4129f81362a743 Mon Sep 17 00:00:00 2001 From: Mike Krus Date: Sat, 4 Feb 2017 19:59:34 +0000 Subject: Fix iOS static build (think some of the qml related files need cleaning up) Change-Id: Ibf982c0b168ad845966d42f36ecd616cf74732f4 Reviewed-by: Sean Harmer --- src/quick3d/imports/extras/qt3dquick3dextrasplugin.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/quick3d/imports/extras/qt3dquick3dextrasplugin.h b/src/quick3d/imports/extras/qt3dquick3dextrasplugin.h index f5ea6a7f1..f24a93b3f 100644 --- a/src/quick3d/imports/extras/qt3dquick3dextrasplugin.h +++ b/src/quick3d/imports/extras/qt3dquick3dextrasplugin.h @@ -46,7 +46,6 @@ static void initResources() { #ifdef QT_STATIC Q_INIT_RESOURCE(qmake_Qt3D_Extras); - Q_INIT_RESOURCE(defaults); Q_INIT_RESOURCE(extras); #endif } -- cgit v1.2.3 From a5d76db6b9950301fc2e26dece76d27567181316 Mon Sep 17 00:00:00 2001 From: Mike Krus Date: Sun, 5 Feb 2017 18:07:27 +0000 Subject: Add accessor for QRenderSettings This makes it easier to change rendering and picking settings for client applications. Prompted by QTBUG-58354 Change-Id: I620370946c6b0d48ee47e7aecc81d72915024ee9 Reviewed-by: Paul Lemire --- src/extras/defaults/qt3dwindow.cpp | 5 +++++ src/extras/defaults/qt3dwindow.h | 1 + 2 files changed, 6 insertions(+) diff --git a/src/extras/defaults/qt3dwindow.cpp b/src/extras/defaults/qt3dwindow.cpp index 06ff14212..87a9e6659 100644 --- a/src/extras/defaults/qt3dwindow.cpp +++ b/src/extras/defaults/qt3dwindow.cpp @@ -159,6 +159,11 @@ Qt3DRender::QCamera *Qt3DWindow::camera() const return m_defaultCamera; } +Qt3DRender::QRenderSettings *Qt3DWindow::renderSettings() const +{ + return m_renderSettings; +} + void Qt3DWindow::showEvent(QShowEvent *e) { if (!m_initialized) { diff --git a/src/extras/defaults/qt3dwindow.h b/src/extras/defaults/qt3dwindow.h index 109e1be75..f3ab04aac 100644 --- a/src/extras/defaults/qt3dwindow.h +++ b/src/extras/defaults/qt3dwindow.h @@ -101,6 +101,7 @@ public: Qt3DExtras::QForwardRenderer *defaultFrameGraph() const; Qt3DRender::QCamera *camera() const; + Qt3DRender::QRenderSettings *renderSettings() const; public Q_SLOTS: -- cgit v1.2.3 From 038725435da8f46d161c3f9fd248fab32ac75187 Mon Sep 17 00:00:00 2001 From: Kimmo Ollila Date: Mon, 30 Jan 2017 15:30:06 +0200 Subject: Fix build for INTEGRITY Explicit specialization of class must precede its first use. Change-Id: I99c91e8724b1a66b5c151d2a751a19563b0d9a28 Reviewed-by: Nikola Velinov Reviewed-by: Paul Lemire --- .../geometryloaders/default/basegeometryloader_p.h | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/plugins/geometryloaders/default/basegeometryloader_p.h b/src/plugins/geometryloaders/default/basegeometryloader_p.h index 56bdb23a9..fb1ffc6b0 100644 --- a/src/plugins/geometryloaders/default/basegeometryloader_p.h +++ b/src/plugins/geometryloaders/default/basegeometryloader_p.h @@ -154,6 +154,13 @@ struct FaceIndices }; QT3D_DECLARE_TYPEINFO(Qt3DRender, FaceIndices, Q_PRIMITIVE_TYPE) +struct ByteArraySplitterEntry +{ + int start; + int size; +}; +QT3D_DECLARE_TYPEINFO(Qt3DRender, ByteArraySplitterEntry, Q_PRIMITIVE_TYPE) + /* * A helper class to split a QByteArray and access its sections without * additional memory allocations. @@ -169,7 +176,7 @@ public: for (auto it = begin; it != end; ++it) { if (*it == delimiter) { if (position > lastPosition || splitBehavior == QString::KeepEmptyParts) { // skip multiple consecutive delimiters - const Entry entry = { lastPosition, position - lastPosition }; + const ByteArraySplitterEntry entry = { lastPosition, position - lastPosition }; m_entries.append(entry); } lastPosition = position + 1; @@ -178,7 +185,7 @@ public: ++position; } - const Entry entry = { lastPosition, position - lastPosition }; + const ByteArraySplitterEntry entry = { lastPosition, position - lastPosition }; m_entries.append(entry); } @@ -212,17 +219,10 @@ public: return ByteArraySplitter(m_input + m_entries[index].start, m_input + m_entries[index].start + m_entries[index].size, delimiter, splitBehavior); } - struct Entry - { - int start; - int size; - }; - private: - QVarLengthArray m_entries; + QVarLengthArray m_entries; const char *m_input; }; -QT3D_DECLARE_TYPEINFO(Qt3DRender, ByteArraySplitter::Entry, Q_PRIMITIVE_TYPE) } // namespace Qt3DRender -- cgit v1.2.3 From f865508efd13cae9d09c425d0e419f81057f1948 Mon Sep 17 00:00:00 2001 From: Janne Koskinen Date: Fri, 3 Feb 2017 09:25:23 +0200 Subject: Fix onDemand rendering idle loop CPU burning Sleep render aspect if there are no jobs to create. Task-number: QTBUG-55109 Change-Id: I52ce90ab781d6986321ae0cd72a14cca09098180 Reviewed-by: Miikka Heikkinen Reviewed-by: Mika Salmela Reviewed-by: Paul Lemire Reviewed-by: Sean Harmer --- src/render/frontend/qrenderaspect.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/render/frontend/qrenderaspect.cpp b/src/render/frontend/qrenderaspect.cpp index 36f951301..4d2a73f7d 100644 --- a/src/render/frontend/qrenderaspect.cpp +++ b/src/render/frontend/qrenderaspect.cpp @@ -371,6 +371,7 @@ QVector QRenderAspect::jobsToExecute(qint64 time) // don't spawn any jobs, if the renderer decides to skip this frame if (!d->m_renderer->shouldRender()) { d->m_renderer->skipNextFrame(); + QThread::msleep(1); return jobs; } -- cgit v1.2.3 From d938949ecf920eead676d7fe29504ac114adeb1d Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Sun, 5 Feb 2017 14:22:28 +0000 Subject: Fix QBufferUpdate: type name first seen using 'class' warning Change-Id: I2ff25e678ba81c0cce005f23c1efe4998bd0bec6 Reviewed-by: Mike Krus Reviewed-by: Paul Lemire --- src/render/geometry/buffer_p.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/render/geometry/buffer_p.h b/src/render/geometry/buffer_p.h index 8f6600f7a..9d9606eb0 100644 --- a/src/render/geometry/buffer_p.h +++ b/src/render/geometry/buffer_p.h @@ -60,7 +60,7 @@ QT_BEGIN_NAMESPACE namespace Qt3DRender { -class QBufferUpdate; +struct QBufferUpdate; namespace Render { -- cgit v1.2.3 From 65ff02ca76a705e5b2c552123246109f876f8087 Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Sun, 5 Feb 2017 14:25:05 +0000 Subject: Add missing Q_INTERFACES(QFactoryInterface) Fixes warning about qobject_cast that would fail. Change-Id: Ie628ebe5a40b998946472e540c684354ea1e5016 Reviewed-by: Mike Krus Reviewed-by: Paul Lemire --- src/render/io/qgeometryloaderfactory_p.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/render/io/qgeometryloaderfactory_p.h b/src/render/io/qgeometryloaderfactory_p.h index c6a7344ce..6e0044c4a 100644 --- a/src/render/io/qgeometryloaderfactory_p.h +++ b/src/render/io/qgeometryloaderfactory_p.h @@ -68,6 +68,7 @@ class QGeometryLoaderInterface; class QT3DRENDERSHARED_PRIVATE_EXPORT QGeometryLoaderFactory : public QObject, public QFactoryInterface { Q_OBJECT + Q_INTERFACES(QFactoryInterface) public: explicit QGeometryLoaderFactory(QObject *parent = nullptr); virtual ~QGeometryLoaderFactory(); -- cgit v1.2.3 From 40c9ddabbc4c776adeb9ad440777505d7cb0f262 Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Sun, 5 Feb 2017 14:26:56 +0000 Subject: Fix a couple of warnings in QEventForward::targetDestroyed Change-Id: I8ad388443e8206882eabb383cde9bdb554e518ca Reviewed-by: Mike Krus Reviewed-by: Paul Lemire --- src/render/picking/qeventforward.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/render/picking/qeventforward.cpp b/src/render/picking/qeventforward.cpp index 08546fabd..cb5f9cfbb 100644 --- a/src/render/picking/qeventforward.cpp +++ b/src/render/picking/qeventforward.cpp @@ -154,8 +154,8 @@ QObject *QEventForward::target() const void QEventForward::targetDestroyed(QObject *target) { - Q_D(QEventForward); - Q_ASSERT(target == d->m_target); + Q_ASSERT(target == d_func()->m_target); + Q_UNUSED(target); setTarget(nullptr); } -- cgit v1.2.3 From faa8fc18bfeca06de6c4a7bdbb14e1be9eb96f54 Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Sun, 5 Feb 2017 14:29:05 +0000 Subject: Fix double -> float conversion warnings Change-Id: I7eac42f170de92bb34b69e72855e0b5de514de8c Reviewed-by: Mike Krus Reviewed-by: Paul Lemire --- tests/auto/render/graphicshelpergl2/tst_graphicshelpergl2.cpp | 2 +- tests/manual/custom-mesh-update-data-cpp/main.cpp | 2 +- tools/qgltf/qgltf.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/auto/render/graphicshelpergl2/tst_graphicshelpergl2.cpp b/tests/auto/render/graphicshelpergl2/tst_graphicshelpergl2.cpp index 9bc234c50..58e2373f5 100644 --- a/tests/auto/render/graphicshelpergl2/tst_graphicshelpergl2.cpp +++ b/tests/auto/render/graphicshelpergl2/tst_graphicshelpergl2.cpp @@ -1302,7 +1302,7 @@ private Q_SLOTS: // WHEN m_func->glUseProgram(shaderProgram.programId()); - GLfloat values[16] = { 454.0f, 350.0f, 883.0f, 355.0f, 1340.0f, 1584.0f, 1200.0f, 427.0f, 396.0f, 1603.0f, 55.0f, 5.7, 383.0f, 6.2f, 5.3f, 327.0f }; + GLfloat values[16] = { 454.0f, 350.0f, 883.0f, 355.0f, 1340.0f, 1584.0f, 1200.0f, 427.0f, 396.0f, 1603.0f, 55.0f, 5.7f, 383.0f, 6.2f, 5.3f, 327.0f }; const GLint location = shaderProgram.uniformLocation("m4"); m_glHelper.glUniformMatrix4fv(location, 1, values); diff --git a/tests/manual/custom-mesh-update-data-cpp/main.cpp b/tests/manual/custom-mesh-update-data-cpp/main.cpp index 7485dbec5..c7f5742dc 100644 --- a/tests/manual/custom-mesh-update-data-cpp/main.cpp +++ b/tests/manual/custom-mesh-update-data-cpp/main.cpp @@ -277,7 +277,7 @@ int main(int argc, char* argv[]) void TimerObject::timeout() { - angle += M_PI / 360.0f; + angle += float(M_PI / 360.0); QByteArray updateData; updateData.resize(3*sizeof(float)); diff --git a/tools/qgltf/qgltf.cpp b/tools/qgltf/qgltf.cpp index 788f3cef5..bc011eaa7 100644 --- a/tools/qgltf/qgltf.cpp +++ b/tools/qgltf/qgltf.cpp @@ -1016,7 +1016,7 @@ void AssimpImporter::parseCameras() c.aspectRatio = qFuzzyIsNull(cam->mAspect) ? 1.5f : cam->mAspect; c.yfov = cam->mHorizontalFOV; if (c.yfov < (M_PI / 10.0)) // this can't be right (probably orthographic source camera) - c.yfov = M_PI / 4.0; + c.yfov = float(M_PI / 4.0); c.znear = cam->mClipPlaneNear; c.zfar = cam->mClipPlaneFar; -- cgit v1.2.3 From 8f3f2f336977ca54fe5ec2e78186a0462396b977 Mon Sep 17 00:00:00 2001 From: Paul Lemire Date: Wed, 1 Feb 2017 16:54:56 +0100 Subject: Quick3DExtras: fix QAbstractAnimation import version Change-Id: I7ad91e31b76b5913b8b102413c2ac47ec481ec3e Reviewed-by: Sean Harmer --- src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp b/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp index c03d9d2f8..f8cfc5be9 100644 --- a/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp +++ b/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp @@ -137,7 +137,7 @@ void Qt3DQuick3DExtrasPlugin::registerTypes(const char *uri) qmlRegisterType(uri, 2, 2, "DistanceFieldGlyphCache"); qmlRegisterType(uri, 2, 2, "DistanceFieldText"); - qmlRegisterUncreatableType(uri, 2, 0, "AbstractAnimation", QStringLiteral("AbstractAnimation is abstract")); + qmlRegisterUncreatableType(uri, 2, 2, "AbstractAnimation", QStringLiteral("AbstractAnimation is abstract")); qmlRegisterExtendedType(uri, 2, 2, "KeyframeAnimation"); qmlRegisterExtendedType(uri, 2, 2, "AnimationGroup"); qmlRegisterExtendedType(uri, 2, 2, "AnimationController"); -- cgit v1.2.3 From ff1ca682143fb30789a5aecfe4e1ec939ce0c6cd Mon Sep 17 00:00:00 2001 From: Paul Lemire Date: Wed, 1 Feb 2017 16:54:33 +0100 Subject: EventForward: Fix compile warning Change-Id: Ic8ae5c2332dfd6c868ae37575d311acd691ff437 Reviewed-by: Sean Harmer --- src/render/picking/eventforward.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/render/picking/eventforward.cpp b/src/render/picking/eventforward.cpp index 0216542bd..2b04e4d04 100644 --- a/src/render/picking/eventforward.cpp +++ b/src/render/picking/eventforward.cpp @@ -68,7 +68,7 @@ EventForward::~EventForward() void EventForward::cleanup() { setEnabled(false); - m_coordinateAttribute = ""; + m_coordinateAttribute.clear(); m_coordinateTransform.setToIdentity(); m_forwardMouseEvents = false; m_forwardKeyboardEvents = false; -- cgit v1.2.3 From 3f649fd039369ec14a348bc424eac75a315e6dd6 Mon Sep 17 00:00:00 2001 From: Paul Lemire Date: Mon, 6 Feb 2017 15:12:25 +0100 Subject: Animations: add type to the jobs for the profiler Change-Id: Ifa8d2def025608de6731b6391145df9ebb430d9f Reviewed-by: Sean Harmer --- src/animation/animation.pro | 3 +- src/animation/backend/buildblendtreesjob.cpp | 3 +- .../backend/evaluateblendclipanimatorjob.cpp | 3 +- src/animation/backend/evaluateclipanimatorjob.cpp | 2 + .../backend/findrunningclipanimatorsjob.cpp | 2 + src/animation/backend/loadanimationclipjob.cpp | 2 + src/animation/job_common_p.h | 79 ++++++++++++++++++++++ 7 files changed, 91 insertions(+), 3 deletions(-) create mode 100644 src/animation/job_common_p.h diff --git a/src/animation/animation.pro b/src/animation/animation.pro index 4443e3193..b7d08416c 100644 --- a/src/animation/animation.pro +++ b/src/animation/animation.pro @@ -15,7 +15,8 @@ include(backend/backend.pri) HEADERS += \ qt3danimation_global.h \ qt3danimation_global_p.h \ - animationlogging_p.h + animationlogging_p.h \ + job_common_p.h SOURCES += \ animationlogging.cpp diff --git a/src/animation/backend/buildblendtreesjob.cpp b/src/animation/backend/buildblendtreesjob.cpp index e1c3dd701..e86aa4978 100644 --- a/src/animation/backend/buildblendtreesjob.cpp +++ b/src/animation/backend/buildblendtreesjob.cpp @@ -40,6 +40,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE @@ -49,7 +50,7 @@ namespace Animation { BuildBlendTreesJob::BuildBlendTreesJob() : Qt3DCore::QAspectJob() { - // TO DO: Add Profiler ID + SET_JOB_RUN_STAT_TYPE(this, JobTypes::BuildBlendTree, 0); } void BuildBlendTreesJob::setBlendedClipAnimators(const QVector &blendedClipAnimatorHandles) diff --git a/src/animation/backend/evaluateblendclipanimatorjob.cpp b/src/animation/backend/evaluateblendclipanimatorjob.cpp index 0f79edbe6..440943ce4 100644 --- a/src/animation/backend/evaluateblendclipanimatorjob.cpp +++ b/src/animation/backend/evaluateblendclipanimatorjob.cpp @@ -41,6 +41,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE @@ -52,7 +53,7 @@ EvaluateBlendClipAnimatorJob::EvaluateBlendClipAnimatorJob() , m_currentLoop(std::numeric_limits::max()) , m_isFinalFrame(true) { - // TO DO: Add Profiler ID + SET_JOB_RUN_STAT_TYPE(this, JobTypes::EvaluateBlendClipAnimator, 0); } namespace { diff --git a/src/animation/backend/evaluateclipanimatorjob.cpp b/src/animation/backend/evaluateclipanimatorjob.cpp index 406a46dcd..f4f919d25 100644 --- a/src/animation/backend/evaluateclipanimatorjob.cpp +++ b/src/animation/backend/evaluateclipanimatorjob.cpp @@ -39,6 +39,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE @@ -48,6 +49,7 @@ namespace Animation { EvaluateClipAnimatorJob::EvaluateClipAnimatorJob() : Qt3DCore::QAspectJob() { + SET_JOB_RUN_STAT_TYPE(this, JobTypes::EvaluateClipAnimator, 0); } void EvaluateClipAnimatorJob::run() diff --git a/src/animation/backend/findrunningclipanimatorsjob.cpp b/src/animation/backend/findrunningclipanimatorsjob.cpp index 3b2d9d4f5..fcffab8cc 100644 --- a/src/animation/backend/findrunningclipanimatorsjob.cpp +++ b/src/animation/backend/findrunningclipanimatorsjob.cpp @@ -39,6 +39,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE @@ -48,6 +49,7 @@ namespace Animation { FindRunningClipAnimatorsJob::FindRunningClipAnimatorsJob() : Qt3DCore::QAspectJob() { + SET_JOB_RUN_STAT_TYPE(this, JobTypes::FindRunningClipAnimator, 0); } void FindRunningClipAnimatorsJob::setDirtyClipAnimators(const QVector &clipAnimatorHandles) diff --git a/src/animation/backend/loadanimationclipjob.cpp b/src/animation/backend/loadanimationclipjob.cpp index c94435398..39809f9eb 100644 --- a/src/animation/backend/loadanimationclipjob.cpp +++ b/src/animation/backend/loadanimationclipjob.cpp @@ -39,6 +39,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE @@ -49,6 +50,7 @@ LoadAnimationClipJob::LoadAnimationClipJob() : Qt3DCore::QAspectJob() , m_animationClipHandles() { + SET_JOB_RUN_STAT_TYPE(this, JobTypes::LoadAnimationClip, 0); } void LoadAnimationClipJob::addDirtyAnimationClips(const QVector &animationClipHandles) diff --git a/src/animation/job_common_p.h b/src/animation/job_common_p.h new file mode 100644 index 000000000..882246a42 --- /dev/null +++ b/src/animation/job_common_p.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef QT3DANIMATION_ANIMATION_JOB_COMMON_P_H +#define QT3DANIMATION_ANIMATION_JOB_COMMON_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { + +namespace Animation { + +namespace JobTypes { + +enum JobType { + BuildBlendTree = 8192, + EvaluateBlendClipAnimator, + EvaluateClipAnimator, + LoadAnimationClip, + FindRunningClipAnimator +}; + +} // JobTypes + +} // Animation + +} // Qt3DAnimation + +QT_END_NAMESPACE + +#endif // QT3DANIMATION_ANIMATION_JOB_COMMON_P_H -- cgit v1.2.3 From b6d57c31f5bc97a80c7723f93b94edddccb18d1d Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Mon, 6 Feb 2017 12:15:18 +0000 Subject: Add .qmake.stash to .gitignore Change-Id: If44d04450ca971ebefbdb767ef0e722ae893de3b Reviewed-by: Mike Krus --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 32a748504..490a5cad5 100644 --- a/.gitignore +++ b/.gitignore @@ -27,6 +27,7 @@ include/* *_resource.rc .qmake.cache .qmake.vars +.qmake.stash *.prl moc_*.cpp qrc_*.cpp -- cgit v1.2.3 From 1150383da5f55b44d6101f086cca310fa94db6a5 Mon Sep 17 00:00:00 2001 From: Mike Krus Date: Sun, 5 Feb 2017 17:41:50 +0000 Subject: Improve documentation for QMesh Also use QRegularExpression instead of the older QRegEx in the obj loader Change-Id: I031f98a718d81e9baeba7aeb6e3482bb22d5643f Reviewed-by: Sean Harmer --- .../geometryloaders/default/objgeometryloader.cpp | 6 +++-- src/render/geometry/qmesh.cpp | 31 +++++++++++++++++++--- 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/src/plugins/geometryloaders/default/objgeometryloader.cpp b/src/plugins/geometryloaders/default/objgeometryloader.cpp index ad1bde7d4..ab2f17712 100644 --- a/src/plugins/geometryloaders/default/objgeometryloader.cpp +++ b/src/plugins/geometryloaders/default/objgeometryloader.cpp @@ -40,6 +40,7 @@ #include "objgeometryloader.h" #include +#include QT_BEGIN_NAMESPACE @@ -77,7 +78,7 @@ bool ObjGeometryLoader::doLoad(QIODevice *ioDev, const QString &subMesh) int normalsOffset = 0; int texCoordsOffset = 0; - QRegExp subMeshMatch(subMesh); + QRegularExpression subMeshMatch(subMesh); if (!subMeshMatch.isValid()) subMeshMatch.setPattern(QLatin1String("^(") + subMesh + QLatin1String(")$")); Q_ASSERT(subMeshMatch.isValid()); @@ -196,7 +197,8 @@ bool ObjGeometryLoader::doLoad(QIODevice *ioDev, const QString &subMesh) } else { if (!subMesh.isEmpty() ) { const QString objName = tokens.stringAt(1); - skipping = subMeshMatch.indexIn(objName) < 0; + QRegularExpressionMatch match = subMeshMatch.match(objName); + skipping = !match.hasMatch(); } } } diff --git a/src/render/geometry/qmesh.cpp b/src/render/geometry/qmesh.cpp index 2d9bb54b4..3305fc915 100644 --- a/src/render/geometry/qmesh.cpp +++ b/src/render/geometry/qmesh.cpp @@ -68,7 +68,12 @@ QMeshPrivate::QMeshPrivate() * \qmltype Mesh * \instantiates Qt3DRender::QMesh * \inqmlmodule Qt3D.Render - * \brief A custom mesh. + * \brief A custom mesh loader. + * + * Loads mesh data from external files in a variety of formats. + * + * In Qt3D 5.9, Mesh supports the following formats: Wavefront OBJ, Stanford Triangle Format PLY, STL (STereoLithography). + * QMesh will also support Autodesk FBX files if the SDK is installed and the fbx geometry loader plugin is built and found. */ /*! @@ -80,7 +85,17 @@ QMeshPrivate::QMeshPrivate() /*! * \qmlproperty string Mesh::meshName * - * Holds the name of the mesh. + * Filter indicating which part of the mesh should be loaded. + * + * If meshName is empty (the default), then the entire mesh is loaded. + * + * If meshName is a plain string, then only the sub-mesh matching that name, if present, will be loaded. + * + * If meshName is a regular expression, than all sub-meshes matching the expression will be loaded. + * + * \note Only Wavefront OBJ files support sub-meshes. + * + * \sa QRegularExpression */ /*! @@ -90,7 +105,17 @@ QMeshPrivate::QMeshPrivate() * * \inherits Qt3DRender::QGeometryRenderer * - * \brief A custom mesh. + * \brief A custom mesh loader. + * + * Loads mesh data from external files in a variety of formats. + * Qt3DRender::QMesh loads data into a single mesh. + * + * In Qt3D 5.9, QMesh supports the following formats: Wavefront OBJ, Stanford Triangle Format PLY, STL (STereoLithography). + * QMesh will also support Autodesk FBX files if the SDK is installed and the fbx geometry loader plugin is built and found. + * + * If you wish to load an entire scene made of several objects, you should rather use the Qt3DRender::QSceneLoader instead. + * + * \sa Qt3DRender::QSceneLoader */ /*! -- cgit v1.2.3 From c0df6af32e80a09a8bf72bd6c9cc28270613220b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Mon, 6 Feb 2017 11:01:06 +0200 Subject: Move animations from extras to animations Change-Id: If3bcfe24ebe7ecfb4519e0e400e601819783edad Reviewed-by: Sean Harmer --- src/animation/frontend/frontend.pri | 25 +- src/animation/frontend/qabstractanimation.cpp | 112 +++++++++ src/animation/frontend/qabstractanimation.h | 93 +++++++ src/animation/frontend/qabstractanimation_p.h | 75 ++++++ src/animation/frontend/qanimationcontroller.cpp | 252 +++++++++++++++++++ src/animation/frontend/qanimationcontroller.h | 105 ++++++++ src/animation/frontend/qanimationcontroller_p.h | 84 +++++++ src/animation/frontend/qanimationgroup.cpp | 125 +++++++++ src/animation/frontend/qanimationgroup.h | 89 +++++++ src/animation/frontend/qanimationgroup_p.h | 77 ++++++ src/animation/frontend/qkeyframeanimation.cpp | 262 +++++++++++++++++++ src/animation/frontend/qkeyframeanimation.h | 112 +++++++++ src/animation/frontend/qkeyframeanimation_p.h | 89 +++++++ src/animation/frontend/qmorphinganimation.cpp | 280 +++++++++++++++++++++ src/animation/frontend/qmorphinganimation.h | 116 +++++++++ src/animation/frontend/qmorphinganimation_p.h | 93 +++++++ src/animation/frontend/qmorphtarget.cpp | 120 +++++++++ src/animation/frontend/qmorphtarget.h | 83 ++++++ src/animation/frontend/qmorphtarget_p.h | 76 ++++++ src/animation/frontend/qvertexblendanimation.cpp | 234 +++++++++++++++++ src/animation/frontend/qvertexblendanimation.h | 96 +++++++ src/animation/frontend/qvertexblendanimation_p.h | 86 +++++++ src/extras/animations/animations.pri | 26 -- src/extras/animations/qabstractanimation.cpp | 112 --------- src/extras/animations/qabstractanimation.h | 93 ------- src/extras/animations/qabstractanimation_p.h | 75 ------ src/extras/animations/qanimationcontroller.cpp | 252 ------------------- src/extras/animations/qanimationcontroller.h | 105 -------- src/extras/animations/qanimationcontroller_p.h | 84 ------- src/extras/animations/qanimationgroup.cpp | 125 --------- src/extras/animations/qanimationgroup.h | 89 ------- src/extras/animations/qanimationgroup_p.h | 77 ------ src/extras/animations/qkeyframeanimation.cpp | 262 ------------------- src/extras/animations/qkeyframeanimation.h | 112 --------- src/extras/animations/qkeyframeanimation_p.h | 89 ------- src/extras/animations/qmorphinganimation.cpp | 280 --------------------- src/extras/animations/qmorphinganimation.h | 116 --------- src/extras/animations/qmorphinganimation_p.h | 93 ------- src/extras/animations/qmorphtarget.cpp | 120 --------- src/extras/animations/qmorphtarget.h | 83 ------ src/extras/animations/qmorphtarget_p.h | 76 ------ src/extras/animations/qvertexblendanimation.cpp | 234 ----------------- src/extras/animations/qvertexblendanimation.h | 96 ------- src/extras/animations/qvertexblendanimation_p.h | 86 ------- src/extras/extras.pro | 1 - src/plugins/sceneparsers/assimp/assimp.pro | 2 +- src/plugins/sceneparsers/assimp/assimpimporter.cpp | 40 +-- src/plugins/sceneparsers/assimp/assimpimporter.h | 6 +- .../animation/qt3dquick3danimationplugin.cpp | 20 ++ .../imports/extras/qt3dquick3dextrasplugin.cpp | 19 -- src/quick3d/quick3danimation/items/items.pri | 14 +- .../items/quick3danimationcontroller.cpp | 95 +++++++ .../items/quick3danimationcontroller_p.h | 89 +++++++ .../items/quick3danimationgroup.cpp | 99 ++++++++ .../items/quick3danimationgroup_p.h | 91 +++++++ .../items/quick3dkeyframeanimation.cpp | 101 ++++++++ .../items/quick3dkeyframeanimation_p.h | 92 +++++++ .../items/quick3dmorphinganimation.cpp | 97 +++++++ .../items/quick3dmorphinganimation_p.h | 92 +++++++ .../quick3danimation/items/quick3dmorphtarget.cpp | 93 +++++++ .../quick3danimation/items/quick3dmorphtarget_p.h | 85 +++++++ src/quick3d/quick3dextras/items/items.pri | 14 +- .../items/quick3danimationcontroller.cpp | 95 ------- .../items/quick3danimationcontroller_p.h | 89 ------- .../quick3dextras/items/quick3danimationgroup.cpp | 99 -------- .../quick3dextras/items/quick3danimationgroup_p.h | 91 ------- .../items/quick3dkeyframeanimation.cpp | 101 -------- .../items/quick3dkeyframeanimation_p.h | 92 ------- .../items/quick3dmorphinganimation.cpp | 97 ------- .../items/quick3dmorphinganimation_p.h | 92 ------- .../quick3dextras/items/quick3dmorphtarget.cpp | 93 ------- .../quick3dextras/items/quick3dmorphtarget_p.h | 85 ------- tests/manual/anim-viewer/main.qml | 1 + tests/manual/mesh-morphing/main.cpp | 16 +- tests/manual/mesh-morphing/mesh-morphing.pro | 2 +- 75 files changed, 3684 insertions(+), 3688 deletions(-) create mode 100644 src/animation/frontend/qabstractanimation.cpp create mode 100644 src/animation/frontend/qabstractanimation.h create mode 100644 src/animation/frontend/qabstractanimation_p.h create mode 100644 src/animation/frontend/qanimationcontroller.cpp create mode 100644 src/animation/frontend/qanimationcontroller.h create mode 100644 src/animation/frontend/qanimationcontroller_p.h create mode 100644 src/animation/frontend/qanimationgroup.cpp create mode 100644 src/animation/frontend/qanimationgroup.h create mode 100644 src/animation/frontend/qanimationgroup_p.h create mode 100644 src/animation/frontend/qkeyframeanimation.cpp create mode 100644 src/animation/frontend/qkeyframeanimation.h create mode 100644 src/animation/frontend/qkeyframeanimation_p.h create mode 100644 src/animation/frontend/qmorphinganimation.cpp create mode 100644 src/animation/frontend/qmorphinganimation.h create mode 100644 src/animation/frontend/qmorphinganimation_p.h create mode 100644 src/animation/frontend/qmorphtarget.cpp create mode 100644 src/animation/frontend/qmorphtarget.h create mode 100644 src/animation/frontend/qmorphtarget_p.h create mode 100644 src/animation/frontend/qvertexblendanimation.cpp create mode 100644 src/animation/frontend/qvertexblendanimation.h create mode 100644 src/animation/frontend/qvertexblendanimation_p.h delete mode 100644 src/extras/animations/animations.pri delete mode 100644 src/extras/animations/qabstractanimation.cpp delete mode 100644 src/extras/animations/qabstractanimation.h delete mode 100644 src/extras/animations/qabstractanimation_p.h delete mode 100644 src/extras/animations/qanimationcontroller.cpp delete mode 100644 src/extras/animations/qanimationcontroller.h delete mode 100644 src/extras/animations/qanimationcontroller_p.h delete mode 100644 src/extras/animations/qanimationgroup.cpp delete mode 100644 src/extras/animations/qanimationgroup.h delete mode 100644 src/extras/animations/qanimationgroup_p.h delete mode 100644 src/extras/animations/qkeyframeanimation.cpp delete mode 100644 src/extras/animations/qkeyframeanimation.h delete mode 100644 src/extras/animations/qkeyframeanimation_p.h delete mode 100644 src/extras/animations/qmorphinganimation.cpp delete mode 100644 src/extras/animations/qmorphinganimation.h delete mode 100644 src/extras/animations/qmorphinganimation_p.h delete mode 100644 src/extras/animations/qmorphtarget.cpp delete mode 100644 src/extras/animations/qmorphtarget.h delete mode 100644 src/extras/animations/qmorphtarget_p.h delete mode 100644 src/extras/animations/qvertexblendanimation.cpp delete mode 100644 src/extras/animations/qvertexblendanimation.h delete mode 100644 src/extras/animations/qvertexblendanimation_p.h create mode 100644 src/quick3d/quick3danimation/items/quick3danimationcontroller.cpp create mode 100644 src/quick3d/quick3danimation/items/quick3danimationcontroller_p.h create mode 100644 src/quick3d/quick3danimation/items/quick3danimationgroup.cpp create mode 100644 src/quick3d/quick3danimation/items/quick3danimationgroup_p.h create mode 100644 src/quick3d/quick3danimation/items/quick3dkeyframeanimation.cpp create mode 100644 src/quick3d/quick3danimation/items/quick3dkeyframeanimation_p.h create mode 100644 src/quick3d/quick3danimation/items/quick3dmorphinganimation.cpp create mode 100644 src/quick3d/quick3danimation/items/quick3dmorphinganimation_p.h create mode 100644 src/quick3d/quick3danimation/items/quick3dmorphtarget.cpp create mode 100644 src/quick3d/quick3danimation/items/quick3dmorphtarget_p.h delete mode 100644 src/quick3d/quick3dextras/items/quick3danimationcontroller.cpp delete mode 100644 src/quick3d/quick3dextras/items/quick3danimationcontroller_p.h delete mode 100644 src/quick3d/quick3dextras/items/quick3danimationgroup.cpp delete mode 100644 src/quick3d/quick3dextras/items/quick3danimationgroup_p.h delete mode 100644 src/quick3d/quick3dextras/items/quick3dkeyframeanimation.cpp delete mode 100644 src/quick3d/quick3dextras/items/quick3dkeyframeanimation_p.h delete mode 100644 src/quick3d/quick3dextras/items/quick3dmorphinganimation.cpp delete mode 100644 src/quick3d/quick3dextras/items/quick3dmorphinganimation_p.h delete mode 100644 src/quick3d/quick3dextras/items/quick3dmorphtarget.cpp delete mode 100644 src/quick3d/quick3dextras/items/quick3dmorphtarget_p.h diff --git a/src/animation/frontend/frontend.pri b/src/animation/frontend/frontend.pri index 2716c3d39..0feeb2e42 100644 --- a/src/animation/frontend/frontend.pri +++ b/src/animation/frontend/frontend.pri @@ -20,7 +20,21 @@ HEADERS += \ $$PWD/qclipblendnodecreatedchange.h \ $$PWD/qclipblendnodecreatedchange_p.h \ $$PWD/qadditiveblend.h \ - $$PWD/qadditiveblend_p.h + $$PWD/qadditiveblend_p.h \ + $$PWD/qanimationcontroller.h \ + $$PWD/qanimationcontroller_p.h \ + $$PWD/qanimationgroup.h \ + $$PWD/qanimationgroup_p.h \ + $$PWD/qkeyframeanimation.h \ + $$PWD/qkeyframeanimation_p.h \ + $$PWD/qmorphinganimation.h \ + $$PWD/qmorphinganimation_p.h \ + $$PWD/qabstractanimation.h \ + $$PWD/qabstractanimation_p.h \ + $$PWD/qmorphtarget.h \ + $$PWD/qmorphtarget_p.h \ + $$PWD/qvertexblendanimation.h \ + $$PWD/qvertexblendanimation_p.h SOURCES += \ $$PWD/qanimationaspect.cpp \ @@ -33,6 +47,13 @@ SOURCES += \ $$PWD/qchannelmapping.cpp \ $$PWD/qlerpblend.cpp \ $$PWD/qclipblendnodecreatedchange.cpp \ - $$PWD/qadditiveblend.cpp + $$PWD/qadditiveblend.cpp \ + $$PWD/qanimationcontroller.cpp \ + $$PWD/qanimationgroup.cpp \ + $$PWD/qkeyframeanimation.cpp \ + $$PWD/qmorphinganimation.cpp \ + $$PWD/qabstractanimation.cpp \ + $$PWD/qmorphtarget.cpp \ + $$PWD/qvertexblendanimation.cpp INCLUDEPATH += $$PWD diff --git a/src/animation/frontend/qabstractanimation.cpp b/src/animation/frontend/qabstractanimation.cpp new file mode 100644 index 000000000..6f5aa05d8 --- /dev/null +++ b/src/animation/frontend/qabstractanimation.cpp @@ -0,0 +1,112 @@ +/**************************************************************************** +** +** 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 "qabstractanimation.h" +#include "Qt3DAnimation/private/qabstractanimation_p.h" + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { + +QAbstractAnimationPrivate::QAbstractAnimationPrivate(QAbstractAnimation::AnimationType type) + : QObjectPrivate() + , m_animationType(type) + , m_position(0.0f) + , m_duration(0.0f) +{ + +} + +QAbstractAnimation::QAbstractAnimation(QAbstractAnimationPrivate &dd, QObject *parent) + : QObject(dd, parent) +{ + +} + +QString QAbstractAnimation::animationName() const +{ + Q_D(const QAbstractAnimation); + return d->m_animationName; +} + +QAbstractAnimation::AnimationType QAbstractAnimation::animationType() const +{ + Q_D(const QAbstractAnimation); + return d->m_animationType; +} + +float QAbstractAnimation::position() const +{ + Q_D(const QAbstractAnimation); + return d->m_position; +} + +float QAbstractAnimation::duration() const +{ + Q_D(const QAbstractAnimation); + return d->m_duration; +} + +void QAbstractAnimation::setAnimationName(const QString &name) +{ + Q_D(QAbstractAnimation); + if (name != d->m_animationName) { + d->m_animationName = name; + emit animationNameChanged(name); + } +} + +void QAbstractAnimation::setPosition(float position) +{ + Q_D(QAbstractAnimation); + if (!qFuzzyCompare(position, d->m_position)) { + d->m_position = position; + emit positionChanged(position); + } +} + +void QAbstractAnimation::setDuration(float duration) +{ + Q_D(QAbstractAnimation); + if (!qFuzzyCompare(duration, d->m_duration)) { + d->m_duration = duration; + emit durationChanged(duration); + } +} + +} // Qt3DAnimation + +QT_END_NAMESPACE diff --git a/src/animation/frontend/qabstractanimation.h b/src/animation/frontend/qabstractanimation.h new file mode 100644 index 000000000..af70399b1 --- /dev/null +++ b/src/animation/frontend/qabstractanimation.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QT3DANIMATION_QABSTRACTANIMATION_H +#define QT3DANIMATION_QABSTRACTANIMATION_H + +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { + +class QAbstractAnimationPrivate; + +class QT3DANIMATIONSHARED_EXPORT QAbstractAnimation : public QObject +{ + Q_OBJECT + Q_PROPERTY(QString animationName READ animationName WRITE setAnimationName NOTIFY animationNameChanged) + Q_PROPERTY(QAbstractAnimation::AnimationType animationType READ animationType CONSTANT) + Q_PROPERTY(float position READ position WRITE setPosition NOTIFY positionChanged) + Q_PROPERTY(float duration READ duration NOTIFY durationChanged) + +public: + enum AnimationType { + KeyframeAnimation = 1, + MorphingAnimation = 2, + VertexBlendAnimation = 3, + }; + + QString animationName() const; + QAbstractAnimation::AnimationType animationType() const; + float position() const; + float duration() const; + +public Q_SLOTS: + void setAnimationName(const QString &name); + void setPosition(float position); + +protected: + explicit QAbstractAnimation(QAbstractAnimationPrivate &dd, QObject *parent = nullptr); + + void setDuration(float duration); + +Q_SIGNALS: + void animationNameChanged(const QString &name); + void positionChanged(float position); + void durationChanged(float duration); + +private: + Q_DECLARE_PRIVATE(QAbstractAnimation) +}; + +} // Qt3DAnimation + +QT_END_NAMESPACE + +#endif // QT3DANIMATION_QABSTRACTANIMATION_H diff --git a/src/animation/frontend/qabstractanimation_p.h b/src/animation/frontend/qabstractanimation_p.h new file mode 100644 index 000000000..197d8ab1c --- /dev/null +++ b/src/animation/frontend/qabstractanimation_p.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QT3DANIMATION_QABSTRACTANIMATION_P_H +#define QT3DANIMATION_QABSTRACTANIMATION_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { + +class QAbstractAnimationPrivate : public QObjectPrivate +{ +public: + QAbstractAnimationPrivate(QAbstractAnimation::AnimationType type); + + QString m_animationName; + QAbstractAnimation::AnimationType m_animationType; + float m_position; + float m_duration; + + Q_DECLARE_PUBLIC(QAbstractAnimation) +}; + +} // Qt3DAnimation + +QT_END_NAMESPACE + +#endif // QT3DANIMATION_QANIMATIONCONTROLLER_P_H diff --git a/src/animation/frontend/qanimationcontroller.cpp b/src/animation/frontend/qanimationcontroller.cpp new file mode 100644 index 000000000..86d9eb537 --- /dev/null +++ b/src/animation/frontend/qanimationcontroller.cpp @@ -0,0 +1,252 @@ +/**************************************************************************** +** +** 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 "qanimationcontroller.h" +#include "qanimationgroup.h" + +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { + +QAnimationControllerPrivate::QAnimationControllerPrivate() + : QObjectPrivate() + , m_activeAnimationGroup(0) + , m_position(0.0f) + , m_positionScale(1.0f) + , m_positionOffset(0.0f) + , m_entity(nullptr) + , m_recursive(true) +{ + +} + +void QAnimationControllerPrivate::updatePosition(float position) +{ + m_position = position; + if (m_activeAnimationGroup >= 0 && m_activeAnimationGroup < m_animationGroups.size()) { + const float pos = m_positionScale * position + m_positionOffset; + m_animationGroups[m_activeAnimationGroup]->setPosition(pos); + } +} + +QAnimationGroup *QAnimationControllerPrivate::findGroup(const QString &name) +{ + for (QAnimationGroup *g : m_animationGroups) { + if (g->name() == name) + return g; + } + return nullptr; +} + +void QAnimationControllerPrivate::extractAnimations() +{ + Q_Q(QAnimationController); + if (!m_entity) + return; + QList animations + = m_entity->findChildren(QString(), + m_recursive ? Qt::FindChildrenRecursively : Qt::FindDirectChildrenOnly); + if (animations.size() > 0) { + for (Qt3DAnimation::QAbstractAnimation *a : animations) { + QAnimationGroup *group = findGroup(a->animationName()); + if (!group) { + group = new QAnimationGroup(q); + group->setName(a->animationName()); + m_animationGroups.push_back(group); + } + group->addAnimation(a); + } + } +} +void QAnimationControllerPrivate::clearAnimations() +{ + for (Qt3DAnimation::QAnimationGroup *a : m_animationGroups) + a->deleteLater(); + m_animationGroups.clear(); + m_activeAnimationGroup = 0; +} + +QAnimationController::QAnimationController(QObject *parent) + : QObject(*new QAnimationControllerPrivate, parent) +{ + +} + +QVector QAnimationController::animationGroupList() +{ + Q_D(QAnimationController); + return d->m_animationGroups; +} + +int QAnimationController::activeAnimationGroup() const +{ + Q_D(const QAnimationController); + return d->m_activeAnimationGroup; +} + +float QAnimationController::position() const +{ + Q_D(const QAnimationController); + return d->m_position; +} + +float QAnimationController::positionScale() const +{ + Q_D(const QAnimationController); + return d->m_positionScale; +} + +float QAnimationController::positionOffset() const +{ + Q_D(const QAnimationController); + return d->m_positionOffset; +} + +Qt3DCore::QEntity *QAnimationController::entity() const +{ + Q_D(const QAnimationController); + return d->m_entity; +} + +bool QAnimationController::recursive() const +{ + Q_D(const QAnimationController); + return d->m_recursive; +} + +void QAnimationController::setAnimationGroups(const QVector &animationGroups) +{ + Q_D(QAnimationController); + d->m_animationGroups = animationGroups; + if (d->m_activeAnimationGroup >= d->m_animationGroups.size()) + d->m_activeAnimationGroup = 0; + d->updatePosition(d->m_position); +} + +void QAnimationController::addAnimationGroup(Qt3DAnimation::QAnimationGroup *animationGroup) +{ + Q_D(QAnimationController); + if (!d->m_animationGroups.contains(animationGroup)) + d->m_animationGroups.push_back(animationGroup); +} + +void QAnimationController::removeAnimationGroup(Qt3DAnimation::QAnimationGroup *animationGroup) +{ + Q_D(QAnimationController); + if (d->m_animationGroups.contains(animationGroup)) + d->m_animationGroups.removeAll(animationGroup); + if (d->m_activeAnimationGroup >= d->m_animationGroups.size()) + d->m_activeAnimationGroup = 0; +} + +void QAnimationController::setActiveAnimationGroup(int index) +{ + Q_D(QAnimationController); + if (d->m_activeAnimationGroup != index) { + d->m_activeAnimationGroup = index; + d->updatePosition(d->m_position); + emit activeAnimationGroupChanged(index); + } +} +void QAnimationController::setPosition(float position) +{ + Q_D(QAnimationController); + if (!qFuzzyCompare(d->m_position, position)) { + d->updatePosition(position); + emit positionChanged(position); + } +} + +void QAnimationController::setPositionScale(float scale) +{ + Q_D(QAnimationController); + if (!qFuzzyCompare(d->m_positionScale, scale)) { + d->m_positionScale = scale; + emit positionScaleChanged(scale); + } +} + +void QAnimationController::setPositionOffset(float offset) +{ + Q_D(QAnimationController); + if (!qFuzzyCompare(d->m_positionOffset, offset)) { + d->m_positionOffset = offset; + emit positionOffsetChanged(offset); + } +} + +void QAnimationController::setEntity(Qt3DCore::QEntity *entity) +{ + Q_D(QAnimationController); + if (d->m_entity != entity) { + d->clearAnimations(); + d->m_entity = entity; + d->extractAnimations(); + d->updatePosition(d->m_position); + emit entityChanged(entity); + } +} + +void QAnimationController::setRecursive(bool recursive) +{ + Q_D(QAnimationController); + if (d->m_recursive != recursive) { + d->m_recursive = recursive; + emit recursiveChanged(recursive); + } +} + +int QAnimationController::getAnimationIndex(const QString &name) const +{ + Q_D(const QAnimationController); + for (int i = 0; i < d->m_animationGroups.size(); ++i) { + if (d->m_animationGroups[i]->name() == name) + return i; + } + return -1; +} + +QAnimationGroup *QAnimationController::getGroup(int index) const +{ + Q_D(const QAnimationController); + return d->m_animationGroups.at(index); +} + +} // Qt3DAnimation + +QT_END_NAMESPACE diff --git a/src/animation/frontend/qanimationcontroller.h b/src/animation/frontend/qanimationcontroller.h new file mode 100644 index 000000000..ae3272517 --- /dev/null +++ b/src/animation/frontend/qanimationcontroller.h @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QT3DANIMATION_QANIMATIONCONTROLLER_H +#define QT3DANIMATION_QANIMATIONCONTROLLER_H + +#include +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { + +class QAnimationControllerPrivate; + +class QT3DANIMATIONSHARED_EXPORT QAnimationController : public QObject +{ + Q_OBJECT + Q_PROPERTY(int activeAnimationGroup READ activeAnimationGroup WRITE setActiveAnimationGroup NOTIFY activeAnimationGroupChanged) + Q_PROPERTY(float position READ position WRITE setPosition NOTIFY positionChanged) + Q_PROPERTY(float positionScale READ positionScale WRITE setPositionScale NOTIFY positionScaleChanged) + Q_PROPERTY(float positionOffset READ positionOffset WRITE setPositionOffset NOTIFY positionOffsetChanged) + Q_PROPERTY(Qt3DCore::QEntity *entity READ entity WRITE setEntity NOTIFY entityChanged) + Q_PROPERTY(bool recursive READ recursive WRITE setRecursive NOTIFY recursiveChanged) + +public: + QAnimationController(QObject *parent = nullptr); + + QVector animationGroupList(); + + int activeAnimationGroup() const; + float position() const; + float positionScale() const; + float positionOffset() const; + Qt3DCore::QEntity *entity() const; + bool recursive() const; + + void setAnimationGroups(const QVector &animationGroups); + void addAnimationGroup(Qt3DAnimation::QAnimationGroup *animationGroups); + void removeAnimationGroup(Qt3DAnimation::QAnimationGroup *animationGroups); + + Q_INVOKABLE int getAnimationIndex(const QString &name) const; + Q_INVOKABLE Qt3DAnimation::QAnimationGroup *getGroup(int index) const; + +public Q_SLOTS: + void setActiveAnimationGroup(int index); + void setPosition(float position); + void setPositionScale(float scale); + void setPositionOffset(float offset); + void setEntity(Qt3DCore::QEntity *entity); + void setRecursive(bool recursive); + +Q_SIGNALS: + void activeAnimationGroupChanged(int index); + void positionChanged(float position); + void positionScaleChanged(float scale); + void positionOffsetChanged(float offset); + void entityChanged(Qt3DCore::QEntity *entity); + void recursiveChanged(bool recursive); + +private: + Q_DECLARE_PRIVATE(QAnimationController) +}; + +} // Qt3DAnimation + +QT_END_NAMESPACE + +#endif // QT3DANIMATION_QANIMATIONCONTROLLER_H diff --git a/src/animation/frontend/qanimationcontroller_p.h b/src/animation/frontend/qanimationcontroller_p.h new file mode 100644 index 000000000..1c309a183 --- /dev/null +++ b/src/animation/frontend/qanimationcontroller_p.h @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QT3DANIMATION_QANIMATIONCONTROLLER_P_H +#define QT3DANIMATION_QANIMATIONCONTROLLER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { + +class QAnimationControllerPrivate : public QObjectPrivate +{ +public: + QAnimationControllerPrivate(); + + QString m_name; + int m_activeAnimationGroup; + QVector m_animationGroups; + float m_position; + float m_positionScale; + float m_positionOffset; + Qt3DCore::QEntity *m_entity; + bool m_recursive; + + void updatePosition(float position); + void extractAnimations(); + void clearAnimations(); + QAnimationGroup *findGroup(const QString &name); + + Q_DECLARE_PUBLIC(QAnimationController) +}; + +} // Qt3DAnimation + +QT_END_NAMESPACE + +#endif // QT3DANIMATION_QANIMATIONCONTROLLER_P_H diff --git a/src/animation/frontend/qanimationgroup.cpp b/src/animation/frontend/qanimationgroup.cpp new file mode 100644 index 000000000..91da1ead3 --- /dev/null +++ b/src/animation/frontend/qanimationgroup.cpp @@ -0,0 +1,125 @@ +/**************************************************************************** +** +** 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 "qanimationgroup.h" +#include "Qt3DAnimation/private/qanimationgroup_p.h" + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { + +QAnimationGroupPrivate::QAnimationGroupPrivate() + : QObjectPrivate() + , m_position(0.0f) + , m_duration(0.0f) +{ + +} + +void QAnimationGroupPrivate::updatePosition(float position) +{ + m_position = position; + for (QAbstractAnimation *aa : m_animations) + aa->setPosition(position); +} + +QAnimationGroup::QAnimationGroup(QObject *parent) + : QObject(*new QAnimationGroupPrivate, parent) +{ + +} + +QString QAnimationGroup::name() const +{ + Q_D(const QAnimationGroup); + return d->m_name; +} + +QVector QAnimationGroup::animationList() +{ + Q_D(QAnimationGroup); + return d->m_animations; +} + +float QAnimationGroup::position() const +{ + Q_D(const QAnimationGroup); + return d->m_position; +} + +float QAnimationGroup::duration() const +{ + Q_D(const QAnimationGroup); + return d->m_duration; +} + +void QAnimationGroup::setName(const QString &name) +{ + Q_D(QAnimationGroup); + if (d->m_name != name) { + d->m_name = name; + emit nameChanged(name); + } +} + +void QAnimationGroup::setAnimations(const QVector &animations) +{ + Q_D(QAnimationGroup); + d->m_animations = animations; + d->m_duration = 0.0f; + for (const Qt3DAnimation::QAbstractAnimation *a : animations) + d->m_duration = qMax(d->m_duration, a->duration()); +} + +void QAnimationGroup::addAnimation(QAbstractAnimation *animation) +{ + Q_D(QAnimationGroup); + d->m_animations.push_back(animation); + d->m_duration = qMax(d->m_duration, animation->duration()); +} + +void QAnimationGroup::setPosition(float position) +{ + Q_D(QAnimationGroup); + if (!qFuzzyCompare(d->m_position, position)) { + d->updatePosition(position); + emit positionChanged(position); + } +} + +} // Qt3DAnimation + +QT_END_NAMESPACE diff --git a/src/animation/frontend/qanimationgroup.h b/src/animation/frontend/qanimationgroup.h new file mode 100644 index 000000000..1e23c61ee --- /dev/null +++ b/src/animation/frontend/qanimationgroup.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QT3DANIMATION_QANIMATIONGROUP_H +#define QT3DANIMATION_QANIMATIONGROUP_H + +#include + +#include + +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { + +class QAnimationGroupPrivate; + +class QT3DANIMATIONSHARED_EXPORT QAnimationGroup : public QObject +{ + Q_OBJECT + Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) + Q_PROPERTY(float position READ position WRITE setPosition NOTIFY positionChanged) + Q_PROPERTY(float duration READ duration NOTIFY durationChanged) + +public: + explicit QAnimationGroup(QObject *parent = nullptr); + + QString name() const; + QVector animationList(); + float position() const; + float duration() const; + + void setAnimations(const QVector &animations); + void addAnimation(Qt3DAnimation::QAbstractAnimation *animation); + void removeAnimation(Qt3DAnimation::QAbstractAnimation *animation); + +public Q_SLOTS: + void setName(const QString &name); + void setPosition(float position); + +Q_SIGNALS: + void nameChanged(const QString &name); + void positionChanged(float position); + void durationChanged(float duration); + +private: + + Q_DECLARE_PRIVATE(QAnimationGroup) +}; + +} // Qt3DAnimation + +QT_END_NAMESPACE + +#endif // QT3DANIMATION_QANIMATIONGROUP_H diff --git a/src/animation/frontend/qanimationgroup_p.h b/src/animation/frontend/qanimationgroup_p.h new file mode 100644 index 000000000..1e13952aa --- /dev/null +++ b/src/animation/frontend/qanimationgroup_p.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QT3DANIMATION_QANIMATIONGROUP_P_H +#define QT3DANIMATION_QANIMATIONGROUP_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { + +class QAnimationGroupPrivate : public QObjectPrivate +{ +public: + QAnimationGroupPrivate(); + + QString m_name; + QVector m_animations; + float m_position; + float m_duration; + + void updatePosition(float position); + + Q_DECLARE_PUBLIC(QAnimationGroup) +}; + +} // Qt3DAnimation + +QT_END_NAMESPACE + +#endif // QT3DANIMATION_QANIMATIONGROUP_P_H diff --git a/src/animation/frontend/qkeyframeanimation.cpp b/src/animation/frontend/qkeyframeanimation.cpp new file mode 100644 index 000000000..5c3ca1ca1 --- /dev/null +++ b/src/animation/frontend/qkeyframeanimation.cpp @@ -0,0 +1,262 @@ +/**************************************************************************** +** +** 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 "qkeyframeanimation.h" +#include "Qt3DAnimation/private/qkeyframeanimation_p.h" + +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { + +QKeyframeAnimationPrivate::QKeyframeAnimationPrivate() + : QAbstractAnimationPrivate(QAbstractAnimation::KeyframeAnimation) + , m_minposition(0.0f) + , m_maxposition(0.0f) + , m_prevPosition(-1.0f) + , m_target(nullptr) + , m_startMode(QKeyframeAnimation::Constant) + , m_endMode(QKeyframeAnimation::Constant) +{ + +} + +QKeyframeAnimation::QKeyframeAnimation(QObject *parent) + : QAbstractAnimation(*new QKeyframeAnimationPrivate(), parent) +{ + Q_D(QKeyframeAnimation); + d->m_positionConnection = QObject::connect(this, &QAbstractAnimation::positionChanged, + this, &QKeyframeAnimation::updateAnimation); +} + + +void QKeyframeAnimation::setFramePositions(const QVector &positions) +{ + Q_D(QKeyframeAnimation); + d->m_framePositions = positions; + d->m_prevPosition = -1.0f; + if (d->m_framePositions.size() == 0) { + d->m_minposition = d->m_maxposition = 0.0f; + return; + } + d->m_minposition = d->m_framePositions.first(); + d->m_maxposition = d->m_framePositions.last(); + float lastPos = d->m_minposition; + for (float p : d->m_framePositions) { + if (p < lastPos || p > d->m_maxposition) + qWarning() << "positions not ordered correctly"; + lastPos = p; + } + setDuration(d->m_maxposition); +} + +void QKeyframeAnimation::setKeyframes(const QVector &keyframes) +{ + Q_D(QKeyframeAnimation); + d->m_keyframes = keyframes; +} + +// slerp which allows long path +QQuaternion lslerp(QQuaternion q1, QQuaternion q2, float t) +{ + QQuaternion ret; + // Handle the easy cases first. + if (t <= 0.0f) + return q1; + else if (t >= 1.0f) + return q2; + + float cos = qBound(-1.0f, QQuaternion::dotProduct(q1, q2), 1.0f); + float angle = std::acos(cos); + float sin = std::sin(angle); + if (!qFuzzyIsNull(sin)) { + float a = std::sin((1.0 - t) * angle) / sin; + float b = std::sin(t * angle) / sin; + ret = (q1 * a + q2 * b).normalized(); + } else { + ret = q1 * (1.0f-t) + q2 * t; + } + return ret; +} + +void QKeyframeAnimationPrivate::calculateFrame(float position) +{ + if (m_target && m_framePositions.size() > 0 + && m_keyframes.size() == m_framePositions.size() + && m_prevPosition != m_position) { + if (m_position >= m_minposition && m_position < m_maxposition) { + for (int i = 0; i < m_framePositions.size() - 1; i++) { + if (position >= m_framePositions.at(i) + && position < m_framePositions.at(i+1)) { + float ip = (position - m_framePositions.at(i)) + / (m_framePositions.at(i+1) - m_framePositions.at(i)); + float eIp = m_easing.valueForProgress(ip); + float eIip = 1.0f - eIp; + + Qt3DCore::QTransform *a = m_keyframes.at(i); + Qt3DCore::QTransform *b = m_keyframes.at(i+1); + + QVector3D s = a->scale3D() * eIip + b->scale3D() * eIp; + QVector3D t = a->translation() * eIip + b->translation() * eIp; + QQuaternion r = QQuaternion::slerp(a->rotation(), b->rotation(), eIp); + + m_target->setRotation(r); + m_target->setScale3D(s); + m_target->setTranslation(t); + return; + } + } + } else if (position < m_minposition) { + m_target->setRotation(m_keyframes.first()->rotation()); + m_target->setScale3D(m_keyframes.first()->scale3D()); + m_target->setTranslation(m_keyframes.first()->translation()); + } else { + m_target->setRotation(m_keyframes.last()->rotation()); + m_target->setScale3D(m_keyframes.last()->scale3D()); + m_target->setTranslation(m_keyframes.last()->translation()); + } + m_prevPosition = m_position; + } +} + +void QKeyframeAnimation::updateAnimation(float position) +{ + Q_D(QKeyframeAnimation); + d->calculateFrame(position); +} + +QVector QKeyframeAnimation::framePositions() const +{ + Q_D(const QKeyframeAnimation); + return d->m_framePositions; +} + +QVector QKeyframeAnimation::keyframeList() const +{ + Q_D(const QKeyframeAnimation); + return d->m_keyframes; +} + +void QKeyframeAnimation::setTarget(Qt3DCore::QTransform *target) +{ + Q_D(QKeyframeAnimation); + if (d->m_target != target) { + d->m_target = target; + emit targetChanged(d->m_target); + d->m_prevPosition = -1.0f; + + if (target) { + d->m_baseScale = target->scale3D(); + d->m_baseTranslation = target->translation(); + d->m_baseRotation = target->rotation(); + } + } +} + +QKeyframeAnimation::RepeatMode QKeyframeAnimation::startMode() const +{ + Q_D(const QKeyframeAnimation); + return d->m_startMode; +} + +QKeyframeAnimation::RepeatMode QKeyframeAnimation::endMode() const +{ + Q_D(const QKeyframeAnimation); + return d->m_endMode; +} + +void QKeyframeAnimation::setEasing(QEasingCurve::Type easing) +{ + Q_D(QKeyframeAnimation); + if (d->m_easing.type() != easing) { + d->m_easing.setType(easing); + emit easingChanged(easing); + } +} + +void QKeyframeAnimation::setTargetName(const QString &name) +{ + Q_D(QKeyframeAnimation); + d->m_targetName = name; + emit targetNameChanged(name); +} + +void QKeyframeAnimation::setStartMode(QKeyframeAnimation::RepeatMode mode) +{ + Q_D(QKeyframeAnimation); + if (d->m_startMode != mode) { + d->m_startMode = mode; + emit startModeChanged(mode); + } +} + +void QKeyframeAnimation::setEndMode(QKeyframeAnimation::RepeatMode mode) +{ + Q_D(QKeyframeAnimation); + if (mode != d->m_endMode) { + d->m_endMode = mode; + emit endModeChanged(mode); + } +} + +void QKeyframeAnimation::addKeyframe(Qt3DCore::QTransform *keyframe) +{ + Q_D(QKeyframeAnimation); + d->m_keyframes.push_back(keyframe); +} + +QString QKeyframeAnimation::targetName() const +{ + Q_D(const QKeyframeAnimation); + return d->m_targetName; +} + +QEasingCurve::Type QKeyframeAnimation::easing() const +{ + Q_D(const QKeyframeAnimation); + return d->m_easing.type(); +} + +Qt3DCore::QTransform *QKeyframeAnimation::target() const +{ + Q_D(const QKeyframeAnimation); + return d->m_target; +} + +} // Qt3DAnimation + +QT_END_NAMESPACE diff --git a/src/animation/frontend/qkeyframeanimation.h b/src/animation/frontend/qkeyframeanimation.h new file mode 100644 index 000000000..d34f6cfba --- /dev/null +++ b/src/animation/frontend/qkeyframeanimation.h @@ -0,0 +1,112 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QT3DANIMATION_QKEYFRAMEANIMATION_H +#define QT3DANIMATION_QKEYFRAMEANIMATION_H + +#include + +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { + +class QKeyframeAnimationPrivate; + +class QT3DANIMATIONSHARED_EXPORT QKeyframeAnimation : public QAbstractAnimation +{ + Q_OBJECT + Q_PROPERTY(QVector framePositions READ framePositions WRITE setFramePositions NOTIFY framePositionsChanged) + Q_PROPERTY(Qt3DCore::QTransform *target READ target WRITE setTarget NOTIFY targetChanged) + Q_PROPERTY(QEasingCurve::Type easing READ easing WRITE setEasing NOTIFY easingChanged) + Q_PROPERTY(QString targetName READ targetName WRITE setTargetName NOTIFY targetNameChanged) + Q_PROPERTY(QKeyframeAnimation::RepeatMode startMode READ startMode WRITE setStartMode NOTIFY startModeChanged) + Q_PROPERTY(QKeyframeAnimation::RepeatMode endMode READ endMode WRITE setEndMode NOTIFY endModeChanged) + +public: + explicit QKeyframeAnimation(QObject *parent = nullptr); + + enum RepeatMode + { + None, + Constant, + Repeat, + }; + Q_ENUM(RepeatMode) + + QVector framePositions() const; + QVector keyframeList() const; + Qt3DCore::QTransform *target() const; + QEasingCurve::Type easing() const; + QString targetName() const; + RepeatMode startMode() const; + RepeatMode endMode() const; + + void setKeyframes(const QVector &keyframes); + void addKeyframe(Qt3DCore::QTransform *keyframe); + void removeKeyframe(Qt3DCore::QTransform *keyframe); + +public Q_SLOTS: + void setFramePositions(const QVector &positions); + void setTarget(Qt3DCore::QTransform *target); + void setEasing(QEasingCurve::Type easing); + void setTargetName(const QString &name); + void setStartMode(RepeatMode mode); + void setEndMode(RepeatMode mode); + +Q_SIGNALS: + void framePositionsChanged(const QVector &positions); + void targetChanged(Qt3DCore::QTransform *target); + void easingChanged(QEasingCurve::Type easing); + void targetNameChanged(const QString &name); + void startModeChanged(RepeatMode startMode); + void endModeChanged(RepeatMode endMode); + +private: + void updateAnimation(float position); + + Q_DECLARE_PRIVATE(QKeyframeAnimation) +}; + +} // Qt3DAnimation + +QT_END_NAMESPACE + +#endif // QT3DANIMATION_QKEYFRAMEANIMATION_H diff --git a/src/animation/frontend/qkeyframeanimation_p.h b/src/animation/frontend/qkeyframeanimation_p.h new file mode 100644 index 000000000..60fc50fb1 --- /dev/null +++ b/src/animation/frontend/qkeyframeanimation_p.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QT3DANIMATION_QKEYFRAMEANIMATION_P_H +#define QT3DANIMATION_QKEYFRAMEANIMATION_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { + +class QKeyframeAnimationPrivate : public QAbstractAnimationPrivate +{ +public: + QKeyframeAnimationPrivate(); + + void calculateFrame(float position); + + float m_prevPosition; + QVector m_framePositions; + QVector m_keyframes; + Qt3DCore::QTransform *m_target; + QEasingCurve m_easing; + QString m_animationName; + QString m_targetName; + float m_minposition; + float m_maxposition; + QKeyframeAnimation::RepeatMode m_startMode; + QKeyframeAnimation::RepeatMode m_endMode; + QVector3D m_baseScale; + QVector3D m_baseTranslation; + QQuaternion m_baseRotation; + QMetaObject::Connection m_positionConnection; + + Q_DECLARE_PUBLIC(QKeyframeAnimation) +}; + +} // Qt3DAnimation + +QT_END_NAMESPACE + +#endif // QT3DANIMATION_QKEYFRAMEANIMATION_P_H diff --git a/src/animation/frontend/qmorphinganimation.cpp b/src/animation/frontend/qmorphinganimation.cpp new file mode 100644 index 000000000..2ac09464f --- /dev/null +++ b/src/animation/frontend/qmorphinganimation.cpp @@ -0,0 +1,280 @@ +/**************************************************************************** +** +** 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 "qmorphinganimation.h" +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { + +QMorphingAnimationPrivate::QMorphingAnimationPrivate() + : QAbstractAnimationPrivate(QAbstractAnimation::MorphingAnimation) + , m_flattened(nullptr) + , m_method(QMorphingAnimation::Relative) + , m_interpolator(0.0f) + , m_target(nullptr) + , m_currentTarget(nullptr) +{ + m_easing.setType(QEasingCurve::InOutCubic); +} + +QMorphingAnimationPrivate::~QMorphingAnimationPrivate() +{ + for (QVector *weights : m_weights) + delete weights; +} + +void QMorphingAnimationPrivate::updateAnimation(float position) +{ + Q_Q(QMorphingAnimation); + if (!m_target || !m_target->geometry()) + return; + + m_morphKey.resize(m_morphTargets.size()); + + for (int i = 0; i < m_targetPositions.size() - 1; ++i) { + if (position > m_targetPositions.at(i) && position <= m_targetPositions.at(i + 1)) { + float interpolator = (position - m_targetPositions.at(i)) + / (m_targetPositions.at(i + 1) - m_targetPositions.at(i)); + interpolator = m_easing.valueForProgress(interpolator); + float iip = 1.0f - interpolator; + float sum = 0.0f; + QVector relevantValues; + for (int j = 0; j < m_morphTargets.size(); ++j) { + m_morphKey[j] = interpolator * m_weights.at(i + 1)->at(j) + + iip * m_weights.at(i)->at(j); + sum += m_morphKey[j]; + if (!qFuzzyIsNull(m_morphKey[j])) + relevantValues.push_back(j); + } + + if (relevantValues.size() == 0 || qFuzzyIsNull(sum)) { + // only base is used + interpolator = 0.0f; + } else if (relevantValues.size() == 1) { + // one morph target has non-zero weight + setTargetInterpolated(relevantValues[0]); + interpolator = sum; + } else { + // more than one morph target has non-zero weight + // flatten morph targets to one + qWarning() << Q_FUNC_INFO << "Flattening required"; + } + if (!qFuzzyCompare(interpolator, m_interpolator)) { + if (m_method == QMorphingAnimation::Normalized) + m_interpolator = interpolator; + else + m_interpolator = -interpolator; + emit q->interpolatorChanged(m_interpolator); + } + return; + } + } +} + +void QMorphingAnimationPrivate::setTargetInterpolated(int morphTarget) +{ + QMorphTarget *target = m_morphTargets[morphTarget]; + Qt3DRender::QGeometry *geometry = m_target->geometry(); + + // remove attributes from previous frame + if (m_currentTarget && (target != m_currentTarget)) { + const QVector targetAttributes = m_currentTarget->attributeList(); + for (int i = 0; i < targetAttributes.size(); ++i) + geometry->removeAttribute(targetAttributes.at(i)); + } + + const QVector targetAttributes = target->attributeList(); + + // add attributes from current frame to the geometry + if (target != m_currentTarget) { + for (int i = 0; i < m_attributeNames.size(); ++i) { + QString targetName = m_attributeNames.at(i); + targetName.append("Target"); + targetAttributes[i]->setName(targetName); + geometry->addAttribute(targetAttributes.at(i)); + } + } + m_currentTarget = target; +} + +QMorphingAnimation::QMorphingAnimation(QObject *parent) + : QAbstractAnimation(*new QMorphingAnimationPrivate, parent) +{ + Q_D(QMorphingAnimation); + d->m_positionConnection = QObject::connect(this, &QAbstractAnimation::positionChanged, + this, &QMorphingAnimation::updateAnimation); +} + +QVector QMorphingAnimation::targetPositions() const +{ + Q_D(const QMorphingAnimation); + return d->m_targetPositions; +} + +float QMorphingAnimation::interpolator() const +{ + Q_D(const QMorphingAnimation); + return d->m_interpolator; +} + +Qt3DRender::QGeometryRenderer *QMorphingAnimation::target() const +{ + Q_D(const QMorphingAnimation); + return d->m_target; +} + +QString QMorphingAnimation::targetName() const +{ + Q_D(const QMorphingAnimation); + return d->m_targetName; +} + +QMorphingAnimation::Method QMorphingAnimation::method() const +{ + Q_D(const QMorphingAnimation); + return d->m_method; +} + +QEasingCurve::Type QMorphingAnimation::easing() const +{ + Q_D(const QMorphingAnimation); + return d->m_easing.type(); +} + +void QMorphingAnimation::setMorphTargets(const QVector &targets) +{ + Q_D(QMorphingAnimation); + d->m_morphTargets = targets; + d->m_attributeNames = targets[0]->attributeNames(); +} + +void QMorphingAnimation::addMorphTarget(Qt3DAnimation::QMorphTarget *target) +{ + Q_D(QMorphingAnimation); + if (!d->m_morphTargets.contains(target)) + d->m_morphTargets.push_back(target); +} + +void QMorphingAnimation::removeMorphTarget(Qt3DAnimation::QMorphTarget *target) +{ + Q_D(QMorphingAnimation); + d->m_morphTargets.removeAll(target); +} + +void QMorphingAnimation::setTargetPositions(const QVector &targetPositions) +{ + Q_D(QMorphingAnimation); + d->m_targetPositions = targetPositions; + emit targetPositionsChanged(targetPositions); + setDuration(d->m_targetPositions.last()); + if (d->m_weights.size() < targetPositions.size()) { + d->m_weights.resize(targetPositions.size()); + for (int i = 0; i < d->m_weights.size(); ++i) { + if (d->m_weights[i] == nullptr) + d->m_weights[i] = new QVector(); + } + } +} + +void QMorphingAnimation::setTarget(Qt3DRender::QGeometryRenderer *target) +{ + Q_D(QMorphingAnimation); + if (d->m_target != target) { + d->m_target = target; + emit targetChanged(target); + } +} + +void QMorphingAnimation::setWeights(int positionIndex, const QVector &weights) +{ + Q_D(QMorphingAnimation); + if (d->m_weights.size() < positionIndex) + d->m_weights.resize(positionIndex + 1); + if (d->m_weights[positionIndex] == nullptr) + d->m_weights[positionIndex] = new QVector(); + *d->m_weights[positionIndex] = weights; +} + +QVector QMorphingAnimation::getWeights(int positionIndex) +{ + Q_D(QMorphingAnimation); + return *d->m_weights[positionIndex]; +} + +QVector QMorphingAnimation::morphTargetList() +{ + Q_D(QMorphingAnimation); + return d->m_morphTargets; +} + +void QMorphingAnimation::setTargetName(const QString name) +{ + Q_D(QMorphingAnimation); + if (d->m_targetName != name) { + d->m_targetName = name; + emit targetNameChanged(name); + } +} + +void QMorphingAnimation::setMethod(QMorphingAnimation::Method method) +{ + Q_D(QMorphingAnimation); + if (d->m_method != method) { + d->m_method = method; + emit methodChanged(method); + } +} + +void QMorphingAnimation::setEasing(QEasingCurve::Type easing) +{ + Q_D(QMorphingAnimation); + if (d->m_easing.type() != easing) { + d->m_easing.setType(easing); + emit easingChanged(easing); + } +} + +void QMorphingAnimation::updateAnimation(float position) +{ + Q_D(QMorphingAnimation); + d->updateAnimation(position); +} + +} // Qt3DAnimation + +QT_END_NAMESPACE diff --git a/src/animation/frontend/qmorphinganimation.h b/src/animation/frontend/qmorphinganimation.h new file mode 100644 index 000000000..b83288d04 --- /dev/null +++ b/src/animation/frontend/qmorphinganimation.h @@ -0,0 +1,116 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QT3DANIMATION_QMORPHINGANIMATION_H +#define QT3DANIMATION_QMORPHINGANIMATION_H + +#include + +#include +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { + +class QMorphingAnimationPrivate; + +class QT3DANIMATIONSHARED_EXPORT QMorphingAnimation : public QAbstractAnimation +{ + Q_OBJECT + Q_PROPERTY(QVector targetPositions READ targetPositions WRITE setTargetPositions NOTIFY targetPositionsChanged) + Q_PROPERTY(float interpolator READ interpolator NOTIFY interpolatorChanged) + Q_PROPERTY(Qt3DRender::QGeometryRenderer *target READ target WRITE setTarget NOTIFY targetChanged) + Q_PROPERTY(QString targetName READ targetName WRITE setTargetName NOTIFY targetNameChanged) + Q_PROPERTY(QMorphingAnimation::Method method READ method WRITE setMethod NOTIFY methodChanged) + Q_PROPERTY(QEasingCurve::Type easing READ easing WRITE setEasing NOTIFY easingChanged) + +public: + enum Method + { + Normalized, + Relative + }; + Q_ENUM(Method) + + explicit QMorphingAnimation(QObject *parent = nullptr); + + QVector targetPositions() const; + float interpolator() const; + Qt3DRender::QGeometryRenderer *target() const; + QString targetName() const; + QMorphingAnimation::Method method() const; + QEasingCurve::Type easing() const; + + void setMorphTargets(const QVector &targets); + void addMorphTarget(Qt3DAnimation::QMorphTarget *target); + void removeMorphTarget(Qt3DAnimation::QMorphTarget *target); + + void setWeights(int positionIndex, const QVector &weights); + QVector getWeights(int positionIndex); + + QVector morphTargetList(); + +public Q_SLOTS: + void setTargetPositions(const QVector &targetPositions); + void setTarget(Qt3DRender::QGeometryRenderer *target); + void setTargetName(const QString name); + void setMethod(QMorphingAnimation::Method method); + void setEasing(QEasingCurve::Type easing); + +Q_SIGNALS: + void targetPositionsChanged(const QVector &targetPositions); + void interpolatorChanged(float interpolator); + void targetChanged(Qt3DRender::QGeometryRenderer *target); + void targetNameChanged(const QString &name); + void methodChanged(QMorphingAnimation::Method method); + void easingChanged(QEasingCurve::Type easing); + +private: + + void updateAnimation(float position); + + Q_DECLARE_PRIVATE(QMorphingAnimation) +}; + +} // Qt3DAnimation + +QT_END_NAMESPACE + +#endif // QT3DANIMATION_QMORPHINGANIMATION_H diff --git a/src/animation/frontend/qmorphinganimation_p.h b/src/animation/frontend/qmorphinganimation_p.h new file mode 100644 index 000000000..d9a04343c --- /dev/null +++ b/src/animation/frontend/qmorphinganimation_p.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QT3DANIMATION_QMORPHINGANIMATION_P_H +#define QT3DANIMATION_QMORPHINGANIMATION_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { + +class QMorphingAnimationPrivate : public QAbstractAnimationPrivate +{ +public: + QMorphingAnimationPrivate(); + ~QMorphingAnimationPrivate(); + + void updateAnimation(float position); + void setTargetInterpolated(int morphTarget); + + QVector m_targetPositions; + QVector*> m_weights; + QVector m_morphKey; + QStringList m_attributeNames; + QVector m_morphTargets; + QMorphTarget *m_flattened; + QMorphingAnimation::Method m_method; + QEasingCurve m_easing; + float m_interpolator; + Qt3DRender::QGeometryRenderer *m_target; + QString m_targetName; + + QMorphTarget *m_currentTarget; + + QMetaObject::Connection m_positionConnection; + + Q_DECLARE_PUBLIC(QMorphingAnimation) +}; + +} // Qt3DAnimation + +QT_END_NAMESPACE + +#endif // QT3DANIMATION_QMORPHINGANIMATION_P_H diff --git a/src/animation/frontend/qmorphtarget.cpp b/src/animation/frontend/qmorphtarget.cpp new file mode 100644 index 000000000..1040e33ff --- /dev/null +++ b/src/animation/frontend/qmorphtarget.cpp @@ -0,0 +1,120 @@ +/**************************************************************************** +** +** 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 "qmorphtarget.h" +#include "Qt3DAnimation/private/qmorphtarget_p.h" + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { + +QMorphTargetPrivate::QMorphTargetPrivate() + : QObjectPrivate() +{ + +} + +void QMorphTargetPrivate::updateAttributeNames() +{ + m_attributeNames.clear(); + for (const Qt3DRender::QAttribute *attr : m_targetAttributes) + m_attributeNames.push_back(attr->name()); +} + +QMorphTarget::QMorphTarget(QObject *parent) + : QObject(*new QMorphTargetPrivate, parent) +{ + +} + +QVector QMorphTarget::attributeList() const +{ + Q_D(const QMorphTarget); + return d->m_targetAttributes; +} + +QStringList QMorphTarget::attributeNames() const +{ + Q_D(const QMorphTarget); + return d->m_attributeNames; +} + +void QMorphTarget::setAttributes(const QVector &attributes) +{ + Q_D(QMorphTarget); + d->m_targetAttributes = attributes; + d->m_attributeNames.clear(); + for (const Qt3DRender::QAttribute *attr : attributes) + d->m_attributeNames.push_back(attr->name()); + + emit attributeNamesChanged(d->m_attributeNames); +} + +void QMorphTarget::addAttribute(Qt3DRender::QAttribute *attribute) +{ + Q_D(QMorphTarget); + for (const Qt3DRender::QAttribute *attr : d->m_targetAttributes) { + if (attr->name() == attribute->name()) + return; + } + d->m_targetAttributes.push_back(attribute); + d->m_attributeNames.push_back(attribute->name()); + emit attributeNamesChanged(d->m_attributeNames); +} + +void QMorphTarget::removeAttribute(Qt3DRender::QAttribute *attribute) +{ + Q_D(QMorphTarget); + if (d->m_targetAttributes.contains(attribute)) { + d->m_targetAttributes.removeAll(attribute); + d->updateAttributeNames(); + emit attributeNamesChanged(d->m_attributeNames); + } +} + +QMorphTarget *QMorphTarget::fromGeometry(Qt3DRender::QGeometry *geometry, const QStringList &attributes) +{ + QMorphTarget *target = new QMorphTarget(); + for (Qt3DRender::QAttribute *attr : geometry->attributes()) { + if (attributes.contains(attr->name())) + target->addAttribute(attr); + } + return target; +} + +} // Qt3DAnimation + +QT_END_NAMESPACE diff --git a/src/animation/frontend/qmorphtarget.h b/src/animation/frontend/qmorphtarget.h new file mode 100644 index 000000000..0435924e1 --- /dev/null +++ b/src/animation/frontend/qmorphtarget.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QT3DANIMATION_QMORPHTARGET_H +#define QT3DANIMATION_QMORPHTARGET_H + +#include +#include + +#include + +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { + +class QMorphTargetPrivate; + +class QT3DANIMATIONSHARED_EXPORT QMorphTarget : public QObject +{ + Q_OBJECT + Q_PROPERTY(QStringList attributeNames READ attributeNames NOTIFY attributeNamesChanged) + +public: + explicit QMorphTarget(QObject *parent = nullptr); + + QVector attributeList() const; + QStringList attributeNames() const; + + void setAttributes(const QVector &attributes); + void addAttribute(Qt3DRender::QAttribute *attribute); + void removeAttribute(Qt3DRender::QAttribute *attribute); + + Q_INVOKABLE static QMorphTarget *fromGeometry(Qt3DRender::QGeometry *geometry, + const QStringList &attributes); + +Q_SIGNALS: + void attributeNamesChanged(const QStringList &attributeNames); + +private: + + Q_DECLARE_PRIVATE(QMorphTarget) +}; + +} // Qt3DAnimation + +QT_END_NAMESPACE + +#endif // QT3DANIMATION_QMORPHTARGET_H diff --git a/src/animation/frontend/qmorphtarget_p.h b/src/animation/frontend/qmorphtarget_p.h new file mode 100644 index 000000000..1fc3734ae --- /dev/null +++ b/src/animation/frontend/qmorphtarget_p.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QT3DANIMATION_QMORPHTARGET_P_H +#define QT3DANIMATION_QMORPHTARGET_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { + +class QMorphTargetPrivate : public QObjectPrivate +{ +public: + QMorphTargetPrivate(); + + void updateAttributeNames(); + + QStringList m_attributeNames; + QVector m_targetAttributes; + + Q_DECLARE_PUBLIC(QMorphTarget) +}; + +} // Qt3DAnimation + +QT_END_NAMESPACE + +#endif // QT3DANIMATION_QMORPHTARGET_P_H diff --git a/src/animation/frontend/qvertexblendanimation.cpp b/src/animation/frontend/qvertexblendanimation.cpp new file mode 100644 index 000000000..cd8f95f73 --- /dev/null +++ b/src/animation/frontend/qvertexblendanimation.cpp @@ -0,0 +1,234 @@ +/**************************************************************************** +** +** 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 "qvertexblendanimation.h" + +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { + +QVertexBlendAnimationPrivate::QVertexBlendAnimationPrivate() + : QAbstractAnimationPrivate(QAbstractAnimation::VertexBlendAnimation) + , m_currentBase(nullptr) + , m_currentTarget(nullptr) +{ + +} + +void QVertexBlendAnimationPrivate::getAttributesInPosition(float position, int *target0, + int *target1, float *interpolator) +{ + if (position < m_targetPositions.first()) { + *target0 = 0; + *target1 = qMin(1, m_targetPositions.size()); + *interpolator = 0.0f; + } else if (position > m_targetPositions.last()) { + *target0 = qMax(m_targetPositions.size() - 2, 0); + *target1 = qMax(m_targetPositions.size() - 1, 0); + *interpolator = 1.0f; + } else { + for (int i = 0; i < m_targetPositions.size() - 1; i++) { + if (position >= m_targetPositions[i] && position < m_targetPositions[i + 1]) { + *target0 = i; + *target1 = i + 1; + float a = (position - m_targetPositions[i]) + / (m_targetPositions[i + 1] - m_targetPositions[i]); + *interpolator = a; + } + } + } +} + +static Qt3DRender::QAttribute *findAttribute(QVector &attributes, + QString name) +{ + for (Qt3DRender::QAttribute *gattr : attributes) { + if (gattr->name() == name) + return gattr; + } + return nullptr; +} + +void QVertexBlendAnimationPrivate::updateAnimation(float position) +{ + Q_Q(QVertexBlendAnimation); + if (!m_target || !m_target->geometry()) + return; + + Qt3DAnimation::QMorphTarget *base; + Qt3DAnimation::QMorphTarget *target; + int target0, target1; + float interpolator; + getAttributesInPosition(position, &target0, &target1, &interpolator); + + base = m_morphTargets.at(target0); + target = m_morphTargets.at(target1); + + Qt3DRender::QGeometry *geometry = m_target->geometry(); + + // remove attributes from previous frame + if ((m_currentBase && (base != m_currentBase)) + || (m_currentTarget && (target != m_currentTarget))) { + const QVector baseAttributes = m_currentBase->attributeList(); + const QVector targetAttributes = m_currentTarget->attributeList(); + for (int i = 0; i < baseAttributes.size(); ++i) { + geometry->removeAttribute(baseAttributes.at(i)); + geometry->removeAttribute(targetAttributes.at(i)); + } + } + + const QVector baseAttributes = base->attributeList(); + const QVector targetAttributes = target->attributeList(); + const QStringList attributeNames = base->attributeNames(); + + // add attributes from current frame to the geometry + if (base != m_currentBase || target != m_currentTarget) { + for (int i = 0; i < baseAttributes.size(); ++i) { + const QString baseName = attributeNames.at(i); + QString targetName = baseName; + targetName.append("Target"); + + baseAttributes[i]->setName(baseName); + geometry->addAttribute(baseAttributes.at(i)); + targetAttributes[i]->setName(targetName); + geometry->addAttribute(targetAttributes.at(i)); + } + } + m_currentBase = base; + m_currentTarget = target; + + if (!qFuzzyCompare(interpolator, m_interpolator)) { + m_interpolator = interpolator; + emit q->interpolatorChanged(interpolator); + } +} + +QVertexBlendAnimation::QVertexBlendAnimation(QObject *parent) + : QAbstractAnimation(*new QVertexBlendAnimationPrivate, parent) +{ + Q_D(QVertexBlendAnimation); + d->m_positionConnection = QObject::connect(this, &QAbstractAnimation::positionChanged, + this, &QVertexBlendAnimation::updateAnimation); +} + +QVector QVertexBlendAnimation::targetPositions() const +{ + Q_D(const QVertexBlendAnimation); + return d->m_targetPositions; +} + +float QVertexBlendAnimation::interpolator() const +{ + Q_D(const QVertexBlendAnimation); + return d->m_interpolator; +} + +Qt3DRender::QGeometryRenderer *QVertexBlendAnimation::target() const +{ + Q_D(const QVertexBlendAnimation); + return d->m_target; +} + +QString QVertexBlendAnimation::targetName() const +{ + Q_D(const QVertexBlendAnimation); + return d->m_targetName; +} + +void QVertexBlendAnimation::setMorphTargets(const QVector &targets) +{ + Q_D(QVertexBlendAnimation); + d->m_morphTargets = targets; +} + +void QVertexBlendAnimation::addMorphTarget(Qt3DAnimation::QMorphTarget *target) +{ + Q_D(QVertexBlendAnimation); + if (!d->m_morphTargets.contains(target)) + d->m_morphTargets.push_back(target); +} + +void QVertexBlendAnimation::removeMorphTarget(Qt3DAnimation::QMorphTarget *target) +{ + Q_D(QVertexBlendAnimation); + d->m_morphTargets.removeAll(target); +} + +void QVertexBlendAnimation::setTargetPositions(const QVector &targetPositions) +{ + Q_D(QVertexBlendAnimation); + if (d->m_targetPositions == targetPositions) + return; + d->m_targetPositions = targetPositions; + emit targetPositionsChanged(targetPositions); + setDuration(d->m_targetPositions.last()); +} + +void QVertexBlendAnimation::setTarget(Qt3DRender::QGeometryRenderer *target) +{ + Q_D(QVertexBlendAnimation); + if (d->m_target != target) { + d->m_target = target; + emit targetChanged(target); + } +} + +QVector QVertexBlendAnimation::morphTargetList() +{ + Q_D(QVertexBlendAnimation); + return d->m_morphTargets; +} + +void QVertexBlendAnimation::setTargetName(const QString name) +{ + Q_D(QVertexBlendAnimation); + if (d->m_targetName != name) { + d->m_targetName = name; + emit targetNameChanged(name); + } +} + +void QVertexBlendAnimation::updateAnimation(float position) +{ + Q_D(QVertexBlendAnimation); + d->updateAnimation(position); +} + +} // Qt3DAnimation + +QT_END_NAMESPACE diff --git a/src/animation/frontend/qvertexblendanimation.h b/src/animation/frontend/qvertexblendanimation.h new file mode 100644 index 000000000..a7da2bcda --- /dev/null +++ b/src/animation/frontend/qvertexblendanimation.h @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QT3DANIMATION_QVERTEXBLENDANIMATION_H +#define QT3DANIMATION_QVERTEXBLENDANIMATION_H + +#include +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { + +class QVertexBlendAnimationPrivate; + +class QT3DANIMATIONSHARED_EXPORT QVertexBlendAnimation : public QAbstractAnimation +{ + Q_OBJECT + Q_PROPERTY(QVector targetPositions READ targetPositions WRITE setTargetPositions NOTIFY targetPositionsChanged) + Q_PROPERTY(float interpolator READ interpolator NOTIFY interpolatorChanged) + Q_PROPERTY(Qt3DRender::QGeometryRenderer *target READ target WRITE setTarget NOTIFY targetChanged) + Q_PROPERTY(QString targetName READ targetName WRITE setTargetName NOTIFY targetNameChanged) + +public: + explicit QVertexBlendAnimation(QObject *parent = nullptr); + + QVector targetPositions() const; + float interpolator() const; + Qt3DRender::QGeometryRenderer *target() const; + QString targetName() const; + + void setMorphTargets(const QVector &targets); + void addMorphTarget(Qt3DAnimation::QMorphTarget *target); + void removeMorphTarget(Qt3DAnimation::QMorphTarget *target); + + QVector morphTargetList(); + +public Q_SLOTS: + void setTargetPositions(const QVector &targetPositions); + void setTarget(Qt3DRender::QGeometryRenderer *target); + void setTargetName(const QString name); + +Q_SIGNALS: + void targetPositionsChanged(const QVector &targetPositions); + void interpolatorChanged(float interpolator); + void targetChanged(Qt3DRender::QGeometryRenderer *target); + void targetNameChanged(const QString &name); + +private: + + void updateAnimation(float position); + + Q_DECLARE_PRIVATE(QVertexBlendAnimation) +}; + +} // Qt3DAnimation + +QT_END_NAMESPACE + +#endif // QT3DANIMATION_QVERTEXBLENDANIMATION_H diff --git a/src/animation/frontend/qvertexblendanimation_p.h b/src/animation/frontend/qvertexblendanimation_p.h new file mode 100644 index 000000000..8f2609fc8 --- /dev/null +++ b/src/animation/frontend/qvertexblendanimation_p.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QT3DANIMATION_QVERTEXBLENDANIMATION_P_H +#define QT3DANIMATION_QVERTEXBLENDANIMATION_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + + +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { + +class QVertexBlendAnimationPrivate : public QAbstractAnimationPrivate +{ +public: + QVertexBlendAnimationPrivate(); + + void getAttributesInPosition(float position, int *target0, int *target1, float *interpolator); + void updateAnimation(float position); + + QVector m_targetPositions; + QVector m_morphTargets; + float m_interpolator; + Qt3DRender::QGeometryRenderer *m_target; + QString m_targetName; + QMorphTarget *m_currentBase; + QMorphTarget *m_currentTarget; + + QMetaObject::Connection m_positionConnection; + + Q_DECLARE_PUBLIC(QVertexBlendAnimation) +}; + +} // Qt3DAnimation + +QT_END_NAMESPACE + +#endif // QT3DANIMATION_QVertexBlendANIMATION_P_H diff --git a/src/extras/animations/animations.pri b/src/extras/animations/animations.pri deleted file mode 100644 index 71d6099fc..000000000 --- a/src/extras/animations/animations.pri +++ /dev/null @@ -1,26 +0,0 @@ -HEADERS += \ - $$PWD/qanimationcontroller.h \ - $$PWD/qanimationcontroller_p.h \ - $$PWD/qanimationgroup.h \ - $$PWD/qanimationgroup_p.h \ - $$PWD/qkeyframeanimation.h \ - $$PWD/qkeyframeanimation_p.h \ - $$PWD/qmorphinganimation.h \ - $$PWD/qmorphinganimation_p.h \ - $$PWD/qabstractanimation.h \ - $$PWD/qabstractanimation_p.h \ - $$PWD/qmorphtarget.h \ - $$PWD/qmorphtarget_p.h \ - $$PWD/qvertexblendanimation.h \ - $$PWD/qvertexblendanimation_p.h - -SOURCES += \ - $$PWD/qanimationcontroller.cpp \ - $$PWD/qanimationgroup.cpp \ - $$PWD/qkeyframeanimation.cpp \ - $$PWD/qmorphinganimation.cpp \ - $$PWD/qabstractanimation.cpp \ - $$PWD/qmorphtarget.cpp \ - $$PWD/qvertexblendanimation.cpp - -INCLUDEPATH += $$PWD diff --git a/src/extras/animations/qabstractanimation.cpp b/src/extras/animations/qabstractanimation.cpp deleted file mode 100644 index f87455c18..000000000 --- a/src/extras/animations/qabstractanimation.cpp +++ /dev/null @@ -1,112 +0,0 @@ -/**************************************************************************** -** -** 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 "qabstractanimation.h" -#include "Qt3DExtras/private/qabstractanimation_p.h" - -QT_BEGIN_NAMESPACE - -namespace Qt3DExtras { - -QAbstractAnimationPrivate::QAbstractAnimationPrivate(QAbstractAnimation::AnimationType type) - : QObjectPrivate() - , m_animationType(type) - , m_position(0.0f) - , m_duration(0.0f) -{ - -} - -QAbstractAnimation::QAbstractAnimation(QAbstractAnimationPrivate &dd, QObject *parent) - : QObject(dd, parent) -{ - -} - -QString QAbstractAnimation::animationName() const -{ - Q_D(const QAbstractAnimation); - return d->m_animationName; -} - -QAbstractAnimation::AnimationType QAbstractAnimation::animationType() const -{ - Q_D(const QAbstractAnimation); - return d->m_animationType; -} - -float QAbstractAnimation::position() const -{ - Q_D(const QAbstractAnimation); - return d->m_position; -} - -float QAbstractAnimation::duration() const -{ - Q_D(const QAbstractAnimation); - return d->m_duration; -} - -void QAbstractAnimation::setAnimationName(const QString &name) -{ - Q_D(QAbstractAnimation); - if (name != d->m_animationName) { - d->m_animationName = name; - emit animationNameChanged(name); - } -} - -void QAbstractAnimation::setPosition(float position) -{ - Q_D(QAbstractAnimation); - if (!qFuzzyCompare(position, d->m_position)) { - d->m_position = position; - emit positionChanged(position); - } -} - -void QAbstractAnimation::setDuration(float duration) -{ - Q_D(QAbstractAnimation); - if (!qFuzzyCompare(duration, d->m_duration)) { - d->m_duration = duration; - emit durationChanged(duration); - } -} - -} // Qt3DExtras - -QT_END_NAMESPACE diff --git a/src/extras/animations/qabstractanimation.h b/src/extras/animations/qabstractanimation.h deleted file mode 100644 index 242fe293a..000000000 --- a/src/extras/animations/qabstractanimation.h +++ /dev/null @@ -1,93 +0,0 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ - -#ifndef QT3DEXTRAS_QABSTRACTANIMATION_H -#define QT3DEXTRAS_QABSTRACTANIMATION_H - -#include -#include - -#include - -QT_BEGIN_NAMESPACE - -namespace Qt3DExtras { - -class QAbstractAnimationPrivate; - -class QT3DEXTRASSHARED_EXPORT QAbstractAnimation : public QObject -{ - Q_OBJECT - Q_PROPERTY(QString animationName READ animationName WRITE setAnimationName NOTIFY animationNameChanged) - Q_PROPERTY(QAbstractAnimation::AnimationType animationType READ animationType CONSTANT) - Q_PROPERTY(float position READ position WRITE setPosition NOTIFY positionChanged) - Q_PROPERTY(float duration READ duration NOTIFY durationChanged) - -public: - enum AnimationType { - KeyframeAnimation = 1, - MorphingAnimation = 2, - VertexBlendAnimation = 3, - }; - - QString animationName() const; - QAbstractAnimation::AnimationType animationType() const; - float position() const; - float duration() const; - -public Q_SLOTS: - void setAnimationName(const QString &name); - void setPosition(float position); - -protected: - explicit QAbstractAnimation(QAbstractAnimationPrivate &dd, QObject *parent = nullptr); - - void setDuration(float duration); - -Q_SIGNALS: - void animationNameChanged(const QString &name); - void positionChanged(float position); - void durationChanged(float duration); - -private: - Q_DECLARE_PRIVATE(QAbstractAnimation) -}; - -} // Qt3DExtras - -QT_END_NAMESPACE - -#endif // QT3DEXTRAS_QABSTRACTANIMATION_H diff --git a/src/extras/animations/qabstractanimation_p.h b/src/extras/animations/qabstractanimation_p.h deleted file mode 100644 index 1370ef2c7..000000000 --- a/src/extras/animations/qabstractanimation_p.h +++ /dev/null @@ -1,75 +0,0 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ - -#ifndef QT3DEXTRAS_QABSTRACTANIMATION_P_H -#define QT3DEXTRAS_QABSTRACTANIMATION_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of other Qt classes. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include -#include - -QT_BEGIN_NAMESPACE - -namespace Qt3DExtras { - -class QAbstractAnimationPrivate : public QObjectPrivate -{ -public: - QAbstractAnimationPrivate(QAbstractAnimation::AnimationType type); - - QString m_animationName; - QAbstractAnimation::AnimationType m_animationType; - float m_position; - float m_duration; - - Q_DECLARE_PUBLIC(QAbstractAnimation) -}; - -} // Qt3DExtras - -QT_END_NAMESPACE - -#endif // QT3DEXTRAS_QANIMATIONCONTROLLER_P_H diff --git a/src/extras/animations/qanimationcontroller.cpp b/src/extras/animations/qanimationcontroller.cpp deleted file mode 100644 index adef3d45c..000000000 --- a/src/extras/animations/qanimationcontroller.cpp +++ /dev/null @@ -1,252 +0,0 @@ -/**************************************************************************** -** -** 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 "qanimationcontroller.h" -#include "qanimationgroup.h" - -#include - -QT_BEGIN_NAMESPACE - -namespace Qt3DExtras { - -QAnimationControllerPrivate::QAnimationControllerPrivate() - : QObjectPrivate() - , m_activeAnimationGroup(0) - , m_position(0.0f) - , m_positionScale(1.0f) - , m_positionOffset(0.0f) - , m_entity(nullptr) - , m_recursive(true) -{ - -} - -void QAnimationControllerPrivate::updatePosition(float position) -{ - m_position = position; - if (m_activeAnimationGroup >= 0 && m_activeAnimationGroup < m_animationGroups.size()) { - const float pos = m_positionScale * position + m_positionOffset; - m_animationGroups[m_activeAnimationGroup]->setPosition(pos); - } -} - -QAnimationGroup *QAnimationControllerPrivate::findGroup(const QString &name) -{ - for (QAnimationGroup *g : m_animationGroups) { - if (g->name() == name) - return g; - } - return nullptr; -} - -void QAnimationControllerPrivate::extractAnimations() -{ - Q_Q(QAnimationController); - if (!m_entity) - return; - QList animations - = m_entity->findChildren(QString(), - m_recursive ? Qt::FindChildrenRecursively : Qt::FindDirectChildrenOnly); - if (animations.size() > 0) { - for (Qt3DExtras::QAbstractAnimation *a : animations) { - QAnimationGroup *group = findGroup(a->animationName()); - if (!group) { - group = new QAnimationGroup(q); - group->setName(a->animationName()); - m_animationGroups.push_back(group); - } - group->addAnimation(a); - } - } -} -void QAnimationControllerPrivate::clearAnimations() -{ - for (Qt3DExtras::QAnimationGroup *a : m_animationGroups) - a->deleteLater(); - m_animationGroups.clear(); - m_activeAnimationGroup = 0; -} - -QAnimationController::QAnimationController(QObject *parent) - : QObject(*new QAnimationControllerPrivate, parent) -{ - -} - -QVector QAnimationController::animationGroupList() -{ - Q_D(QAnimationController); - return d->m_animationGroups; -} - -int QAnimationController::activeAnimationGroup() const -{ - Q_D(const QAnimationController); - return d->m_activeAnimationGroup; -} - -float QAnimationController::position() const -{ - Q_D(const QAnimationController); - return d->m_position; -} - -float QAnimationController::positionScale() const -{ - Q_D(const QAnimationController); - return d->m_positionScale; -} - -float QAnimationController::positionOffset() const -{ - Q_D(const QAnimationController); - return d->m_positionOffset; -} - -Qt3DCore::QEntity *QAnimationController::entity() const -{ - Q_D(const QAnimationController); - return d->m_entity; -} - -bool QAnimationController::recursive() const -{ - Q_D(const QAnimationController); - return d->m_recursive; -} - -void QAnimationController::setAnimationGroups(const QVector &animationGroups) -{ - Q_D(QAnimationController); - d->m_animationGroups = animationGroups; - if (d->m_activeAnimationGroup >= d->m_animationGroups.size()) - d->m_activeAnimationGroup = 0; - d->updatePosition(d->m_position); -} - -void QAnimationController::addAnimationGroup(Qt3DExtras::QAnimationGroup *animationGroup) -{ - Q_D(QAnimationController); - if (!d->m_animationGroups.contains(animationGroup)) - d->m_animationGroups.push_back(animationGroup); -} - -void QAnimationController::removeAnimationGroup(Qt3DExtras::QAnimationGroup *animationGroup) -{ - Q_D(QAnimationController); - if (d->m_animationGroups.contains(animationGroup)) - d->m_animationGroups.removeAll(animationGroup); - if (d->m_activeAnimationGroup >= d->m_animationGroups.size()) - d->m_activeAnimationGroup = 0; -} - -void QAnimationController::setActiveAnimationGroup(int index) -{ - Q_D(QAnimationController); - if (d->m_activeAnimationGroup != index) { - d->m_activeAnimationGroup = index; - d->updatePosition(d->m_position); - emit activeAnimationGroupChanged(index); - } -} -void QAnimationController::setPosition(float position) -{ - Q_D(QAnimationController); - if (!qFuzzyCompare(d->m_position, position)) { - d->updatePosition(position); - emit positionChanged(position); - } -} - -void QAnimationController::setPositionScale(float scale) -{ - Q_D(QAnimationController); - if (!qFuzzyCompare(d->m_positionScale, scale)) { - d->m_positionScale = scale; - emit positionScaleChanged(scale); - } -} - -void QAnimationController::setPositionOffset(float offset) -{ - Q_D(QAnimationController); - if (!qFuzzyCompare(d->m_positionOffset, offset)) { - d->m_positionOffset = offset; - emit positionOffsetChanged(offset); - } -} - -void QAnimationController::setEntity(Qt3DCore::QEntity *entity) -{ - Q_D(QAnimationController); - if (d->m_entity != entity) { - d->clearAnimations(); - d->m_entity = entity; - d->extractAnimations(); - d->updatePosition(d->m_position); - emit entityChanged(entity); - } -} - -void QAnimationController::setRecursive(bool recursive) -{ - Q_D(QAnimationController); - if (d->m_recursive != recursive) { - d->m_recursive = recursive; - emit recursiveChanged(recursive); - } -} - -int QAnimationController::getAnimationIndex(const QString &name) const -{ - Q_D(const QAnimationController); - for (int i = 0; i < d->m_animationGroups.size(); ++i) { - if (d->m_animationGroups[i]->name() == name) - return i; - } - return -1; -} - -QAnimationGroup *QAnimationController::getGroup(int index) const -{ - Q_D(const QAnimationController); - return d->m_animationGroups.at(index); -} - -} // Qt3DExtras - -QT_END_NAMESPACE diff --git a/src/extras/animations/qanimationcontroller.h b/src/extras/animations/qanimationcontroller.h deleted file mode 100644 index 4ee32dd8b..000000000 --- a/src/extras/animations/qanimationcontroller.h +++ /dev/null @@ -1,105 +0,0 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ - -#ifndef QT3DEXTRAS_QANIMATIONCONTROLLER_H -#define QT3DEXTRAS_QANIMATIONCONTROLLER_H - -#include -#include -#include - -#include - -QT_BEGIN_NAMESPACE - -namespace Qt3DExtras { - -class QAnimationControllerPrivate; - -class QT3DEXTRASSHARED_EXPORT QAnimationController : public QObject -{ - Q_OBJECT - Q_PROPERTY(int activeAnimationGroup READ activeAnimationGroup WRITE setActiveAnimationGroup NOTIFY activeAnimationGroupChanged) - Q_PROPERTY(float position READ position WRITE setPosition NOTIFY positionChanged) - Q_PROPERTY(float positionScale READ positionScale WRITE setPositionScale NOTIFY positionScaleChanged) - Q_PROPERTY(float positionOffset READ positionOffset WRITE setPositionOffset NOTIFY positionOffsetChanged) - Q_PROPERTY(Qt3DCore::QEntity *entity READ entity WRITE setEntity NOTIFY entityChanged) - Q_PROPERTY(bool recursive READ recursive WRITE setRecursive NOTIFY recursiveChanged) - -public: - QAnimationController(QObject *parent = nullptr); - - QVector animationGroupList(); - - int activeAnimationGroup() const; - float position() const; - float positionScale() const; - float positionOffset() const; - Qt3DCore::QEntity *entity() const; - bool recursive() const; - - void setAnimationGroups(const QVector &animationGroups); - void addAnimationGroup(Qt3DExtras::QAnimationGroup *animationGroups); - void removeAnimationGroup(Qt3DExtras::QAnimationGroup *animationGroups); - - Q_INVOKABLE int getAnimationIndex(const QString &name) const; - Q_INVOKABLE Qt3DExtras::QAnimationGroup *getGroup(int index) const; - -public Q_SLOTS: - void setActiveAnimationGroup(int index); - void setPosition(float position); - void setPositionScale(float scale); - void setPositionOffset(float offset); - void setEntity(Qt3DCore::QEntity *entity); - void setRecursive(bool recursive); - -Q_SIGNALS: - void activeAnimationGroupChanged(int index); - void positionChanged(float position); - void positionScaleChanged(float scale); - void positionOffsetChanged(float offset); - void entityChanged(Qt3DCore::QEntity *entity); - void recursiveChanged(bool recursive); - -private: - Q_DECLARE_PRIVATE(QAnimationController) -}; - -} // Qt3DExtras - -QT_END_NAMESPACE - -#endif // QT3DEXTRAS_QANIMATIONCONTROLLER_H diff --git a/src/extras/animations/qanimationcontroller_p.h b/src/extras/animations/qanimationcontroller_p.h deleted file mode 100644 index dd5079ef5..000000000 --- a/src/extras/animations/qanimationcontroller_p.h +++ /dev/null @@ -1,84 +0,0 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ - -#ifndef QT3DEXTRAS_QANIMATIONCONTROLLER_P_H -#define QT3DEXTRAS_QANIMATIONCONTROLLER_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of other Qt classes. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include -#include - -QT_BEGIN_NAMESPACE - -namespace Qt3DExtras { - -class QAnimationControllerPrivate : public QObjectPrivate -{ -public: - QAnimationControllerPrivate(); - - QString m_name; - int m_activeAnimationGroup; - QVector m_animationGroups; - float m_position; - float m_positionScale; - float m_positionOffset; - Qt3DCore::QEntity *m_entity; - bool m_recursive; - - void updatePosition(float position); - void extractAnimations(); - void clearAnimations(); - QAnimationGroup *findGroup(const QString &name); - - Q_DECLARE_PUBLIC(QAnimationController) -}; - -} // Qt3DExtras - -QT_END_NAMESPACE - -#endif // QT3DEXTRAS_QANIMATIONCONTROLLER_P_H diff --git a/src/extras/animations/qanimationgroup.cpp b/src/extras/animations/qanimationgroup.cpp deleted file mode 100644 index e9febe811..000000000 --- a/src/extras/animations/qanimationgroup.cpp +++ /dev/null @@ -1,125 +0,0 @@ -/**************************************************************************** -** -** 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 "qanimationgroup.h" -#include "Qt3DExtras/private/qanimationgroup_p.h" - -QT_BEGIN_NAMESPACE - -namespace Qt3DExtras { - -QAnimationGroupPrivate::QAnimationGroupPrivate() - : QObjectPrivate() - , m_position(0.0f) - , m_duration(0.0f) -{ - -} - -void QAnimationGroupPrivate::updatePosition(float position) -{ - m_position = position; - for (QAbstractAnimation *aa : m_animations) - aa->setPosition(position); -} - -QAnimationGroup::QAnimationGroup(QObject *parent) - : QObject(*new QAnimationGroupPrivate, parent) -{ - -} - -QString QAnimationGroup::name() const -{ - Q_D(const QAnimationGroup); - return d->m_name; -} - -QVector QAnimationGroup::animationList() -{ - Q_D(QAnimationGroup); - return d->m_animations; -} - -float QAnimationGroup::position() const -{ - Q_D(const QAnimationGroup); - return d->m_position; -} - -float QAnimationGroup::duration() const -{ - Q_D(const QAnimationGroup); - return d->m_duration; -} - -void QAnimationGroup::setName(const QString &name) -{ - Q_D(QAnimationGroup); - if (d->m_name != name) { - d->m_name = name; - emit nameChanged(name); - } -} - -void QAnimationGroup::setAnimations(const QVector &animations) -{ - Q_D(QAnimationGroup); - d->m_animations = animations; - d->m_duration = 0.0f; - for (const Qt3DExtras::QAbstractAnimation *a : animations) - d->m_duration = qMax(d->m_duration, a->duration()); -} - -void QAnimationGroup::addAnimation(QAbstractAnimation *animation) -{ - Q_D(QAnimationGroup); - d->m_animations.push_back(animation); - d->m_duration = qMax(d->m_duration, animation->duration()); -} - -void QAnimationGroup::setPosition(float position) -{ - Q_D(QAnimationGroup); - if (!qFuzzyCompare(d->m_position, position)) { - d->updatePosition(position); - emit positionChanged(position); - } -} - -} // Qt3DExtras - -QT_END_NAMESPACE diff --git a/src/extras/animations/qanimationgroup.h b/src/extras/animations/qanimationgroup.h deleted file mode 100644 index 4595a2082..000000000 --- a/src/extras/animations/qanimationgroup.h +++ /dev/null @@ -1,89 +0,0 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ - -#ifndef QT3DEXTRAS_QANIMATIONGROUP_H -#define QT3DEXTRAS_QANIMATIONGROUP_H - -#include - -#include - -#include - -QT_BEGIN_NAMESPACE - -namespace Qt3DExtras { - -class QAnimationGroupPrivate; - -class QT3DEXTRASSHARED_EXPORT QAnimationGroup : public QObject -{ - Q_OBJECT - Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) - Q_PROPERTY(float position READ position WRITE setPosition NOTIFY positionChanged) - Q_PROPERTY(float duration READ duration NOTIFY durationChanged) - -public: - explicit QAnimationGroup(QObject *parent = nullptr); - - QString name() const; - QVector animationList(); - float position() const; - float duration() const; - - void setAnimations(const QVector &animations); - void addAnimation(Qt3DExtras::QAbstractAnimation *animation); - void removeAnimation(Qt3DExtras::QAbstractAnimation *animation); - -public Q_SLOTS: - void setName(const QString &name); - void setPosition(float position); - -Q_SIGNALS: - void nameChanged(const QString &name); - void positionChanged(float position); - void durationChanged(float duration); - -private: - - Q_DECLARE_PRIVATE(QAnimationGroup) -}; - -} // Qt3DExtras - -QT_END_NAMESPACE - -#endif // QT3DEXTRAS_QANIMATIONGROUP_H diff --git a/src/extras/animations/qanimationgroup_p.h b/src/extras/animations/qanimationgroup_p.h deleted file mode 100644 index cffe44636..000000000 --- a/src/extras/animations/qanimationgroup_p.h +++ /dev/null @@ -1,77 +0,0 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ - -#ifndef QT3DEXTRAS_QANIMATIONGROUP_P_H -#define QT3DEXTRAS_QANIMATIONGROUP_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of other Qt classes. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include -#include - -QT_BEGIN_NAMESPACE - -namespace Qt3DExtras { - -class QAnimationGroupPrivate : public QObjectPrivate -{ -public: - QAnimationGroupPrivate(); - - QString m_name; - QVector m_animations; - float m_position; - float m_duration; - - void updatePosition(float position); - - Q_DECLARE_PUBLIC(QAnimationGroup) -}; - -} // Qt3DExtras - -QT_END_NAMESPACE - -#endif // QT3DEXTRAS_QANIMATIONGROUP_P_H diff --git a/src/extras/animations/qkeyframeanimation.cpp b/src/extras/animations/qkeyframeanimation.cpp deleted file mode 100644 index 425cbe0df..000000000 --- a/src/extras/animations/qkeyframeanimation.cpp +++ /dev/null @@ -1,262 +0,0 @@ -/**************************************************************************** -** -** 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 "qkeyframeanimation.h" -#include "Qt3DExtras/private/qkeyframeanimation_p.h" - -#include - -QT_BEGIN_NAMESPACE - -namespace Qt3DExtras { - -QKeyframeAnimationPrivate::QKeyframeAnimationPrivate() - : QAbstractAnimationPrivate(QAbstractAnimation::KeyframeAnimation) - , m_minposition(0.0f) - , m_maxposition(0.0f) - , m_prevPosition(-1.0f) - , m_target(nullptr) - , m_startMode(QKeyframeAnimation::Constant) - , m_endMode(QKeyframeAnimation::Constant) -{ - -} - -QKeyframeAnimation::QKeyframeAnimation(QObject *parent) - : QAbstractAnimation(*new QKeyframeAnimationPrivate(), parent) -{ - Q_D(QKeyframeAnimation); - d->m_positionConnection = QObject::connect(this, &QAbstractAnimation::positionChanged, - this, &QKeyframeAnimation::updateAnimation); -} - - -void QKeyframeAnimation::setFramePositions(const QVector &positions) -{ - Q_D(QKeyframeAnimation); - d->m_framePositions = positions; - d->m_prevPosition = -1.0f; - if (d->m_framePositions.size() == 0) { - d->m_minposition = d->m_maxposition = 0.0f; - return; - } - d->m_minposition = d->m_framePositions.first(); - d->m_maxposition = d->m_framePositions.last(); - float lastPos = d->m_minposition; - for (float p : d->m_framePositions) { - if (p < lastPos || p > d->m_maxposition) - qWarning() << "positions not ordered correctly"; - lastPos = p; - } - setDuration(d->m_maxposition); -} - -void QKeyframeAnimation::setKeyframes(const QVector &keyframes) -{ - Q_D(QKeyframeAnimation); - d->m_keyframes = keyframes; -} - -// slerp which allows long path -QQuaternion lslerp(QQuaternion q1, QQuaternion q2, float t) -{ - QQuaternion ret; - // Handle the easy cases first. - if (t <= 0.0f) - return q1; - else if (t >= 1.0f) - return q2; - - float cos = qBound(-1.0f, QQuaternion::dotProduct(q1, q2), 1.0f); - float angle = std::acos(cos); - float sin = std::sin(angle); - if (!qFuzzyIsNull(sin)) { - float a = std::sin((1.0 - t) * angle) / sin; - float b = std::sin(t * angle) / sin; - ret = (q1 * a + q2 * b).normalized(); - } else { - ret = q1 * (1.0f-t) + q2 * t; - } - return ret; -} - -void QKeyframeAnimationPrivate::calculateFrame(float position) -{ - if (m_target && m_framePositions.size() > 0 - && m_keyframes.size() == m_framePositions.size() - && m_prevPosition != m_position) { - if (m_position >= m_minposition && m_position < m_maxposition) { - for (int i = 0; i < m_framePositions.size() - 1; i++) { - if (position >= m_framePositions.at(i) - && position < m_framePositions.at(i+1)) { - float ip = (position - m_framePositions.at(i)) - / (m_framePositions.at(i+1) - m_framePositions.at(i)); - float eIp = m_easing.valueForProgress(ip); - float eIip = 1.0f - eIp; - - Qt3DCore::QTransform *a = m_keyframes.at(i); - Qt3DCore::QTransform *b = m_keyframes.at(i+1); - - QVector3D s = a->scale3D() * eIip + b->scale3D() * eIp; - QVector3D t = a->translation() * eIip + b->translation() * eIp; - QQuaternion r = QQuaternion::slerp(a->rotation(), b->rotation(), eIp); - - m_target->setRotation(r); - m_target->setScale3D(s); - m_target->setTranslation(t); - return; - } - } - } else if (position < m_minposition) { - m_target->setRotation(m_keyframes.first()->rotation()); - m_target->setScale3D(m_keyframes.first()->scale3D()); - m_target->setTranslation(m_keyframes.first()->translation()); - } else { - m_target->setRotation(m_keyframes.last()->rotation()); - m_target->setScale3D(m_keyframes.last()->scale3D()); - m_target->setTranslation(m_keyframes.last()->translation()); - } - m_prevPosition = m_position; - } -} - -void QKeyframeAnimation::updateAnimation(float position) -{ - Q_D(QKeyframeAnimation); - d->calculateFrame(position); -} - -QVector QKeyframeAnimation::framePositions() const -{ - Q_D(const QKeyframeAnimation); - return d->m_framePositions; -} - -QVector QKeyframeAnimation::keyframeList() const -{ - Q_D(const QKeyframeAnimation); - return d->m_keyframes; -} - -void QKeyframeAnimation::setTarget(Qt3DCore::QTransform *target) -{ - Q_D(QKeyframeAnimation); - if (d->m_target != target) { - d->m_target = target; - emit targetChanged(d->m_target); - d->m_prevPosition = -1.0f; - - if (target) { - d->m_baseScale = target->scale3D(); - d->m_baseTranslation = target->translation(); - d->m_baseRotation = target->rotation(); - } - } -} - -QKeyframeAnimation::RepeatMode QKeyframeAnimation::startMode() const -{ - Q_D(const QKeyframeAnimation); - return d->m_startMode; -} - -QKeyframeAnimation::RepeatMode QKeyframeAnimation::endMode() const -{ - Q_D(const QKeyframeAnimation); - return d->m_endMode; -} - -void QKeyframeAnimation::setEasing(QEasingCurve::Type easing) -{ - Q_D(QKeyframeAnimation); - if (d->m_easing.type() != easing) { - d->m_easing.setType(easing); - emit easingChanged(easing); - } -} - -void QKeyframeAnimation::setTargetName(const QString &name) -{ - Q_D(QKeyframeAnimation); - d->m_targetName = name; - emit targetNameChanged(name); -} - -void QKeyframeAnimation::setStartMode(QKeyframeAnimation::RepeatMode mode) -{ - Q_D(QKeyframeAnimation); - if (d->m_startMode != mode) { - d->m_startMode = mode; - emit startModeChanged(mode); - } -} - -void QKeyframeAnimation::setEndMode(QKeyframeAnimation::RepeatMode mode) -{ - Q_D(QKeyframeAnimation); - if (mode != d->m_endMode) { - d->m_endMode = mode; - emit endModeChanged(mode); - } -} - -void QKeyframeAnimation::addKeyframe(Qt3DCore::QTransform *keyframe) -{ - Q_D(QKeyframeAnimation); - d->m_keyframes.push_back(keyframe); -} - -QString QKeyframeAnimation::targetName() const -{ - Q_D(const QKeyframeAnimation); - return d->m_targetName; -} - -QEasingCurve::Type QKeyframeAnimation::easing() const -{ - Q_D(const QKeyframeAnimation); - return d->m_easing.type(); -} - -Qt3DCore::QTransform *QKeyframeAnimation::target() const -{ - Q_D(const QKeyframeAnimation); - return d->m_target; -} - -} // Qt3DExtras - -QT_END_NAMESPACE diff --git a/src/extras/animations/qkeyframeanimation.h b/src/extras/animations/qkeyframeanimation.h deleted file mode 100644 index 178c9dbf1..000000000 --- a/src/extras/animations/qkeyframeanimation.h +++ /dev/null @@ -1,112 +0,0 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ - -#ifndef QT3DEXTRAS_QKEYFRAMEANIMATION_H -#define QT3DEXTRAS_QKEYFRAMEANIMATION_H - -#include - -#include -#include - -#include - -QT_BEGIN_NAMESPACE - -namespace Qt3DExtras { - -class QKeyframeAnimationPrivate; - -class QT3DEXTRASSHARED_EXPORT QKeyframeAnimation : public QAbstractAnimation -{ - Q_OBJECT - Q_PROPERTY(QVector framePositions READ framePositions WRITE setFramePositions NOTIFY framePositionsChanged) - Q_PROPERTY(Qt3DCore::QTransform *target READ target WRITE setTarget NOTIFY targetChanged) - Q_PROPERTY(QEasingCurve::Type easing READ easing WRITE setEasing NOTIFY easingChanged) - Q_PROPERTY(QString targetName READ targetName WRITE setTargetName NOTIFY targetNameChanged) - Q_PROPERTY(QKeyframeAnimation::RepeatMode startMode READ startMode WRITE setStartMode NOTIFY startModeChanged) - Q_PROPERTY(QKeyframeAnimation::RepeatMode endMode READ endMode WRITE setEndMode NOTIFY endModeChanged) - -public: - explicit QKeyframeAnimation(QObject *parent = nullptr); - - enum RepeatMode - { - None, - Constant, - Repeat, - }; - Q_ENUM(RepeatMode) - - QVector framePositions() const; - QVector keyframeList() const; - Qt3DCore::QTransform *target() const; - QEasingCurve::Type easing() const; - QString targetName() const; - RepeatMode startMode() const; - RepeatMode endMode() const; - - void setKeyframes(const QVector &keyframes); - void addKeyframe(Qt3DCore::QTransform *keyframe); - void removeKeyframe(Qt3DCore::QTransform *keyframe); - -public Q_SLOTS: - void setFramePositions(const QVector &positions); - void setTarget(Qt3DCore::QTransform *target); - void setEasing(QEasingCurve::Type easing); - void setTargetName(const QString &name); - void setStartMode(RepeatMode mode); - void setEndMode(RepeatMode mode); - -Q_SIGNALS: - void framePositionsChanged(const QVector &positions); - void targetChanged(Qt3DCore::QTransform *target); - void easingChanged(QEasingCurve::Type easing); - void targetNameChanged(const QString &name); - void startModeChanged(RepeatMode startMode); - void endModeChanged(RepeatMode endMode); - -private: - void updateAnimation(float position); - - Q_DECLARE_PRIVATE(QKeyframeAnimation) -}; - -} // Qt3DExtras - -QT_END_NAMESPACE - -#endif // QT3DEXTRAS_QKEYFRAMEANIMATION_H diff --git a/src/extras/animations/qkeyframeanimation_p.h b/src/extras/animations/qkeyframeanimation_p.h deleted file mode 100644 index 0095b9432..000000000 --- a/src/extras/animations/qkeyframeanimation_p.h +++ /dev/null @@ -1,89 +0,0 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ - -#ifndef QT3DEXTRAS_QKEYFRAMEANIMATION_P_H -#define QT3DEXTRAS_QKEYFRAMEANIMATION_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of other Qt classes. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include -#include -#include - -QT_BEGIN_NAMESPACE - -namespace Qt3DExtras { - -class QKeyframeAnimationPrivate : public QAbstractAnimationPrivate -{ -public: - QKeyframeAnimationPrivate(); - - void calculateFrame(float position); - - float m_prevPosition; - QVector m_framePositions; - QVector m_keyframes; - Qt3DCore::QTransform *m_target; - QEasingCurve m_easing; - QString m_animationName; - QString m_targetName; - float m_minposition; - float m_maxposition; - QKeyframeAnimation::RepeatMode m_startMode; - QKeyframeAnimation::RepeatMode m_endMode; - QVector3D m_baseScale; - QVector3D m_baseTranslation; - QQuaternion m_baseRotation; - QMetaObject::Connection m_positionConnection; - - Q_DECLARE_PUBLIC(QKeyframeAnimation) -}; - -} // Qt3DExtras - -QT_END_NAMESPACE - -#endif // QT3DEXTRAS_QKEYFRAMEANIMATION_P_H diff --git a/src/extras/animations/qmorphinganimation.cpp b/src/extras/animations/qmorphinganimation.cpp deleted file mode 100644 index e7fe05147..000000000 --- a/src/extras/animations/qmorphinganimation.cpp +++ /dev/null @@ -1,280 +0,0 @@ -/**************************************************************************** -** -** 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 "qmorphinganimation.h" -#include - -QT_BEGIN_NAMESPACE - -namespace Qt3DExtras { - -QMorphingAnimationPrivate::QMorphingAnimationPrivate() - : QAbstractAnimationPrivate(QAbstractAnimation::MorphingAnimation) - , m_flattened(nullptr) - , m_method(QMorphingAnimation::Relative) - , m_interpolator(0.0f) - , m_target(nullptr) - , m_currentTarget(nullptr) -{ - m_easing.setType(QEasingCurve::InOutCubic); -} - -QMorphingAnimationPrivate::~QMorphingAnimationPrivate() -{ - for (QVector *weights : m_weights) - delete weights; -} - -void QMorphingAnimationPrivate::updateAnimation(float position) -{ - Q_Q(QMorphingAnimation); - if (!m_target || !m_target->geometry()) - return; - - m_morphKey.resize(m_morphTargets.size()); - - for (int i = 0; i < m_targetPositions.size() - 1; ++i) { - if (position > m_targetPositions.at(i) && position <= m_targetPositions.at(i + 1)) { - float interpolator = (position - m_targetPositions.at(i)) - / (m_targetPositions.at(i + 1) - m_targetPositions.at(i)); - interpolator = m_easing.valueForProgress(interpolator); - float iip = 1.0f - interpolator; - float sum = 0.0f; - QVector relevantValues; - for (int j = 0; j < m_morphTargets.size(); ++j) { - m_morphKey[j] = interpolator * m_weights.at(i + 1)->at(j) - + iip * m_weights.at(i)->at(j); - sum += m_morphKey[j]; - if (!qFuzzyIsNull(m_morphKey[j])) - relevantValues.push_back(j); - } - - if (relevantValues.size() == 0 || qFuzzyIsNull(sum)) { - // only base is used - interpolator = 0.0f; - } else if (relevantValues.size() == 1) { - // one morph target has non-zero weight - setTargetInterpolated(relevantValues[0]); - interpolator = sum; - } else { - // more than one morph target has non-zero weight - // flatten morph targets to one - qWarning() << Q_FUNC_INFO << "Flattening required"; - } - if (!qFuzzyCompare(interpolator, m_interpolator)) { - if (m_method == QMorphingAnimation::Normalized) - m_interpolator = interpolator; - else - m_interpolator = -interpolator; - emit q->interpolatorChanged(m_interpolator); - } - return; - } - } -} - -void QMorphingAnimationPrivate::setTargetInterpolated(int morphTarget) -{ - QMorphTarget *target = m_morphTargets[morphTarget]; - Qt3DRender::QGeometry *geometry = m_target->geometry(); - - // remove attributes from previous frame - if (m_currentTarget && (target != m_currentTarget)) { - const QVector targetAttributes = m_currentTarget->attributeList(); - for (int i = 0; i < targetAttributes.size(); ++i) - geometry->removeAttribute(targetAttributes.at(i)); - } - - const QVector targetAttributes = target->attributeList(); - - // add attributes from current frame to the geometry - if (target != m_currentTarget) { - for (int i = 0; i < m_attributeNames.size(); ++i) { - QString targetName = m_attributeNames.at(i); - targetName.append("Target"); - targetAttributes[i]->setName(targetName); - geometry->addAttribute(targetAttributes.at(i)); - } - } - m_currentTarget = target; -} - -QMorphingAnimation::QMorphingAnimation(QObject *parent) - : QAbstractAnimation(*new QMorphingAnimationPrivate, parent) -{ - Q_D(QMorphingAnimation); - d->m_positionConnection = QObject::connect(this, &QAbstractAnimation::positionChanged, - this, &QMorphingAnimation::updateAnimation); -} - -QVector QMorphingAnimation::targetPositions() const -{ - Q_D(const QMorphingAnimation); - return d->m_targetPositions; -} - -float QMorphingAnimation::interpolator() const -{ - Q_D(const QMorphingAnimation); - return d->m_interpolator; -} - -Qt3DRender::QGeometryRenderer *QMorphingAnimation::target() const -{ - Q_D(const QMorphingAnimation); - return d->m_target; -} - -QString QMorphingAnimation::targetName() const -{ - Q_D(const QMorphingAnimation); - return d->m_targetName; -} - -QMorphingAnimation::Method QMorphingAnimation::method() const -{ - Q_D(const QMorphingAnimation); - return d->m_method; -} - -QEasingCurve::Type QMorphingAnimation::easing() const -{ - Q_D(const QMorphingAnimation); - return d->m_easing.type(); -} - -void QMorphingAnimation::setMorphTargets(const QVector &targets) -{ - Q_D(QMorphingAnimation); - d->m_morphTargets = targets; - d->m_attributeNames = targets[0]->attributeNames(); -} - -void QMorphingAnimation::addMorphTarget(Qt3DExtras::QMorphTarget *target) -{ - Q_D(QMorphingAnimation); - if (!d->m_morphTargets.contains(target)) - d->m_morphTargets.push_back(target); -} - -void QMorphingAnimation::removeMorphTarget(Qt3DExtras::QMorphTarget *target) -{ - Q_D(QMorphingAnimation); - d->m_morphTargets.removeAll(target); -} - -void QMorphingAnimation::setTargetPositions(const QVector &targetPositions) -{ - Q_D(QMorphingAnimation); - d->m_targetPositions = targetPositions; - emit targetPositionsChanged(targetPositions); - setDuration(d->m_targetPositions.last()); - if (d->m_weights.size() < targetPositions.size()) { - d->m_weights.resize(targetPositions.size()); - for (int i = 0; i < d->m_weights.size(); ++i) { - if (d->m_weights[i] == nullptr) - d->m_weights[i] = new QVector(); - } - } -} - -void QMorphingAnimation::setTarget(Qt3DRender::QGeometryRenderer *target) -{ - Q_D(QMorphingAnimation); - if (d->m_target != target) { - d->m_target = target; - emit targetChanged(target); - } -} - -void QMorphingAnimation::setWeights(int positionIndex, const QVector &weights) -{ - Q_D(QMorphingAnimation); - if (d->m_weights.size() < positionIndex) - d->m_weights.resize(positionIndex + 1); - if (d->m_weights[positionIndex] == nullptr) - d->m_weights[positionIndex] = new QVector(); - *d->m_weights[positionIndex] = weights; -} - -QVector QMorphingAnimation::getWeights(int positionIndex) -{ - Q_D(QMorphingAnimation); - return *d->m_weights[positionIndex]; -} - -QVector QMorphingAnimation::morphTargetList() -{ - Q_D(QMorphingAnimation); - return d->m_morphTargets; -} - -void QMorphingAnimation::setTargetName(const QString name) -{ - Q_D(QMorphingAnimation); - if (d->m_targetName != name) { - d->m_targetName = name; - emit targetNameChanged(name); - } -} - -void QMorphingAnimation::setMethod(QMorphingAnimation::Method method) -{ - Q_D(QMorphingAnimation); - if (d->m_method != method) { - d->m_method = method; - emit methodChanged(method); - } -} - -void QMorphingAnimation::setEasing(QEasingCurve::Type easing) -{ - Q_D(QMorphingAnimation); - if (d->m_easing.type() != easing) { - d->m_easing.setType(easing); - emit easingChanged(easing); - } -} - -void QMorphingAnimation::updateAnimation(float position) -{ - Q_D(QMorphingAnimation); - d->updateAnimation(position); -} - -} // Qt3DExtras - -QT_END_NAMESPACE diff --git a/src/extras/animations/qmorphinganimation.h b/src/extras/animations/qmorphinganimation.h deleted file mode 100644 index f8ca71ec9..000000000 --- a/src/extras/animations/qmorphinganimation.h +++ /dev/null @@ -1,116 +0,0 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ - -#ifndef QT3DEXTRAS_QMORPHINGANIMATION_H -#define QT3DEXTRAS_QMORPHINGANIMATION_H - -#include - -#include -#include -#include - -#include - -QT_BEGIN_NAMESPACE - -namespace Qt3DExtras { - -class QMorphingAnimationPrivate; - -class QT3DEXTRASSHARED_EXPORT QMorphingAnimation : public QAbstractAnimation -{ - Q_OBJECT - Q_PROPERTY(QVector targetPositions READ targetPositions WRITE setTargetPositions NOTIFY targetPositionsChanged) - Q_PROPERTY(float interpolator READ interpolator NOTIFY interpolatorChanged) - Q_PROPERTY(Qt3DRender::QGeometryRenderer *target READ target WRITE setTarget NOTIFY targetChanged) - Q_PROPERTY(QString targetName READ targetName WRITE setTargetName NOTIFY targetNameChanged) - Q_PROPERTY(QMorphingAnimation::Method method READ method WRITE setMethod NOTIFY methodChanged) - Q_PROPERTY(QEasingCurve::Type easing READ easing WRITE setEasing NOTIFY easingChanged) - -public: - enum Method - { - Normalized, - Relative - }; - Q_ENUM(Method) - - explicit QMorphingAnimation(QObject *parent = nullptr); - - QVector targetPositions() const; - float interpolator() const; - Qt3DRender::QGeometryRenderer *target() const; - QString targetName() const; - QMorphingAnimation::Method method() const; - QEasingCurve::Type easing() const; - - void setMorphTargets(const QVector &targets); - void addMorphTarget(Qt3DExtras::QMorphTarget *target); - void removeMorphTarget(Qt3DExtras::QMorphTarget *target); - - void setWeights(int positionIndex, const QVector &weights); - QVector getWeights(int positionIndex); - - QVector morphTargetList(); - -public Q_SLOTS: - void setTargetPositions(const QVector &targetPositions); - void setTarget(Qt3DRender::QGeometryRenderer *target); - void setTargetName(const QString name); - void setMethod(QMorphingAnimation::Method method); - void setEasing(QEasingCurve::Type easing); - -Q_SIGNALS: - void targetPositionsChanged(const QVector &targetPositions); - void interpolatorChanged(float interpolator); - void targetChanged(Qt3DRender::QGeometryRenderer *target); - void targetNameChanged(const QString &name); - void methodChanged(QMorphingAnimation::Method method); - void easingChanged(QEasingCurve::Type easing); - -private: - - void updateAnimation(float position); - - Q_DECLARE_PRIVATE(QMorphingAnimation) -}; - -} // Qt3DExtras - -QT_END_NAMESPACE - -#endif // QT3DEXTRAS_QMORPHINGANIMATION_H diff --git a/src/extras/animations/qmorphinganimation_p.h b/src/extras/animations/qmorphinganimation_p.h deleted file mode 100644 index e4a18f199..000000000 --- a/src/extras/animations/qmorphinganimation_p.h +++ /dev/null @@ -1,93 +0,0 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ - -#ifndef QT3DEXTRAS_QMORPHINGANIMATION_P_H -#define QT3DEXTRAS_QMORPHINGANIMATION_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of other Qt classes. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include -#include - -#include -#include - -QT_BEGIN_NAMESPACE - -namespace Qt3DExtras { - -class QMorphingAnimationPrivate : public QAbstractAnimationPrivate -{ -public: - QMorphingAnimationPrivate(); - ~QMorphingAnimationPrivate(); - - void updateAnimation(float position); - void setTargetInterpolated(int morphTarget); - - QVector m_targetPositions; - QVector*> m_weights; - QVector m_morphKey; - QStringList m_attributeNames; - QVector m_morphTargets; - QMorphTarget *m_flattened; - QMorphingAnimation::Method m_method; - QEasingCurve m_easing; - float m_interpolator; - Qt3DRender::QGeometryRenderer *m_target; - QString m_targetName; - - QMorphTarget *m_currentTarget; - - QMetaObject::Connection m_positionConnection; - - Q_DECLARE_PUBLIC(QMorphingAnimation) -}; - -} // Qt3DExtras - -QT_END_NAMESPACE - -#endif // QT3DEXTRAS_QMORPHINGANIMATION_P_H diff --git a/src/extras/animations/qmorphtarget.cpp b/src/extras/animations/qmorphtarget.cpp deleted file mode 100644 index 0c327a490..000000000 --- a/src/extras/animations/qmorphtarget.cpp +++ /dev/null @@ -1,120 +0,0 @@ -/**************************************************************************** -** -** 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 "qmorphtarget.h" -#include "Qt3DExtras/private/qmorphtarget_p.h" - -QT_BEGIN_NAMESPACE - -namespace Qt3DExtras { - -QMorphTargetPrivate::QMorphTargetPrivate() - : QObjectPrivate() -{ - -} - -void QMorphTargetPrivate::updateAttributeNames() -{ - m_attributeNames.clear(); - for (const Qt3DRender::QAttribute *attr : m_targetAttributes) - m_attributeNames.push_back(attr->name()); -} - -QMorphTarget::QMorphTarget(QObject *parent) - : QObject(*new QMorphTargetPrivate, parent) -{ - -} - -QVector QMorphTarget::attributeList() const -{ - Q_D(const QMorphTarget); - return d->m_targetAttributes; -} - -QStringList QMorphTarget::attributeNames() const -{ - Q_D(const QMorphTarget); - return d->m_attributeNames; -} - -void QMorphTarget::setAttributes(const QVector &attributes) -{ - Q_D(QMorphTarget); - d->m_targetAttributes = attributes; - d->m_attributeNames.clear(); - for (const Qt3DRender::QAttribute *attr : attributes) - d->m_attributeNames.push_back(attr->name()); - - emit attributeNamesChanged(d->m_attributeNames); -} - -void QMorphTarget::addAttribute(Qt3DRender::QAttribute *attribute) -{ - Q_D(QMorphTarget); - for (const Qt3DRender::QAttribute *attr : d->m_targetAttributes) { - if (attr->name() == attribute->name()) - return; - } - d->m_targetAttributes.push_back(attribute); - d->m_attributeNames.push_back(attribute->name()); - emit attributeNamesChanged(d->m_attributeNames); -} - -void QMorphTarget::removeAttribute(Qt3DRender::QAttribute *attribute) -{ - Q_D(QMorphTarget); - if (d->m_targetAttributes.contains(attribute)) { - d->m_targetAttributes.removeAll(attribute); - d->updateAttributeNames(); - emit attributeNamesChanged(d->m_attributeNames); - } -} - -QMorphTarget *QMorphTarget::fromGeometry(Qt3DRender::QGeometry *geometry, const QStringList &attributes) -{ - QMorphTarget *target = new QMorphTarget(); - for (Qt3DRender::QAttribute *attr : geometry->attributes()) { - if (attributes.contains(attr->name())) - target->addAttribute(attr); - } - return target; -} - -} // Qt3DExtras - -QT_END_NAMESPACE diff --git a/src/extras/animations/qmorphtarget.h b/src/extras/animations/qmorphtarget.h deleted file mode 100644 index 64c3037cb..000000000 --- a/src/extras/animations/qmorphtarget.h +++ /dev/null @@ -1,83 +0,0 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ - -#ifndef QT3DEXTRAS_QMORPHTARGET_H -#define QT3DEXTRAS_QMORPHTARGET_H - -#include -#include - -#include - -#include - -QT_BEGIN_NAMESPACE - -namespace Qt3DExtras { - -class QMorphTargetPrivate; - -class QT3DEXTRASSHARED_EXPORT QMorphTarget : public QObject -{ - Q_OBJECT - Q_PROPERTY(QStringList attributeNames READ attributeNames NOTIFY attributeNamesChanged) - -public: - explicit QMorphTarget(QObject *parent = nullptr); - - QVector attributeList() const; - QStringList attributeNames() const; - - void setAttributes(const QVector &attributes); - void addAttribute(Qt3DRender::QAttribute *attribute); - void removeAttribute(Qt3DRender::QAttribute *attribute); - - Q_INVOKABLE static QMorphTarget *fromGeometry(Qt3DRender::QGeometry *geometry, - const QStringList &attributes); - -Q_SIGNALS: - void attributeNamesChanged(const QStringList &attributeNames); - -private: - - Q_DECLARE_PRIVATE(QMorphTarget) -}; - -} // Qt3DExtras - -QT_END_NAMESPACE - -#endif // QT3DEXTRAS_QMORPHTARGET_H diff --git a/src/extras/animations/qmorphtarget_p.h b/src/extras/animations/qmorphtarget_p.h deleted file mode 100644 index 7d42f8eb4..000000000 --- a/src/extras/animations/qmorphtarget_p.h +++ /dev/null @@ -1,76 +0,0 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ - -#ifndef QT3DEXTRAS_QMORPHTARGET_P_H -#define QT3DEXTRAS_QMORPHTARGET_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of other Qt classes. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include - -#include - -QT_BEGIN_NAMESPACE - -namespace Qt3DExtras { - -class QMorphTargetPrivate : public QObjectPrivate -{ -public: - QMorphTargetPrivate(); - - void updateAttributeNames(); - - QStringList m_attributeNames; - QVector m_targetAttributes; - - Q_DECLARE_PUBLIC(QMorphTarget) -}; - -} // Qt3DExtras - -QT_END_NAMESPACE - -#endif // QT3DEXTRAS_QMORPHTARGET_P_H diff --git a/src/extras/animations/qvertexblendanimation.cpp b/src/extras/animations/qvertexblendanimation.cpp deleted file mode 100644 index 1b45992fe..000000000 --- a/src/extras/animations/qvertexblendanimation.cpp +++ /dev/null @@ -1,234 +0,0 @@ -/**************************************************************************** -** -** 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 "qvertexblendanimation.h" - -#include - -QT_BEGIN_NAMESPACE - -namespace Qt3DExtras { - -QVertexBlendAnimationPrivate::QVertexBlendAnimationPrivate() - : QAbstractAnimationPrivate(QAbstractAnimation::VertexBlendAnimation) - , m_currentBase(nullptr) - , m_currentTarget(nullptr) -{ - -} - -void QVertexBlendAnimationPrivate::getAttributesInPosition(float position, int *target0, - int *target1, float *interpolator) -{ - if (position < m_targetPositions.first()) { - *target0 = 0; - *target1 = qMin(1, m_targetPositions.size()); - *interpolator = 0.0f; - } else if (position > m_targetPositions.last()) { - *target0 = qMax(m_targetPositions.size() - 2, 0); - *target1 = qMax(m_targetPositions.size() - 1, 0); - *interpolator = 1.0f; - } else { - for (int i = 0; i < m_targetPositions.size() - 1; i++) { - if (position >= m_targetPositions[i] && position < m_targetPositions[i + 1]) { - *target0 = i; - *target1 = i + 1; - float a = (position - m_targetPositions[i]) - / (m_targetPositions[i + 1] - m_targetPositions[i]); - *interpolator = a; - } - } - } -} - -static Qt3DRender::QAttribute *findAttribute(QVector &attributes, - QString name) -{ - for (Qt3DRender::QAttribute *gattr : attributes) { - if (gattr->name() == name) - return gattr; - } - return nullptr; -} - -void QVertexBlendAnimationPrivate::updateAnimation(float position) -{ - Q_Q(QVertexBlendAnimation); - if (!m_target || !m_target->geometry()) - return; - - Qt3DExtras::QMorphTarget *base; - Qt3DExtras::QMorphTarget *target; - int target0, target1; - float interpolator; - getAttributesInPosition(position, &target0, &target1, &interpolator); - - base = m_morphTargets.at(target0); - target = m_morphTargets.at(target1); - - Qt3DRender::QGeometry *geometry = m_target->geometry(); - - // remove attributes from previous frame - if ((m_currentBase && (base != m_currentBase)) - || (m_currentTarget && (target != m_currentTarget))) { - const QVector baseAttributes = m_currentBase->attributeList(); - const QVector targetAttributes = m_currentTarget->attributeList(); - for (int i = 0; i < baseAttributes.size(); ++i) { - geometry->removeAttribute(baseAttributes.at(i)); - geometry->removeAttribute(targetAttributes.at(i)); - } - } - - const QVector baseAttributes = base->attributeList(); - const QVector targetAttributes = target->attributeList(); - const QStringList attributeNames = base->attributeNames(); - - // add attributes from current frame to the geometry - if (base != m_currentBase || target != m_currentTarget) { - for (int i = 0; i < baseAttributes.size(); ++i) { - const QString baseName = attributeNames.at(i); - QString targetName = baseName; - targetName.append("Target"); - - baseAttributes[i]->setName(baseName); - geometry->addAttribute(baseAttributes.at(i)); - targetAttributes[i]->setName(targetName); - geometry->addAttribute(targetAttributes.at(i)); - } - } - m_currentBase = base; - m_currentTarget = target; - - if (!qFuzzyCompare(interpolator, m_interpolator)) { - m_interpolator = interpolator; - emit q->interpolatorChanged(interpolator); - } -} - -QVertexBlendAnimation::QVertexBlendAnimation(QObject *parent) - : QAbstractAnimation(*new QVertexBlendAnimationPrivate, parent) -{ - Q_D(QVertexBlendAnimation); - d->m_positionConnection = QObject::connect(this, &QAbstractAnimation::positionChanged, - this, &QVertexBlendAnimation::updateAnimation); -} - -QVector QVertexBlendAnimation::targetPositions() const -{ - Q_D(const QVertexBlendAnimation); - return d->m_targetPositions; -} - -float QVertexBlendAnimation::interpolator() const -{ - Q_D(const QVertexBlendAnimation); - return d->m_interpolator; -} - -Qt3DRender::QGeometryRenderer *QVertexBlendAnimation::target() const -{ - Q_D(const QVertexBlendAnimation); - return d->m_target; -} - -QString QVertexBlendAnimation::targetName() const -{ - Q_D(const QVertexBlendAnimation); - return d->m_targetName; -} - -void QVertexBlendAnimation::setMorphTargets(const QVector &targets) -{ - Q_D(QVertexBlendAnimation); - d->m_morphTargets = targets; -} - -void QVertexBlendAnimation::addMorphTarget(Qt3DExtras::QMorphTarget *target) -{ - Q_D(QVertexBlendAnimation); - if (!d->m_morphTargets.contains(target)) - d->m_morphTargets.push_back(target); -} - -void QVertexBlendAnimation::removeMorphTarget(Qt3DExtras::QMorphTarget *target) -{ - Q_D(QVertexBlendAnimation); - d->m_morphTargets.removeAll(target); -} - -void QVertexBlendAnimation::setTargetPositions(const QVector &targetPositions) -{ - Q_D(QVertexBlendAnimation); - if (d->m_targetPositions == targetPositions) - return; - d->m_targetPositions = targetPositions; - emit targetPositionsChanged(targetPositions); - setDuration(d->m_targetPositions.last()); -} - -void QVertexBlendAnimation::setTarget(Qt3DRender::QGeometryRenderer *target) -{ - Q_D(QVertexBlendAnimation); - if (d->m_target != target) { - d->m_target = target; - emit targetChanged(target); - } -} - -QVector QVertexBlendAnimation::morphTargetList() -{ - Q_D(QVertexBlendAnimation); - return d->m_morphTargets; -} - -void QVertexBlendAnimation::setTargetName(const QString name) -{ - Q_D(QVertexBlendAnimation); - if (d->m_targetName != name) { - d->m_targetName = name; - emit targetNameChanged(name); - } -} - -void QVertexBlendAnimation::updateAnimation(float position) -{ - Q_D(QVertexBlendAnimation); - d->updateAnimation(position); -} - -} // Qt3DExtras - -QT_END_NAMESPACE diff --git a/src/extras/animations/qvertexblendanimation.h b/src/extras/animations/qvertexblendanimation.h deleted file mode 100644 index ebd313e83..000000000 --- a/src/extras/animations/qvertexblendanimation.h +++ /dev/null @@ -1,96 +0,0 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ - -#ifndef QT3DEXTRAS_QVERTEXBLENDANIMATION_H -#define QT3DEXTRAS_QVERTEXBLENDANIMATION_H - -#include -#include -#include - -#include - -QT_BEGIN_NAMESPACE - -namespace Qt3DExtras { - -class QVertexBlendAnimationPrivate; - -class QT3DEXTRASSHARED_EXPORT QVertexBlendAnimation : public QAbstractAnimation -{ - Q_OBJECT - Q_PROPERTY(QVector targetPositions READ targetPositions WRITE setTargetPositions NOTIFY targetPositionsChanged) - Q_PROPERTY(float interpolator READ interpolator NOTIFY interpolatorChanged) - Q_PROPERTY(Qt3DRender::QGeometryRenderer *target READ target WRITE setTarget NOTIFY targetChanged) - Q_PROPERTY(QString targetName READ targetName WRITE setTargetName NOTIFY targetNameChanged) - -public: - explicit QVertexBlendAnimation(QObject *parent = nullptr); - - QVector targetPositions() const; - float interpolator() const; - Qt3DRender::QGeometryRenderer *target() const; - QString targetName() const; - - void setMorphTargets(const QVector &targets); - void addMorphTarget(Qt3DExtras::QMorphTarget *target); - void removeMorphTarget(Qt3DExtras::QMorphTarget *target); - - QVector morphTargetList(); - -public Q_SLOTS: - void setTargetPositions(const QVector &targetPositions); - void setTarget(Qt3DRender::QGeometryRenderer *target); - void setTargetName(const QString name); - -Q_SIGNALS: - void targetPositionsChanged(const QVector &targetPositions); - void interpolatorChanged(float interpolator); - void targetChanged(Qt3DRender::QGeometryRenderer *target); - void targetNameChanged(const QString &name); - -private: - - void updateAnimation(float position); - - Q_DECLARE_PRIVATE(QVertexBlendAnimation) -}; - -} // Qt3DExtras - -QT_END_NAMESPACE - -#endif // QT3DEXTRAS_QVERTEXBLENDANIMATION_H diff --git a/src/extras/animations/qvertexblendanimation_p.h b/src/extras/animations/qvertexblendanimation_p.h deleted file mode 100644 index 812953e04..000000000 --- a/src/extras/animations/qvertexblendanimation_p.h +++ /dev/null @@ -1,86 +0,0 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ - -#ifndef QT3DEXTRAS_QVERTEXBLENDANIMATION_P_H -#define QT3DEXTRAS_QVERTEXBLENDANIMATION_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of other Qt classes. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - - -#include - -#include -#include - -QT_BEGIN_NAMESPACE - -namespace Qt3DExtras { - -class QVertexBlendAnimationPrivate : public QAbstractAnimationPrivate -{ -public: - QVertexBlendAnimationPrivate(); - - void getAttributesInPosition(float position, int *target0, int *target1, float *interpolator); - void updateAnimation(float position); - - QVector m_targetPositions; - QVector m_morphTargets; - float m_interpolator; - Qt3DRender::QGeometryRenderer *m_target; - QString m_targetName; - QMorphTarget *m_currentBase; - QMorphTarget *m_currentTarget; - - QMetaObject::Connection m_positionConnection; - - Q_DECLARE_PUBLIC(QVertexBlendAnimation) -}; - -} // Qt3DExtras - -QT_END_NAMESPACE - -#endif // QT3DEXTRAS_QVertexBlendANIMATION_P_H diff --git a/src/extras/extras.pro b/src/extras/extras.pro index 51c9f8cd4..22c9fcb93 100644 --- a/src/extras/extras.pro +++ b/src/extras/extras.pro @@ -9,7 +9,6 @@ DEFINES += QT_NO_FOREACH load(qt_module) -include (animations/animations.pri) include (geometries/geometries.pri) include (3dtext/3dtext.pri) include (defaults/defaults.pri) diff --git a/src/plugins/sceneparsers/assimp/assimp.pro b/src/plugins/sceneparsers/assimp/assimp.pro index da8393f0c..28abef2b8 100644 --- a/src/plugins/sceneparsers/assimp/assimp.pro +++ b/src/plugins/sceneparsers/assimp/assimp.pro @@ -1,5 +1,5 @@ TARGET = assimpsceneimport -QT += core-private 3dcore 3dcore-private 3drender 3drender-private 3dextras +QT += core-private 3dcore 3dcore-private 3drender 3drender-private 3dextras 3danimation include(../../../3rdparty/assimp/assimp_dependency.pri) diff --git a/src/plugins/sceneparsers/assimp/assimpimporter.cpp b/src/plugins/sceneparsers/assimp/assimpimporter.cpp index 66c219fe9..02773877e 100644 --- a/src/plugins/sceneparsers/assimp/assimpimporter.cpp +++ b/src/plugins/sceneparsers/assimp/assimpimporter.cpp @@ -55,8 +55,8 @@ #include #include #include -#include -#include +#include +#include #include #include #include @@ -420,7 +420,7 @@ Qt3DCore::QEntity *AssimpImporter::scene(const QString &id) if (m_scene->m_animations.size() > 0) { qWarning() << "No target found for " << m_scene->m_animations.size() << " animations!"; - for (Qt3DExtras::QKeyframeAnimation *anim : m_scene->m_animations) + for (Qt3DAnimation::QKeyframeAnimation *anim : m_scene->m_animations) delete anim; m_scene->m_animations.clear(); } @@ -472,24 +472,24 @@ Qt3DCore::QEntity *AssimpImporter::node(aiNode *node) if (m_scene->m_materials.contains(materialIndex)) material = m_scene->m_materials[materialIndex]; - QList morphingAnimations - = mesh->findChildren(); + QList morphingAnimations + = mesh->findChildren(); if (morphingAnimations.size() > 0) { material = new Qt3DExtras::QMorphPhongMaterial(entityNode); - QVector animations; - findAnimationsForNode(m_scene->m_morphAnimations, + QVector animations; + findAnimationsForNode(m_scene->m_morphAnimations, animations, aiStringToQString(node->mName)); const auto morphTargetList = morphingAnimations.at(0)->morphTargetList(); - for (Qt3DExtras::QMorphingAnimation *anim : animations) { + for (Qt3DAnimation::QMorphingAnimation *anim : animations) { anim->setParent(entityNode); anim->setTarget(mesh); anim->setMorphTargets(morphTargetList); } for (int j = 0; j < animations.size(); ++j) { - QObject::connect(animations[j], &Qt3DExtras::QMorphingAnimation::interpolatorChanged, + QObject::connect(animations[j], &Qt3DAnimation::QMorphingAnimation::interpolatorChanged, (Qt3DExtras::QMorphPhongMaterial *)material, &Qt3DExtras::QMorphPhongMaterial::setInterpolator); } @@ -530,12 +530,12 @@ Qt3DCore::QEntity *AssimpImporter::node(aiNode *node) transform->setMatrix(qTransformMatrix); entityNode->addComponent(transform); - QVector animations; - findAnimationsForNode(m_scene->m_animations, + QVector animations; + findAnimationsForNode(m_scene->m_animations, animations, aiStringToQString(node->mName)); - for (Qt3DExtras::QKeyframeAnimation *anim : animations) { + for (Qt3DAnimation::QKeyframeAnimation *anim : animations) { anim->setTarget(transform); anim->setParent(entityNode); } @@ -792,10 +792,10 @@ void AssimpImporter::loadMesh(uint meshIndex) if (animesh->mNumVertices != mesh->mNumVertices) return; - Qt3DExtras::QMorphingAnimation *morphingAnimation - = new Qt3DExtras::QMorphingAnimation(geometryRenderer); + Qt3DAnimation::QMorphingAnimation *morphingAnimation + = new Qt3DAnimation::QMorphingAnimation(geometryRenderer); QVector names; - QVector targets; + QVector targets; uint voff = 0; uint noff = 0; uint tanoff = 0; @@ -835,7 +835,7 @@ void AssimpImporter::loadMesh(uint meshIndex) for (uint i = 0; i < mesh->mNumAnimMeshes; i++) { aiAnimMesh *animesh = mesh->mAnimMeshes[i]; - Qt3DExtras::QMorphTarget *target = new Qt3DExtras::QMorphTarget(geometryRenderer); + Qt3DAnimation::QMorphTarget *target = new Qt3DAnimation::QMorphTarget(geometryRenderer); targets.push_back(target); QVector attributes; QByteArray targetBufferArray; @@ -1029,7 +1029,7 @@ void AssimpImporter::loadAnimation(uint animationIndex) aiNodeAnim *nodeAnim = assimpAnim->mChannels[i]; aiNode *targetNode = m_scene->m_aiScene->mRootNode->FindNode(nodeAnim->mNodeName); - Qt3DExtras::QKeyframeAnimation *kfa = new Qt3DExtras::QKeyframeAnimation(); + Qt3DAnimation::QKeyframeAnimation *kfa = new Qt3DAnimation::QKeyframeAnimation(); QVector positions; QVector transforms; if ((nodeAnim->mNumPositionKeys > 1) @@ -1102,7 +1102,7 @@ void AssimpImporter::loadAnimation(uint animationIndex) aiNode *targetNode = m_scene->m_aiScene->mRootNode->FindNode(morphAnim->mName); aiMesh *mesh = m_scene->m_aiScene->mMeshes[targetNode->mMeshes[0]]; - Qt3DExtras::QMorphingAnimation *morphingAnimation = new Qt3DExtras::QMorphingAnimation; + Qt3DAnimation::QMorphingAnimation *morphingAnimation = new Qt3DAnimation::QMorphingAnimation; QVector positions; positions.resize(morphAnim->mNumKeys); // set so that weights array is allocated to correct size in morphingAnimation @@ -1125,8 +1125,8 @@ void AssimpImporter::loadAnimation(uint animationIndex) morphingAnimation->setAnimationName(QString(assimpAnim->mName.C_Str())); morphingAnimation->setTargetName(QString(targetNode->mName.C_Str())); morphingAnimation->setMethod((mesh->mMethod == aiMorphingMethod_MORPH_NORMALIZED) - ? Qt3DExtras::QMorphingAnimation::Normalized - : Qt3DExtras::QMorphingAnimation::Relative); + ? Qt3DAnimation::QMorphingAnimation::Normalized + : Qt3DAnimation::QMorphingAnimation::Relative); m_scene->m_morphAnimations.push_back(morphingAnimation); } } diff --git a/src/plugins/sceneparsers/assimp/assimpimporter.h b/src/plugins/sceneparsers/assimp/assimpimporter.h index 0d2c0c9e5..aa7258840 100644 --- a/src/plugins/sceneparsers/assimp/assimpimporter.h +++ b/src/plugins/sceneparsers/assimp/assimpimporter.h @@ -72,7 +72,7 @@ namespace Qt3DCore { class QCamera; } -namespace Qt3DExtras { +namespace Qt3DAnimation { class QKeyframeAnimation; class QMorphingAnimation; } @@ -144,8 +144,8 @@ private: QMap m_materialTextures; QMap m_cameras; QHash m_textureToParameterName; - QVector m_animations; - QVector m_morphAnimations; + QVector m_animations; + QVector m_morphAnimations; // QMap m_lights; }; diff --git a/src/quick3d/imports/animation/qt3dquick3danimationplugin.cpp b/src/quick3d/imports/animation/qt3dquick3danimationplugin.cpp index 85c2afee9..bd54f73e8 100644 --- a/src/quick3d/imports/animation/qt3dquick3danimationplugin.cpp +++ b/src/quick3d/imports/animation/qt3dquick3danimationplugin.cpp @@ -45,9 +45,22 @@ #include #include #include + +#include +#include +#include +#include +#include +#include + #include #include #include +#include +#include +#include +#include +#include QT_BEGIN_NAMESPACE @@ -67,6 +80,13 @@ void Qt3DQuick3DAnimationPlugin::registerTypes(const char *uri) Qt3DAnimation::Animation::Quick::Quick3DAbstractClipBlendNode>(uri, 2, 2, "AbstractClipBlendNode", QStringLiteral("QAbstractClipBlendNode is abstract")); qmlRegisterType(uri, 2, 2, "LerpBlend"); qmlRegisterType(uri, 2, 2, "AdditiveBlend"); + + qmlRegisterUncreatableType(uri, 2, 2, "AbstractAnimation", QStringLiteral("AbstractAnimation is abstract")); + qmlRegisterExtendedType(uri, 2, 2, "KeyframeAnimation"); + qmlRegisterExtendedType(uri, 2, 2, "AnimationGroup"); + qmlRegisterExtendedType(uri, 2, 2, "AnimationController"); + qmlRegisterExtendedType(uri, 2, 2, "MorphingAnimation"); + qmlRegisterExtendedType(uri, 2, 2, "MorphTarget"); } QT_END_NAMESPACE diff --git a/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp b/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp index f8cfc5be9..823670e8d 100644 --- a/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp +++ b/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp @@ -72,18 +72,6 @@ #include #include #include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include #include @@ -136,13 +124,6 @@ void Qt3DQuick3DExtrasPlugin::registerTypes(const char *uri) qmlRegisterType(uri, 2, 2, "DistanceFieldGlyphCache"); qmlRegisterType(uri, 2, 2, "DistanceFieldText"); - - qmlRegisterUncreatableType(uri, 2, 2, "AbstractAnimation", QStringLiteral("AbstractAnimation is abstract")); - qmlRegisterExtendedType(uri, 2, 2, "KeyframeAnimation"); - qmlRegisterExtendedType(uri, 2, 2, "AnimationGroup"); - qmlRegisterExtendedType(uri, 2, 2, "AnimationController"); - qmlRegisterExtendedType(uri, 2, 2, "MorphingAnimation"); - qmlRegisterExtendedType(uri, 2, 2, "MorphTarget"); } diff --git a/src/quick3d/quick3danimation/items/items.pri b/src/quick3d/quick3danimation/items/items.pri index 0c3511902..1c88df570 100644 --- a/src/quick3d/quick3danimation/items/items.pri +++ b/src/quick3d/quick3danimation/items/items.pri @@ -1,9 +1,19 @@ SOURCES += \ $$PWD/quick3dchannelmapper.cpp \ - $$PWD/quick3dabstractclipblendnode.cpp + $$PWD/quick3dabstractclipblendnode.cpp \ + $$PWD/quick3danimationcontroller.cpp \ + $$PWD/quick3danimationgroup.cpp \ + $$PWD/quick3dkeyframeanimation.cpp \ + $$PWD/quick3dmorphinganimation.cpp \ + $$PWD/quick3dmorphtarget.cpp HEADERS += \ $$PWD/quick3dchannelmapper_p.h \ - $$PWD/quick3dabstractclipblendnode_p.h + $$PWD/quick3dabstractclipblendnode_p.h \ + $$PWD/quick3danimationcontroller_p.h \ + $$PWD/quick3danimationgroup_p.h \ + $$PWD/quick3dkeyframeanimation_p.h \ + $$PWD/quick3dmorphinganimation_p.h \ + $$PWD/quick3dmorphtarget_p.h INCLUDEPATH += $$PWD diff --git a/src/quick3d/quick3danimation/items/quick3danimationcontroller.cpp b/src/quick3d/quick3danimation/items/quick3danimationcontroller.cpp new file mode 100644 index 000000000..dc6183989 --- /dev/null +++ b/src/quick3d/quick3danimation/items/quick3danimationcontroller.cpp @@ -0,0 +1,95 @@ +/**************************************************************************** +** +** 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 "quick3danimationcontroller_p.h" + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { +namespace Quick { + +QQuick3DAnimationController::QQuick3DAnimationController(QObject *parent) + : QObject(parent) +{ +} + +QQmlListProperty QQuick3DAnimationController::animationGroups() +{ + return QQmlListProperty(this, 0, + &QQuick3DAnimationController::appendAnimationGroup, + &QQuick3DAnimationController::animationGroupCount, + &QQuick3DAnimationController::animationGroupAt, + &QQuick3DAnimationController::clearAnimationGroups); +} + + +void QQuick3DAnimationController::appendAnimationGroup(QQmlListProperty *list, QAnimationGroup *bar) +{ + QQuick3DAnimationController *controller = qobject_cast(list->object); + if (controller) + controller->parentAnimationController()->addAnimationGroup(bar); +} + +int QQuick3DAnimationController::animationGroupCount(QQmlListProperty *list) +{ + QQuick3DAnimationController *controller = qobject_cast(list->object); + if (controller) + return controller->parentAnimationController()->animationGroupList().count(); + return 0; +} + +QAnimationGroup *QQuick3DAnimationController::animationGroupAt(QQmlListProperty *list, int index) +{ + QQuick3DAnimationController *controller = qobject_cast(list->object); + if (controller) + return qobject_cast(controller->parentAnimationController()->getGroup(index)); + return nullptr; +} + +void QQuick3DAnimationController::clearAnimationGroups(QQmlListProperty *list) +{ + QQuick3DAnimationController *controller = qobject_cast(list->object); + if (controller) { + QVector emptyList; + controller->parentAnimationController()->setAnimationGroups(emptyList); + } +} + + +} // namespace Quick +} // namespace Qt3DAnimation + +QT_END_NAMESPACE diff --git a/src/quick3d/quick3danimation/items/quick3danimationcontroller_p.h b/src/quick3d/quick3danimation/items/quick3danimationcontroller_p.h new file mode 100644 index 000000000..a3033e537 --- /dev/null +++ b/src/quick3d/quick3danimation/items/quick3danimationcontroller_p.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QT3DANIMATION_QUICK_QUICK3DANIMATIONCONTROLLER_P_H +#define QT3DANIMATION_QUICK_QUICK3DANIMATIONCONTROLLER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { +namespace Quick { + +class QT3DQUICKANIMATIONSHARED_PRIVATE_EXPORT QQuick3DAnimationController : public QObject +{ + Q_OBJECT + Q_PROPERTY(QQmlListProperty animationGroups READ animationGroups) + +public: + + explicit QQuick3DAnimationController(QObject *parent = nullptr); + + inline Qt3DAnimation::QAnimationController *parentAnimationController() const + { + return qobject_cast(parent()); + } + + QQmlListProperty animationGroups(); + +private: + + static void appendAnimationGroup(QQmlListProperty *list, Qt3DAnimation::QAnimationGroup *bar); + static QAnimationGroup *animationGroupAt(QQmlListProperty *list, int index); + static int animationGroupCount(QQmlListProperty *list); + static void clearAnimationGroups(QQmlListProperty *list); +}; + +} // namespace Quick +} // namespace Qt3DAnimation + +QT_END_NAMESPACE + +#endif // QT3DRENDER_RENDER_QUICK_QUICK3DEFFECT_P_H diff --git a/src/quick3d/quick3danimation/items/quick3danimationgroup.cpp b/src/quick3d/quick3danimation/items/quick3danimationgroup.cpp new file mode 100644 index 000000000..f10450280 --- /dev/null +++ b/src/quick3d/quick3danimation/items/quick3danimationgroup.cpp @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** 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 "quick3danimationgroup_p.h" + +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { +namespace Quick { + +QQuick3DAnimationGroup::QQuick3DAnimationGroup(QObject *parent) + : QObject(parent) +{ +} + +QQmlListProperty QQuick3DAnimationGroup::animations() +{ + return QQmlListProperty(this, 0, + &QQuick3DAnimationGroup::appendAnimation, + &QQuick3DAnimationGroup::animationCount, + &QQuick3DAnimationGroup::animationAt, + &QQuick3DAnimationGroup::clearAnimation); +} + + +void QQuick3DAnimationGroup::appendAnimation(QQmlListProperty *list, + Qt3DAnimation::QAbstractAnimation *animation) +{ + QQuick3DAnimationGroup *animationGroup = qobject_cast(list->object); + if (animationGroup) + animationGroup->parentAnimationGroup()->addAnimation(animation); +} + +int QQuick3DAnimationGroup::animationCount(QQmlListProperty *list) +{ + QQuick3DAnimationGroup *animationGroup = qobject_cast(list->object); + if (animationGroup) + return animationGroup->parentAnimationGroup()->animationList().count(); + return 0; +} + +Qt3DAnimation::QAbstractAnimation *QQuick3DAnimationGroup::animationAt(QQmlListProperty *list, int index) +{ + QQuick3DAnimationGroup *animationGroup = qobject_cast(list->object); + if (animationGroup) { + return qobject_cast( + animationGroup->parentAnimationGroup()->animationList().at(index)); + } + return nullptr; +} + +void QQuick3DAnimationGroup::clearAnimation(QQmlListProperty *list) +{ + QQuick3DAnimationGroup *animationGroup = qobject_cast(list->object); + if (animationGroup) { + QVector emptyList; + animationGroup->parentAnimationGroup()->setAnimations(emptyList); + } +} + +} // namespace Quick +} // namespace Qt3DAnimation + +QT_END_NAMESPACE diff --git a/src/quick3d/quick3danimation/items/quick3danimationgroup_p.h b/src/quick3d/quick3danimation/items/quick3danimationgroup_p.h new file mode 100644 index 000000000..aef202480 --- /dev/null +++ b/src/quick3d/quick3danimation/items/quick3danimationgroup_p.h @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QT3DANIMATION_QUICK_QUICK3DANIMATIONGROUP_P_H +#define QT3DANIMATION_QUICK_QUICK3DANIMATIONGROUP_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { +namespace Quick { + +class QT3DQUICKANIMATIONSHARED_PRIVATE_EXPORT QQuick3DAnimationGroup : public QObject +{ + Q_OBJECT + Q_PROPERTY(QQmlListProperty animations READ animations) + +public: + + explicit QQuick3DAnimationGroup(QObject *parent = nullptr); + + inline Qt3DAnimation::QAnimationGroup *parentAnimationGroup() const + { + return qobject_cast(parent()); + } + + QQmlListProperty animations(); + +private: + + static void appendAnimation(QQmlListProperty *list, Qt3DAnimation::QAbstractAnimation *animation); + static Qt3DAnimation::QAbstractAnimation *animationAt(QQmlListProperty *list, int index); + static int animationCount(QQmlListProperty *list); + static void clearAnimation(QQmlListProperty *list); +}; + +} // namespace Quick +} // namespace Qt3DAnimation + +QT_END_NAMESPACE + +#endif // QT3DRENDER_RENDER_QUICK_QUICK3DEFFECT_P_H diff --git a/src/quick3d/quick3danimation/items/quick3dkeyframeanimation.cpp b/src/quick3d/quick3danimation/items/quick3dkeyframeanimation.cpp new file mode 100644 index 000000000..f7cf133fe --- /dev/null +++ b/src/quick3d/quick3danimation/items/quick3dkeyframeanimation.cpp @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** 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 "quick3dkeyframeanimation_p.h" + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { +namespace Quick { + +QQuick3DKeyframeAnimation::QQuick3DKeyframeAnimation(QObject *parent) + : QObject(parent) +{ +} + +QQmlListProperty QQuick3DKeyframeAnimation::keyframes() +{ + return QQmlListProperty(this, 0, + &QQuick3DKeyframeAnimation::appendKeyframe, + &QQuick3DKeyframeAnimation::keyframeCount, + &QQuick3DKeyframeAnimation::keyframeAt, + &QQuick3DKeyframeAnimation::clearKeyframes); +} + +void QQuick3DKeyframeAnimation::appendKeyframe(QQmlListProperty *list, + Qt3DCore::QTransform *transform) +{ + QQuick3DKeyframeAnimation *keyframeAnimation + = qobject_cast(list->object); + if (keyframeAnimation) + keyframeAnimation->parentKeyframeAnimation()->addKeyframe(transform); +} + +int QQuick3DKeyframeAnimation::keyframeCount(QQmlListProperty *list) +{ + QQuick3DKeyframeAnimation *keyframeAnimation + = qobject_cast(list->object); + if (keyframeAnimation) + return keyframeAnimation->parentKeyframeAnimation()->keyframeList().count(); + return 0; +} + +Qt3DCore::QTransform *QQuick3DKeyframeAnimation::keyframeAt(QQmlListProperty *list, + int index) +{ + QQuick3DKeyframeAnimation *keyframeAnimation + = qobject_cast(list->object); + if (keyframeAnimation) { + return qobject_cast( + keyframeAnimation->parentKeyframeAnimation()->keyframeList().at(index)); + } + return nullptr; +} + +void QQuick3DKeyframeAnimation::clearKeyframes(QQmlListProperty *list) +{ + QQuick3DKeyframeAnimation *keyframeAnimation + = qobject_cast(list->object); + if (keyframeAnimation) { + QVector emptyList; + keyframeAnimation->parentKeyframeAnimation()->setKeyframes(emptyList); + } +} + +} // namespace Quick +} // namespace Qt3DAnimation + +QT_END_NAMESPACE diff --git a/src/quick3d/quick3danimation/items/quick3dkeyframeanimation_p.h b/src/quick3d/quick3danimation/items/quick3dkeyframeanimation_p.h new file mode 100644 index 000000000..944cdbe67 --- /dev/null +++ b/src/quick3d/quick3danimation/items/quick3dkeyframeanimation_p.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QT3DANIMATION_QUICK_QUICK3DKEYFRAMEANIMATION_P_H +#define QT3DANIMATION_QUICK_QUICK3DKEYFRAMEANIMATION_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +#include + +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { +namespace Quick { + +class QT3DQUICKANIMATIONSHARED_PRIVATE_EXPORT QQuick3DKeyframeAnimation : public QObject +{ + Q_OBJECT + Q_PROPERTY(QQmlListProperty keyframes READ keyframes) + +public: + QQuick3DKeyframeAnimation(QObject *parent = nullptr); + + inline QKeyframeAnimation *parentKeyframeAnimation() const + { + return qobject_cast(parent()); + } + + QQmlListProperty keyframes(); + +private: + + static void appendKeyframe(QQmlListProperty *list, + Qt3DCore::QTransform *transform); + static Qt3DCore::QTransform *keyframeAt(QQmlListProperty *list, + int index); + static int keyframeCount(QQmlListProperty *list); + static void clearKeyframes(QQmlListProperty *list); +}; + +} // namespace Quick +} // namespace Qt3DAnimation + +QT_END_NAMESPACE + +#endif // QT3DANIMATION_QUICK_QUICK3DKEYFRAMEANIMATION_P_H diff --git a/src/quick3d/quick3danimation/items/quick3dmorphinganimation.cpp b/src/quick3d/quick3danimation/items/quick3dmorphinganimation.cpp new file mode 100644 index 000000000..997e2e215 --- /dev/null +++ b/src/quick3d/quick3danimation/items/quick3dmorphinganimation.cpp @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** 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 "quick3dmorphinganimation_p.h" + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { +namespace Quick { + +QQuick3DMorphingAnimation::QQuick3DMorphingAnimation(QObject *parent) + : QObject(parent) +{ +} + +QQmlListProperty QQuick3DMorphingAnimation::morphTargets() +{ + return QQmlListProperty(this, 0, + &QQuick3DMorphingAnimation::appendMorphTarget, + &QQuick3DMorphingAnimation::morphTargetCount, + &QQuick3DMorphingAnimation::morphTargetAt, + &QQuick3DMorphingAnimation::clearMorphTargets); +} + +void QQuick3DMorphingAnimation::appendMorphTarget(QQmlListProperty *list, + Qt3DAnimation::QMorphTarget *morphTarget) +{ + QQuick3DMorphingAnimation *animation = qobject_cast(list->object); + if (animation) + animation->parentMorphingAnimation()->addMorphTarget(morphTarget); +} + +int QQuick3DMorphingAnimation::morphTargetCount(QQmlListProperty *list) +{ + QQuick3DMorphingAnimation *animation = qobject_cast(list->object); + if (animation) + return animation->parentMorphingAnimation()->morphTargetList().count(); + return 0; +} + +Qt3DAnimation::QMorphTarget *QQuick3DMorphingAnimation::morphTargetAt(QQmlListProperty *list, + int index) +{ + QQuick3DMorphingAnimation *animation = qobject_cast(list->object); + if (animation) { + return qobject_cast( + animation->parentMorphingAnimation()->morphTargetList().at(index)); + } + return nullptr; +} + +void QQuick3DMorphingAnimation::clearMorphTargets(QQmlListProperty *list) +{ + QQuick3DMorphingAnimation *animation = qobject_cast(list->object); + if (animation) { + QVector emptyList; + animation->parentMorphingAnimation()->setMorphTargets(emptyList); + } +} + +} // namespace Quick +} // namespace Qt3DAnimation + +QT_END_NAMESPACE diff --git a/src/quick3d/quick3danimation/items/quick3dmorphinganimation_p.h b/src/quick3d/quick3danimation/items/quick3dmorphinganimation_p.h new file mode 100644 index 000000000..31d008a89 --- /dev/null +++ b/src/quick3d/quick3danimation/items/quick3dmorphinganimation_p.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QT3DANIMATION_QUICK_QUICK3DMORPHINGANIMATION_P_H +#define QT3DANIMATION_QUICK_QUICK3DMORPHINGANIMATION_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +#include + +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { +namespace Quick { + +class QT3DQUICKANIMATIONSHARED_PRIVATE_EXPORT QQuick3DMorphingAnimation : public QObject +{ + Q_OBJECT + Q_PROPERTY(QQmlListProperty morphTargets READ morphTargets) + +public: + QQuick3DMorphingAnimation(QObject *parent = nullptr); + + inline QMorphingAnimation *parentMorphingAnimation() const + { + return qobject_cast(parent()); + } + + QQmlListProperty morphTargets(); + +private: + + static void appendMorphTarget(QQmlListProperty *list, + Qt3DAnimation::QMorphTarget *morphTarget); + static Qt3DAnimation::QMorphTarget *morphTargetAt(QQmlListProperty *list, + int index); + static int morphTargetCount(QQmlListProperty *list); + static void clearMorphTargets(QQmlListProperty *list); +}; + +} // namespace Quick +} // namespace Qt3DAnimation + +QT_END_NAMESPACE + +#endif // QT3DANIMATION_QUICK_QUICK3DMORPHINGANIMATION_P_H diff --git a/src/quick3d/quick3danimation/items/quick3dmorphtarget.cpp b/src/quick3d/quick3danimation/items/quick3dmorphtarget.cpp new file mode 100644 index 000000000..81144e186 --- /dev/null +++ b/src/quick3d/quick3danimation/items/quick3dmorphtarget.cpp @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** 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 "quick3dmorphtarget_p.h" + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { +namespace Quick { + +QQuick3DMorphTarget::QQuick3DMorphTarget(QObject *parent) + : QObject(parent) +{ +} + +QQmlListProperty QQuick3DMorphTarget::attributes() +{ + return QQmlListProperty(this, 0, + &QQuick3DMorphTarget::appendAttribute, + &QQuick3DMorphTarget::attributeCount, + &QQuick3DMorphTarget::attributeAt, + &QQuick3DMorphTarget::clearAttributes); +} + +void QQuick3DMorphTarget::appendAttribute(QQmlListProperty *list, Qt3DRender::QAttribute *bar) +{ + QQuick3DMorphTarget *target = qobject_cast(list->object); + if (target) + target->parentMorphTarget()->addAttribute(bar); +} + +int QQuick3DMorphTarget::attributeCount(QQmlListProperty *list) +{ + QQuick3DMorphTarget *target = qobject_cast(list->object); + if (target) + return target->parentMorphTarget()->attributeList().count(); + return 0; +} + +Qt3DRender::QAttribute *QQuick3DMorphTarget::attributeAt(QQmlListProperty *list, int index) +{ + QQuick3DMorphTarget *target = qobject_cast(list->object); + if (target) + return qobject_cast(target->parentMorphTarget()->attributeList().at(index)); + return nullptr; +} + +void QQuick3DMorphTarget::clearAttributes(QQmlListProperty *list) +{ + QQuick3DMorphTarget *target = qobject_cast(list->object); + if (target) { + QVector emptyList; + target->parentMorphTarget()->setAttributes(emptyList); + } +} + +} // namespace Quick +} // namespace Qt3DAnimation + +QT_END_NAMESPACE diff --git a/src/quick3d/quick3danimation/items/quick3dmorphtarget_p.h b/src/quick3d/quick3danimation/items/quick3dmorphtarget_p.h new file mode 100644 index 000000000..03b52dfeb --- /dev/null +++ b/src/quick3d/quick3danimation/items/quick3dmorphtarget_p.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QT3DANIMATION_QUICK_QUICK3DMORPHTARGET_P_H +#define QT3DANIMATION_QUICK_QUICK3DMORPHTARGET_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { +namespace Quick { + +class QT3DQUICKANIMATIONSHARED_PRIVATE_EXPORT QQuick3DMorphTarget : public QObject +{ + Q_OBJECT + Q_PROPERTY(QQmlListProperty attributes READ attributes) + +public: + QQuick3DMorphTarget(QObject *parent = nullptr); + + inline QMorphTarget *parentMorphTarget() const { return qobject_cast(parent()); } + + QQmlListProperty attributes(); + +private: + + static void appendAttribute(QQmlListProperty *list, Qt3DRender::QAttribute *bar); + static Qt3DRender::QAttribute *attributeAt(QQmlListProperty *list, int index); + static int attributeCount(QQmlListProperty *list); + static void clearAttributes(QQmlListProperty *list); +}; + +} // namespace Quick +} // namespace Qt3DAnimation + +QT_END_NAMESPACE + +#endif // QT3DANIMATION_QUICK_QUICK3DMORPHTARGET_P_H diff --git a/src/quick3d/quick3dextras/items/items.pri b/src/quick3d/quick3dextras/items/items.pri index f7ca73a58..b6f5d1877 100644 --- a/src/quick3d/quick3dextras/items/items.pri +++ b/src/quick3d/quick3dextras/items/items.pri @@ -1,18 +1,8 @@ HEADERS += \ $$PWD/quick3dlevelofdetailloader_p.h \ - $$PWD/quick3dlevelofdetailloader_p_p.h \ - $$PWD/quick3danimationcontroller_p.h \ - $$PWD/quick3danimationgroup_p.h \ - $$PWD/quick3dkeyframeanimation_p.h \ - $$PWD/quick3dmorphinganimation_p.h \ - $$PWD/quick3dmorphtarget_p.h + $$PWD/quick3dlevelofdetailloader_p_p.h SOURCES += \ - $$PWD/quick3dlevelofdetailloader.cpp \ - $$PWD/quick3danimationcontroller.cpp \ - $$PWD/quick3danimationgroup.cpp \ - $$PWD/quick3dkeyframeanimation.cpp \ - $$PWD/quick3dmorphinganimation.cpp \ - $$PWD/quick3dmorphtarget.cpp + $$PWD/quick3dlevelofdetailloader.cpp INCLUDEPATH += $$PWD diff --git a/src/quick3d/quick3dextras/items/quick3danimationcontroller.cpp b/src/quick3d/quick3dextras/items/quick3danimationcontroller.cpp deleted file mode 100644 index 4aceb0d55..000000000 --- a/src/quick3d/quick3dextras/items/quick3danimationcontroller.cpp +++ /dev/null @@ -1,95 +0,0 @@ -/**************************************************************************** -** -** 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 "quick3danimationcontroller_p.h" - -QT_BEGIN_NAMESPACE - -namespace Qt3DExtras { -namespace Quick { - -QQuick3DAnimationController::QQuick3DAnimationController(QObject *parent) - : QObject(parent) -{ -} - -QQmlListProperty QQuick3DAnimationController::animationGroups() -{ - return QQmlListProperty(this, 0, - &QQuick3DAnimationController::appendAnimationGroup, - &QQuick3DAnimationController::animationGroupCount, - &QQuick3DAnimationController::animationGroupAt, - &QQuick3DAnimationController::clearAnimationGroups); -} - - -void QQuick3DAnimationController::appendAnimationGroup(QQmlListProperty *list, QAnimationGroup *bar) -{ - QQuick3DAnimationController *controller = qobject_cast(list->object); - if (controller) - controller->parentAnimationController()->addAnimationGroup(bar); -} - -int QQuick3DAnimationController::animationGroupCount(QQmlListProperty *list) -{ - QQuick3DAnimationController *controller = qobject_cast(list->object); - if (controller) - return controller->parentAnimationController()->animationGroupList().count(); - return 0; -} - -QAnimationGroup *QQuick3DAnimationController::animationGroupAt(QQmlListProperty *list, int index) -{ - QQuick3DAnimationController *controller = qobject_cast(list->object); - if (controller) - return qobject_cast(controller->parentAnimationController()->getGroup(index)); - return nullptr; -} - -void QQuick3DAnimationController::clearAnimationGroups(QQmlListProperty *list) -{ - QQuick3DAnimationController *controller = qobject_cast(list->object); - if (controller) { - QVector emptyList; - controller->parentAnimationController()->setAnimationGroups(emptyList); - } -} - - -} // namespace Quick -} // namespace Qt3DExtras - -QT_END_NAMESPACE diff --git a/src/quick3d/quick3dextras/items/quick3danimationcontroller_p.h b/src/quick3d/quick3dextras/items/quick3danimationcontroller_p.h deleted file mode 100644 index 82ad29e2c..000000000 --- a/src/quick3d/quick3dextras/items/quick3danimationcontroller_p.h +++ /dev/null @@ -1,89 +0,0 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ - -#ifndef QT3DEXTRAS_QUICK_QUICK3DANIMATIONCONTROLLER_P_H -#define QT3DEXTRAS_QUICK_QUICK3DANIMATIONCONTROLLER_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of other Qt classes. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include -#include -#include - -QT_BEGIN_NAMESPACE - -namespace Qt3DExtras { -namespace Quick { - -class QT3DQUICKEXTRASSHARED_EXPORT QQuick3DAnimationController : public QObject -{ - Q_OBJECT - Q_PROPERTY(QQmlListProperty animationGroups READ animationGroups) - -public: - - explicit QQuick3DAnimationController(QObject *parent = nullptr); - - inline Qt3DExtras::QAnimationController *parentAnimationController() const - { - return qobject_cast(parent()); - } - - QQmlListProperty animationGroups(); - -private: - - static void appendAnimationGroup(QQmlListProperty *list, Qt3DExtras::QAnimationGroup *bar); - static QAnimationGroup *animationGroupAt(QQmlListProperty *list, int index); - static int animationGroupCount(QQmlListProperty *list); - static void clearAnimationGroups(QQmlListProperty *list); -}; - -} // namespace Quick -} // namespace Qt3DExtras - -QT_END_NAMESPACE - -#endif // QT3DRENDER_RENDER_QUICK_QUICK3DEFFECT_P_H diff --git a/src/quick3d/quick3dextras/items/quick3danimationgroup.cpp b/src/quick3d/quick3dextras/items/quick3danimationgroup.cpp deleted file mode 100644 index 3e3813227..000000000 --- a/src/quick3d/quick3dextras/items/quick3danimationgroup.cpp +++ /dev/null @@ -1,99 +0,0 @@ -/**************************************************************************** -** -** 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 "quick3danimationgroup_p.h" - -#include - -QT_BEGIN_NAMESPACE - -namespace Qt3DExtras { -namespace Quick { - -QQuick3DAnimationGroup::QQuick3DAnimationGroup(QObject *parent) - : QObject(parent) -{ -} - -QQmlListProperty QQuick3DAnimationGroup::animations() -{ - return QQmlListProperty(this, 0, - &QQuick3DAnimationGroup::appendAnimation, - &QQuick3DAnimationGroup::animationCount, - &QQuick3DAnimationGroup::animationAt, - &QQuick3DAnimationGroup::clearAnimation); -} - - -void QQuick3DAnimationGroup::appendAnimation(QQmlListProperty *list, - Qt3DExtras::QAbstractAnimation *animation) -{ - QQuick3DAnimationGroup *animationGroup = qobject_cast(list->object); - if (animationGroup) - animationGroup->parentAnimationGroup()->addAnimation(animation); -} - -int QQuick3DAnimationGroup::animationCount(QQmlListProperty *list) -{ - QQuick3DAnimationGroup *animationGroup = qobject_cast(list->object); - if (animationGroup) - return animationGroup->parentAnimationGroup()->animationList().count(); - return 0; -} - -Qt3DExtras::QAbstractAnimation *QQuick3DAnimationGroup::animationAt(QQmlListProperty *list, int index) -{ - QQuick3DAnimationGroup *animationGroup = qobject_cast(list->object); - if (animationGroup) { - return qobject_cast( - animationGroup->parentAnimationGroup()->animationList().at(index)); - } - return nullptr; -} - -void QQuick3DAnimationGroup::clearAnimation(QQmlListProperty *list) -{ - QQuick3DAnimationGroup *animationGroup = qobject_cast(list->object); - if (animationGroup) { - QVector emptyList; - animationGroup->parentAnimationGroup()->setAnimations(emptyList); - } -} - -} // namespace Quick -} // namespace Qt3DExtras - -QT_END_NAMESPACE diff --git a/src/quick3d/quick3dextras/items/quick3danimationgroup_p.h b/src/quick3d/quick3dextras/items/quick3danimationgroup_p.h deleted file mode 100644 index c7140c946..000000000 --- a/src/quick3d/quick3dextras/items/quick3danimationgroup_p.h +++ /dev/null @@ -1,91 +0,0 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ - -#ifndef QT3DEXTRAS_QUICK_QUICK3DANIMATIONGROUP_P_H -#define QT3DEXTRAS_QUICK_QUICK3DANIMATIONGROUP_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of other Qt classes. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include -#include -#include - -#include - -QT_BEGIN_NAMESPACE - -namespace Qt3DExtras { -namespace Quick { - -class QT3DQUICKEXTRASSHARED_EXPORT QQuick3DAnimationGroup : public QObject -{ - Q_OBJECT - Q_PROPERTY(QQmlListProperty animations READ animations) - -public: - - explicit QQuick3DAnimationGroup(QObject *parent = nullptr); - - inline Qt3DExtras::QAnimationGroup *parentAnimationGroup() const - { - return qobject_cast(parent()); - } - - QQmlListProperty animations(); - -private: - - static void appendAnimation(QQmlListProperty *list, Qt3DExtras::QAbstractAnimation *animation); - static Qt3DExtras::QAbstractAnimation *animationAt(QQmlListProperty *list, int index); - static int animationCount(QQmlListProperty *list); - static void clearAnimation(QQmlListProperty *list); -}; - -} // namespace Quick -} // namespace Qt3DExtras - -QT_END_NAMESPACE - -#endif // QT3DRENDER_RENDER_QUICK_QUICK3DEFFECT_P_H diff --git a/src/quick3d/quick3dextras/items/quick3dkeyframeanimation.cpp b/src/quick3d/quick3dextras/items/quick3dkeyframeanimation.cpp deleted file mode 100644 index cfd9ca7d2..000000000 --- a/src/quick3d/quick3dextras/items/quick3dkeyframeanimation.cpp +++ /dev/null @@ -1,101 +0,0 @@ -/**************************************************************************** -** -** 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 "quick3dkeyframeanimation_p.h" - -QT_BEGIN_NAMESPACE - -namespace Qt3DExtras { -namespace Quick { - -QQuick3DKeyframeAnimation::QQuick3DKeyframeAnimation(QObject *parent) - : QObject(parent) -{ -} - -QQmlListProperty QQuick3DKeyframeAnimation::keyframes() -{ - return QQmlListProperty(this, 0, - &QQuick3DKeyframeAnimation::appendKeyframe, - &QQuick3DKeyframeAnimation::keyframeCount, - &QQuick3DKeyframeAnimation::keyframeAt, - &QQuick3DKeyframeAnimation::clearKeyframes); -} - -void QQuick3DKeyframeAnimation::appendKeyframe(QQmlListProperty *list, - Qt3DCore::QTransform *transform) -{ - QQuick3DKeyframeAnimation *keyframeAnimation - = qobject_cast(list->object); - if (keyframeAnimation) - keyframeAnimation->parentKeyframeAnimation()->addKeyframe(transform); -} - -int QQuick3DKeyframeAnimation::keyframeCount(QQmlListProperty *list) -{ - QQuick3DKeyframeAnimation *keyframeAnimation - = qobject_cast(list->object); - if (keyframeAnimation) - return keyframeAnimation->parentKeyframeAnimation()->keyframeList().count(); - return 0; -} - -Qt3DCore::QTransform *QQuick3DKeyframeAnimation::keyframeAt(QQmlListProperty *list, - int index) -{ - QQuick3DKeyframeAnimation *keyframeAnimation - = qobject_cast(list->object); - if (keyframeAnimation) { - return qobject_cast( - keyframeAnimation->parentKeyframeAnimation()->keyframeList().at(index)); - } - return nullptr; -} - -void QQuick3DKeyframeAnimation::clearKeyframes(QQmlListProperty *list) -{ - QQuick3DKeyframeAnimation *keyframeAnimation - = qobject_cast(list->object); - if (keyframeAnimation) { - QVector emptyList; - keyframeAnimation->parentKeyframeAnimation()->setKeyframes(emptyList); - } -} - -} // namespace Quick -} // namespace Qt3DExtras - -QT_END_NAMESPACE diff --git a/src/quick3d/quick3dextras/items/quick3dkeyframeanimation_p.h b/src/quick3d/quick3dextras/items/quick3dkeyframeanimation_p.h deleted file mode 100644 index e8309de9e..000000000 --- a/src/quick3d/quick3dextras/items/quick3dkeyframeanimation_p.h +++ /dev/null @@ -1,92 +0,0 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ - -#ifndef QT3DEXTRAS_QUICK_QUICK3DKEYFRAMEANIMATION_P_H -#define QT3DEXTRAS_QUICK_QUICK3DKEYFRAMEANIMATION_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of other Qt classes. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include - -#include - -#include - -QT_BEGIN_NAMESPACE - -namespace Qt3DExtras { -namespace Quick { - -class QT3DQUICKEXTRASSHARED_EXPORT QQuick3DKeyframeAnimation : public QObject -{ - Q_OBJECT - Q_PROPERTY(QQmlListProperty keyframes READ keyframes) - -public: - QQuick3DKeyframeAnimation(QObject *parent = nullptr); - - inline QKeyframeAnimation *parentKeyframeAnimation() const - { - return qobject_cast(parent()); - } - - QQmlListProperty keyframes(); - -private: - - static void appendKeyframe(QQmlListProperty *list, - Qt3DCore::QTransform *transform); - static Qt3DCore::QTransform *keyframeAt(QQmlListProperty *list, - int index); - static int keyframeCount(QQmlListProperty *list); - static void clearKeyframes(QQmlListProperty *list); -}; - -} // namespace Quick -} // namespace Qt3DExtras - -QT_END_NAMESPACE - -#endif // QT3DEXTRAS_QUICK_QUICK3DKEYFRAMEANIMATION_P_H diff --git a/src/quick3d/quick3dextras/items/quick3dmorphinganimation.cpp b/src/quick3d/quick3dextras/items/quick3dmorphinganimation.cpp deleted file mode 100644 index 61636f06d..000000000 --- a/src/quick3d/quick3dextras/items/quick3dmorphinganimation.cpp +++ /dev/null @@ -1,97 +0,0 @@ -/**************************************************************************** -** -** 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 "quick3dmorphinganimation_p.h" - -QT_BEGIN_NAMESPACE - -namespace Qt3DExtras { -namespace Quick { - -QQuick3DMorphingAnimation::QQuick3DMorphingAnimation(QObject *parent) - : QObject(parent) -{ -} - -QQmlListProperty QQuick3DMorphingAnimation::morphTargets() -{ - return QQmlListProperty(this, 0, - &QQuick3DMorphingAnimation::appendMorphTarget, - &QQuick3DMorphingAnimation::morphTargetCount, - &QQuick3DMorphingAnimation::morphTargetAt, - &QQuick3DMorphingAnimation::clearMorphTargets); -} - -void QQuick3DMorphingAnimation::appendMorphTarget(QQmlListProperty *list, - Qt3DExtras::QMorphTarget *morphTarget) -{ - QQuick3DMorphingAnimation *animation = qobject_cast(list->object); - if (animation) - animation->parentMorphingAnimation()->addMorphTarget(morphTarget); -} - -int QQuick3DMorphingAnimation::morphTargetCount(QQmlListProperty *list) -{ - QQuick3DMorphingAnimation *animation = qobject_cast(list->object); - if (animation) - return animation->parentMorphingAnimation()->morphTargetList().count(); - return 0; -} - -Qt3DExtras::QMorphTarget *QQuick3DMorphingAnimation::morphTargetAt(QQmlListProperty *list, - int index) -{ - QQuick3DMorphingAnimation *animation = qobject_cast(list->object); - if (animation) { - return qobject_cast( - animation->parentMorphingAnimation()->morphTargetList().at(index)); - } - return nullptr; -} - -void QQuick3DMorphingAnimation::clearMorphTargets(QQmlListProperty *list) -{ - QQuick3DMorphingAnimation *animation = qobject_cast(list->object); - if (animation) { - QVector emptyList; - animation->parentMorphingAnimation()->setMorphTargets(emptyList); - } -} - -} // namespace Quick -} // namespace Qt3DExtras - -QT_END_NAMESPACE diff --git a/src/quick3d/quick3dextras/items/quick3dmorphinganimation_p.h b/src/quick3d/quick3dextras/items/quick3dmorphinganimation_p.h deleted file mode 100644 index 5f052fd04..000000000 --- a/src/quick3d/quick3dextras/items/quick3dmorphinganimation_p.h +++ /dev/null @@ -1,92 +0,0 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ - -#ifndef QT3DEXTRAS_QUICK_QUICK3DMORPHINGANIMATION_P_H -#define QT3DEXTRAS_QUICK_QUICK3DMORPHINGANIMATION_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of other Qt classes. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include - -#include - -#include - -QT_BEGIN_NAMESPACE - -namespace Qt3DExtras { -namespace Quick { - -class QT3DQUICKEXTRASSHARED_EXPORT QQuick3DMorphingAnimation : public QObject -{ - Q_OBJECT - Q_PROPERTY(QQmlListProperty morphTargets READ morphTargets) - -public: - QQuick3DMorphingAnimation(QObject *parent = nullptr); - - inline QMorphingAnimation *parentMorphingAnimation() const - { - return qobject_cast(parent()); - } - - QQmlListProperty morphTargets(); - -private: - - static void appendMorphTarget(QQmlListProperty *list, - Qt3DExtras::QMorphTarget *morphTarget); - static Qt3DExtras::QMorphTarget *morphTargetAt(QQmlListProperty *list, - int index); - static int morphTargetCount(QQmlListProperty *list); - static void clearMorphTargets(QQmlListProperty *list); -}; - -} // namespace Quick -} // namespace Qt3DExtras - -QT_END_NAMESPACE - -#endif // QT3DEXTRAS_QUICK_QUICK3DMORPHINGANIMATION_P_H diff --git a/src/quick3d/quick3dextras/items/quick3dmorphtarget.cpp b/src/quick3d/quick3dextras/items/quick3dmorphtarget.cpp deleted file mode 100644 index 8c1b9f0c1..000000000 --- a/src/quick3d/quick3dextras/items/quick3dmorphtarget.cpp +++ /dev/null @@ -1,93 +0,0 @@ -/**************************************************************************** -** -** 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 "quick3dmorphtarget_p.h" - -QT_BEGIN_NAMESPACE - -namespace Qt3DExtras { -namespace Quick { - -QQuick3DMorphTarget::QQuick3DMorphTarget(QObject *parent) - : QObject(parent) -{ -} - -QQmlListProperty QQuick3DMorphTarget::attributes() -{ - return QQmlListProperty(this, 0, - &QQuick3DMorphTarget::appendAttribute, - &QQuick3DMorphTarget::attributeCount, - &QQuick3DMorphTarget::attributeAt, - &QQuick3DMorphTarget::clearAttributes); -} - -void QQuick3DMorphTarget::appendAttribute(QQmlListProperty *list, Qt3DRender::QAttribute *bar) -{ - QQuick3DMorphTarget *target = qobject_cast(list->object); - if (target) - target->parentMorphTarget()->addAttribute(bar); -} - -int QQuick3DMorphTarget::attributeCount(QQmlListProperty *list) -{ - QQuick3DMorphTarget *target = qobject_cast(list->object); - if (target) - return target->parentMorphTarget()->attributeList().count(); - return 0; -} - -Qt3DRender::QAttribute *QQuick3DMorphTarget::attributeAt(QQmlListProperty *list, int index) -{ - QQuick3DMorphTarget *target = qobject_cast(list->object); - if (target) - return qobject_cast(target->parentMorphTarget()->attributeList().at(index)); - return nullptr; -} - -void QQuick3DMorphTarget::clearAttributes(QQmlListProperty *list) -{ - QQuick3DMorphTarget *target = qobject_cast(list->object); - if (target) { - QVector emptyList; - target->parentMorphTarget()->setAttributes(emptyList); - } -} - -} // namespace Quick -} // namespace Qt3DExtras - -QT_END_NAMESPACE diff --git a/src/quick3d/quick3dextras/items/quick3dmorphtarget_p.h b/src/quick3d/quick3dextras/items/quick3dmorphtarget_p.h deleted file mode 100644 index e5c664370..000000000 --- a/src/quick3d/quick3dextras/items/quick3dmorphtarget_p.h +++ /dev/null @@ -1,85 +0,0 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ - -#ifndef QT3DEXTRAS_QUICK_QUICK3DMORPHTARGET_P_H -#define QT3DEXTRAS_QUICK_QUICK3DMORPHTARGET_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of other Qt classes. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include -#include -#include - -QT_BEGIN_NAMESPACE - -namespace Qt3DExtras { -namespace Quick { - -class QT3DQUICKEXTRASSHARED_EXPORT QQuick3DMorphTarget : public QObject -{ - Q_OBJECT - Q_PROPERTY(QQmlListProperty attributes READ attributes) - -public: - QQuick3DMorphTarget(QObject *parent = nullptr); - - inline QMorphTarget *parentMorphTarget() const { return qobject_cast(parent()); } - - QQmlListProperty attributes(); - -private: - - static void appendAttribute(QQmlListProperty *list, Qt3DRender::QAttribute *bar); - static Qt3DRender::QAttribute *attributeAt(QQmlListProperty *list, int index); - static int attributeCount(QQmlListProperty *list); - static void clearAttributes(QQmlListProperty *list); -}; - -} // namespace Quick -} // namespace Qt3DExtras - -QT_END_NAMESPACE - -#endif // QT3DEXTRAS_QUICK_QUICK3DMORPHTARGET_P_H diff --git a/tests/manual/anim-viewer/main.qml b/tests/manual/anim-viewer/main.qml index 95a4900e3..a31f8182d 100644 --- a/tests/manual/anim-viewer/main.qml +++ b/tests/manual/anim-viewer/main.qml @@ -43,6 +43,7 @@ import Qt3D.Core 2.0 import Qt3D.Render 2.0 import Qt3D.Input 2.0 import Qt3D.Extras 2.2 +import Qt3D.Animation 2.2 import QtQuick.Scene3D 2.0 diff --git a/tests/manual/mesh-morphing/main.cpp b/tests/manual/mesh-morphing/main.cpp index 4ae791181..641722a4c 100644 --- a/tests/manual/mesh-morphing/main.cpp +++ b/tests/manual/mesh-morphing/main.cpp @@ -43,8 +43,8 @@ #include #include #include -#include -#include +#include +#include #include #include @@ -111,13 +111,13 @@ int main(int argc, char **argv) attributes.push_back(Qt3DRender::QAttribute::defaultPositionAttributeName()); attributes.push_back(Qt3DRender::QAttribute::defaultNormalAttributeName()); - QVector morphTargets; - morphTargets.push_back(Qt3DExtras::QMorphTarget::fromGeometry(cylinder1, attributes)); - morphTargets.push_back(Qt3DExtras::QMorphTarget::fromGeometry(cylinder2, attributes)); - morphTargets.push_back(Qt3DExtras::QMorphTarget::fromGeometry(cylinder3, attributes)); + QVector morphTargets; + morphTargets.push_back(Qt3DAnimation::QMorphTarget::fromGeometry(cylinder1, attributes)); + morphTargets.push_back(Qt3DAnimation::QMorphTarget::fromGeometry(cylinder2, attributes)); + morphTargets.push_back(Qt3DAnimation::QMorphTarget::fromGeometry(cylinder3, attributes)); morphTargets.push_back(morphTargets.first()); - Qt3DExtras::QVertexBlendAnimation *animation = new Qt3DExtras::QVertexBlendAnimation; + Qt3DAnimation::QVertexBlendAnimation *animation = new Qt3DAnimation::QVertexBlendAnimation; QVector times; times.push_back(0.0f); times.push_back(5.0f); @@ -132,7 +132,7 @@ int main(int argc, char **argv) Qt3DExtras::QMorphPhongMaterial *material = new Qt3DExtras::QMorphPhongMaterial(rootEntity); material->setDiffuse(Qt::red); - QObject::connect(animation, &Qt3DExtras::QVertexBlendAnimation::interpolatorChanged, + QObject::connect(animation, &Qt3DAnimation::QVertexBlendAnimation::interpolatorChanged, material, &Qt3DExtras::QMorphPhongMaterial::setInterpolator); // Cylinder diff --git a/tests/manual/mesh-morphing/mesh-morphing.pro b/tests/manual/mesh-morphing/mesh-morphing.pro index ad2a31b8b..27419655f 100644 --- a/tests/manual/mesh-morphing/mesh-morphing.pro +++ b/tests/manual/mesh-morphing/mesh-morphing.pro @@ -2,7 +2,7 @@ error( "Couldn't find the manual.pri file!" ) } -QT += 3dcore 3drender 3dquick 3dinput quick qml 3dextras 3dquickextras +QT += 3dcore 3drender 3dquick 3dinput quick qml 3dextras 3dquickextras 3danimation 3dquickanimation SOURCES += \ main.cpp -- cgit v1.2.3 From 69b94b86e3141f1204c5a1121e1d289cd6f04a7b Mon Sep 17 00:00:00 2001 From: David Morgan Date: Tue, 7 Feb 2017 10:14:08 +0000 Subject: Add QBackendNode wizard template Change-Id: I0cca7a6037c4c599cc953c0d5d293c77f09216a0 Reviewed-by: Sean Harmer --- .../templates/wizards/classes/qt3d/backendnode.cpp | 20 +++++++++++++ .../templates/wizards/classes/qt3d/backendnode_p.h | 35 ++++++++++++++++++++++ .../templates/wizards/classes/qt3d/file.cpp | 6 ---- .../templates/wizards/classes/qt3d/file.h | 2 -- .../templates/wizards/classes/qt3d/file_p.h | 2 -- .../templates/wizards/classes/qt3d/wizard.json | 18 ++++++++++- 6 files changed, 72 insertions(+), 11 deletions(-) create mode 100644 tools/utils/qtcreator/templates/wizards/classes/qt3d/backendnode.cpp create mode 100644 tools/utils/qtcreator/templates/wizards/classes/qt3d/backendnode_p.h diff --git a/tools/utils/qtcreator/templates/wizards/classes/qt3d/backendnode.cpp b/tools/utils/qtcreator/templates/wizards/classes/qt3d/backendnode.cpp new file mode 100644 index 000000000..46f711849 --- /dev/null +++ b/tools/utils/qtcreator/templates/wizards/classes/qt3d/backendnode.cpp @@ -0,0 +1,20 @@ +%{Cpp:LicenseTemplate}\ +#include "%{PrivateHdrFileName}" + +QT_BEGIN_NAMESPACE +%{JS: Cpp.openNamespaces('%{Class}')} +%{CN}::%{CN}() +{ +} + +void %{CN}::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) +{ +} + +void %{CN}::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) +{ +} + +%{JS: Cpp.closeNamespaces('%{Class}')}\ + +QT_END_NAMESPACE diff --git a/tools/utils/qtcreator/templates/wizards/classes/qt3d/backendnode_p.h b/tools/utils/qtcreator/templates/wizards/classes/qt3d/backendnode_p.h new file mode 100644 index 000000000..12ee68155 --- /dev/null +++ b/tools/utils/qtcreator/templates/wizards/classes/qt3d/backendnode_p.h @@ -0,0 +1,35 @@ +%{Cpp:LicenseTemplate}\ + +#ifndef %{GUARD} +#define %{GUARD} + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE +%{JS: Cpp.openNamespaces('%{Class}')} +class %{CN} : public Qt3DCore::%{Base} +{ +public: + %{CN}(); + + void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_OVERRIDE; + +private: + void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL; +}; +%{JS: Cpp.closeNamespaces('%{Class}')} + +QT_END_NAMESPACE + +#endif // %{GUARD}\ diff --git a/tools/utils/qtcreator/templates/wizards/classes/qt3d/file.cpp b/tools/utils/qtcreator/templates/wizards/classes/qt3d/file.cpp index 4200859a9..5106a9e74 100644 --- a/tools/utils/qtcreator/templates/wizards/classes/qt3d/file.cpp +++ b/tools/utils/qtcreator/templates/wizards/classes/qt3d/file.cpp @@ -4,7 +4,6 @@ QT_BEGIN_NAMESPACE %{JS: Cpp.openNamespaces('%{Class}')} -@if '%{Base}' === 'QNode' || '%{Base}' === 'QComponent' || '%{Base}' === 'QEntity' %{CN}Private::%{CN}Private() : Qt3DCore::%{Base}Private() { @@ -23,11 +22,7 @@ QT_BEGIN_NAMESPACE %{CN}::~%{CN}() { } -@else -// TODO: Implement QBackendNode template -@endif -@if '%{Base}' === 'QNode' || '%{Base}' === 'QComponent' || '%{Base}' === 'QEntity' Qt3DCore::QNodeCreatedChangeBasePtr %{CN}::createNodeCreationChange() const { auto creationChange = Qt3DCore::QNodeCreatedChangePtr<%{CN}Data>::create(this); @@ -36,7 +31,6 @@ Qt3DCore::QNodeCreatedChangeBasePtr %{CN}::createNodeCreationChange() const // TODO: Send data members in creation change return creationChange; } -@endif %{JS: Cpp.closeNamespaces('%{Class}')}\ QT_END_NAMESPACE diff --git a/tools/utils/qtcreator/templates/wizards/classes/qt3d/file.h b/tools/utils/qtcreator/templates/wizards/classes/qt3d/file.h index 9060461eb..c4162d647 100644 --- a/tools/utils/qtcreator/templates/wizards/classes/qt3d/file.h +++ b/tools/utils/qtcreator/templates/wizards/classes/qt3d/file.h @@ -9,8 +9,6 @@ #include @elsif '%{Base}' === 'QEntity' #include -@elsif '%{Base}' === 'QBackendNode' -#include @endif QT_BEGIN_NAMESPACE diff --git a/tools/utils/qtcreator/templates/wizards/classes/qt3d/file_p.h b/tools/utils/qtcreator/templates/wizards/classes/qt3d/file_p.h index 9de21e805..d1acea35e 100644 --- a/tools/utils/qtcreator/templates/wizards/classes/qt3d/file_p.h +++ b/tools/utils/qtcreator/templates/wizards/classes/qt3d/file_p.h @@ -20,8 +20,6 @@ #include @elsif '%{Base}' === 'QEntity' #include -@elsif '%{Base}' === 'QBackendNode' -#include @endif QT_BEGIN_NAMESPACE diff --git a/tools/utils/qtcreator/templates/wizards/classes/qt3d/wizard.json b/tools/utils/qtcreator/templates/wizards/classes/qt3d/wizard.json index c9fe63685..8079aa4b4 100644 --- a/tools/utils/qtcreator/templates/wizards/classes/qt3d/wizard.json +++ b/tools/utils/qtcreator/templates/wizards/classes/qt3d/wizard.json @@ -73,7 +73,8 @@ "name": "HdrFileName", "type": "LineEdit", "trDisplayName": "Header file:", - "mandatory": true, + "mandatory": false, + "enabled": "%{JS: '%{BaseCB}' !== 'QBackendNode'}", "data": { "trText": "%{JS: Cpp.classToFileName('%{Class}', '%{JS: Util.preferredSuffix('text/x-c++hdr')}')}" } }, { @@ -120,16 +121,31 @@ { "source": "file.h", "target": "%{HdrPath}", + "condition": "%{JS: '%{Base}' !== 'QBackendNode'}", "openInEditor": true }, { "source": "file_p.h", "target": "%{PrivateHdrPath}", + "condition": "%{JS: '%{Base}' !== 'QBackendNode'}", "openInEditor": true }, { "source": "file.cpp", "target": "%{SrcPath}", + "condition": "%{JS: '%{Base}' !== 'QBackendNode'}", + "openInEditor": true + }, + { + "source": "backendnode.cpp", + "target": "%{SrcPath}", + "condition": "%{JS: '%{Base}' === 'QBackendNode'}", + "openInEditor": true + }, + { + "source": "backendnode_p.h", + "target": "%{PrivateHdrPath}", + "condition": "%{JS: '%{Base}' === 'QBackendNode'}", "openInEditor": true } ] -- cgit v1.2.3 From 45a651bd36d17e0fca852bdf1a6a0084119b4e3d Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Mon, 6 Feb 2017 12:00:38 +0000 Subject: Fix warning about set but not used variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Ic36141a63988a3070f7de453a8b6a3c0088866c8 Reviewed-by: Antti Määttä --- src/render/picking/objectpicker.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/render/picking/objectpicker.cpp b/src/render/picking/objectpicker.cpp index b85bdc723..13d6d505c 100644 --- a/src/render/picking/objectpicker.cpp +++ b/src/render/picking/objectpicker.cpp @@ -92,17 +92,11 @@ void ObjectPicker::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) { if (e->type() == Qt3DCore::PropertyUpdated) { const Qt3DCore::QPropertyUpdatedChangePtr propertyChange = qSharedPointerCast(e); - bool notifyPickJob = false; if (propertyChange->propertyName() == QByteArrayLiteral("hoverEnabled")) { m_hoverEnabled = propertyChange->value().toBool(); - notifyPickJob = true; } else if (propertyChange->propertyName() == QByteArrayLiteral("dragEnabled")) { m_dragEnabled = propertyChange->value().toBool(); - notifyPickJob = true; - } else if (propertyChange->propertyName() == QByteArrayLiteral("enabled")) { - notifyPickJob = true; - // actual value change handled in BackendNode::sceneChangeEvent } markDirty(AbstractRenderer::AllDirty); -- cgit v1.2.3 From c6a1930d583732e99070233c3e55ab22fc8f940d Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Mon, 6 Feb 2017 12:05:37 +0000 Subject: Fix -Wreorder warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I53e040b84fa9fcc8ecec34c85d93da780b0e97ae Reviewed-by: Antti Määttä --- tests/manual/rendercapture-cpp/mycapture.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/manual/rendercapture-cpp/mycapture.h b/tests/manual/rendercapture-cpp/mycapture.h index 803ef7336..249561a1e 100644 --- a/tests/manual/rendercapture-cpp/mycapture.h +++ b/tests/manual/rendercapture-cpp/mycapture.h @@ -60,10 +60,10 @@ class MyCapture : public QObject public: MyCapture(Qt3DRender::QRenderCapture* capture, QLabel *imageLabel) : m_capture(capture) - , m_cid(1) - , m_imageLabel(imageLabel) , m_reply(nullptr) + , m_imageLabel(imageLabel) , m_continuous(false) + , m_cid(1) { } -- cgit v1.2.3 From 8f2e0c0948a2afcf94536e2b78a40f380422a322 Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Mon, 6 Feb 2017 12:14:32 +0000 Subject: Fix deprecation warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I64bd08889fcd95dd41724652b84b34e8b9497ad3 Reviewed-by: Antti Määttä --- src/render/io/qsceneloader.cpp | 20 +++++++++++++------- src/render/io/qsceneloader_p.h | 2 ++ 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/render/io/qsceneloader.cpp b/src/render/io/qsceneloader.cpp index 9cb067161..626c70eba 100644 --- a/src/render/io/qsceneloader.cpp +++ b/src/render/io/qsceneloader.cpp @@ -174,6 +174,17 @@ QSceneLoaderPrivate::QSceneLoaderPrivate() m_shareable = false; } +void QSceneLoaderPrivate::setStatus(QSceneLoader::Status status) +{ + if (m_status != status) { + Q_Q(QSceneLoader); + m_status = status; + const bool wasBlocked = q->blockNotifications(true); + emit q->statusChanged(status); + q->blockNotifications(wasBlocked); + } +} + /*! The constructor creates an instance with the specified \a parent. */ @@ -219,7 +230,7 @@ void QSceneLoader::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) d->m_subTreeRoot = subTreeRoot; } } else if (e->propertyName() == QByteArrayLiteral("status")) { - setStatus(e->value().value()); + d->setStatus(e->value().value()); } } } @@ -249,12 +260,7 @@ QSceneLoader::Status QSceneLoader::status() const void QSceneLoader::setStatus(QSceneLoader::Status status) { Q_D(QSceneLoader); - if (d->m_status != status) { - d->m_status = status; - const bool wasBlocked = blockNotifications(true); - emit statusChanged(status); - blockNotifications(wasBlocked); - } + d->setStatus(status); } Qt3DCore::QNodeCreatedChangeBasePtr QSceneLoader::createNodeCreationChange() const diff --git a/src/render/io/qsceneloader_p.h b/src/render/io/qsceneloader_p.h index b002957b2..6d64387d2 100644 --- a/src/render/io/qsceneloader_p.h +++ b/src/render/io/qsceneloader_p.h @@ -66,6 +66,8 @@ class QT3DRENDERSHARED_PRIVATE_EXPORT QSceneLoaderPrivate : public Qt3DCore::QCo public: QSceneLoaderPrivate(); + void setStatus(QSceneLoader::Status status); + Q_DECLARE_PUBLIC(QSceneLoader) QUrl m_source; -- cgit v1.2.3 From 601ee9146676ef78f6ad486420ba9849ac44c844 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Wed, 1 Feb 2017 12:01:41 +0200 Subject: Fix KeyEvent forwarding Renderer needs to set the key events also to the pick job. Change-Id: I305f96ef2cb836dac07b7710877cc6440ddb9216 Reviewed-by: Paul Lemire Reviewed-by: Guillermo A. Amaral --- src/render/backend/renderer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/render/backend/renderer.cpp b/src/render/backend/renderer.cpp index 4e4301b39..da4936a8b 100644 --- a/src/render/backend/renderer.cpp +++ b/src/render/backend/renderer.cpp @@ -1388,6 +1388,7 @@ QVector Renderer::renderBinJobs() m_pickBoundingVolumeJob->setFrameGraphRoot(frameGraphRoot()); m_pickBoundingVolumeJob->setRenderSettings(settings()); m_pickBoundingVolumeJob->setMouseEvents(pendingPickingEvents()); + m_pickBoundingVolumeJob->setKeyEvents(pendingKeyEvents()); m_updateLevelOfDetailJob->setFrameGraphRoot(frameGraphRoot()); // Set dependencies of resource gatherer -- cgit v1.2.3 From e29f8cf68e2f1ed22244f84099589e9444eaf5ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Fri, 3 Feb 2017 12:20:36 +0200 Subject: Enable blitFramebuffer with ES2 when it is supported Task-number: QTBUG-57573 Change-Id: Ie1be0282fbab6e4346a81f37eff7597b932da07e Reviewed-by: Sean Harmer --- src/render/graphicshelpers/graphicscontext.cpp | 17 ++++++++-------- src/render/graphicshelpers/graphicshelperes2.cpp | 25 ++++++++++++------------ src/render/graphicshelpers/graphicshelperes2_p.h | 4 ++++ 3 files changed, 24 insertions(+), 22 deletions(-) diff --git a/src/render/graphicshelpers/graphicscontext.cpp b/src/render/graphicshelpers/graphicscontext.cpp index aba74c8d9..cee1a568a 100644 --- a/src/render/graphicshelpers/graphicscontext.cpp +++ b/src/render/graphicshelpers/graphicscontext.cpp @@ -81,6 +81,14 @@ QT_BEGIN_NAMESPACE +#ifndef GL_READ_FRAMEBUFFER +#define GL_READ_FRAMEBUFFER 0x8CA8 +#endif + +#ifndef GL_DRAW_FRAMEBUFFER +#define GL_DRAW_FRAMEBUFFER 0x8CA9 +#endif + namespace { QOpenGLShader::ShaderType shaderType(Qt3DRender::QShaderProgram::ShaderType type) @@ -1630,10 +1638,8 @@ QImage GraphicsContext::readFramebuffer(QSize size) QImage::Format imageFormat; uint stride; -#ifndef QT_OPENGL_ES_2 /* format value should match GL internalFormat */ GLenum internalFormat = m_renderTargetFormat; -#endif switch (m_renderTargetFormat) { case QAbstractTexture::RGBAFormat: @@ -1709,18 +1715,15 @@ QImage GraphicsContext::readFramebuffer(QSize size) return img; } -#ifndef QT_OPENGL_ES_2 GLint samples = 0; m_gl->functions()->glGetIntegerv(GL_SAMPLES, &samples); if (samples > 0 && !m_glHelper->supportsFeature(GraphicsHelperInterface::BlitFramebuffer)) return img; -#endif img = QImage(size.width(), size.height(), imageFormat); QScopedArrayPointer data(new uchar [bytes]); -#ifndef QT_OPENGL_ES_2 if (samples > 0) { // resolve multisample-framebuffer to renderbuffer and read pixels from it GLuint fbo, rb; @@ -1752,14 +1755,10 @@ QImage GraphicsContext::readFramebuffer(QSize size) gl->glBindFramebuffer(GL_FRAMEBUFFER, m_activeFBO); gl->glDeleteFramebuffers(1, &fbo); } else { -#endif // read pixels directly from framebuffer m_gl->functions()->glReadPixels(0,0,size.width(), size.height(), format, type, data.data()); copyGLFramebufferDataToImage(img, data.data(), stride, size.width(), size.height(), m_renderTargetFormat); - -#ifndef QT_OPENGL_ES_2 } -#endif return img; } diff --git a/src/render/graphicshelpers/graphicshelperes2.cpp b/src/render/graphicshelpers/graphicshelperes2.cpp index 1335b250f..b409cf5af 100644 --- a/src/render/graphicshelpers/graphicshelperes2.cpp +++ b/src/render/graphicshelpers/graphicshelperes2.cpp @@ -65,8 +65,9 @@ QT_BEGIN_NAMESPACE namespace Qt3DRender { namespace Render { -GraphicsHelperES2::GraphicsHelperES2() : - m_funcs(0) +GraphicsHelperES2::GraphicsHelperES2() + : m_funcs(0) + , m_supportFramebufferBlit(false) { } @@ -80,6 +81,9 @@ void GraphicsHelperES2::initializeHelper(QOpenGLContext *context, Q_ASSERT(context); m_funcs = context->functions(); Q_ASSERT(m_funcs); + m_ext.reset(new QOpenGLExtensions(context)); + if (m_ext->hasOpenGLExtension(QOpenGLExtensions::FramebufferBlit)) + m_supportFramebufferBlit = true; } void GraphicsHelperES2::drawElementsInstancedBaseVertexBaseInstance(GLenum primitiveType, @@ -356,6 +360,8 @@ bool GraphicsHelperES2::supportsFeature(GraphicsHelperInterface::Feature feature switch (feature) { case RenderBufferDimensionRetrieval: return true; + case BlitFramebuffer: + return m_supportFramebufferBlit; default: return false; } @@ -709,17 +715,10 @@ UniformType GraphicsHelperES2::uniformTypeFromGLType(GLenum type) void GraphicsHelperES2::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) { - Q_UNUSED(srcX0); - Q_UNUSED(srcX1); - Q_UNUSED(srcY0); - Q_UNUSED(srcY1); - Q_UNUSED(dstX0); - Q_UNUSED(dstX1); - Q_UNUSED(dstY0); - Q_UNUSED(dstY1); - Q_UNUSED(mask); - Q_UNUSED(filter); - qWarning() << "Framebuffer blits are not supported by ES 2.0 (since ES 3.1)"; + if (!m_supportFramebufferBlit) + qWarning() << "Framebuffer blits are not supported by ES 2.0 (since ES 3.1)"; + else + m_ext->glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); } } // namespace Render diff --git a/src/render/graphicshelpers/graphicshelperes2_p.h b/src/render/graphicshelpers/graphicshelperes2_p.h index 17249ef23..ddcd28ca5 100644 --- a/src/render/graphicshelpers/graphicshelperes2_p.h +++ b/src/render/graphicshelpers/graphicshelperes2_p.h @@ -57,6 +57,8 @@ QT_BEGIN_NAMESPACE +class QOpenGLExtensions; + namespace Qt3DRender { namespace Render { @@ -148,6 +150,8 @@ public: protected: QOpenGLFunctions *m_funcs; + bool m_supportFramebufferBlit; + QScopedPointer m_ext; }; } // namespace Render -- cgit v1.2.3 From d1271dba68f03610c27e87963653bf1600b5f659 Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Tue, 7 Feb 2017 11:07:26 +0000 Subject: Deliver all events by default unless marked as intermediate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This change inverts m_final flag on property change events so that now, all events are delivered by default. The animation aspect now marks intermediate calculated changes and these are not delivered unless the user subscribes to them. Change-Id: Ide6c30b29a91ed874d47c52d0ee1352f6680c3d8 Reviewed-by: Antti Määttä --- src/animation/backend/animationclip.cpp | 2 - src/animation/backend/animationutils.cpp | 3 +- src/core/changes/qpropertyupdatedchangebase.cpp | 2 +- src/core/changes/qpropertyupdatedchangebase_p.h | 7 +- src/core/qpostman.cpp | 16 +-- src/input/backend/action.cpp | 2 - src/input/backend/axis.cpp | 2 - src/input/backend/axisaccumulator.cpp | 3 - src/input/backend/keyboardhandler.cpp | 3 - src/input/backend/mousehandler.cpp | 3 - src/input/backend/physicaldeviceproxy.cpp | 2 - src/render/backend/levelofdetail.cpp | 2 - src/render/geometry/buffer.cpp | 3 - src/render/io/scene.cpp | 3 - src/render/picking/objectpicker.cpp | 7 -- .../animation/animationclip/tst_animationclip.cpp | 3 +- tests/auto/core/qpostman/tst_qpostman.cpp | 108 ++++++++++++--------- tests/auto/input/action/tst_action.cpp | 2 - tests/auto/input/axis/tst_axis.cpp | 2 - .../input/axisaccumulator/tst_axisaccumulator.cpp | 3 - .../tst_physicaldeviceproxy.cpp | 1 - tests/auto/render/buffer/tst_buffer.cpp | 2 - .../auto/render/objectpicker/tst_objectpicker.cpp | 6 -- tests/auto/render/sceneloader/tst_sceneloader.cpp | 2 - 24 files changed, 81 insertions(+), 108 deletions(-) diff --git a/src/animation/backend/animationclip.cpp b/src/animation/backend/animationclip.cpp index 3265a8fc5..7b96f66e9 100644 --- a/src/animation/backend/animationclip.cpp +++ b/src/animation/backend/animationclip.cpp @@ -40,7 +40,6 @@ #include #include #include -#include #include #include @@ -161,7 +160,6 @@ void AnimationClip::setDuration(float duration) // Send a change to the frontend auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId()); e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll); - Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(e.data())->m_isFinal = true; e->setPropertyName("duration"); e->setValue(m_duration); notifyObservers(e); diff --git a/src/animation/backend/animationutils.cpp b/src/animation/backend/animationutils.cpp index 0e202a5b3..c81893013 100644 --- a/src/animation/backend/animationutils.cpp +++ b/src/animation/backend/animationutils.cpp @@ -197,7 +197,7 @@ QVector AnimationUtils::preparePropertyChanges(Qt3DCo e->setPropertyName(mappingData.propertyName); // Handle intermediate updates vs final flag properly - Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(e.data())->m_isFinal = finalFrame; + Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(e.data())->m_isIntermediate = !finalFrame; // Build the new value from the channel/fcurve evaluation results QVariant v; @@ -258,7 +258,6 @@ QVector AnimationUtils::preparePropertyChanges(Qt3DCo e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll); e->setPropertyName("running"); e->setValue(false); - Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(e.data())->m_isFinal = true; changes.push_back(e); } return changes; diff --git a/src/core/changes/qpropertyupdatedchangebase.cpp b/src/core/changes/qpropertyupdatedchangebase.cpp index d33c737e5..5d79b9049 100644 --- a/src/core/changes/qpropertyupdatedchangebase.cpp +++ b/src/core/changes/qpropertyupdatedchangebase.cpp @@ -46,7 +46,7 @@ namespace Qt3DCore { QPropertyUpdatedChangeBasePrivate::QPropertyUpdatedChangeBasePrivate() : QSceneChangePrivate() - , m_isFinal(false) + , m_isIntermediate(false) { } diff --git a/src/core/changes/qpropertyupdatedchangebase_p.h b/src/core/changes/qpropertyupdatedchangebase_p.h index 3c32b2237..b86f2dccf 100644 --- a/src/core/changes/qpropertyupdatedchangebase_p.h +++ b/src/core/changes/qpropertyupdatedchangebase_p.h @@ -69,7 +69,12 @@ public: static QPropertyUpdatedChangeBasePrivate *get(QPropertyUpdatedChangeBase *q); Q_DECLARE_PUBLIC(QPropertyUpdatedChangeBase) - bool m_isFinal; + + // Frontend nodes should not receive intermediate animated property + // updated by default. Only if they subscribe. The animation aspect + // will set this to true for animating properties apart from the final + // frame's update. + bool m_isIntermediate; }; } // namespace Qt3DCore diff --git a/src/core/qpostman.cpp b/src/core/qpostman.cpp index 2b8e6c3a8..206399070 100644 --- a/src/core/qpostman.cpp +++ b/src/core/qpostman.cpp @@ -116,17 +116,21 @@ bool QPostman::shouldNotifyFrontend(const QSceneChangePtr &e) Q_D(QPostman); const QPropertyUpdatedChangePtr propertyChange = qSharedPointerDynamicCast(e); if (Q_LIKELY(d->m_scene != nullptr) && !propertyChange.isNull()) { - const bool isFinal = QPropertyUpdatedChangeBasePrivate::get(propertyChange.data())->m_isFinal; - if (isFinal) - return true; - const QScene::NodePropertyTrackData propertyTrackData = d->m_scene->lookupNodePropertyTrackData(e->subjectId()); + const QScene::NodePropertyTrackData propertyTrackData + = d->m_scene->lookupNodePropertyTrackData(e->subjectId()); switch (propertyTrackData.updateMode) { case QNode::TrackAllPropertiesMode: return true; + case QNode::TrackNamedPropertiesMode: return propertyTrackData.namedProperties.contains(QLatin1String(propertyChange->propertyName())); - case QNode::DefaultTrackMode: - return false; + + case QNode::DefaultTrackMode: { + const bool isIntermediate + = QPropertyUpdatedChangeBasePrivate::get(propertyChange.data())->m_isIntermediate; + return !isIntermediate; + } + default: Q_UNREACHABLE(); return false; diff --git a/src/input/backend/action.cpp b/src/input/backend/action.cpp index 2b8ada042..b7fa8740e 100644 --- a/src/input/backend/action.cpp +++ b/src/input/backend/action.cpp @@ -44,7 +44,6 @@ #include #include #include -#include QT_BEGIN_NAMESPACE @@ -82,7 +81,6 @@ void Action::setActionTriggered(bool actionTriggered) e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll); e->setPropertyName("active"); e->setValue(m_actionTriggered); - Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(e.data())->m_isFinal = true; notifyObservers(e); } } diff --git a/src/input/backend/axis.cpp b/src/input/backend/axis.cpp index 579c9fe7d..4239749c1 100644 --- a/src/input/backend/axis.cpp +++ b/src/input/backend/axis.cpp @@ -44,7 +44,6 @@ #include #include #include -#include QT_BEGIN_NAMESPACE @@ -82,7 +81,6 @@ void Axis::setAxisValue(float axisValue) e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll); e->setPropertyName("value"); e->setValue(m_axisValue); - Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(e.data())->m_isFinal = true; notifyObservers(e); } } diff --git a/src/input/backend/axisaccumulator.cpp b/src/input/backend/axisaccumulator.cpp index 815c25cb0..3b0423f47 100644 --- a/src/input/backend/axisaccumulator.cpp +++ b/src/input/backend/axisaccumulator.cpp @@ -41,7 +41,6 @@ #include #include #include -#include QT_BEGIN_NAMESPACE @@ -88,7 +87,6 @@ void AxisAccumulator::setValue(float value) e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll); e->setPropertyName("value"); e->setValue(m_value); - Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(e.data())->m_isFinal = true; notifyObservers(e); } } @@ -103,7 +101,6 @@ void AxisAccumulator::setVelocity(float velocity) e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll); e->setPropertyName("velocity"); e->setValue(m_velocity); - Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(e.data())->m_isFinal = true; notifyObservers(e); } } diff --git a/src/input/backend/keyboardhandler.cpp b/src/input/backend/keyboardhandler.cpp index b674ac372..b96334e50 100644 --- a/src/input/backend/keyboardhandler.cpp +++ b/src/input/backend/keyboardhandler.cpp @@ -44,7 +44,6 @@ #include "inputhandler_p.h" #include "inputmanagers_p.h" #include -#include #include QT_BEGIN_NAMESPACE @@ -91,7 +90,6 @@ void KeyboardHandler::setFocus(bool focus) e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll); e->setPropertyName("focus"); e->setValue(m_focus); - Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(e.data())->m_isFinal = true; notifyObservers(e); } } @@ -102,7 +100,6 @@ void KeyboardHandler::keyEvent(const QKeyEventPtr &event) e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll); e->setPropertyName("event"); e->setValue(QVariant::fromValue(event)); - Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(e.data())->m_isFinal = true; notifyObservers(e); } diff --git a/src/input/backend/mousehandler.cpp b/src/input/backend/mousehandler.cpp index 770c318e1..b7b748843 100644 --- a/src/input/backend/mousehandler.cpp +++ b/src/input/backend/mousehandler.cpp @@ -46,7 +46,6 @@ #include #include #include -#include QT_BEGIN_NAMESPACE @@ -88,7 +87,6 @@ void MouseHandler::mouseEvent(const QMouseEventPtr &event) e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll); e->setPropertyName("mouse"); e->setValue(QVariant::fromValue(event)); - Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(e.data())->m_isFinal = true; notifyObservers(e); } @@ -98,7 +96,6 @@ void MouseHandler::wheelEvent(const QWheelEventPtr &event) e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll); e->setPropertyName("wheel"); e->setValue(QVariant::fromValue(event)); - Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(e.data())->m_isFinal = true; notifyObservers(e); } diff --git a/src/input/backend/physicaldeviceproxy.cpp b/src/input/backend/physicaldeviceproxy.cpp index 083f2438a..2e46309fd 100644 --- a/src/input/backend/physicaldeviceproxy.cpp +++ b/src/input/backend/physicaldeviceproxy.cpp @@ -42,7 +42,6 @@ #include #include #include -#include #include QT_BEGIN_NAMESPACE @@ -93,7 +92,6 @@ void PhysicalDeviceProxy::setDevice(QAbstractPhysicalDevice *device) e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll); e->setPropertyName("device"); e->setValue(QVariant::fromValue(device)); - Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(e.data())->m_isFinal = true; notifyObservers(e); } diff --git a/src/render/backend/levelofdetail.cpp b/src/render/backend/levelofdetail.cpp index 474133d1c..9ff0ef532 100644 --- a/src/render/backend/levelofdetail.cpp +++ b/src/render/backend/levelofdetail.cpp @@ -43,7 +43,6 @@ #include #include #include -#include #include QT_BEGIN_NAMESPACE @@ -119,7 +118,6 @@ void LevelOfDetail::setCurrentIndex(int currentIndex) e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll); e->setPropertyName("currentIndex"); e->setValue(m_currentIndex); - Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(e.data())->m_isFinal = true; notifyObservers(e); } } diff --git a/src/render/geometry/buffer.cpp b/src/render/geometry/buffer.cpp index 7fefcfbbb..d91f2779f 100644 --- a/src/render/geometry/buffer.cpp +++ b/src/render/geometry/buffer.cpp @@ -41,7 +41,6 @@ #include #include #include -#include QT_BEGIN_NAMESPACE @@ -95,7 +94,6 @@ void Buffer::executeFunctor() e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll); e->setPropertyName("data"); e->setValue(QVariant::fromValue(m_data)); - Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(e.data())->m_isFinal = true; notifyObservers(e); } } @@ -109,7 +107,6 @@ void Buffer::updateDataFromGPUToCPU(QByteArray data) e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll); e->setPropertyName("downloadedData"); e->setValue(QVariant::fromValue(m_data)); - Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(e.data())->m_isFinal = true; notifyObservers(e); } diff --git a/src/render/io/scene.cpp b/src/render/io/scene.cpp index 2057ffd3d..cf1ca4736 100644 --- a/src/render/io/scene.cpp +++ b/src/render/io/scene.cpp @@ -46,7 +46,6 @@ #include #include #include -#include QT_BEGIN_NAMESPACE @@ -73,7 +72,6 @@ void Scene::setStatus(QSceneLoader::Status status) e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll); e->setPropertyName("status"); e->setValue(QVariant::fromValue(status)); - Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(e.data())->m_isFinal = true; notifyObservers(e); } @@ -116,7 +114,6 @@ void Scene::setSceneSubtree(Qt3DCore::QEntity *subTree) e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll); e->setPropertyName("scene"); e->setValue(QVariant::fromValue(subTree)); - Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(e.data())->m_isFinal = true; notifyObservers(e); } diff --git a/src/render/picking/objectpicker.cpp b/src/render/picking/objectpicker.cpp index a90d8f537..6d84ec2a0 100644 --- a/src/render/picking/objectpicker.cpp +++ b/src/render/picking/objectpicker.cpp @@ -44,7 +44,6 @@ #include #include #include -#include QT_BEGIN_NAMESPACE @@ -142,7 +141,6 @@ void ObjectPicker::onClicked(QPickEventPtr event) e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll); e->setPropertyName("clicked"); e->setValue(QVariant::fromValue(event)); - Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(e.data())->m_isFinal = true; notifyObservers(e); } @@ -152,7 +150,6 @@ void ObjectPicker::onMoved(QPickEventPtr event) e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll); e->setPropertyName("moved"); e->setValue(QVariant::fromValue(event)); - Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(e.data())->m_isFinal = true; notifyObservers(e); } @@ -163,7 +160,6 @@ void ObjectPicker::onPressed(QPickEventPtr event) e->setPropertyName("pressed"); e->setValue(QVariant::fromValue(event)); m_isPressed = true; - Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(e.data())->m_isFinal = true; notifyObservers(e); } @@ -174,7 +170,6 @@ void ObjectPicker::onReleased(QPickEventPtr event) e->setPropertyName("released"); e->setValue(QVariant::fromValue(event)); m_isPressed = false; - Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(e.data())->m_isFinal = true; notifyObservers(e); } @@ -183,7 +178,6 @@ void ObjectPicker::onEntered() auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId()); e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll); e->setPropertyName("entered"); - Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(e.data())->m_isFinal = true; notifyObservers(e); } @@ -192,7 +186,6 @@ void ObjectPicker::onExited() auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId()); e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll); e->setPropertyName("exited"); - Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(e.data())->m_isFinal = true; notifyObservers(e); } diff --git a/tests/auto/animation/animationclip/tst_animationclip.cpp b/tests/auto/animation/animationclip/tst_animationclip.cpp index f0b45bfeb..1a61dec2c 100644 --- a/tests/auto/animation/animationclip/tst_animationclip.cpp +++ b/tests/auto/animation/animationclip/tst_animationclip.cpp @@ -134,7 +134,8 @@ private Q_SLOTS: Qt3DCore::QPropertyUpdatedChangePtr change = arbiter.events.first().staticCast(); QCOMPARE(change->propertyName(), "duration"); QCOMPARE(change->value().toFloat(), backendClip.duration()); - QCOMPARE(Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(change.data())->m_isFinal, true); + QCOMPARE(Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(change.data())->m_isIntermediate, + false); arbiter.events.clear(); diff --git a/tests/auto/core/qpostman/tst_qpostman.cpp b/tests/auto/core/qpostman/tst_qpostman.cpp index e51c21b59..1dabf143f 100644 --- a/tests/auto/core/qpostman/tst_qpostman.cpp +++ b/tests/auto/core/qpostman/tst_qpostman.cpp @@ -38,21 +38,22 @@ #include #include "testpostmanarbiter.h" +using namespace Qt3DCore; namespace { -class NodeChangeReceiver: public Qt3DCore::QNode +class NodeChangeReceiver: public QNode { public: - NodeChangeReceiver(Qt3DCore::QNode *parent = nullptr) - : Qt3DCore::QNode(parent) + NodeChangeReceiver(QNode *parent = nullptr) + : QNode(parent) , m_hasReceivedChange(false) {} inline bool hasReceivedChange() const { return m_hasReceivedChange; } protected: - void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &) Q_DECL_OVERRIDE + void sceneChangeEvent(const QSceneChangePtr &) Q_DECL_OVERRIDE { m_hasReceivedChange = true; } @@ -72,42 +73,42 @@ private Q_SLOTS: void checkSetScene() { // GIVEN - Qt3DCore::QPostman postman; + QPostman postman; // THEN - QVERIFY(Qt3DCore::QPostmanPrivate::get(&postman)->m_scene == nullptr); + QVERIFY(QPostmanPrivate::get(&postman)->m_scene == nullptr); // WHEN - Qt3DCore::QScene scene; + QScene scene; postman.setScene(&scene); // THEN - QCOMPARE(Qt3DCore::QPostmanPrivate::get(&postman)->m_scene, &scene); + QCOMPARE(QPostmanPrivate::get(&postman)->m_scene, &scene); } void checkSceneChangeEvent() { // GIVEN - QScopedPointer scene(new Qt3DCore::QScene); - Qt3DCore::QPostman postman; + QScopedPointer scene(new QScene); + QPostman postman; TestArbiter arbiter; - Qt3DCore::QNode rootNode; + QNode rootNode; NodeChangeReceiver *receiverNode = new NodeChangeReceiver(); - Qt3DCore::QNodePrivate::get(&rootNode)->m_scene = scene.data(); + QNodePrivate::get(&rootNode)->m_scene = scene.data(); scene->setArbiter(&arbiter); postman.setScene(scene.data()); // Setting the parent (which has a scene) adds the node into the observable lookup // table of the scene which is needed by the postman to distribute changes - static_cast(receiverNode)->setParent(&rootNode); + static_cast(receiverNode)->setParent(&rootNode); QCoreApplication::processEvents(); // THEN QCOMPARE(receiverNode->hasReceivedChange(), false); - QCOMPARE(Qt3DCore::QNodePrivate::get(receiverNode)->m_scene, scene.data()); + QCOMPARE(QNodePrivate::get(receiverNode)->m_scene, scene.data()); // WHEN - Qt3DCore::QPropertyUpdatedChangePtr updateChange(new Qt3DCore::QPropertyUpdatedChange(receiverNode->id())); + QPropertyUpdatedChangePtr updateChange(new QPropertyUpdatedChange(receiverNode->id())); updateChange->setValue(1584); updateChange->setPropertyName("someName"); postman.sceneChangeEvent(updateChange); @@ -120,8 +121,8 @@ private Q_SLOTS: void checkNotifyBackend() { // GIVEN - QScopedPointer scene(new Qt3DCore::QScene); - Qt3DCore::QPostman postman; + QScopedPointer scene(new QScene); + QPostman postman; TestArbiter arbiter; scene->setArbiter(&arbiter); @@ -131,7 +132,7 @@ private Q_SLOTS: QCOMPARE(arbiter.events.size(), 0); // WHEN - Qt3DCore::QPropertyUpdatedChangePtr updateChange(new Qt3DCore::QPropertyUpdatedChange(Qt3DCore::QNodeId())); + QPropertyUpdatedChangePtr updateChange(new QPropertyUpdatedChange(QNodeId())); updateChange->setValue(1584); updateChange->setPropertyName("someName"); postman.notifyBackend(updateChange); @@ -145,62 +146,72 @@ private Q_SLOTS: void checkShouldNotifyFrontend() { // GIVEN - QScopedPointer scene(new Qt3DCore::QScene); - Qt3DCore::QPostman postman; + QScopedPointer scene(new QScene); + QPostman postman; TestArbiter arbiter; - Qt3DCore::QNode rootNode; + QNode rootNode; NodeChangeReceiver *receiverNode = new NodeChangeReceiver(); - Qt3DCore::QNodePrivate::get(&rootNode)->m_scene = scene.data(); + QNodePrivate::get(&rootNode)->m_scene = scene.data(); scene->setArbiter(&arbiter); postman.setScene(scene.data()); // Setting the parent (which has a scene) adds the node into the observable lookup // table of the scene which is needed by the postman to distribute changes - static_cast(receiverNode)->setParent(&rootNode); + static_cast(receiverNode)->setParent(&rootNode); QCoreApplication::processEvents(); { // WHEN - Qt3DCore::QPropertyUpdatedChangePtr updateChange(new Qt3DCore::QPropertyUpdatedChange(receiverNode->id())); + auto updateChange = QPropertyUpdatedChangePtr::create(receiverNode->id()); updateChange->setValue(1584); updateChange->setPropertyName("someName"); - // THEN -> we don't track properties by default Qt3DCore::QNode::DontTrackProperties - QCOMPARE(postman.shouldNotifyFrontend(updateChange), false); + + // THEN -> we do track properties by default QNode::DefaultTrackMode + // (unless marked as an intermediate change) + QCOMPARE(postman.shouldNotifyFrontend(updateChange), true); } { // WHEN - receiverNode->setPropertyTrackMode(Qt3DCore::QNode::TrackAllPropertiesMode); + receiverNode->setPropertyTrackMode(QNode::TrackAllPropertiesMode); - Qt3DCore::QPropertyUpdatedChangePtr updateChange(new Qt3DCore::QPropertyUpdatedChange(receiverNode->id())); + auto updateChange = QPropertyUpdatedChangePtr::create(receiverNode->id()); updateChange->setValue(1584); updateChange->setPropertyName("someName"); + QPropertyUpdatedChangeBasePrivate::get(updateChange.data())->m_isIntermediate + = true; - // THEN -> we don't track properties by default + // THEN -> we do track properties marked as intermediate when + // using TrackAllPropertiesMode QCOMPARE(postman.shouldNotifyFrontend(updateChange), true); } { // GIVEN - receiverNode->setPropertyTrackMode(Qt3DCore::QNode::TrackNamedPropertiesMode); + receiverNode->setPropertyTrackMode(QNode::TrackNamedPropertiesMode); receiverNode->setTrackedProperties(QStringList() << QStringLiteral("vette")); { // WHEN - Qt3DCore::QPropertyUpdatedChangePtr updateChange(new Qt3DCore::QPropertyUpdatedChange(receiverNode->id())); + auto updateChange = QPropertyUpdatedChangePtr::create(receiverNode->id()); updateChange->setValue(1584); updateChange->setPropertyName("someName"); + QPropertyUpdatedChangeBasePrivate::get(updateChange.data())->m_isIntermediate + = true; - // THEN -> we don't track properties by default + // THEN -> we don't track properties by default, unless named when + // using TrackNamedPropertiesMode QCOMPARE(postman.shouldNotifyFrontend(updateChange), false); } { // WHEN - Qt3DCore::QPropertyUpdatedChangePtr updateChange(new Qt3DCore::QPropertyUpdatedChange(receiverNode->id())); + auto updateChange = QPropertyUpdatedChangePtr::create(receiverNode->id()); updateChange->setValue(1584); updateChange->setPropertyName("vette"); + QPropertyUpdatedChangeBasePrivate::get(updateChange.data())->m_isIntermediate + = true; // THEN QCOMPARE(postman.shouldNotifyFrontend(updateChange), true); @@ -210,11 +221,11 @@ private Q_SLOTS: { // GIVEN receiverNode->setTrackedProperties(QStringList() << QStringLiteral("vette")); - receiverNode->setPropertyTrackMode(Qt3DCore::QNode::TrackAllPropertiesMode); + receiverNode->setPropertyTrackMode(QNode::TrackAllPropertiesMode); { // WHEN - Qt3DCore::QPropertyUpdatedChangePtr updateChange(new Qt3DCore::QPropertyUpdatedChange(receiverNode->id())); + auto updateChange = QPropertyUpdatedChangePtr::create(receiverNode->id()); updateChange->setValue(1584); updateChange->setPropertyName("someName"); @@ -224,7 +235,7 @@ private Q_SLOTS: { // WHEN - Qt3DCore::QPropertyUpdatedChangePtr updateChange(new Qt3DCore::QPropertyUpdatedChange(receiverNode->id())); + auto updateChange = QPropertyUpdatedChangePtr::create(receiverNode->id()); updateChange->setValue(1584); updateChange->setPropertyName("vette"); @@ -236,28 +247,30 @@ private Q_SLOTS: { // GIVEN receiverNode->setTrackedProperties(QStringList()); - receiverNode->setPropertyTrackMode(Qt3DCore::QNode::DefaultTrackMode); + receiverNode->setPropertyTrackMode(QNode::DefaultTrackMode); { // WHEN - Qt3DCore::QPropertyUpdatedChangePtr updateChange(new Qt3DCore::QPropertyUpdatedChange(receiverNode->id())); + auto updateChange = QPropertyUpdatedChangePtr::create(receiverNode->id()); updateChange->setValue(1584); updateChange->setPropertyName("someName"); - // THEN -> we don't track properties by default - QCOMPARE(postman.shouldNotifyFrontend(updateChange), false); + // THEN -> we do track properties by default, unless marked as intermediate + QCOMPARE(postman.shouldNotifyFrontend(updateChange), true); } { // WHEN - Qt3DCore::QPropertyNodeAddedChangePtr addedChange(new Qt3DCore::QPropertyNodeAddedChange(receiverNode->id(), receiverNode)); + auto addedChange + = QPropertyNodeAddedChangePtr::create(receiverNode->id(), receiverNode); // THEN -> only QPropertyUpdatedChangePtr are filtered QCOMPARE(postman.shouldNotifyFrontend(addedChange), true); } { // WHEN - Qt3DCore::QPropertyNodeRemovedChangePtr removedChange(new Qt3DCore::QPropertyNodeRemovedChange(receiverNode->id(), receiverNode)); + auto removedChange + = QPropertyNodeRemovedChangePtr::create(receiverNode->id(), receiverNode); // THEN -> only QPropertyUpdatedChangePtr are filtered QCOMPARE(postman.shouldNotifyFrontend(removedChange), true); @@ -267,24 +280,25 @@ private Q_SLOTS: { // GIVEN receiverNode->setTrackedProperties(QStringList()); - receiverNode->setPropertyTrackMode(Qt3DCore::QNode::DefaultTrackMode); + receiverNode->setPropertyTrackMode(QNode::DefaultTrackMode); { // WHEN - Qt3DCore::QPropertyUpdatedChangePtr updateChange(new Qt3DCore::QPropertyUpdatedChange(receiverNode->id())); + auto updateChange = QPropertyUpdatedChangePtr::create(receiverNode->id()); updateChange->setValue(1584); updateChange->setPropertyName("someName"); + QPropertyUpdatedChangeBasePrivate::get(updateChange.data())->m_isIntermediate + = true; - // THEN -> we don't track properties by default + // THEN -> we don't track intermediate properties by default QCOMPARE(postman.shouldNotifyFrontend(updateChange), false); } { // WHEN - Qt3DCore::QPropertyUpdatedChangePtr updateChange(new Qt3DCore::QPropertyUpdatedChange(receiverNode->id())); + auto updateChange = QPropertyUpdatedChangePtr::create(receiverNode->id()); updateChange->setValue(1584); updateChange->setPropertyName("someName"); - Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(updateChange.data())->m_isFinal = true; // THEN QCOMPARE(postman.shouldNotifyFrontend(updateChange), true); diff --git a/tests/auto/input/action/tst_action.cpp b/tests/auto/input/action/tst_action.cpp index da27446f6..91ca2f794 100644 --- a/tests/auto/input/action/tst_action.cpp +++ b/tests/auto/input/action/tst_action.cpp @@ -37,7 +37,6 @@ #include #include #include -#include #include "testpostmanarbiter.h" class DummyActionInput : public Qt3DInput::QActionInput @@ -160,7 +159,6 @@ private Q_SLOTS: Qt3DCore::QPropertyUpdatedChangePtr change = arbiter.events.first().staticCast(); QCOMPARE(change->propertyName(), "active"); QCOMPARE(change->value().toBool(), backendAction.actionTriggered()); - QCOMPARE(Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(change.data())->m_isFinal, true); arbiter.events.clear(); diff --git a/tests/auto/input/axis/tst_axis.cpp b/tests/auto/input/axis/tst_axis.cpp index 90f774489..dc8b225ba 100644 --- a/tests/auto/input/axis/tst_axis.cpp +++ b/tests/auto/input/axis/tst_axis.cpp @@ -38,7 +38,6 @@ #include #include #include -#include #include "testpostmanarbiter.h" class DummyAxisInput : public Qt3DInput::QAbstractAxisInput @@ -160,7 +159,6 @@ private Q_SLOTS: Qt3DCore::QPropertyUpdatedChangePtr change = arbiter.events.first().staticCast(); QCOMPARE(change->propertyName(), "value"); QCOMPARE(change->value().toFloat(), backendAxis.axisValue()); - QCOMPARE(Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(change.data())->m_isFinal, true); arbiter.events.clear(); diff --git a/tests/auto/input/axisaccumulator/tst_axisaccumulator.cpp b/tests/auto/input/axisaccumulator/tst_axisaccumulator.cpp index 9728ac0d0..94cb71030 100644 --- a/tests/auto/input/axisaccumulator/tst_axisaccumulator.cpp +++ b/tests/auto/input/axisaccumulator/tst_axisaccumulator.cpp @@ -41,7 +41,6 @@ #include #include #include -#include #include "testpostmanarbiter.h" class tst_AxisAccumulator: public Qt3DCore::QBackendNodeTester @@ -170,7 +169,6 @@ private Q_SLOTS: Qt3DCore::QPropertyUpdatedChangePtr change = arbiter.events.first().staticCast(); QCOMPARE(change->propertyName(), "value"); QCOMPARE(change->value().toFloat(), backendAxisAccumulator.value()); - QCOMPARE(Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(change.data())->m_isFinal, true); arbiter.events.clear(); @@ -193,7 +191,6 @@ private Q_SLOTS: Qt3DCore::QPropertyUpdatedChangePtr velocityChange = arbiter.events.first().staticCast(); QCOMPARE(velocityChange->propertyName(), "velocity"); QCOMPARE(velocityChange->value().toFloat(), backendAxisAccumulator.velocity()); - QCOMPARE(Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(change.data())->m_isFinal, true); arbiter.events.clear(); diff --git a/tests/auto/input/physicaldeviceproxy/tst_physicaldeviceproxy.cpp b/tests/auto/input/physicaldeviceproxy/tst_physicaldeviceproxy.cpp index a5f54aec9..d19e69ecc 100644 --- a/tests/auto/input/physicaldeviceproxy/tst_physicaldeviceproxy.cpp +++ b/tests/auto/input/physicaldeviceproxy/tst_physicaldeviceproxy.cpp @@ -128,7 +128,6 @@ private Q_SLOTS: QCOMPARE(change->value().value(), &physicalDevice); QCOMPARE(change->subjectId(), backendPhysicalDeviceProxy.peerId()); QCOMPARE(backendPhysicalDeviceProxy.physicalDeviceId(), physicalDevice.id()); - QCOMPARE(Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(change.data())->m_isFinal, true); } void checkCleanupState() diff --git a/tests/auto/render/buffer/tst_buffer.cpp b/tests/auto/render/buffer/tst_buffer.cpp index da5f74dd6..b06425bd7 100644 --- a/tests/auto/render/buffer/tst_buffer.cpp +++ b/tests/auto/render/buffer/tst_buffer.cpp @@ -33,7 +33,6 @@ #include #include #include -#include #include "testpostmanarbiter.h" #include "testrenderer.h" @@ -234,7 +233,6 @@ private Q_SLOTS: Qt3DCore::QPropertyUpdatedChangePtr change = arbiter.events.first().staticCast(); QCOMPARE(change->propertyName(), "data"); QCOMPARE(change->value().toByteArray(), QByteArrayLiteral("454")); - QCOMPARE(Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(change.data())->m_isFinal, true); arbiter.events.clear(); diff --git a/tests/auto/render/objectpicker/tst_objectpicker.cpp b/tests/auto/render/objectpicker/tst_objectpicker.cpp index c0e986e08..4ba57b0ad 100644 --- a/tests/auto/render/objectpicker/tst_objectpicker.cpp +++ b/tests/auto/render/objectpicker/tst_objectpicker.cpp @@ -33,7 +33,6 @@ #include #include #include -#include #include "testpostmanarbiter.h" #include "testrenderer.h" @@ -130,7 +129,6 @@ private Q_SLOTS: QCOMPARE(arbiter.events.count(), 1); Qt3DCore::QPropertyUpdatedChangePtr change = arbiter.events.first().staticCast(); QCOMPARE(change->propertyName(), "pressed"); - QCOMPARE(Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(change.data())->m_isFinal, true); arbiter.events.clear(); @@ -141,7 +139,6 @@ private Q_SLOTS: QCOMPARE(arbiter.events.count(), 1); change = arbiter.events.first().staticCast(); QCOMPARE(change->propertyName(), "released"); - QCOMPARE(Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(change.data())->m_isFinal, true); arbiter.events.clear(); @@ -152,7 +149,6 @@ private Q_SLOTS: QCOMPARE(arbiter.events.count(), 1); change = arbiter.events.first().staticCast(); QCOMPARE(change->propertyName(), "clicked"); - QCOMPARE(Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(change.data())->m_isFinal, true); arbiter.events.clear(); @@ -163,7 +159,6 @@ private Q_SLOTS: QCOMPARE(arbiter.events.count(), 1); change = arbiter.events.first().staticCast(); QCOMPARE(change->propertyName(), "entered"); - QCOMPARE(Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(change.data())->m_isFinal, true); arbiter.events.clear(); @@ -174,7 +169,6 @@ private Q_SLOTS: QCOMPARE(arbiter.events.count(), 1); change = arbiter.events.first().staticCast(); QCOMPARE(change->propertyName(), "exited"); - QCOMPARE(Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(change.data())->m_isFinal, true); arbiter.events.clear(); } diff --git a/tests/auto/render/sceneloader/tst_sceneloader.cpp b/tests/auto/render/sceneloader/tst_sceneloader.cpp index edd6fabda..cd6d76a5a 100644 --- a/tests/auto/render/sceneloader/tst_sceneloader.cpp +++ b/tests/auto/render/sceneloader/tst_sceneloader.cpp @@ -147,7 +147,6 @@ private Q_SLOTS: QCOMPARE(arbiter.events.count(), 1); QCOMPARE(change->propertyName(), "scene"); QCOMPARE(change->value().value(), &subtree); - QCOMPARE(Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(change.data())->m_isFinal, true); arbiter.events.clear(); } @@ -170,7 +169,6 @@ private Q_SLOTS: QCOMPARE(arbiter.events.count(), 1); QCOMPARE(change->propertyName(), "status"); QCOMPARE(change->value().value(), Qt3DRender::QSceneLoader::Ready); - QCOMPARE(Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(change.data())->m_isFinal, true); arbiter.events.clear(); } -- cgit v1.2.3 From 5b890620adfd4f554eb8eed54a05cd53be9ac809 Mon Sep 17 00:00:00 2001 From: Mike Krus Date: Thu, 9 Feb 2017 13:08:12 +0000 Subject: Fix Clang warnings: out of order initialization Change-Id: Iea0b93082167bda9502e6947f213ab3430fa00d1 Reviewed-by: Sean Harmer --- src/animation/frontend/qkeyframeanimation.cpp | 4 ++-- src/quick3d/quick3drender/scene2d/scene2d.cpp | 6 +++--- src/render/backend/renderer.cpp | 4 ++-- src/render/backend/renderview.cpp | 4 ++-- src/render/backend/resourceaccessor.cpp | 4 ++-- tests/manual/render-qml-to-texture/planematerial.cpp | 2 +- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/animation/frontend/qkeyframeanimation.cpp b/src/animation/frontend/qkeyframeanimation.cpp index 5c3ca1ca1..2e63e96c8 100644 --- a/src/animation/frontend/qkeyframeanimation.cpp +++ b/src/animation/frontend/qkeyframeanimation.cpp @@ -45,10 +45,10 @@ namespace Qt3DAnimation { QKeyframeAnimationPrivate::QKeyframeAnimationPrivate() : QAbstractAnimationPrivate(QAbstractAnimation::KeyframeAnimation) - , m_minposition(0.0f) - , m_maxposition(0.0f) , m_prevPosition(-1.0f) , m_target(nullptr) + , m_minposition(0.0f) + , m_maxposition(0.0f) , m_startMode(QKeyframeAnimation::Constant) , m_endMode(QKeyframeAnimation::Constant) { diff --git a/src/quick3d/quick3drender/scene2d/scene2d.cpp b/src/quick3d/quick3drender/scene2d/scene2d.cpp index 710284be2..51a4304af 100644 --- a/src/quick3d/quick3drender/scene2d/scene2d.cpp +++ b/src/quick3d/quick3drender/scene2d/scene2d.cpp @@ -105,13 +105,13 @@ bool RenderQmlEventHandler::event(QEvent *e) Scene2D::Scene2D() : m_context(nullptr) , m_shareContext(nullptr) - , m_sharedObject(nullptr) , m_renderThread(nullptr) + , m_sharedObject(nullptr) + , m_fbo(0) + , m_rbo(0) , m_initialized(false) , m_renderInitialized(false) , m_renderPolicy(Qt3DRender::Quick::QScene2D::Continuous) - , m_fbo(0) - , m_rbo(0) { renderThreadClientCount->fetchAndAddAcquire(1); } diff --git a/src/render/backend/renderer.cpp b/src/render/backend/renderer.cpp index da4936a8b..7b8e5315f 100644 --- a/src/render/backend/renderer.cpp +++ b/src/render/backend/renderer.cpp @@ -155,10 +155,10 @@ Renderer::Renderer(QRenderAspect::RenderType type) , m_waitForInitializationToBeCompleted(0) , m_pickEventFilter(new PickEventFilter()) , m_exposed(0) - , m_shareContext(nullptr) , m_changeSet(0) , m_lastFrameCorrect(0) , m_glContext(nullptr) + , m_shareContext(nullptr) , m_pickBoundingVolumeJob(PickBoundingVolumeJobPtr::create()) , m_time(0) , m_settings(nullptr) @@ -170,8 +170,8 @@ Renderer::Renderer(QRenderAspect::RenderType type) , m_updateWorldBoundingVolumeJob(Render::UpdateWorldBoundingVolumeJobPtr::create()) , m_updateTreeEnabledJob(Render::UpdateTreeEnabledJobPtr::create()) , m_sendRenderCaptureJob(Render::SendRenderCaptureJobPtr::create(this)) - , m_updateLevelOfDetailJob(Render::UpdateLevelOfDetailJobPtr::create()) , m_sendBufferCaptureJob(Render::SendBufferCaptureJobPtr::create(this)) + , m_updateLevelOfDetailJob(Render::UpdateLevelOfDetailJobPtr::create()) , m_updateMeshTriangleListJob(Render::UpdateMeshTriangleListJobPtr::create()) , m_filterCompatibleTechniqueJob(Render::FilterCompatibleTechniqueJobPtr::create()) , m_bufferGathererJob(Render::GenericLambdaJobPtr>::create([this] { lookForDirtyBuffers(); }, JobTypes::DirtyBufferGathering)) diff --git a/src/render/backend/renderview.cpp b/src/render/backend/renderview.cpp index e5e75aee9..c7d2c7864 100644 --- a/src/render/backend/renderview.cpp +++ b/src/render/backend/renderview.cpp @@ -208,7 +208,8 @@ UniformValue RenderView::standardUniformValue(RenderView::StandardUniform standa } RenderView::RenderView() - : m_renderer(nullptr) + : m_isDownloadBuffersEnable(false) + , m_renderer(nullptr) , m_devicePixelRatio(1.) , m_viewport(QRectF(0.0f, 0.0f, 1.0f, 1.0f)) , m_gamma(2.2f) @@ -217,7 +218,6 @@ RenderView::RenderView() , m_stateSet(nullptr) , m_noDraw(false) , m_compute(false) - , m_isDownloadBuffersEnable(false) , m_frustumCulling(false) , m_memoryBarrier(QMemoryBarrier::None) { diff --git a/src/render/backend/resourceaccessor.cpp b/src/render/backend/resourceaccessor.cpp index c02130aa9..43f416d16 100644 --- a/src/render/backend/resourceaccessor.cpp +++ b/src/render/backend/resourceaccessor.cpp @@ -55,9 +55,9 @@ namespace Qt3DRender { namespace Render { ResourceAccessor::ResourceAccessor(NodeManagers *mgr) - : m_textureManager(mgr->textureManager()) + : m_glTextureManager(mgr->glTextureManager()) + , m_textureManager(mgr->textureManager()) , m_attachmentManager(mgr->attachmentManager()) - , m_glTextureManager(mgr->glTextureManager()) { } diff --git a/tests/manual/render-qml-to-texture/planematerial.cpp b/tests/manual/render-qml-to-texture/planematerial.cpp index e3886a296..4435766bb 100644 --- a/tests/manual/render-qml-to-texture/planematerial.cpp +++ b/tests/manual/render-qml-to-texture/planematerial.cpp @@ -52,8 +52,8 @@ PlaneMaterial::PlaneMaterial(Qt3DRender::QAbstractTexture *texture, Qt3DCore::QNode *parent) : QMaterial(parent) - , m_texture(texture) , m_effect(new Qt3DRender::QEffect(this)) + , m_texture(texture) { setEffect(m_effect); -- cgit v1.2.3 From 4ec16f079604f16eeb0703bc9ee3d696707995b6 Mon Sep 17 00:00:00 2001 From: Mike Krus Date: Thu, 9 Feb 2017 13:10:37 +0000 Subject: Fix Clang warnings: use of deprecated api Change-Id: I72f92bfcbbd253cb3912c6dc51db9612d695fee9 Reviewed-by: Sean Harmer --- src/animation/frontend/qmorphinganimation.cpp | 2 +- src/animation/frontend/qvertexblendanimation.cpp | 2 +- src/render/picking/qeventforward_p.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/animation/frontend/qmorphinganimation.cpp b/src/animation/frontend/qmorphinganimation.cpp index 2ac09464f..4463f6cbf 100644 --- a/src/animation/frontend/qmorphinganimation.cpp +++ b/src/animation/frontend/qmorphinganimation.cpp @@ -124,7 +124,7 @@ void QMorphingAnimationPrivate::setTargetInterpolated(int morphTarget) if (target != m_currentTarget) { for (int i = 0; i < m_attributeNames.size(); ++i) { QString targetName = m_attributeNames.at(i); - targetName.append("Target"); + targetName.append(QLatin1String("Target")); targetAttributes[i]->setName(targetName); geometry->addAttribute(targetAttributes.at(i)); } diff --git a/src/animation/frontend/qvertexblendanimation.cpp b/src/animation/frontend/qvertexblendanimation.cpp index cd8f95f73..4f7388087 100644 --- a/src/animation/frontend/qvertexblendanimation.cpp +++ b/src/animation/frontend/qvertexblendanimation.cpp @@ -121,7 +121,7 @@ void QVertexBlendAnimationPrivate::updateAnimation(float position) for (int i = 0; i < baseAttributes.size(); ++i) { const QString baseName = attributeNames.at(i); QString targetName = baseName; - targetName.append("Target"); + targetName.append(QLatin1String("Target")); baseAttributes[i]->setName(baseName); geometry->addAttribute(baseAttributes.at(i)); diff --git a/src/render/picking/qeventforward_p.h b/src/render/picking/qeventforward_p.h index c087bc8f5..d3c3018e0 100644 --- a/src/render/picking/qeventforward_p.h +++ b/src/render/picking/qeventforward_p.h @@ -65,7 +65,7 @@ public: QEventForwardPrivate() : QNodePrivate() , m_target(nullptr) - , m_attribute("default") + , m_attribute(QLatin1String("default")) , m_forwardMouseEvents(true) , m_forwardKeyboardEvents(false) , m_focus(false) -- cgit v1.2.3 From b68028dbce811a0b4f5a3793b1bf7a2a546911be Mon Sep 17 00:00:00 2001 From: Mike Krus Date: Thu, 9 Feb 2017 13:11:55 +0000 Subject: Fix Clang warnings: remove unused code and data Change-Id: Ida1118c6471f35bff195395ed1df8f4dac2f0e6f Reviewed-by: Sean Harmer --- src/animation/frontend/qvertexblendanimation.cpp | 10 ---------- src/render/backend/renderer.cpp | 2 +- src/render/jobs/sendbuffercapturejob.cpp | 3 +-- src/render/jobs/sendbuffercapturejob_p.h | 3 +-- tests/manual/deferred-renderer-cpp/gbuffer.h | 1 - 5 files changed, 3 insertions(+), 16 deletions(-) diff --git a/src/animation/frontend/qvertexblendanimation.cpp b/src/animation/frontend/qvertexblendanimation.cpp index 4f7388087..0bad72abf 100644 --- a/src/animation/frontend/qvertexblendanimation.cpp +++ b/src/animation/frontend/qvertexblendanimation.cpp @@ -74,16 +74,6 @@ void QVertexBlendAnimationPrivate::getAttributesInPosition(float position, int * } } -static Qt3DRender::QAttribute *findAttribute(QVector &attributes, - QString name) -{ - for (Qt3DRender::QAttribute *gattr : attributes) { - if (gattr->name() == name) - return gattr; - } - return nullptr; -} - void QVertexBlendAnimationPrivate::updateAnimation(float position) { Q_Q(QVertexBlendAnimation); diff --git a/src/render/backend/renderer.cpp b/src/render/backend/renderer.cpp index 7b8e5315f..9564c6e8b 100644 --- a/src/render/backend/renderer.cpp +++ b/src/render/backend/renderer.cpp @@ -170,7 +170,7 @@ Renderer::Renderer(QRenderAspect::RenderType type) , m_updateWorldBoundingVolumeJob(Render::UpdateWorldBoundingVolumeJobPtr::create()) , m_updateTreeEnabledJob(Render::UpdateTreeEnabledJobPtr::create()) , m_sendRenderCaptureJob(Render::SendRenderCaptureJobPtr::create(this)) - , m_sendBufferCaptureJob(Render::SendBufferCaptureJobPtr::create(this)) + , m_sendBufferCaptureJob(Render::SendBufferCaptureJobPtr::create()) , m_updateLevelOfDetailJob(Render::UpdateLevelOfDetailJobPtr::create()) , m_updateMeshTriangleListJob(Render::UpdateMeshTriangleListJobPtr::create()) , m_filterCompatibleTechniqueJob(Render::FilterCompatibleTechniqueJobPtr::create()) diff --git a/src/render/jobs/sendbuffercapturejob.cpp b/src/render/jobs/sendbuffercapturejob.cpp index 90d328b96..3785d8238 100644 --- a/src/render/jobs/sendbuffercapturejob.cpp +++ b/src/render/jobs/sendbuffercapturejob.cpp @@ -51,9 +51,8 @@ namespace Qt3DRender { namespace Render { -SendBufferCaptureJob::SendBufferCaptureJob(Renderer *renderer) +SendBufferCaptureJob::SendBufferCaptureJob() : Qt3DCore::QAspectJob() - , m_renderer(renderer) { SET_JOB_RUN_STAT_TYPE(this, JobTypes::SendBufferCapture, 0); } diff --git a/src/render/jobs/sendbuffercapturejob_p.h b/src/render/jobs/sendbuffercapturejob_p.h index 9a7f839c7..d01ecec72 100644 --- a/src/render/jobs/sendbuffercapturejob_p.h +++ b/src/render/jobs/sendbuffercapturejob_p.h @@ -71,7 +71,7 @@ class Buffer; class QT3DRENDERSHARED_PRIVATE_EXPORT SendBufferCaptureJob : public Qt3DCore::QAspectJob { public: - explicit SendBufferCaptureJob(Renderer *renderer); + explicit SendBufferCaptureJob(); ~SendBufferCaptureJob(); void setManagers(NodeManagers *managers); @@ -81,7 +81,6 @@ public: void run() Q_DECL_FINAL; private: - Renderer *m_renderer; NodeManagers *m_managers; QMutex m_mutex; diff --git a/tests/manual/deferred-renderer-cpp/gbuffer.h b/tests/manual/deferred-renderer-cpp/gbuffer.h index dab8b6752..7ffaffe2a 100644 --- a/tests/manual/deferred-renderer-cpp/gbuffer.h +++ b/tests/manual/deferred-renderer-cpp/gbuffer.h @@ -75,7 +75,6 @@ public: private: Qt3DRender::QAbstractTexture *m_textures[AttachmentsCount]; - Qt3DRender::QRenderTargetOutput *m_attachments[AttachmentsCount]; }; #endif // GBUFFER_H -- cgit v1.2.3 From 387e60071b97234c135769401b5d288574d4fb3d Mon Sep 17 00:00:00 2001 From: Mike Krus Date: Thu, 9 Feb 2017 13:12:45 +0000 Subject: Fix Clang warnings: silence unused variables Change-Id: I2dd185c1ae098034055fb1bbf7474554f8d1d13c Reviewed-by: Sean Harmer --- src/render/backend/frameprofiler_p.h | 2 ++ tests/auto/core/nodes/tst_nodes.cpp | 2 +- tests/auto/render/gltfplugins/tst_gltfplugins.cpp | 2 ++ tests/auto/render/texturedatamanager/tst_texturedatamanager.cpp | 4 +++- 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/render/backend/frameprofiler_p.h b/src/render/backend/frameprofiler_p.h index 2412a8053..59d76b692 100644 --- a/src/render/backend/frameprofiler_p.h +++ b/src/render/backend/frameprofiler_p.h @@ -227,6 +227,8 @@ public: { #ifdef QT3D_JOBS_RUN_STATS frameProfiler.recordEvent(m_type); +#else + Q_UNUSED(m_type); #endif } diff --git a/tests/auto/core/nodes/tst_nodes.cpp b/tests/auto/core/nodes/tst_nodes.cpp index 407e8d816..90e0084e8 100644 --- a/tests/auto/core/nodes/tst_nodes.cpp +++ b/tests/auto/core/nodes/tst_nodes.cpp @@ -105,7 +105,7 @@ public: void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &) Q_DECL_FINAL {}; void setScene(Qt3DCore::QScene *) Q_DECL_FINAL {}; void notifyBackend(const Qt3DCore::QSceneChangePtr &change) Q_DECL_FINAL; - bool shouldNotifyFrontend(const Qt3DCore::QSceneChangePtr &changee) Q_DECL_FINAL { return false; } + bool shouldNotifyFrontend(const Qt3DCore::QSceneChangePtr &changee) Q_DECL_FINAL { Q_UNUSED(changee); return false; } private: ObserverSpy *m_spy; diff --git a/tests/auto/render/gltfplugins/tst_gltfplugins.cpp b/tests/auto/render/gltfplugins/tst_gltfplugins.cpp index a800fc1fa..33aff94f8 100644 --- a/tests/auto/render/gltfplugins/tst_gltfplugins.cpp +++ b/tests/auto/render/gltfplugins/tst_gltfplugins.cpp @@ -139,8 +139,10 @@ private: Qt3DRender::QEffect *createOnTopEffect(); QTemporaryDir *m_exportDir; +#ifdef VISUAL_CHECK Qt3DExtras::Qt3DWindow *m_view1; Qt3DExtras::Qt3DWindow *m_view2; +#endif Qt3DCore::QEntity *m_sceneRoot1; Qt3DCore::QEntity *m_sceneRoot2; QHash m_entityMap; diff --git a/tests/auto/render/texturedatamanager/tst_texturedatamanager.cpp b/tests/auto/render/texturedatamanager/tst_texturedatamanager.cpp index b76495d93..5ba43aedc 100644 --- a/tests/auto/render/texturedatamanager/tst_texturedatamanager.cpp +++ b/tests/auto/render/texturedatamanager/tst_texturedatamanager.cpp @@ -58,7 +58,9 @@ class FakeData public: explicit FakeData(int value) : m_value(value) - {} + { + Q_UNUSED(m_value); + } private: int m_value; -- cgit v1.2.3 From 3e9375c9ec8b0a5458950c65b44564d0807541e5 Mon Sep 17 00:00:00 2001 From: Mike Krus Date: Thu, 9 Feb 2017 13:13:07 +0000 Subject: Fix Clang warnings: missing virtual destructor Change-Id: Ifdb7c5ade912fb885b522d5a08d7569c14cbb48d Reviewed-by: Sean Harmer --- src/render/backend/resourceaccessor.cpp | 5 +++++ src/render/backend/resourceaccessor_p.h | 1 + 2 files changed, 6 insertions(+) diff --git a/src/render/backend/resourceaccessor.cpp b/src/render/backend/resourceaccessor.cpp index 43f416d16..9c7211a70 100644 --- a/src/render/backend/resourceaccessor.cpp +++ b/src/render/backend/resourceaccessor.cpp @@ -54,6 +54,11 @@ QT_BEGIN_NAMESPACE namespace Qt3DRender { namespace Render { +RenderBackendResourceAccessor::~RenderBackendResourceAccessor() +{ + +} + ResourceAccessor::ResourceAccessor(NodeManagers *mgr) : m_glTextureManager(mgr->glTextureManager()) , m_textureManager(mgr->textureManager()) diff --git a/src/render/backend/resourceaccessor_p.h b/src/render/backend/resourceaccessor_p.h index 653a8adda..d99a64ddb 100644 --- a/src/render/backend/resourceaccessor_p.h +++ b/src/render/backend/resourceaccessor_p.h @@ -71,6 +71,7 @@ class NodeManagers; class RenderBackendResourceAccessor { public: + virtual ~RenderBackendResourceAccessor(); virtual bool accessResource(Qt3DCore::QNodeId nodeId, void **handle, QMutex **lock) = 0; }; -- cgit v1.2.3 From 74d78e55ecd932bf2d17657906b3f67de5291520 Mon Sep 17 00:00:00 2001 From: Mike Krus Date: Thu, 9 Feb 2017 13:13:45 +0000 Subject: Fix Clang warnings: missing enum values in switch Change-Id: Id5087114283d5ef978ebb77d415f67c6254cbee0 Reviewed-by: Sean Harmer --- tests/auto/render/geometryloaders/tst_geometryloaders.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/auto/render/geometryloaders/tst_geometryloaders.cpp b/tests/auto/render/geometryloaders/tst_geometryloaders.cpp index 15600dc75..7b9f09d23 100644 --- a/tests/auto/render/geometryloaders/tst_geometryloaders.cpp +++ b/tests/auto/render/geometryloaders/tst_geometryloaders.cpp @@ -102,6 +102,9 @@ void tst_geometryloaders::testOBJLoader() case QAttribute::VertexAttribute: QCOMPARE(attr->count(), 24u); break; + default: + Q_UNREACHABLE(); + break; } } @@ -141,6 +144,9 @@ void tst_geometryloaders::testPLYLoader() case QAttribute::VertexAttribute: QCOMPARE(attr->count(), 24u); break; + default: + Q_UNREACHABLE(); + break; } } @@ -212,6 +218,9 @@ void tst_geometryloaders::testGLTFLoader() case QAttribute::VertexAttribute: QCOMPARE(attr->count(), 24u); break; + default: + Q_UNREACHABLE(); + break; } } -- cgit v1.2.3 From 7a4ab54b9265ac17bdd3355b5ec26ab82dacddde Mon Sep 17 00:00:00 2001 From: Mike Krus Date: Thu, 9 Feb 2017 13:14:28 +0000 Subject: Fix Clang warnings: missing override declarations Change-Id: Ifd6d83cd38358eef44af74e887d3a649917d764c Reviewed-by: Sean Harmer --- tests/auto/render/textures/tst_textures.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/auto/render/textures/tst_textures.cpp b/tests/auto/render/textures/tst_textures.cpp index 9246bba34..58cb76c94 100644 --- a/tests/auto/render/textures/tst_textures.cpp +++ b/tests/auto/render/textures/tst_textures.cpp @@ -52,11 +52,11 @@ class TestImageDataGenerator : public Qt3DRender::QTextureImageDataGenerator public: TestImageDataGenerator(int id) : m_id(id) {} - Qt3DRender::QTextureImageDataPtr operator ()() { + Qt3DRender::QTextureImageDataPtr operator ()() Q_DECL_OVERRIDE { return Qt3DRender::QTextureImageDataPtr::create(); } - bool operator ==(const Qt3DRender::QTextureImageDataGenerator &other) const { + bool operator ==(const Qt3DRender::QTextureImageDataGenerator &other) const Q_DECL_OVERRIDE { const TestImageDataGenerator *otherFunctor = functor_cast(&other); return (otherFunctor != Q_NULLPTR && otherFunctor->m_id == m_id); } @@ -73,11 +73,11 @@ class TestTextureGenerator : public Qt3DRender::QTextureGenerator public: TestTextureGenerator(int id) : m_id(id) {} - Qt3DRender::QTextureDataPtr operator ()() { + Qt3DRender::QTextureDataPtr operator ()() Q_DECL_OVERRIDE { return Qt3DRender::QTextureDataPtr::create(); } - bool operator ==(const Qt3DRender::QTextureGenerator &other) const { + bool operator ==(const Qt3DRender::QTextureGenerator &other) const Q_DECL_OVERRIDE { const TestTextureGenerator *otherFunctor = functor_cast(&other); return (otherFunctor != Q_NULLPTR && otherFunctor->m_id == m_id); } -- cgit v1.2.3 From 9e0571eedd75be6761bfc8ec32c07042379d66f9 Mon Sep 17 00:00:00 2001 From: Mike Krus Date: Thu, 9 Feb 2017 13:15:08 +0000 Subject: Fix Clang warnings: wrong types in enum comparisons Change-Id: Ib3795f141eaa65d76c8e7aeda4d8a9f2531c7205 Reviewed-by: Sean Harmer --- tests/auto/render/gltfplugins/tst_gltfplugins.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/auto/render/gltfplugins/tst_gltfplugins.cpp b/tests/auto/render/gltfplugins/tst_gltfplugins.cpp index 33aff94f8..e5a0eef21 100644 --- a/tests/auto/render/gltfplugins/tst_gltfplugins.cpp +++ b/tests/auto/render/gltfplugins/tst_gltfplugins.cpp @@ -783,7 +783,7 @@ void tst_gltfPlugins::compareComponents(Qt3DCore::QComponent *c1, Qt3DCore::QCom auto property = c1->metaObject()->property(i); auto v1 = c1->property(property.name()); auto v2 = c2->property(property.name()); - if (v1.type() == QMetaType::Bool) { + if (v1.type() == QVariant::Bool) { QCOMPARE(v1.toBool(), v2.toBool()); } else if (v1.type() == QVariant::Color) { QCOMPARE(v1.value(), v2.value()); -- cgit v1.2.3 From 5c5d0d11127e52f1d1b49fda7b9e72cd3a84bdd5 Mon Sep 17 00:00:00 2001 From: Mike Krus Date: Thu, 9 Feb 2017 20:03:23 +0000 Subject: Ignore compiled qml files (.qmlc) Change-Id: Ic2b0e0f99947481bd05ca620d1d3d3c9f8ef9772 Reviewed-by: Sean Harmer --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 490a5cad5..17ab804c9 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,7 @@ include/* *.o *.obj *.orig +*.qmlc *.rej *.so *.so.* -- cgit v1.2.3 From be8099cd83a9fedf84508538ab49a86a41fc61d6 Mon Sep 17 00:00:00 2001 From: Mike Krus Date: Fri, 10 Feb 2017 22:08:28 +0000 Subject: Unit test for bounding spheres Change-Id: Iee1e7aeaf43a4b783a914d808e2e7ac1e215b263 Reviewed-by: Sean Harmer --- .../auto/render/boundingsphere/boundingsphere.pro | 17 ++ .../auto/render/boundingsphere/boundingsphere.qrc | 6 + tests/auto/render/boundingsphere/cube.qml | 69 +++++++ tests/auto/render/boundingsphere/sphere.qml | 69 +++++++ .../render/boundingsphere/tst_boundingsphere.cpp | 201 +++++++++++++++++++++ tests/auto/render/render.pro | 1 + 6 files changed, 363 insertions(+) create mode 100644 tests/auto/render/boundingsphere/boundingsphere.pro create mode 100644 tests/auto/render/boundingsphere/boundingsphere.qrc create mode 100644 tests/auto/render/boundingsphere/cube.qml create mode 100644 tests/auto/render/boundingsphere/sphere.qml create mode 100644 tests/auto/render/boundingsphere/tst_boundingsphere.cpp diff --git a/tests/auto/render/boundingsphere/boundingsphere.pro b/tests/auto/render/boundingsphere/boundingsphere.pro new file mode 100644 index 000000000..cebba17e7 --- /dev/null +++ b/tests/auto/render/boundingsphere/boundingsphere.pro @@ -0,0 +1,17 @@ +TEMPLATE = app + +TARGET = tst_boundingsphere +QT += core-private 3dcore 3dcore-private 3drender 3drender-private 3dextras testlib + +CONFIG += testcase + +SOURCES += tst_boundingsphere.cpp + +include(../commons/commons.pri) +include(../../core/common/common.pri) +include(../qmlscenereader/qmlscenereader.pri) +# Extra dependencies to build test scenes needed by the tests +QT += quick 3dquick 3dquick-private 3dextras 3dquickextras + +RESOURCES += \ + boundingsphere.qrc diff --git a/tests/auto/render/boundingsphere/boundingsphere.qrc b/tests/auto/render/boundingsphere/boundingsphere.qrc new file mode 100644 index 000000000..5ea2cb958 --- /dev/null +++ b/tests/auto/render/boundingsphere/boundingsphere.qrc @@ -0,0 +1,6 @@ + + + sphere.qml + cube.qml + + diff --git a/tests/auto/render/boundingsphere/cube.qml b/tests/auto/render/boundingsphere/cube.qml new file mode 100644 index 000000000..11d6d4db1 --- /dev/null +++ b/tests/auto/render/boundingsphere/cube.qml @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import Qt3D.Core 2.0 +import Qt3D.Render 2.0 +import Qt3D.Extras 2.0 + +Entity { + id: sceneRoot + + components: [ ] + + // Parent Entity + Entity { + + components: [ + CuboidMesh { id: testMesh; objectName: "testMesh" }, + PhongMaterial { id: material } + ] + } + +} diff --git a/tests/auto/render/boundingsphere/sphere.qml b/tests/auto/render/boundingsphere/sphere.qml new file mode 100644 index 000000000..1f0e2245a --- /dev/null +++ b/tests/auto/render/boundingsphere/sphere.qml @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import Qt3D.Core 2.0 +import Qt3D.Render 2.0 +import Qt3D.Extras 2.0 + +Entity { + id: sceneRoot + + components: [ ] + + // Parent Entity + Entity { + + components: [ + SphereMesh { id: testMesh; objectName: "testMesh" }, + PhongMaterial { id: material } + ] + } + +} diff --git a/tests/auto/render/boundingsphere/tst_boundingsphere.cpp b/tests/auto/render/boundingsphere/tst_boundingsphere.cpp new file mode 100644 index 000000000..fcbfaf6ba --- /dev/null +++ b/tests/auto/render/boundingsphere/tst_boundingsphere.cpp @@ -0,0 +1,201 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $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 "qmlscenereader.h" +#include "testpostmanarbiter.h" + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +class TestAspect : public Qt3DRender::QRenderAspect +{ +public: + TestAspect(Qt3DCore::QNode *root) + : Qt3DRender::QRenderAspect(Qt3DRender::QRenderAspect::Synchronous) + , m_sceneRoot(nullptr) + { + QRenderAspect::onRegistered(); + + const Qt3DCore::QNodeCreatedChangeGenerator generator(root); + const QVector creationChanges = generator.creationChanges(); + + d_func()->setRootAndCreateNodes(qobject_cast(root), creationChanges); + + Render::Entity *rootEntity = nodeManagers()->lookupResource(rootEntityId()); + Q_ASSERT(rootEntity); + m_sceneRoot = rootEntity; + } + + ~TestAspect() + { + QRenderAspect::onUnregistered(); + } + + void onRegistered() { QRenderAspect::onRegistered(); } + void onUnregistered() { QRenderAspect::onUnregistered(); } + + Qt3DRender::Render::NodeManagers *nodeManagers() const { return d_func()->m_renderer->nodeManagers(); } + Qt3DRender::Render::FrameGraphNode *frameGraphRoot() const { return d_func()->m_renderer->frameGraphRoot(); } + Qt3DRender::Render::RenderSettings *renderSettings() const { return d_func()->m_renderer->settings(); } + Qt3DRender::Render::Entity *sceneRoot() const { return m_sceneRoot; } + +private: + Render::Entity *m_sceneRoot; +}; + +} // namespace Qt3DRender + +QT_END_NAMESPACE + +namespace { + +void runRequiredJobs(Qt3DRender::TestAspect *test) +{ + Qt3DRender::Render::UpdateWorldTransformJob updateWorldTransform; + updateWorldTransform.setRoot(test->sceneRoot()); + updateWorldTransform.run(); + + // For each buffer + QVector bufferHandles = test->nodeManagers()->bufferManager()->activeHandles(); + for (auto bufferHandle : bufferHandles) { + Qt3DRender::Render::LoadBufferJob loadBuffer(bufferHandle); + loadBuffer.setNodeManager(test->nodeManagers()); + loadBuffer.run(); + } + + Qt3DRender::Render::CalculateBoundingVolumeJob calcBVolume; + calcBVolume.setManagers(test->nodeManagers()); + calcBVolume.setRoot(test->sceneRoot()); + calcBVolume.run(); + + Qt3DRender::Render::UpdateWorldBoundingVolumeJob updateWorldBVolume; + updateWorldBVolume.setManager(test->nodeManagers()->renderNodesManager()); + updateWorldBVolume.run(); + + Qt3DRender::Render::ExpandBoundingVolumeJob expandBVolume; + expandBVolume.setRoot(test->sceneRoot()); + expandBVolume.run(); + + Qt3DRender::Render::UpdateMeshTriangleListJob updateTriangleList; + updateTriangleList.setManagers(test->nodeManagers()); + updateTriangleList.run(); + + // For each geometry id + QVector geometryRenderHandles = test->nodeManagers()->geometryRendererManager()->activeHandles(); + for (auto geometryRenderHandle : geometryRenderHandles) { + Qt3DCore::QNodeId geometryRendererId = test->nodeManagers()->geometryRendererManager()->data(geometryRenderHandle)->peerId(); + Qt3DRender::Render::CalcGeometryTriangleVolumes calcGeometryTriangles(geometryRendererId, test->nodeManagers()); + calcGeometryTriangles.run(); + } +} + +} // anonymous + +class tst_BoundingSphere : public QObject +{ + Q_OBJECT +private: + +private Q_SLOTS: + void checkExtraGeometries_data() + { + QTest::addColumn("qmlFile"); + QTest::addColumn("sphereCenter"); + QTest::addColumn("sphereRadius"); + QTest::newRow("SphereMesh") << "qrc:/sphere.qml" << QVector3D(0.f, 0.f, 0.f) << 1.f; + QTest::newRow("CubeMesh") << "qrc:/cube.qml" << QVector3D(0.0928356f, -0.212021f, -0.0467958f) << 1.07583f; // weird! + } + + void checkExtraGeometries() + { + // GIVEN + QFETCH(QString, qmlFile); + QFETCH(QVector3D, sphereCenter); + QFETCH(float, sphereRadius); + + QUrl qmlUrl(qmlFile); + QmlSceneReader sceneReader(qmlUrl); + QScopedPointer root(qobject_cast(sceneReader.root())); + QVERIFY(root); + + QScopedPointer test(new Qt3DRender::TestAspect(root.data())); + + // Runs Required jobs + runRequiredJobs(test.data()); + + // THEN + QVERIFY(test->sceneRoot()->worldBoundingVolumeWithChildren()); + const auto boundingSphere = test->sceneRoot()->worldBoundingVolumeWithChildren(); + qDebug() << qmlFile << boundingSphere->radius() << boundingSphere->center(); + QCOMPARE(boundingSphere->radius(), sphereRadius); + QVERIFY(qAbs(boundingSphere->center().x() - sphereCenter.x()) < 0.000001f); // qFuzzyCompare hates 0s + QVERIFY(qAbs(boundingSphere->center().y() - sphereCenter.y()) < 0.000001f); + QVERIFY(qAbs(boundingSphere->center().z() - sphereCenter.z()) < 0.000001f); + } +}; + +QTEST_MAIN(tst_BoundingSphere) + +#include "tst_boundingsphere.moc" diff --git a/tests/auto/render/render.pro b/tests/auto/render/render.pro index 4f536d3f4..052b19dd3 100644 --- a/tests/auto/render/render.pro +++ b/tests/auto/render/render.pro @@ -45,6 +45,7 @@ qtConfig(private_tests) { picking \ # qboundingvolumedebug \ # boundingvolumedebug \ + boundingsphere \ qdefaultmeshes \ trianglesextractor \ triangleboundingvolume \ -- cgit v1.2.3 From 518a7a922cc90865744c4e302650528796c75147 Mon Sep 17 00:00:00 2001 From: Mike Krus Date: Fri, 10 Feb 2017 22:09:03 +0000 Subject: Use coordinates visitor to avoid copying vertex data Change-Id: Ibab8d6cf8cedc93b0585a3af2d989eef7e8263b4 Reviewed-by: Sean Harmer --- src/render/backend/bufferutils_p.h | 115 ++++++++++++++++ src/render/backend/coordinatevisitor_p.h | 212 ++++++++++++++++++++++++++++++ src/render/backend/render-backend.pri | 2 + src/render/backend/trianglesvisitor.cpp | 50 +++---- src/render/backend/trianglesvisitor_p.h | 19 +-- src/render/jobs/calcboundingvolumejob.cpp | 164 ++++++++++++++++++----- 6 files changed, 477 insertions(+), 85 deletions(-) create mode 100644 src/render/backend/bufferutils_p.h create mode 100644 src/render/backend/coordinatevisitor_p.h diff --git a/src/render/backend/bufferutils_p.h b/src/render/backend/bufferutils_p.h new file mode 100644 index 000000000..2bb35fac6 --- /dev/null +++ b/src/render/backend/bufferutils_p.h @@ -0,0 +1,115 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Paul Lemire paul.lemire350@gmail.com +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3DRENDER_RENDER_BUFFERUTILS_P_H +#define QT3DRENDER_RENDER_BUFFERUTILS_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include + +QT_BEGIN_NAMESPACE + + +namespace Qt3DRender { + +namespace Render { + +class GeometryRenderer; +class NodeManagers; +class Attribute; +class Buffer; + +struct BufferInfo +{ + BufferInfo() + : type(QAttribute::VertexBaseType::Float) + , dataSize(0) + , count(0) + , byteStride(0) + , byteOffset(0) + {} + + QByteArray data; + QAttribute::VertexBaseType type; + uint dataSize; + uint count; + uint byteStride; + uint byteOffset; +}; + + +namespace BufferTypeInfo { + + template struct EnumToType; + template <> struct EnumToType { typedef const char type; }; + template <> struct EnumToType { typedef const uchar type; }; + template <> struct EnumToType { typedef const short type; }; + template <> struct EnumToType { typedef const ushort type; }; + template <> struct EnumToType { typedef const int type; }; + template <> struct EnumToType { typedef const uint type; }; + template <> struct EnumToType { typedef const float type; }; + template <> struct EnumToType { typedef const double type; }; + + template + typename EnumToType::type *castToType(const QByteArray &u, uint byteOffset) + { + return reinterpret_cast< typename EnumToType::type *>(u.constData() + byteOffset); + } + +} // namespace BufferTypeInfo + +} // namespace Render + +} // namespace Qt3DRender + +QT_END_NAMESPACE + + +#endif // QT3DRENDER_RENDER_BUFFERUTILS_P_H diff --git a/src/render/backend/coordinatevisitor_p.h b/src/render/backend/coordinatevisitor_p.h new file mode 100644 index 000000000..e7687ab3a --- /dev/null +++ b/src/render/backend/coordinatevisitor_p.h @@ -0,0 +1,212 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3DRENDER_RENDER_COORDINATEVISITOR_P_H +#define QT3DRENDER_RENDER_COORDINATEVISITOR_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DCore { +class QEntity; +} + +namespace Qt3DRender { +namespace Render { + + +template +class Q_AUTOTEST_EXPORT CoordinateVisitor +{ +public: + explicit CoordinateVisitor(NodeManagers *manager) + : m_manager(manager) + { + } + virtual ~CoordinateVisitor() { } + + virtual void visit(uint ndx, ValueType x) { + Q_UNUSED(ndx); Q_UNUSED(x); + } + virtual void visit(uint ndx, ValueType x, ValueType y) { + Q_UNUSED(ndx); Q_UNUSED(x); Q_UNUSED(y); + } + virtual void visit(uint ndx, ValueType x, ValueType y, ValueType z) { + Q_UNUSED(ndx); Q_UNUSED(x); Q_UNUSED(y); Q_UNUSED(z); + } + virtual void visit(uint ndx, ValueType x, ValueType y, ValueType z, ValueType w) { + Q_UNUSED(ndx); Q_UNUSED(x); Q_UNUSED(y); Q_UNUSED(z); Q_UNUSED(w); + } + + bool apply(const GeometryRenderer *renderer, const QString &attributeName) + { + if (renderer == nullptr || renderer->instanceCount() != 1) { + return false; + } + + Geometry *geom = m_manager->lookupResource(renderer->geometryId()); + + if (!geom) + return false; + + Attribute *attribute = nullptr; + + const auto attrIds = geom->attributes(); + for (const Qt3DCore::QNodeId attrId : attrIds) { + attribute = m_manager->lookupResource(attrId); + if (attribute){ + if (attribute->name() == attributeName + || (attributeName == QStringLiteral("default") + && attribute->name() == QAttribute::defaultTextureCoordinateAttributeName())) { + break; + } + } + attribute = nullptr; + } + + if (!attribute) + return false; + + return apply(attribute); + } + + bool apply(Qt3DRender::Render::Attribute *attribute) + { + if (attribute->vertexBaseType() != VertexBaseType) + return false; + if (attribute->vertexSize() < dataSize) + return false; + + auto data = m_manager->lookupResource(attribute->bufferId())->data(); + auto buffer = BufferTypeInfo::castToType(data, attribute->byteOffset()); + switch (dataSize) { + case 1: traverseCoordinates1(buffer, attribute->byteStride(), attribute->count()); break; + case 2: traverseCoordinates2(buffer, attribute->byteStride(), attribute->count()); break; + case 3: traverseCoordinates3(buffer, attribute->byteStride(), attribute->count()); break; + case 4: traverseCoordinates4(buffer, attribute->byteStride(), attribute->count()); break; + default: Q_UNREACHABLE(); + } + + return true; + } + +protected: + + template + void traverseCoordinates1(Coordinate *coordinates, + const uint byteStride, + const uint count) + { + const uint stride = byteStride / sizeof(Coordinate); + for (uint ndx = 0; ndx < count; ++ndx) { + visit(ndx, coordinates[0]); + coordinates += stride; + } + } + + template + void traverseCoordinates2(Coordinate *coordinates, + const uint byteStride, + const uint count) + { + const uint stride = byteStride / sizeof(Coordinate); + for (uint ndx = 0; ndx < count; ++ndx) { + visit(ndx, coordinates[0], coordinates[1]); + coordinates += stride; + } + } + + template + void traverseCoordinates3(Coordinate *coordinates, + const uint byteStride, + const uint count) + { + const uint stride = byteStride / sizeof(Coordinate); + for (uint ndx = 0; ndx < count; ++ndx) { + visit(ndx, coordinates[0], coordinates[1], coordinates[2]); + coordinates += stride; + } + } + + template + void traverseCoordinates4(Coordinate *coordinates, + const uint byteStride, + const uint count) + { + const uint stride = byteStride / sizeof(Coordinate); + for (uint ndx = 0; ndx < count; ++ndx) { + visit(ndx, coordinates[0], coordinates[1], coordinates[2], coordinates[3]); + coordinates += stride; + } + } + + NodeManagers *m_manager; +}; + +typedef CoordinateVisitor Coordinate3fVisitor; + +} // namespace Render + +} // namespace Qt3DRender + +QT_END_NAMESPACE + + +#endif // QT3DRENDER_RENDER_COORDINATEVISITOR_P_H diff --git a/src/render/backend/render-backend.pri b/src/render/backend/render-backend.pri index 1cd911df8..f694e7cea 100644 --- a/src/render/backend/render-backend.pri +++ b/src/render/backend/render-backend.pri @@ -29,6 +29,8 @@ HEADERS += \ $$PWD/triangleboundingvolume_p.h \ $$PWD/openglvertexarrayobject_p.h \ $$PWD/trianglesextractor_p.h \ + $$PWD/coordinatevisitor_p.h \ + $$PWD/bufferutils_p.h \ $$PWD/trianglesvisitor_p.h \ $$PWD/abstractrenderer_p.h \ $$PWD/computecommand_p.h \ diff --git a/src/render/backend/trianglesvisitor.cpp b/src/render/backend/trianglesvisitor.cpp index 5453661e0..036f43fa0 100644 --- a/src/render/backend/trianglesvisitor.cpp +++ b/src/render/backend/trianglesvisitor.cpp @@ -48,6 +48,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE @@ -321,42 +322,25 @@ QVector4D readCoordinate(const BufferInfo &info, Coordinate *coordinates, uint i return ret; } - -template struct EnumToType; -template <> struct EnumToType { typedef const char type; }; -template <> struct EnumToType { typedef const uchar type; }; -template <> struct EnumToType { typedef const short type; }; -template <> struct EnumToType { typedef const ushort type; }; -template <> struct EnumToType { typedef const int type; }; -template <> struct EnumToType { typedef const uint type; }; -template <> struct EnumToType { typedef const float type; }; -template <> struct EnumToType { typedef const double type; }; - -template -typename EnumToType::type *castToType(const QByteArray &u, uint byteOffset) -{ - return reinterpret_cast< typename EnumToType::type *>(u.constData() + byteOffset); -} - template void processBuffer(const BufferInfo &info, Func &f) { switch (info.type) { - case QAttribute::Byte: f(info, castToType(info.data, info.byteOffset)); + case QAttribute::Byte: f(info, BufferTypeInfo::castToType(info.data, info.byteOffset)); return; - case QAttribute::UnsignedByte: f(info, castToType(info.data, info.byteOffset)); + case QAttribute::UnsignedByte: f(info, BufferTypeInfo::castToType(info.data, info.byteOffset)); return; - case QAttribute::Short: f(info, castToType(info.data, info.byteOffset)); + case QAttribute::Short: f(info, BufferTypeInfo::castToType(info.data, info.byteOffset)); return; - case QAttribute::UnsignedShort: f(info, castToType(info.data, info.byteOffset)); + case QAttribute::UnsignedShort: f(info, BufferTypeInfo::castToType(info.data, info.byteOffset)); return; - case QAttribute::Int: f(info, castToType(info.data, info.byteOffset)); + case QAttribute::Int: f(info, BufferTypeInfo::castToType(info.data, info.byteOffset)); return; - case QAttribute::UnsignedInt: f(info, castToType(info.data, info.byteOffset)); + case QAttribute::UnsignedInt: f(info, BufferTypeInfo::castToType(info.data, info.byteOffset)); return; - case QAttribute::Float: f(info, castToType(info.data, info.byteOffset)); + case QAttribute::Float: f(info, BufferTypeInfo::castToType(info.data, info.byteOffset)); return; - case QAttribute::Double: f(info, castToType(info.data, info.byteOffset)); + case QAttribute::Double: f(info, BufferTypeInfo::castToType(info.data, info.byteOffset)); return; default: return; @@ -367,21 +351,21 @@ QVector4D readBuffer(const BufferInfo &info, uint index) { switch (info.type) { case QAttribute::Byte: - return readCoordinate(info, castToType(info.data, info.byteOffset), index); + return readCoordinate(info, BufferTypeInfo::castToType(info.data, info.byteOffset), index); case QAttribute::UnsignedByte: - return readCoordinate(info, castToType(info.data, info.byteOffset), index); + return readCoordinate(info, BufferTypeInfo::castToType(info.data, info.byteOffset), index); case QAttribute::Short: - return readCoordinate(info, castToType(info.data, info.byteOffset), index); + return readCoordinate(info, BufferTypeInfo::castToType(info.data, info.byteOffset), index); case QAttribute::UnsignedShort: - return readCoordinate(info, castToType(info.data, info.byteOffset), index); + return readCoordinate(info, BufferTypeInfo::castToType(info.data, info.byteOffset), index); case QAttribute::Int: - return readCoordinate(info, castToType(info.data, info.byteOffset), index); + return readCoordinate(info, BufferTypeInfo::castToType(info.data, info.byteOffset), index); case QAttribute::UnsignedInt: - return readCoordinate(info, castToType(info.data, info.byteOffset), index); + return readCoordinate(info, BufferTypeInfo::castToType(info.data, info.byteOffset), index); case QAttribute::Float: - return readCoordinate(info, castToType(info.data, info.byteOffset), index); + return readCoordinate(info, BufferTypeInfo::castToType(info.data, info.byteOffset), index); case QAttribute::Double: - return readCoordinate(info, castToType(info.data, info.byteOffset), index); + return readCoordinate(info, BufferTypeInfo::castToType(info.data, info.byteOffset), index); default: break; } diff --git a/src/render/backend/trianglesvisitor_p.h b/src/render/backend/trianglesvisitor_p.h index a0fa89efb..149ac2a65 100644 --- a/src/render/backend/trianglesvisitor_p.h +++ b/src/render/backend/trianglesvisitor_p.h @@ -53,6 +53,7 @@ #include #include +#include QT_BEGIN_NAMESPACE @@ -69,24 +70,6 @@ class NodeManagers; class Attribute; class Buffer; -struct BufferInfo -{ - BufferInfo() - : type(QAttribute::VertexBaseType::Float) - , dataSize(0) - , count(0) - , byteStride(0) - , byteOffset(0) - {} - - QByteArray data; - QAttribute::VertexBaseType type; - uint dataSize; - uint count; - uint byteStride; - uint byteOffset; -}; - class Q_AUTOTEST_EXPORT TrianglesVisitor { public: diff --git a/src/render/jobs/calcboundingvolumejob.cpp b/src/render/jobs/calcboundingvolumejob.cpp index 9e373c655..2f2d471d6 100644 --- a/src/render/jobs/calcboundingvolumejob.cpp +++ b/src/render/jobs/calcboundingvolumejob.cpp @@ -50,6 +50,7 @@ #include #include #include +#include #include #include @@ -73,6 +74,114 @@ struct UpdateBoundFunctor { } }; +class BoundingVolumeCalculator +{ +public: + BoundingVolumeCalculator(NodeManagers *manager) : m_manager(manager) { } + + const Sphere& result() { return m_volume; } + + bool apply(Qt3DRender::Render::Attribute *positionAttribute) + { + FindExtremePoints findExtremePoints(m_manager); + if (!findExtremePoints.apply(positionAttribute)) + return false; + + // Calculate squared distance for the pairs of points + const float xDist2 = (findExtremePoints.xMaxPt - findExtremePoints.xMinPt).lengthSquared(); + const float yDist2 = (findExtremePoints.yMaxPt - findExtremePoints.yMinPt).lengthSquared(); + const float zDist2 = (findExtremePoints.zMaxPt - findExtremePoints.zMinPt).lengthSquared(); + + // Select most distant pair + QVector3D p = findExtremePoints.xMinPt; + QVector3D q = findExtremePoints.xMaxPt; + if (yDist2 > xDist2 && yDist2 > zDist2) { + p = findExtremePoints.yMinPt; + q = findExtremePoints.yMaxPt; + } + if (zDist2 > xDist2 && zDist2 > yDist2) { + p = findExtremePoints.zMinPt; + q = findExtremePoints.zMaxPt; + } + + const QVector3D c = 0.5f * (p + q); + m_volume.setCenter(c); + m_volume.setRadius((q - c).length()); + + ExpandSphere expandSphere(m_manager, m_volume); + if (!expandSphere.apply(positionAttribute)) + return false; + + return true; + } + +private: + Sphere m_volume; + NodeManagers *m_manager; + + class FindExtremePoints : public Coordinate3fVisitor + { + public: + FindExtremePoints(NodeManagers *manager) + : Coordinate3fVisitor(manager) + , xMin(0.0f), xMax(0.0f), yMin(0.0f), yMax(0.0f), zMin(0.0f), zMax(0.0f) + { } + + float xMin, xMax, yMin, yMax, zMin, zMax; + QVector3D xMinPt, xMaxPt, yMinPt, yMaxPt, zMinPt, zMaxPt; + + void visit(uint ndx, float x, float y, float z) override + { + if (ndx) { + if (x < xMin) { + xMin = x; + xMinPt = QVector3D(x, y, z); + } + if (x > xMax) { + xMax = x; + xMaxPt = QVector3D(x, y, z); + } + if (y < yMin) { + yMin = y; + yMinPt = QVector3D(x, y, z); + } + if (y > yMax) { + yMax = y; + yMaxPt = QVector3D(x, y, z); + } + if (z < zMin) { + zMin = z; + zMinPt = QVector3D(x, y, z); + } + if (z > zMax) { + zMax = z; + zMaxPt = QVector3D(x, y, z); + } + } else { + xMin = xMax = x; + yMin = yMax = y; + zMin = zMax = z; + xMinPt = xMaxPt = yMinPt = yMaxPt = zMinPt = zMaxPt = QVector3D(x, y, z); + } + } + }; + + class ExpandSphere : public Coordinate3fVisitor + { + public: + ExpandSphere(NodeManagers *manager, Sphere& volume) + : Coordinate3fVisitor(manager), m_volume(volume) + { } + + Sphere& m_volume; + void visit(uint ndx, float x, float y, float z) override + { + Q_UNUSED(ndx); + m_volume.expandToContain(QVector3D(x, y, z)); + } + }; +}; + void calculateLocalBoundingVolume(NodeManagers *manager, Entity *node) { // The Bounding volume will only be computed if the position Buffer @@ -86,32 +195,32 @@ void calculateLocalBoundingVolume(NodeManagers *manager, Entity *node) Geometry *geom = manager->lookupResource(gRenderer->geometryId()); if (geom) { - Qt3DRender::Render::Attribute *pickVolumeAttribute = manager->lookupResource(geom->boundingPositionAttribute()); + Qt3DRender::Render::Attribute *positionAttribute = manager->lookupResource(geom->boundingPositionAttribute()); // Use the default position attribute if attribute is null - if (!pickVolumeAttribute) { + if (!positionAttribute) { const auto attrIds = geom->attributes(); for (const Qt3DCore::QNodeId attrId : attrIds) { - pickVolumeAttribute = manager->lookupResource(attrId); - if (pickVolumeAttribute && - pickVolumeAttribute->name() == QAttribute::defaultPositionAttributeName()) + positionAttribute = manager->lookupResource(attrId); + if (positionAttribute && + positionAttribute->name() == QAttribute::defaultPositionAttributeName()) break; } } - if (pickVolumeAttribute) { - if (!pickVolumeAttribute - || pickVolumeAttribute->attributeType() != QAttribute::VertexAttribute - || pickVolumeAttribute->vertexBaseType() != QAttribute::Float - || pickVolumeAttribute->vertexSize() < 3) { - qWarning() << "QGeometry::boundingVolumePositionAttribute pickVolume Attribute not suited for bounding volume computation"; - return; - } + if (!positionAttribute + || positionAttribute->attributeType() != QAttribute::VertexAttribute + || positionAttribute->vertexBaseType() != QAttribute::Float + || positionAttribute->vertexSize() < 3) { + qWarning() << "QGeometry::boundingVolumePositionAttribute position Attribute not suited for bounding volume computation"; + return; + } - Buffer *buf = manager->lookupResource(pickVolumeAttribute->bufferId()); + if (positionAttribute) { + Buffer *buf = manager->lookupResource(positionAttribute->bufferId()); // No point in continuing if the positionAttribute doesn't have a suitable buffer if (!buf) { - qWarning() << "ObjectPicker pickVolume Attribute not referencing a valid buffer"; + qWarning() << "ObjectPicker position Attribute not referencing a valid buffer"; return; } @@ -121,29 +230,16 @@ void calculateLocalBoundingVolume(NodeManagers *manager, Entity *node) // If anything in the GeometryRenderer has changed if (buf->isDirty() || node->isBoundingVolumeDirty() || - pickVolumeAttribute->isDirty() || + positionAttribute->isDirty() || geom->isDirty() || gRenderer->isDirty()) { - const QByteArray buffer = buf->data(); - const char *rawBuffer = buffer.constData(); - rawBuffer += pickVolumeAttribute->byteOffset(); - const int stride = pickVolumeAttribute->byteStride() ? pickVolumeAttribute->byteStride() : sizeof(float) * pickVolumeAttribute->vertexSize(); - QVector vertices(pickVolumeAttribute->count()); - - // TODO avoid copying the vertices - for (int c = 0, vC = vertices.size(); c < vC; ++c) { - QVector3D v; - const float *fptr = reinterpret_cast(rawBuffer); - // TODO unwrap loop (switch?) - for (uint i = 0, m = qMin(pickVolumeAttribute->vertexSize(), 3U); i < m; ++i) - v[i] = fptr[i]; - vertices[c] = v; - rawBuffer += stride; + BoundingVolumeCalculator reader(manager); + if (reader.apply(positionAttribute)) { + node->localBoundingVolume()->setCenter(reader.result().center()); + node->localBoundingVolume()->setRadius(reader.result().radius()); + node->unsetBoundingVolumeDirty(); } - - node->localBoundingVolume()->initializeFromPoints(vertices); - node->unsetBoundingVolumeDirty(); } } } -- cgit v1.2.3 From a49094c50e8971d92e918a71f2371dc23587497e Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Sun, 12 Feb 2017 13:37:38 +0000 Subject: Silence warning 4828 in assimp on MSVC Change-Id: I50dc8a64cfbf292228a88a7e7356dd958d592b4c Reviewed-by: Paul Lemire --- src/3rdparty/assimp/assimp.pri | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/3rdparty/assimp/assimp.pri b/src/3rdparty/assimp/assimp.pri index 802a645fe..771c291bf 100644 --- a/src/3rdparty/assimp/assimp.pri +++ b/src/3rdparty/assimp/assimp.pri @@ -38,7 +38,9 @@ intel_icc: { # 4189: 'identifier' : local variable is initialized but not referenced # 4267: coversion from 'size_t' to 'int', possible loss of data # 4996: Function call with parameters that may be unsafe - QMAKE_CFLAGS_WARN_ON += -wd"4100" -wd"4189" -wd"4267" -wd"4996" + # 4828: The file contains a character starting at offset 0x167b that + # is illegal in the current source character set (codepage 65001) + QMAKE_CFLAGS_WARN_ON += -wd"4100" -wd"4189" -wd"4267" -wd"4996" -wd"4828" QMAKE_CXXFLAGS_WARN_ON = $$QMAKE_CFLAGS_WARN_ON } -- cgit v1.2.3 From 37dc83a94cf8be9471a0ba773fd5e2552ba5a9e4 Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Sun, 12 Feb 2017 13:39:16 +0000 Subject: Initialize member variable in RenderViewBuilder Change-Id: I16aeb64c88802c08f5328f00ec9dddfaa0922c80 Coverity-Id: 154536 Reviewed-by: Paul Lemire --- src/render/jobs/renderviewjobutils.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/render/jobs/renderviewjobutils.cpp b/src/render/jobs/renderviewjobutils.cpp index b2b995cfa..694c4b8ac 100644 --- a/src/render/jobs/renderviewjobutils.cpp +++ b/src/render/jobs/renderviewjobutils.cpp @@ -414,7 +414,8 @@ const int qNodeIdTypeId = qMetaTypeId(); } UniformBlockValueBuilder::UniformBlockValueBuilder() - : shaderDataManager(nullptr) + : updatedPropertiesOnly(false) + , shaderDataManager(nullptr) { } -- cgit v1.2.3 From dc6e242c0bba2034801bf91d283aa8b7b7469583 Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Sun, 12 Feb 2017 13:41:39 +0000 Subject: Initialize variable in ShaderUniforms Change-Id: I65843908edfc7aba6eeb74f33f0df55444bd028c Coverity-Id: 154544 Reviewed-by: Paul Lemire --- src/render/backend/shadervariables_p.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/render/backend/shadervariables_p.h b/src/render/backend/shadervariables_p.h index 2177abe0e..e0fa07dff 100644 --- a/src/render/backend/shadervariables_p.h +++ b/src/render/backend/shadervariables_p.h @@ -81,6 +81,7 @@ struct ShaderUniform { ShaderUniform() : m_nameId(-1) + , m_type(GL_NONE) , m_size(0) , m_offset(-1) , m_location(-1) -- cgit v1.2.3 From 27b16da4f509678bae574f2bbbc3d38615c658c1 Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Sun, 12 Feb 2017 13:44:35 +0000 Subject: Initialize member in QBufferPrivate Change-Id: If4c908bef743a44334e8492aa613b8d14de18ee8 Coverity-Id: 154549 Reviewed-by: Paul Lemire --- src/render/geometry/qbuffer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/render/geometry/qbuffer.cpp b/src/render/geometry/qbuffer.cpp index 250ba7829..e767e0f74 100644 --- a/src/render/geometry/qbuffer.cpp +++ b/src/render/geometry/qbuffer.cpp @@ -51,6 +51,7 @@ namespace Qt3DRender { QBufferPrivate::QBufferPrivate() : QNodePrivate() + , m_type(QBuffer::VertexBuffer) , m_usage(QBuffer::StaticDraw) , m_syncData(false) , m_access(QBuffer::Write) -- cgit v1.2.3 From f001289614455c5ec4f48980c595ecf10ece3972 Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Sun, 12 Feb 2017 13:46:43 +0000 Subject: Initialize member in Renderer Change-Id: I875f05fd7f6f19f3ccfd3fc44baecb1bf99312a1 Coverity-Id: 154568 Reviewed-by: Paul Lemire --- src/render/backend/renderer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/render/backend/renderer.cpp b/src/render/backend/renderer.cpp index 9564c6e8b..4016f9709 100644 --- a/src/render/backend/renderer.cpp +++ b/src/render/backend/renderer.cpp @@ -147,6 +147,7 @@ namespace Render { Renderer::Renderer(QRenderAspect::RenderType type) : m_services(nullptr) , m_nodesManager(nullptr) + , m_renderSceneRoot(nullptr) , m_defaultRenderStateSet(nullptr) , m_graphicsContext(nullptr) , m_renderQueue(new RenderQueue()) -- cgit v1.2.3 From b8bb539eacb90ed0939479ad2ea4426025658233 Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Sun, 12 Feb 2017 13:51:27 +0000 Subject: Initialize members in Scene3DSGMaterialShader Change-Id: Ia2f4f7840ad68c3868a7dfba9c81689f96ee524c Coverity-Id: 154584 Reviewed-by: Paul Lemire --- src/quick3d/imports/scene3d/scene3dsgmaterialshader.cpp | 7 +++++++ src/quick3d/imports/scene3d/scene3dsgmaterialshader_p.h | 1 + 2 files changed, 8 insertions(+) diff --git a/src/quick3d/imports/scene3d/scene3dsgmaterialshader.cpp b/src/quick3d/imports/scene3d/scene3dsgmaterialshader.cpp index 5ce0f4d60..6cef032f7 100644 --- a/src/quick3d/imports/scene3d/scene3dsgmaterialshader.cpp +++ b/src/quick3d/imports/scene3d/scene3dsgmaterialshader.cpp @@ -71,6 +71,13 @@ namespace Qt3DRender { QSGMaterialType Scene3DSGMaterialShader::type; +Scene3DSGMaterialShader::Scene3DSGMaterialShader() + : QSGMaterialShader() + , m_matrixId(-1) + , m_opacityId(-1) +{ +} + const char * const *Scene3DSGMaterialShader::attributeNames() const { static char const *const attr[] = { "qt_VertexPosition", "qt_VertexTexCoord", 0 }; diff --git a/src/quick3d/imports/scene3d/scene3dsgmaterialshader_p.h b/src/quick3d/imports/scene3d/scene3dsgmaterialshader_p.h index 64d281ec4..a1222b07d 100644 --- a/src/quick3d/imports/scene3d/scene3dsgmaterialshader_p.h +++ b/src/quick3d/imports/scene3d/scene3dsgmaterialshader_p.h @@ -60,6 +60,7 @@ namespace Qt3DRender { class Scene3DSGMaterialShader : public QSGMaterialShader { public: + Scene3DSGMaterialShader(); void updateState(const RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial) Q_DECL_FINAL; const char * const *attributeNames() const Q_DECL_FINAL; -- cgit v1.2.3 From f5ce8c41cdf8f2c0e84331d5f87437e009587d54 Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Sun, 12 Feb 2017 14:03:06 +0000 Subject: Initialize members in Scene3DRenderer Change-Id: Ifd2015207346987be498a63302ec6f352a489fb1 Coverity-Id: 154585 Reviewed-by: Paul Lemire --- src/quick3d/imports/scene3d/scene3drenderer.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/quick3d/imports/scene3d/scene3drenderer.cpp b/src/quick3d/imports/scene3d/scene3drenderer.cpp index 3065b19ac..d3b9efdb1 100644 --- a/src/quick3d/imports/scene3d/scene3drenderer.cpp +++ b/src/quick3d/imports/scene3d/scene3drenderer.cpp @@ -120,6 +120,8 @@ Scene3DRenderer::Scene3DRenderer(Scene3DItem *item, Qt3DCore::QAspectEngine *asp , m_multisampledFBO(nullptr) , m_finalFBO(nullptr) , m_texture(nullptr) + , m_node(nullptr) + , m_cleaner(nullptr) , m_multisample(false) // this value is not used, will be synced from the Scene3DItem instead , m_lastMultisample(false) { -- cgit v1.2.3 From 73dbcc52cd4cd35bdc67123b4479a18499465243 Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Sun, 12 Feb 2017 14:05:07 +0000 Subject: Initialize member in QScheduler Change-Id: Idac9e42676ad92143e94dd5df02214fb79e5204e Coverity-Id: 154594 Reviewed-by: Paul Lemire --- src/core/qscheduler.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/qscheduler.cpp b/src/core/qscheduler.cpp index 1df6d2607..4765f618d 100644 --- a/src/core/qscheduler.cpp +++ b/src/core/qscheduler.cpp @@ -50,6 +50,7 @@ namespace Qt3DCore { QScheduler::QScheduler(QObject *parent) : QObject(parent) + , m_aspectManager(nullptr) { } -- cgit v1.2.3 From 0c2185ddaf98edf6eb5491f643c4bf31880e0a00 Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Sun, 12 Feb 2017 14:08:01 +0000 Subject: Remove unused member from QEntityPrivate Change-Id: I21847fa56249cc403638b001bd49e6785f5e3ec3 Coverity-Id: 154597 Reviewed-by: Paul Lemire --- src/core/nodes/qentity_p.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/core/nodes/qentity_p.h b/src/core/nodes/qentity_p.h index a9dfb9b0d..2c159807b 100644 --- a/src/core/nodes/qentity_p.h +++ b/src/core/nodes/qentity_p.h @@ -70,10 +70,6 @@ public : QNodeId parentEntityId() const; QComponentVector m_components; - bool m_visible; - - // TODO: Is a bool enough here or do we need additional states for entities? - // Perhaps aboutToBeDeleted would be useful? mutable QNodeId m_parentEntityId; }; -- cgit v1.2.3 From 65903ba8aa2b27a36b2e8dd636190c551b420623 Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Sun, 12 Feb 2017 15:17:43 +0000 Subject: Initialize member in AspectTaskRunnable Change-Id: I370f798e7408c2bc47e64cfcc2e55b3e6e9f689b Coverity-Id: 154598 Reviewed-by: Paul Lemire --- src/core/jobs/task.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/core/jobs/task.cpp b/src/core/jobs/task.cpp index 45da858f4..0d1f49de2 100644 --- a/src/core/jobs/task.cpp +++ b/src/core/jobs/task.cpp @@ -56,8 +56,9 @@ RunnableInterface::~RunnableInterface() // Aspect task AspectTaskRunnable::AspectTaskRunnable() - : m_dependencyHandler(0), - m_reserved(false) + : m_dependencyHandler(nullptr) + , m_pooler(nullptr) + , m_reserved(false) { } -- cgit v1.2.3 From 9a01602c00969fc1db4a824aa9aa8749a5627a1f Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Sun, 12 Feb 2017 16:03:55 +0000 Subject: Initialize member in SyncTaskRunnable Covrity-Id: 154599 Change-Id: Iacb9d98c8357a37ad8764875785862ee43506d37 Reviewed-by: Paul Lemire --- src/core/jobs/task.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/core/jobs/task.cpp b/src/core/jobs/task.cpp index 0d1f49de2..7c9fb89a7 100644 --- a/src/core/jobs/task.cpp +++ b/src/core/jobs/task.cpp @@ -107,11 +107,12 @@ DependencyHandler *AspectTaskRunnable::dependencyHandler() SyncTaskRunnable::SyncTaskRunnable(QAbstractAspectJobManager::JobFunction func, void *arg, QAtomicInt *atomicCount) - : m_func(func), - m_arg(arg), - m_atomicCount(atomicCount), - m_pooler(nullptr), - m_reserved(false) + : m_func(func) + , m_arg(arg) + , m_atomicCount(atomicCount) + , m_pooler(nullptr) + , m_reserved(false) + , m_id(0) { } -- cgit v1.2.3 From c73b19eab15eff9dcd9cfac7a0b217b2a1a61494 Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Sun, 12 Feb 2017 16:06:06 +0000 Subject: Initialize member in QThreadPooler Change-Id: I7c59c48fbdeac30d0f2f3caefb6b71e19550e9f8 Coverity-Id: 154600 Reviewed-by: Paul Lemire --- src/core/jobs/qthreadpooler.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/core/jobs/qthreadpooler.cpp b/src/core/jobs/qthreadpooler.cpp index 35e2df2a1..0fd08430e 100644 --- a/src/core/jobs/qthreadpooler.cpp +++ b/src/core/jobs/qthreadpooler.cpp @@ -57,10 +57,11 @@ QElapsedTimer QThreadPooler::m_jobsStatTimer; #endif QThreadPooler::QThreadPooler(QObject *parent) - : QObject(parent), - m_futureInterface(nullptr), - m_mutex(), - m_taskCount(0) + : QObject(parent) + , m_futureInterface(nullptr) + , m_mutex() + , m_dependencyHandler(nullptr) + , m_taskCount(0) { // Ensures that threads will never be recycled m_threadPool.setExpiryTimeout(-1); -- cgit v1.2.3 From 5c6d6aa44f5fe327b61d2209f30eb40405c1596d Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Sun, 12 Feb 2017 16:13:13 +0000 Subject: Initialize members in Dependency Change-Id: I0b6ee508099bc12d95da5ad7da519a25e5923747 Coverity-Id: 154602 Reviewed-by: Paul Lemire --- src/core/jobs/dependencyhandler_p.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/core/jobs/dependencyhandler_p.h b/src/core/jobs/dependencyhandler_p.h index abaa8e55f..db9389c9a 100644 --- a/src/core/jobs/dependencyhandler_p.h +++ b/src/core/jobs/dependencyhandler_p.h @@ -62,7 +62,10 @@ namespace Qt3DCore { struct Dependency { - Dependency() {} + Dependency() + : depender(nullptr) + , dependee(nullptr) + {} Dependency(RunnableInterface *depender, RunnableInterface *dependee) : depender(qMove(depender)), dependee(qMove(dependee)) {} -- cgit v1.2.3 From c8308fd1fcf58f8b72dff8982abaeae5ad361fdf Mon Sep 17 00:00:00 2001 From: Paul Lemire Date: Mon, 6 Feb 2017 10:37:02 +0100 Subject: Quick3DEntity: use dedicated list of QML components So that we can add layers to prebuilt Entities Change-Id: I608c3dfcb6351c95f4cd373f14bea0f3a247508c Reviewed-by: Sean Harmer --- src/quick3d/quick3d/items/quick3dentity.cpp | 6 +++--- src/quick3d/quick3d/items/quick3dentity_p.h | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/quick3d/quick3d/items/quick3dentity.cpp b/src/quick3d/quick3d/items/quick3dentity.cpp index ebc92e843..0a95815af 100644 --- a/src/quick3d/quick3d/items/quick3dentity.cpp +++ b/src/quick3d/quick3d/items/quick3dentity.cpp @@ -92,6 +92,7 @@ void Quick3DEntity::qmlAppendComponent(QQmlListProperty *list, QComp if (comp == nullptr) return; Quick3DEntity *self = static_cast(list->object); + self->m_managedComponents.push_back(comp); self->parentEntity()->addComponent(comp); } @@ -110,10 +111,9 @@ int Quick3DEntity::qmlComponentsCount(QQmlListProperty *list) void Quick3DEntity::qmlClearComponents(QQmlListProperty *list) { Quick3DEntity *self = static_cast(list->object); - const QComponentVector components = self->parentEntity()->components(); - for (QComponent *comp : components) { + for (QComponent *comp : qAsConst(self->m_managedComponents)) self->parentEntity()->removeComponent(comp); - } + self->m_managedComponents.clear(); } } // namespace Quick diff --git a/src/quick3d/quick3d/items/quick3dentity_p.h b/src/quick3d/quick3d/items/quick3dentity_p.h index eb716a0c3..519ea4bd1 100644 --- a/src/quick3d/quick3d/items/quick3dentity_p.h +++ b/src/quick3d/quick3d/items/quick3dentity_p.h @@ -82,6 +82,8 @@ private: static QComponent *qmlComponentAt(QQmlListProperty *list, int index); static int qmlComponentsCount(QQmlListProperty *list); static void qmlClearComponents(QQmlListProperty *list); + + QVector m_managedComponents; }; } // namespace Quick -- cgit v1.2.3 From def6ae900bea0a6e10e765be5d6a814f6e1b0f7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Fri, 16 Dec 2016 12:58:37 +0200 Subject: Fix autotests Change-Id: If7bd1299c7ccd4f5f40714a45025a40ac164db43 Reviewed-by: Sean Harmer --- src/animation/frontend/qabstractanimation_p.h | 2 +- src/animation/frontend/qanimationcontroller.cpp | 15 ++- src/animation/frontend/qanimationcontroller_p.h | 2 + src/animation/frontend/qkeyframeanimation.cpp | 62 ++++++++----- src/animation/frontend/qkeyframeanimation.h | 12 +-- src/animation/frontend/qkeyframeanimation_p.h | 1 - src/animation/frontend/qmorphinganimation.cpp | 113 ++++++++++++++--------- src/animation/frontend/qmorphinganimation.h | 8 +- src/animation/frontend/qmorphinganimation_p.h | 2 + src/animation/frontend/qvertexblendanimation.cpp | 2 + 10 files changed, 138 insertions(+), 81 deletions(-) diff --git a/src/animation/frontend/qabstractanimation_p.h b/src/animation/frontend/qabstractanimation_p.h index 197d8ab1c..e1c412b01 100644 --- a/src/animation/frontend/qabstractanimation_p.h +++ b/src/animation/frontend/qabstractanimation_p.h @@ -55,7 +55,7 @@ QT_BEGIN_NAMESPACE namespace Qt3DAnimation { -class QAbstractAnimationPrivate : public QObjectPrivate +class Q_AUTOTEST_EXPORT QAbstractAnimationPrivate : public QObjectPrivate { public: QAbstractAnimationPrivate(QAbstractAnimation::AnimationType type); diff --git a/src/animation/frontend/qanimationcontroller.cpp b/src/animation/frontend/qanimationcontroller.cpp index 86d9eb537..a735ba7ed 100644 --- a/src/animation/frontend/qanimationcontroller.cpp +++ b/src/animation/frontend/qanimationcontroller.cpp @@ -47,6 +47,7 @@ QAnimationControllerPrivate::QAnimationControllerPrivate() : QObjectPrivate() , m_activeAnimationGroup(0) , m_position(0.0f) + , m_scaledPosition(0.0f) , m_positionScale(1.0f) , m_positionOffset(0.0f) , m_entity(nullptr) @@ -58,10 +59,14 @@ QAnimationControllerPrivate::QAnimationControllerPrivate() void QAnimationControllerPrivate::updatePosition(float position) { m_position = position; - if (m_activeAnimationGroup >= 0 && m_activeAnimationGroup < m_animationGroups.size()) { - const float pos = m_positionScale * position + m_positionOffset; - m_animationGroups[m_activeAnimationGroup]->setPosition(pos); - } + m_scaledPosition = scaledPosition(position); + if (m_activeAnimationGroup >= 0 && m_activeAnimationGroup < m_animationGroups.size()) + m_animationGroups[m_activeAnimationGroup]->setPosition(m_scaledPosition); +} + +float QAnimationControllerPrivate::scaledPosition(float position) const +{ + return m_positionScale * position + m_positionOffset; } QAnimationGroup *QAnimationControllerPrivate::findGroup(const QString &name) @@ -186,7 +191,7 @@ void QAnimationController::setActiveAnimationGroup(int index) void QAnimationController::setPosition(float position) { Q_D(QAnimationController); - if (!qFuzzyCompare(d->m_position, position)) { + if (!qFuzzyCompare(d->m_scaledPosition, d->scaledPosition(position))) { d->updatePosition(position); emit positionChanged(position); } diff --git a/src/animation/frontend/qanimationcontroller_p.h b/src/animation/frontend/qanimationcontroller_p.h index 1c309a183..c06484911 100644 --- a/src/animation/frontend/qanimationcontroller_p.h +++ b/src/animation/frontend/qanimationcontroller_p.h @@ -64,6 +64,7 @@ public: int m_activeAnimationGroup; QVector m_animationGroups; float m_position; + float m_scaledPosition; float m_positionScale; float m_positionOffset; Qt3DCore::QEntity *m_entity; @@ -73,6 +74,7 @@ public: void extractAnimations(); void clearAnimations(); QAnimationGroup *findGroup(const QString &name); + float scaledPosition(float position) const; Q_DECLARE_PUBLIC(QAnimationController) }; diff --git a/src/animation/frontend/qkeyframeanimation.cpp b/src/animation/frontend/qkeyframeanimation.cpp index 2e63e96c8..981437d28 100644 --- a/src/animation/frontend/qkeyframeanimation.cpp +++ b/src/animation/frontend/qkeyframeanimation.cpp @@ -45,7 +45,6 @@ namespace Qt3DAnimation { QKeyframeAnimationPrivate::QKeyframeAnimationPrivate() : QAbstractAnimationPrivate(QAbstractAnimation::KeyframeAnimation) - , m_prevPosition(-1.0f) , m_target(nullptr) , m_minposition(0.0f) , m_maxposition(0.0f) @@ -68,7 +67,7 @@ void QKeyframeAnimation::setFramePositions(const QVector &positions) { Q_D(QKeyframeAnimation); d->m_framePositions = positions; - d->m_prevPosition = -1.0f; + d->m_position = -1.0f; if (d->m_framePositions.size() == 0) { d->m_minposition = d->m_maxposition = 0.0f; return; @@ -116,9 +115,35 @@ QQuaternion lslerp(QQuaternion q1, QQuaternion q2, float t) void QKeyframeAnimationPrivate::calculateFrame(float position) { if (m_target && m_framePositions.size() > 0 - && m_keyframes.size() == m_framePositions.size() - && m_prevPosition != m_position) { - if (m_position >= m_minposition && m_position < m_maxposition) { + && m_keyframes.size() == m_framePositions.size()) { + if (position < m_minposition) { + if (m_startMode == QKeyframeAnimation::None) { + return; + } else if (m_startMode == QKeyframeAnimation::Constant) { + m_target->setRotation(m_keyframes.first()->rotation()); + m_target->setScale3D(m_keyframes.first()->scale3D()); + m_target->setTranslation(m_keyframes.first()->translation()); + return; + } else { + // must be repeat + position = std::fmod(-(position - m_minposition), m_maxposition - m_minposition) + + m_minposition; + } + } else if (position >= m_maxposition) { + if (m_endMode == QKeyframeAnimation::None) { + return; + } else if (m_endMode == QKeyframeAnimation::Constant) { + m_target->setRotation(m_keyframes.last()->rotation()); + m_target->setScale3D(m_keyframes.last()->scale3D()); + m_target->setTranslation(m_keyframes.last()->translation()); + return; + } else { + // must be repeat + position = std::fmod(position - m_minposition, m_maxposition - m_minposition) + + m_minposition; + } + } + if (position >= m_minposition && position < m_maxposition) { for (int i = 0; i < m_framePositions.size() - 1; i++) { if (position >= m_framePositions.at(i) && position < m_framePositions.at(i+1)) { @@ -140,16 +165,7 @@ void QKeyframeAnimationPrivate::calculateFrame(float position) return; } } - } else if (position < m_minposition) { - m_target->setRotation(m_keyframes.first()->rotation()); - m_target->setScale3D(m_keyframes.first()->scale3D()); - m_target->setTranslation(m_keyframes.first()->translation()); - } else { - m_target->setRotation(m_keyframes.last()->rotation()); - m_target->setScale3D(m_keyframes.last()->scale3D()); - m_target->setTranslation(m_keyframes.last()->translation()); } - m_prevPosition = m_position; } } @@ -177,7 +193,7 @@ void QKeyframeAnimation::setTarget(Qt3DCore::QTransform *target) if (d->m_target != target) { d->m_target = target; emit targetChanged(d->m_target); - d->m_prevPosition = -1.0f; + d->m_position = -1.0f; if (target) { d->m_baseScale = target->scale3D(); @@ -199,11 +215,11 @@ QKeyframeAnimation::RepeatMode QKeyframeAnimation::endMode() const return d->m_endMode; } -void QKeyframeAnimation::setEasing(QEasingCurve::Type easing) +void QKeyframeAnimation::setEasing(const QEasingCurve &easing) { Q_D(QKeyframeAnimation); - if (d->m_easing.type() != easing) { - d->m_easing.setType(easing); + if (d->m_easing != easing) { + d->m_easing = easing; emit easingChanged(easing); } } @@ -211,8 +227,10 @@ void QKeyframeAnimation::setEasing(QEasingCurve::Type easing) void QKeyframeAnimation::setTargetName(const QString &name) { Q_D(QKeyframeAnimation); - d->m_targetName = name; - emit targetNameChanged(name); + if (d->m_targetName != name) { + d->m_targetName = name; + emit targetNameChanged(name); + } } void QKeyframeAnimation::setStartMode(QKeyframeAnimation::RepeatMode mode) @@ -245,10 +263,10 @@ QString QKeyframeAnimation::targetName() const return d->m_targetName; } -QEasingCurve::Type QKeyframeAnimation::easing() const +QEasingCurve QKeyframeAnimation::easing() const { Q_D(const QKeyframeAnimation); - return d->m_easing.type(); + return d->m_easing; } Qt3DCore::QTransform *QKeyframeAnimation::target() const diff --git a/src/animation/frontend/qkeyframeanimation.h b/src/animation/frontend/qkeyframeanimation.h index d34f6cfba..19cb192b4 100644 --- a/src/animation/frontend/qkeyframeanimation.h +++ b/src/animation/frontend/qkeyframeanimation.h @@ -55,7 +55,7 @@ class QT3DANIMATIONSHARED_EXPORT QKeyframeAnimation : public QAbstractAnimation Q_OBJECT Q_PROPERTY(QVector framePositions READ framePositions WRITE setFramePositions NOTIFY framePositionsChanged) Q_PROPERTY(Qt3DCore::QTransform *target READ target WRITE setTarget NOTIFY targetChanged) - Q_PROPERTY(QEasingCurve::Type easing READ easing WRITE setEasing NOTIFY easingChanged) + Q_PROPERTY(QEasingCurve easing READ easing WRITE setEasing NOTIFY easingChanged) Q_PROPERTY(QString targetName READ targetName WRITE setTargetName NOTIFY targetNameChanged) Q_PROPERTY(QKeyframeAnimation::RepeatMode startMode READ startMode WRITE setStartMode NOTIFY startModeChanged) Q_PROPERTY(QKeyframeAnimation::RepeatMode endMode READ endMode WRITE setEndMode NOTIFY endModeChanged) @@ -74,7 +74,7 @@ public: QVector framePositions() const; QVector keyframeList() const; Qt3DCore::QTransform *target() const; - QEasingCurve::Type easing() const; + QEasingCurve easing() const; QString targetName() const; RepeatMode startMode() const; RepeatMode endMode() const; @@ -86,7 +86,7 @@ public: public Q_SLOTS: void setFramePositions(const QVector &positions); void setTarget(Qt3DCore::QTransform *target); - void setEasing(QEasingCurve::Type easing); + void setEasing(const QEasingCurve &easing); void setTargetName(const QString &name); void setStartMode(RepeatMode mode); void setEndMode(RepeatMode mode); @@ -94,10 +94,10 @@ public Q_SLOTS: Q_SIGNALS: void framePositionsChanged(const QVector &positions); void targetChanged(Qt3DCore::QTransform *target); - void easingChanged(QEasingCurve::Type easing); + void easingChanged(const QEasingCurve &easing); void targetNameChanged(const QString &name); - void startModeChanged(RepeatMode startMode); - void endModeChanged(RepeatMode endMode); + void startModeChanged(QKeyframeAnimation::RepeatMode startMode); + void endModeChanged(QKeyframeAnimation::RepeatMode endMode); private: void updateAnimation(float position); diff --git a/src/animation/frontend/qkeyframeanimation_p.h b/src/animation/frontend/qkeyframeanimation_p.h index 60fc50fb1..b9b1f8585 100644 --- a/src/animation/frontend/qkeyframeanimation_p.h +++ b/src/animation/frontend/qkeyframeanimation_p.h @@ -63,7 +63,6 @@ public: void calculateFrame(float position); - float m_prevPosition; QVector m_framePositions; QVector m_keyframes; Qt3DCore::QTransform *m_target; diff --git a/src/animation/frontend/qmorphinganimation.cpp b/src/animation/frontend/qmorphinganimation.cpp index 4463f6cbf..4ee20f9cf 100644 --- a/src/animation/frontend/qmorphinganimation.cpp +++ b/src/animation/frontend/qmorphinganimation.cpp @@ -43,13 +43,15 @@ namespace Qt3DAnimation { QMorphingAnimationPrivate::QMorphingAnimationPrivate() : QAbstractAnimationPrivate(QAbstractAnimation::MorphingAnimation) + , m_minposition(0.0f) + , m_maxposition(0.0f) , m_flattened(nullptr) , m_method(QMorphingAnimation::Relative) , m_interpolator(0.0f) , m_target(nullptr) , m_currentTarget(nullptr) { - m_easing.setType(QEasingCurve::InOutCubic); + } QMorphingAnimationPrivate::~QMorphingAnimationPrivate() @@ -64,46 +66,60 @@ void QMorphingAnimationPrivate::updateAnimation(float position) if (!m_target || !m_target->geometry()) return; + QVector relevantValues; + float sum = 0.0f; + float interpolator; m_morphKey.resize(m_morphTargets.size()); - for (int i = 0; i < m_targetPositions.size() - 1; ++i) { - if (position > m_targetPositions.at(i) && position <= m_targetPositions.at(i + 1)) { - float interpolator = (position - m_targetPositions.at(i)) - / (m_targetPositions.at(i + 1) - m_targetPositions.at(i)); - interpolator = m_easing.valueForProgress(interpolator); - float iip = 1.0f - interpolator; - float sum = 0.0f; - QVector relevantValues; - for (int j = 0; j < m_morphTargets.size(); ++j) { - m_morphKey[j] = interpolator * m_weights.at(i + 1)->at(j) - + iip * m_weights.at(i)->at(j); - sum += m_morphKey[j]; - if (!qFuzzyIsNull(m_morphKey[j])) - relevantValues.push_back(j); - } - - if (relevantValues.size() == 0 || qFuzzyIsNull(sum)) { - // only base is used - interpolator = 0.0f; - } else if (relevantValues.size() == 1) { - // one morph target has non-zero weight - setTargetInterpolated(relevantValues[0]); - interpolator = sum; - } else { - // more than one morph target has non-zero weight - // flatten morph targets to one - qWarning() << Q_FUNC_INFO << "Flattening required"; + // calculate morph key + if (position < m_minposition) { + m_morphKey = *m_weights.first(); + } else if (position >= m_maxposition) { + m_morphKey = *m_weights.last(); + } else { + for (int i = 0; i < m_targetPositions.size() - 1; ++i) { + if (position >= m_targetPositions.at(i) && position < m_targetPositions.at(i + 1)) { + interpolator = (position - m_targetPositions.at(i)) + / (m_targetPositions.at(i + 1) - m_targetPositions.at(i)); + interpolator = m_easing.valueForProgress(interpolator); + float iip = 1.0f - interpolator; + + for (int j = 0; j < m_morphTargets.size(); ++j) { + m_morphKey[j] = interpolator * m_weights.at(i + 1)->at(j) + + iip * m_weights.at(i)->at(j); + } } - if (!qFuzzyCompare(interpolator, m_interpolator)) { - if (m_method == QMorphingAnimation::Normalized) - m_interpolator = interpolator; - else - m_interpolator = -interpolator; - emit q->interpolatorChanged(m_interpolator); - } - return; } } + + // check relevant values + for (int j = 0; j < m_morphKey.size(); ++j) { + sum += m_morphKey[j]; + if (!qFuzzyIsNull(m_morphKey[j])) + relevantValues.push_back(j); + } + + if (relevantValues.size() == 0 || qFuzzyIsNull(sum)) { + // only base is used + interpolator = 0.0f; + } else if (relevantValues.size() == 1) { + // one morph target has non-zero weight + setTargetInterpolated(relevantValues[0]); + interpolator = sum; + } else { + // more than one morph target has non-zero weight + // flatten morph targets to one + qWarning() << Q_FUNC_INFO << "Flattening required"; + } + + // Relative method uses negative interpolator, normalized uses positive + if (m_method == QMorphingAnimation::Relative) + interpolator = -interpolator; + + if (!qFuzzyCompare(interpolator, m_interpolator)) { + m_interpolator = interpolator; + emit q->interpolatorChanged(m_interpolator); + } } void QMorphingAnimationPrivate::setTargetInterpolated(int morphTarget) @@ -170,10 +186,10 @@ QMorphingAnimation::Method QMorphingAnimation::method() const return d->m_method; } -QEasingCurve::Type QMorphingAnimation::easing() const +QEasingCurve QMorphingAnimation::easing() const { Q_D(const QMorphingAnimation); - return d->m_easing.type(); + return d->m_easing; } void QMorphingAnimation::setMorphTargets(const QVector &targets) @@ -181,19 +197,25 @@ void QMorphingAnimation::setMorphTargets(const QVectorm_morphTargets = targets; d->m_attributeNames = targets[0]->attributeNames(); + d->m_position = -1.0f; } void QMorphingAnimation::addMorphTarget(Qt3DAnimation::QMorphTarget *target) { Q_D(QMorphingAnimation); - if (!d->m_morphTargets.contains(target)) + if (!d->m_morphTargets.contains(target)) { d->m_morphTargets.push_back(target); + d->m_position = -1.0f; + if (d->m_attributeNames.empty()) + d->m_attributeNames = target->attributeNames(); + } } void QMorphingAnimation::removeMorphTarget(Qt3DAnimation::QMorphTarget *target) { Q_D(QMorphingAnimation); d->m_morphTargets.removeAll(target); + d->m_position = -1.0f; } void QMorphingAnimation::setTargetPositions(const QVector &targetPositions) @@ -201,6 +223,8 @@ void QMorphingAnimation::setTargetPositions(const QVector &targetPosition Q_D(QMorphingAnimation); d->m_targetPositions = targetPositions; emit targetPositionsChanged(targetPositions); + d->m_minposition = targetPositions.first(); + d->m_maxposition = targetPositions.last(); setDuration(d->m_targetPositions.last()); if (d->m_weights.size() < targetPositions.size()) { d->m_weights.resize(targetPositions.size()); @@ -209,12 +233,14 @@ void QMorphingAnimation::setTargetPositions(const QVector &targetPosition d->m_weights[i] = new QVector(); } } + d->m_position = -1.0f; } void QMorphingAnimation::setTarget(Qt3DRender::QGeometryRenderer *target) { Q_D(QMorphingAnimation); if (d->m_target != target) { + d->m_position = -1.0f; d->m_target = target; emit targetChanged(target); } @@ -228,6 +254,7 @@ void QMorphingAnimation::setWeights(int positionIndex, const QVector &wei if (d->m_weights[positionIndex] == nullptr) d->m_weights[positionIndex] = new QVector(); *d->m_weights[positionIndex] = weights; + d->m_position = -1.0f; } QVector QMorphingAnimation::getWeights(int positionIndex) @@ -256,15 +283,17 @@ void QMorphingAnimation::setMethod(QMorphingAnimation::Method method) Q_D(QMorphingAnimation); if (d->m_method != method) { d->m_method = method; + d->m_position = -1.0f; emit methodChanged(method); } } -void QMorphingAnimation::setEasing(QEasingCurve::Type easing) +void QMorphingAnimation::setEasing(const QEasingCurve &easing) { Q_D(QMorphingAnimation); - if (d->m_easing.type() != easing) { - d->m_easing.setType(easing); + if (d->m_easing != easing) { + d->m_easing = easing; + d->m_position = -1.0f; emit easingChanged(easing); } } diff --git a/src/animation/frontend/qmorphinganimation.h b/src/animation/frontend/qmorphinganimation.h index b83288d04..2944fad91 100644 --- a/src/animation/frontend/qmorphinganimation.h +++ b/src/animation/frontend/qmorphinganimation.h @@ -59,7 +59,7 @@ class QT3DANIMATIONSHARED_EXPORT QMorphingAnimation : public QAbstractAnimation Q_PROPERTY(Qt3DRender::QGeometryRenderer *target READ target WRITE setTarget NOTIFY targetChanged) Q_PROPERTY(QString targetName READ targetName WRITE setTargetName NOTIFY targetNameChanged) Q_PROPERTY(QMorphingAnimation::Method method READ method WRITE setMethod NOTIFY methodChanged) - Q_PROPERTY(QEasingCurve::Type easing READ easing WRITE setEasing NOTIFY easingChanged) + Q_PROPERTY(QEasingCurve easing READ easing WRITE setEasing NOTIFY easingChanged) public: enum Method @@ -76,7 +76,7 @@ public: Qt3DRender::QGeometryRenderer *target() const; QString targetName() const; QMorphingAnimation::Method method() const; - QEasingCurve::Type easing() const; + QEasingCurve easing() const; void setMorphTargets(const QVector &targets); void addMorphTarget(Qt3DAnimation::QMorphTarget *target); @@ -92,7 +92,7 @@ public Q_SLOTS: void setTarget(Qt3DRender::QGeometryRenderer *target); void setTargetName(const QString name); void setMethod(QMorphingAnimation::Method method); - void setEasing(QEasingCurve::Type easing); + void setEasing(const QEasingCurve &easing); Q_SIGNALS: void targetPositionsChanged(const QVector &targetPositions); @@ -100,7 +100,7 @@ Q_SIGNALS: void targetChanged(Qt3DRender::QGeometryRenderer *target); void targetNameChanged(const QString &name); void methodChanged(QMorphingAnimation::Method method); - void easingChanged(QEasingCurve::Type easing); + void easingChanged(const QEasingCurve &easing); private: diff --git a/src/animation/frontend/qmorphinganimation_p.h b/src/animation/frontend/qmorphinganimation_p.h index d9a04343c..c306f3309 100644 --- a/src/animation/frontend/qmorphinganimation_p.h +++ b/src/animation/frontend/qmorphinganimation_p.h @@ -67,6 +67,8 @@ public: void updateAnimation(float position); void setTargetInterpolated(int morphTarget); + float m_minposition; + float m_maxposition; QVector m_targetPositions; QVector*> m_weights; QVector m_morphKey; diff --git a/src/animation/frontend/qvertexblendanimation.cpp b/src/animation/frontend/qvertexblendanimation.cpp index 0bad72abf..8eb0e5751 100644 --- a/src/animation/frontend/qvertexblendanimation.cpp +++ b/src/animation/frontend/qvertexblendanimation.cpp @@ -44,6 +44,8 @@ namespace Qt3DAnimation { QVertexBlendAnimationPrivate::QVertexBlendAnimationPrivate() : QAbstractAnimationPrivate(QAbstractAnimation::VertexBlendAnimation) + , m_interpolator(0.0f) + , m_target(nullptr) , m_currentBase(nullptr) , m_currentTarget(nullptr) { -- cgit v1.2.3 From fb1c1950f89caaaf0bd554a8c73a72ea63057674 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Wed, 8 Feb 2017 11:34:51 +0200 Subject: Register QMorphPhongMaterial for qml Change-Id: Ie15dbf44ccbdc09f51cb8525cbe77984d7e29791 Reviewed-by: Sean Harmer --- src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp b/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp index 823670e8d..62cb1f55e 100644 --- a/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp +++ b/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp @@ -71,6 +71,7 @@ #include #include #include +#include #include #include @@ -103,6 +104,7 @@ void Qt3DQuick3DExtrasPlugin::registerTypes(const char *uri) qmlRegisterType(uri, 2, 0, "TextureMaterial"); qmlRegisterType(uri, 2, 2, "MetalRoughMaterial"); qmlRegisterType(uri, 2, 2, "TexturedMetalRoughMaterial"); + qmlRegisterType(uri, 2, 2, "MorphPhongMaterial"); // Meshes qmlRegisterType(uri, 2, 0, "ConeMesh"); -- cgit v1.2.3 From ad5bd61b6a7ff706130c48d9ae6f5c132f6327b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Tue, 20 Dec 2016 12:15:18 +0200 Subject: Add docs for animations Also updated docs of other classes due to property changes. Change-Id: I1b1d44ad574ebb6ddf2ce7de5fe888c7b02a450b Reviewed-by: Sean Harmer --- src/animation/frontend/qabstractanimation.cpp | 79 +++++++++++- src/animation/frontend/qabstractanimation.h | 1 + src/animation/frontend/qanimationcontroller.cpp | 137 ++++++++++++++++++++- src/animation/frontend/qanimationgroup.cpp | 93 ++++++++++++++- src/animation/frontend/qkeyframeanimation.cpp | 137 ++++++++++++++++++++- src/animation/frontend/qmorphinganimation.cpp | 146 ++++++++++++++++++++++- src/animation/frontend/qmorphtarget.cpp | 70 ++++++++++- src/animation/frontend/qvertexblendanimation.cpp | 109 +++++++++++++++++ 8 files changed, 763 insertions(+), 9 deletions(-) diff --git a/src/animation/frontend/qabstractanimation.cpp b/src/animation/frontend/qabstractanimation.cpp index 6f5aa05d8..efac3f5ec 100644 --- a/src/animation/frontend/qabstractanimation.cpp +++ b/src/animation/frontend/qabstractanimation.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2017 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt3D module of the Qt Toolkit. @@ -41,6 +41,80 @@ QT_BEGIN_NAMESPACE namespace Qt3DAnimation { +/*! + \class Qt3DAnimation::QAbstractAnimation + \brief An abstract base class for Qt3D animations + \inmodule Qt3DAnimation + \since 5.9 + \inherits QObject + + Qt3DAnimation::QAbstractAnimation is an abstract base class for all animations. + Qt3DAnimation::QAbstractAnimation can not be directly instantiated, but rather + through its subclasses. QAbstractAnimation specifies common properties + for all Qt3D animations, such as animation name and type, current position and animation + duration, while leaving the actual animating for the subclasses. +*/ + +/*! + \qmltype AbstractAnimation + \brief An abstract base type for Qt3D animations + \inqmlmodule Qt3D.Animation + \since 5.9 + \instantiates Qt3DAnimation::QAbstractAnimation + + AbstractAnimation is an abstract base type for all animations. + AbstractAnimation can not be directly instantiated, but rather + through its subtypes. AbstractAnimation specifies common properties + for all Qt3D animations, such as animation type, current position and animation + duration, while leaving the actual animating for the subtypes. +*/ +/*! + \enum QAbstractAnimation::AnimationType + + This enumeration specifies the type of the animation + \value KeyframeAnimation Simple keyframe animation implementation for QTransform + \value MorphingAnimation Blend-shape morphing animation + \value VertexBlendAnimation Vertex-blend animation +*/ +/*! + \property Qt3DAnimation::QAbstractAnimation::animationName + Holds the name of the animation. +*/ +/*! + \property Qt3DAnimation::QAbstractAnimation::animationType + Holds the type of the animation. +*/ +/*! + \property Qt3DAnimation::QAbstractAnimation::position + Holds the current position of the animation. +*/ +/*! + \property Qt3DAnimation::QAbstractAnimation::duration + Holds the duration of the animation. +*/ + +/*! + \qmlproperty string AbstractAnimation::animationName + Holds the name of the animation. +*/ +/*! + \qmlproperty enumeration AbstractAnimation::animationType + Holds the type of the animation. + \list + \li KeyframeAnimation + \li MorphingAnimation + \li VertexBlendAnimation + \endlist +*/ +/*! + \qmlproperty real AbstractAnimation::position + Holds the current position of the animation. +*/ +/*! + \qmlproperty real AbstractAnimation::duration + Holds the duration of the animation. +*/ + QAbstractAnimationPrivate::QAbstractAnimationPrivate(QAbstractAnimation::AnimationType type) : QObjectPrivate() , m_animationType(type) @@ -98,6 +172,9 @@ void QAbstractAnimation::setPosition(float position) } } +/*! + Sets the \a duration of the animation. +*/ void QAbstractAnimation::setDuration(float duration) { Q_D(QAbstractAnimation); diff --git a/src/animation/frontend/qabstractanimation.h b/src/animation/frontend/qabstractanimation.h index af70399b1..0c6fe865e 100644 --- a/src/animation/frontend/qabstractanimation.h +++ b/src/animation/frontend/qabstractanimation.h @@ -62,6 +62,7 @@ public: MorphingAnimation = 2, VertexBlendAnimation = 3, }; + Q_ENUM(AnimationType) QString animationName() const; QAbstractAnimation::AnimationType animationType() const; diff --git a/src/animation/frontend/qanimationcontroller.cpp b/src/animation/frontend/qanimationcontroller.cpp index a735ba7ed..5df2c713a 100644 --- a/src/animation/frontend/qanimationcontroller.cpp +++ b/src/animation/frontend/qanimationcontroller.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2017 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt3D module of the Qt Toolkit. @@ -43,6 +43,117 @@ QT_BEGIN_NAMESPACE namespace Qt3DAnimation { +/*! + \class Qt3DAnimation::QAnimationController + \brief A controller class for animations + \inmodule Qt3DAnimation + \since 5.9 + \inherits QObject + + Qt3DAnimation::QAnimationController class controls the selection and playback of animations. + The class can be used to find all animations from Qt3DCore::QEntity tree and create + \l {Qt3DAnimation::QAnimationGroup} {QAnimationGroups} from the animations with the same name. + The user can select which animation group is currently controlled with the animation + controller by setting the active animation. The animation position is then propagated to + that group after scaling and offsetting the provided position value with the + positionScale and positionOffset values. + + \note that the animation controller doesn't have internal timer, but instead the user + is responsible for updating the position property in timely manner. +*/ + +/*! + \qmltype AnimationController + \brief A controller type for animations + \inqmlmodule Qt3D.Animation + \since 5.9 + \instantiates Qt3DAnimation::QAnimationController + + AnimationController type controls the selection and playback of animations. + The type can be used to find all animations from Entity tree and create + \l {AnimationGroup} {AnimationGroups} from the animations with the same name. + The user can select which animation group is currently controlled with the animation + controller by setting the active animation. The animation position is then propagated to + that group after scaling and offsetting the provided position value with the + positionScale and positionOffset values. + + \note that the animation controller doesn't have internal timer, but instead the user + is responsible for updating the position property in timely manner. +*/ + +/*! + \property Qt3DAnimation::QAnimationController::activeAnimationGroup + Holds the currectly active animation group. +*/ +/*! + \property Qt3DAnimation::QAnimationController::position + Holds the current position of the animation. When the position is set, + it is scaled and offset with positionScale/positionOffset and propagated + to the active animation group. +*/ +/*! + \property Qt3DAnimation::QAnimationController::positionScale + Holds the position scale of the animation. +*/ +/*! + \property Qt3DAnimation::QAnimationController::positionOffset + Holds the position offset of the animation. +*/ +/*! + \property Qt3DAnimation::QAnimationController::entity + Holds the entity animations are gathered and grouped from. If the controller already + holds animations, they are cleared. +*/ +/*! + \property Qt3DAnimation::QAnimationController::recursive + Holds whether the recursively search the entity tree when gathering animations from the entity. + If set to true, the animations are searched also from the child entities of the entity. + If set to false, only the entity passed to the controller is searched. +*/ + +/*! + \qmlproperty int AnimationController::activeAnimationGroup + Holds the currectly active animation group. +*/ +/*! + \qmlproperty real AnimationController::position + Holds the current position of the animation. When the position is set, + it is scaled and offset with positionScale/positionOffset and propagated + to the active animation group. +*/ +/*! + \qmlproperty real AnimationController::positionScale + Holds the position scale of the animation. +*/ +/*! + \qmlproperty real AnimationController::positionOffset + Holds the position offset of the animation. +*/ +/*! + \qmlproperty Entity AnimationController::entity + Holds the entity animations are gathered and grouped from. If the controller already + holds animations, they are cleared. +*/ +/*! + \qmlproperty bool AnimationController::recursive + Holds whether the recursively search the entity tree when gathering animations from the entity. + If set to true, the animations are searched also from the child entities of the entity. + If set to false, only the entity passed to the controller is searched. +*/ +/*! + \qmlproperty list AnimationController::animationGroups + Holds the list of animation groups in the controller. +*/ +/*! + \qmlmethod int Qt3D.Animation::AnimationController::getAnimationIndex(name) + Returns the index of the animation with \a name. Returns -1 if no AnimationGroup + with the given name is found. +*/ +/*! + \qmlmethod AnimationGroup Qt3D.Animation::AnimationController::getGroup(index) + Returns the AnimationGroup with the given \a index. +*/ + QAnimationControllerPrivate::QAnimationControllerPrivate() : QObjectPrivate() , m_activeAnimationGroup(0) @@ -106,12 +217,18 @@ void QAnimationControllerPrivate::clearAnimations() m_activeAnimationGroup = 0; } +/*! + Constructs a new QAnimationController with \a parent. + */ QAnimationController::QAnimationController(QObject *parent) : QObject(*new QAnimationControllerPrivate, parent) { } +/*! + Returns the list of animation groups the conroller is currently holding. + */ QVector QAnimationController::animationGroupList() { Q_D(QAnimationController); @@ -154,7 +271,10 @@ bool QAnimationController::recursive() const return d->m_recursive; } -void QAnimationController::setAnimationGroups(const QVector &animationGroups) +/*! + Sets the \a animationGroups for the controller. Old groups are cleared. + */ +void QAnimationController::setAnimationGroups(const QVector &animationGroups) { Q_D(QAnimationController); d->m_animationGroups = animationGroups; @@ -163,6 +283,9 @@ void QAnimationController::setAnimationGroups(const QVector & d->updatePosition(d->m_position); } +/*! + Adds the given \a animationGroup to the controller. + */ void QAnimationController::addAnimationGroup(Qt3DAnimation::QAnimationGroup *animationGroup) { Q_D(QAnimationController); @@ -170,6 +293,9 @@ void QAnimationController::addAnimationGroup(Qt3DAnimation::QAnimationGroup *ani d->m_animationGroups.push_back(animationGroup); } +/*! + Removes the given \a animationGroup from the controller. + */ void QAnimationController::removeAnimationGroup(Qt3DAnimation::QAnimationGroup *animationGroup) { Q_D(QAnimationController); @@ -236,6 +362,10 @@ void QAnimationController::setRecursive(bool recursive) } } +/*! + Returns the index of the animation with \a name. Returns -1 if no AnimationGroup + with the given name is found. +*/ int QAnimationController::getAnimationIndex(const QString &name) const { Q_D(const QAnimationController); @@ -246,6 +376,9 @@ int QAnimationController::getAnimationIndex(const QString &name) const return -1; } +/*! + Returns the AnimationGroup with the given \a index. +*/ QAnimationGroup *QAnimationController::getGroup(int index) const { Q_D(const QAnimationController); diff --git a/src/animation/frontend/qanimationgroup.cpp b/src/animation/frontend/qanimationgroup.cpp index 91da1ead3..07d0fadc5 100644 --- a/src/animation/frontend/qanimationgroup.cpp +++ b/src/animation/frontend/qanimationgroup.cpp @@ -41,6 +41,63 @@ QT_BEGIN_NAMESPACE namespace Qt3DAnimation { +/*! + \class Qt3DAnimation::QAnimationGroup + \brief A class grouping animations together + \inmodule Qt3DAnimation + \since 5.9 + \inherits QObject + + Qt3DAnimation::QAnimationGroup class is used to group multiple animations so that + they can act as one animation. The position set to the group is also set to + all animations in a group. The duration is the maximum of the individual animations. + The animations can be any supported animation type and do not have to have the same name. +*/ +/*! + \qmltype AnimationGroup + \brief A type grouping animations together + \inqmlmodule Qt3D.Animation + \since 5.9 + \inherits QObject + + AnimationGroup type is used to group multiple animations so that + they can act as one animation. The position set to the group is also set to + all animations in a group. The duration is the maximum of the individual animations. + The animations can be any supported animation type and do not have to have the same name. +*/ + +/*! + \property Qt3DAnimation::QAnimationGroup::name + Holds the name of the animation group. +*/ +/*! + \property Qt3DAnimation::QAnimationGroup::position + Holds the animation position. +*/ +/*! + \property Qt3DAnimation::QAnimationGroup::duration + Holds the maximum duration of the animations in the group. + \readonly +*/ + +/*! + \qmlproperty string AnimationGroup::name + Holds the name of the animation group. +*/ +/*! + \qmlproperty real AnimationGroup::position + Holds the animation position. +*/ +/*! + \qmlproperty real AnimationGroup::duration + Holds the maximum duration of the animations in the group. + \readonly +*/ +/*! + \qmlproperty list AnimationGroup::animations + Holds the list of animations in the animation group. +*/ + QAnimationGroupPrivate::QAnimationGroupPrivate() : QObjectPrivate() , m_position(0.0f) @@ -56,6 +113,9 @@ void QAnimationGroupPrivate::updatePosition(float position) aa->setPosition(position); } +/*! + Constructs an QAnimationGroup with \a parent. +*/ QAnimationGroup::QAnimationGroup(QObject *parent) : QObject(*new QAnimationGroupPrivate, parent) { @@ -68,6 +128,9 @@ QString QAnimationGroup::name() const return d->m_name; } +/*! + Returns the list of animations in the group. + */ QVector QAnimationGroup::animationList() { Q_D(QAnimationGroup); @@ -95,6 +158,9 @@ void QAnimationGroup::setName(const QString &name) } } +/*! + Sets the \a animations to the group. Old animations are removed. + */ void QAnimationGroup::setAnimations(const QVector &animations) { Q_D(QAnimationGroup); @@ -104,11 +170,32 @@ void QAnimationGroup::setAnimations(const QVectorm_duration = qMax(d->m_duration, a->duration()); } -void QAnimationGroup::addAnimation(QAbstractAnimation *animation) +/*! + Adds new \a animation to the group. + */ +void QAnimationGroup::addAnimation(Qt3DAnimation::QAbstractAnimation *animation) { Q_D(QAnimationGroup); - d->m_animations.push_back(animation); - d->m_duration = qMax(d->m_duration, animation->duration()); + if (!d->m_animations.contains(animation)) { + d->m_animations.push_back(animation); + d->m_duration = qMax(d->m_duration, animation->duration()); + } +} + +/*! + Removes \a animation from the group. + */ +void QAnimationGroup::removeAnimation(Qt3DAnimation::QAbstractAnimation *animation) +{ + Q_D(QAnimationGroup); + if (!d->m_animations.contains(animation)) { + d->m_animations.removeAll(animation); + if (qFuzzyCompare(d->m_duration, animation->duration())) { + d->m_duration = 0.0f; + for (const Qt3DAnimation::QAbstractAnimation *a : d->m_animations) + d->m_duration = qMax(d->m_duration, a->duration()); + } + } } void QAnimationGroup::setPosition(float position) diff --git a/src/animation/frontend/qkeyframeanimation.cpp b/src/animation/frontend/qkeyframeanimation.cpp index 981437d28..0b17265a6 100644 --- a/src/animation/frontend/qkeyframeanimation.cpp +++ b/src/animation/frontend/qkeyframeanimation.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2017 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt3D module of the Qt Toolkit. @@ -43,6 +43,118 @@ QT_BEGIN_NAMESPACE namespace Qt3DAnimation { +/*! + \class Qt3DAnimation::QKeyframeAnimation + \brief A class implementing simple keyframe animation to a QTransform + \inmodule Qt3DAnimation + \since 5.9 + \inherits Qt3DAnimation::QAbstractAnimation + + A Qt3DAnimation::QKeyframeAnimation class implements simple keyframe animation + that can be used to animate \l QTransform. The keyframes consists of multiple + timed QTransforms, which are interpolated and applied to the target \l QTransform. + \l QEasingCurve is used between keyframes to control the interpolator. RepeatMode + can be set for when the position set to the QKeyframeAnimation is below or above + the values defined in the keyframe positions. +*/ + +/*! + \qmltype KeyframeAnimation + \brief A type implementing simple keyframe animation to a Transform + \inqmlmodule Qt3D.Animation + \since 5.9 + \inherits AbstractAnimation + \instantiates Qt3DAnimation::QKeyframeAnimation + + A KeyframeAnimation type implements simple keyframe animation + that can be used to animate \l Transform. The keyframes consists of multiple + timed \l {Qt3D.Render::Transform}{Transforms}, which are interpolated and applied + to the target Transform. EasingCurve is used between keyframes to control + the interpolator. RepeatMode can be set for when the position set to the + KeyframeAnimation is less or or greater than the values defined in the keyframe positions. +*/ + +/*! + \property Qt3DAnimation::QKeyframeAnimation::framePositions + Holds the positions of the keyframes. Each position in the list specifies the position + of the corresponding keyframe with the same index. The values must be in an ascending order. + Values can be positive or negative and do not have any predefined unit. +*/ +/*! + \property Qt3DAnimation::QKeyframeAnimation::target + Holds the target QTransform the animation is applied to. +*/ +/*! + \property Qt3DAnimation::QKeyframeAnimation::easing + Holds the easing curve of the interpolator between keyframes. +*/ +/*! + \property Qt3DAnimation::QKeyframeAnimation::targetName + Holds the name of the target transform. This is a convenience property making it + easier to match the target transform to the keyframe animation. The name + is usually same as the name of the parent entity of the target transform, but + does not have to be. +*/ +/*! + \property Qt3DAnimation::QKeyframeAnimation::startMode + Holds the repeat mode for the position values less than the first frame position. +*/ +/*! + \property Qt3DAnimation::QKeyframeAnimation::endMode + Holds the repeat mode for the position values greater than the last frame position. +*/ +/*! + \enum QKeyframeAnimation::RepeatMode + + This enumeration specifies how position values outside keyframe values are handled. + \value None The animation is not applied to the target transform. + \value Constant The edge keyframe value is used. + \value Repeat The animation is repeated. +*/ +/*! + \qmlproperty list KeyframeAnimation::framePositions + Holds the positions of the keyframes. Each position in the list specifies the position + of the corresponding keyframe. The values must be in an ascending order. Values can + be positive or negative and do not have any predefined unit. +*/ +/*! + \qmlproperty Transform KeyframeAnimation::target + Holds the target Transform the animation is applied to. +*/ +/*! + \qmlproperty EasingCurve KeyframeAnimation::easing + Holds the easing curve of the interpolator between keyframes. +*/ +/*! + \qmlproperty string KeyframeAnimation::targetName + Holds the name of the target transform. This is a convenience property making it + easier to match the target transform to the keyframe animation. The name + is usually same as the name of the parent entity of the target transform, but + does not have to be. +*/ +/*! + \qmlproperty enumeration KeyframeAnimation::startMode + Holds the repeat mode for the position values less than the first frame position. + \list + \li None + \li Constant + \li Repeat + \endlist +*/ +/*! + \qmlproperty enumeration KeyframeAnimation::endMode + Holds the repeat mode for the position values greater than the last frame position. + \list + \li None + \li Constant + \li Repeat + \endlist +*/ +/*! + \qmlproperty list KeyframeAnimation::keyframes + Holds the list of keyframes in the keyframe animation. +*/ + QKeyframeAnimationPrivate::QKeyframeAnimationPrivate() : QAbstractAnimationPrivate(QAbstractAnimation::KeyframeAnimation) , m_target(nullptr) @@ -54,6 +166,9 @@ QKeyframeAnimationPrivate::QKeyframeAnimationPrivate() } +/*! + Constructs an QKeyframeAnimation with \a parent. +*/ QKeyframeAnimation::QKeyframeAnimation(QObject *parent) : QAbstractAnimation(*new QKeyframeAnimationPrivate(), parent) { @@ -83,6 +198,9 @@ void QKeyframeAnimation::setFramePositions(const QVector &positions) setDuration(d->m_maxposition); } +/*! + Sets the \a keyframes of the animation. Old keyframes are cleared. + */ void QKeyframeAnimation::setKeyframes(const QVector &keyframes) { Q_D(QKeyframeAnimation); @@ -181,6 +299,9 @@ QVector QKeyframeAnimation::framePositions() const return d->m_framePositions; } +/*! + Returns the list of keyframes. + */ QVector QKeyframeAnimation::keyframeList() const { Q_D(const QKeyframeAnimation); @@ -251,12 +372,26 @@ void QKeyframeAnimation::setEndMode(QKeyframeAnimation::RepeatMode mode) } } +/*! + Adds new \a keyframe at the end of the animation. The QTransform can + be added to the animation multiple times. + */ void QKeyframeAnimation::addKeyframe(Qt3DCore::QTransform *keyframe) { Q_D(QKeyframeAnimation); d->m_keyframes.push_back(keyframe); } +/*! + Removes a \a keyframe from the animation. If the same QTransform + is set as keyframe multiple times, all occurrences are removed. + */ +void QKeyframeAnimation::removeKeyframe(Qt3DCore::QTransform *keyframe) +{ + Q_D(QKeyframeAnimation); + d->m_keyframes.removeAll(keyframe); +} + QString QKeyframeAnimation::targetName() const { Q_D(const QKeyframeAnimation); diff --git a/src/animation/frontend/qmorphinganimation.cpp b/src/animation/frontend/qmorphinganimation.cpp index 4ee20f9cf..4191b9eab 100644 --- a/src/animation/frontend/qmorphinganimation.cpp +++ b/src/animation/frontend/qmorphinganimation.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2017 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt3D module of the Qt Toolkit. @@ -41,6 +41,129 @@ QT_BEGIN_NAMESPACE namespace Qt3DAnimation { +/*! + \class Qt3DAnimation::QMorphingAnimation + \brief A class implementing blend-shape morphing animation + \inmodule Qt3DAnimation + \since 5.9 + \inherits Qt3DAnimation::QAbstractAnimation + + A Qt3DAnimation::QMorphingAnimation class implements blend-shape morphing animation + to a target \l {Qt3DRender::QGeometryRenderer}{QGeometryRenderer}. The QMorphingAnimation + sets the correct \l {Qt3DRender::QAttribute}{QAttributes} from the + \l {Qt3DAnimation::QMorphTarget}{morph targets} to the target + \l {Qt3DRender::QGeometryRenderer::geometry} {QGeometryRenderer::geometry} and calculates + interpolator for the current position. The actual blending between the attributes must + be implemented in the material. Qt3DAnimation::QMorphPhongMaterial implements material + with morphing support for phong lighting model. The blending happens between + 2 attributes - 'base' and 'target'. The names for the base and target attributes are taken from + the morph target names, where the base attribute retains the name it already has and the + target attribute name gets 'Target' appended to the name. The interpolator can be + set as a \l {Qt3DRender::QParameter}{QParameter} to the used material. + All morph targets in the animation should contain the attributes with same names as those + in the base geometry. + +*/ +/*! + \qmltype MorphingAnimation + \brief A type implementing blend-shape morphing animation + \inqmlmodule Qt3D.Animation + \since 5.9 + \inherits AbstractAnimation + \instantiates Qt3DAnimation::QMorphingAnimation + + A MorphingAnimation type implements blend-shape morphing animation + to a target \l GeometryRenderer. The MorphingAnimation sets the correct + \l {Attribute}{Attributes} from the morph targets to the target + \l {Qt3D.Render::GeometryRenderer::geometry}{GeometryRenderer::geometry} and calculates + interpolator for the current position. The actual blending between the attributes must + be implemented in the material. MorphPhongMaterial implements material + with morphing support for phong lighting model. The blending happens between + 2 attributes - 'base' and 'target'. The names for the base and target attributes are taken from + the morph target names, where the base attribute retains the name it already has and the + target attribute name gets 'Target' appended to the name. All morph targets in the animation + should contain the attributes with same names as those in the base geometry. + +*/ +/*! + \property Qt3DAnimation::QMorphingAnimation::targetPositions + Holds the position values of the morph target. Each position in the list specifies the position + of the corresponding morph target with the same index. The values must be in an ascending order. + Values can be positive or negative and do not have any predefined unit. +*/ +/*! + \property Qt3DAnimation::QMorphingAnimation::interpolator + Holds the interpolator between base and target attributes. + \readonly +*/ +/*! + \property Qt3DAnimation::QMorphingAnimation::target + Holds the target QGeometryRenderer the morphing animation is applied to. +*/ +/*! + \property Qt3DAnimation::QMorphingAnimation::targetName + Holds the name of the target geometry. This is a convenience property making it + easier to match the target geometry to the morphing animation. The name + is usually same as the name of the parent entity of the target QGeometryRenderer, but + does not have to be. +*/ +/*! + \property Qt3DAnimation::QMorphingAnimation::method + Holds the morphing method. The default is Relative. +*/ +/*! + \property Qt3DAnimation::QMorphingAnimation::easing + Holds the easing curve of the interpolator between morph targets. +*/ +/*! + \enum Qt3DAnimation::QMorphingAnimation::Method + + This enumeration specifies the morphing method. + \value Normalized The blending should use the normalized formula; + V' = Vbase * (1.0 - sum(Wi)) + sum[Vi * Wi] + \value Relative The blending should use the relative formula; + V' = Vbase + sum[Vi * Wi] +*/ + +/*! + \qmlproperty list MorphingAnimation::targetPositions + Holds the position values of the morph target. Each position in the list specifies the position + of the corresponding morph target with the same index. The values must be in an ascending order. + Values can be positive or negative and do not have any predefined unit. +*/ +/*! + \qmlproperty real MorphingAnimation::interpolator + Holds the interpolator between base and target attributes. + \readonly +*/ +/*! + \qmlproperty GeometryRenderer MorphingAnimation::target + Holds the target GeometryRenderer the morphing animation is applied to. +*/ +/*! + \qmlproperty string MorphingAnimation::targetName + Holds the name of the target geometry. This is a convenience property making it + easier to match the target geometry to the morphing animation. The name + is usually same as the name of the parent entity of the target GeometryRenderer, but + does not have to be. +*/ +/*! + \qmlproperty enumeration MorphingAnimation::method + Holds the morphing method. The default is Relative. + \list + \li Normalized + \li Relative + \endlist +*/ +/*! + \qmlproperty EasingCurve MorphingAnimation::easing + Holds the easing curve of the interpolator between morph targets. +*/ +/*! + \qmlproperty list MorphingAnimation::morphTargets + Holds the list of morph targets in the morphing animation. +*/ + QMorphingAnimationPrivate::QMorphingAnimationPrivate() : QAbstractAnimationPrivate(QAbstractAnimation::MorphingAnimation) , m_minposition(0.0f) @@ -148,6 +271,9 @@ void QMorphingAnimationPrivate::setTargetInterpolated(int morphTarget) m_currentTarget = target; } +/*! + Construct a new QMorphingAnimation with \a parent. + */ QMorphingAnimation::QMorphingAnimation(QObject *parent) : QAbstractAnimation(*new QMorphingAnimationPrivate, parent) { @@ -192,6 +318,9 @@ QEasingCurve QMorphingAnimation::easing() const return d->m_easing; } +/*! + Set morph \a targets to animation. Old targets are cleared. +*/ void QMorphingAnimation::setMorphTargets(const QVector &targets) { Q_D(QMorphingAnimation); @@ -200,6 +329,9 @@ void QMorphingAnimation::setMorphTargets(const QVectorm_position = -1.0f; } +/*! + Add new morph \a target at the end of the animation. +*/ void QMorphingAnimation::addMorphTarget(Qt3DAnimation::QMorphTarget *target) { Q_D(QMorphingAnimation); @@ -211,6 +343,9 @@ void QMorphingAnimation::addMorphTarget(Qt3DAnimation::QMorphTarget *target) } } +/*! + Remove morph \a target from the animation. +*/ void QMorphingAnimation::removeMorphTarget(Qt3DAnimation::QMorphTarget *target) { Q_D(QMorphingAnimation); @@ -246,6 +381,9 @@ void QMorphingAnimation::setTarget(Qt3DRender::QGeometryRenderer *target) } } +/*! + Sets morph \a weights at \a positionIndex. +*/ void QMorphingAnimation::setWeights(int positionIndex, const QVector &weights) { Q_D(QMorphingAnimation); @@ -257,12 +395,18 @@ void QMorphingAnimation::setWeights(int positionIndex, const QVector &wei d->m_position = -1.0f; } +/*! + Return morph weights at \a positionIndex. +*/ QVector QMorphingAnimation::getWeights(int positionIndex) { Q_D(QMorphingAnimation); return *d->m_weights[positionIndex]; } +/*! + Return morph target list. +*/ QVector QMorphingAnimation::morphTargetList() { Q_D(QMorphingAnimation); diff --git a/src/animation/frontend/qmorphtarget.cpp b/src/animation/frontend/qmorphtarget.cpp index 1040e33ff..e16dd8698 100644 --- a/src/animation/frontend/qmorphtarget.cpp +++ b/src/animation/frontend/qmorphtarget.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2017 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt3D module of the Qt Toolkit. @@ -41,6 +41,55 @@ QT_BEGIN_NAMESPACE namespace Qt3DAnimation { +/*! + \class Qt3DAnimation::QMorphTarget + \brief A class providing morph targets to blend-shape animation + \inmodule Qt3DAnimation + \since 5.9 + \inherits QObject + + A Qt3DAnimation::QMorphTarget class is a convenience class, which provides a list + of \l {Qt3DRender::QAttribute} {QAttributes}, which the QMorphingAnimation uses + to animate geometry. A QMorphTarget can also be created based on existing + \l Qt3DRender::QGeometry. + +*/ +/*! + \qmltype MorphTarget + \brief A type providing morph targets to blend-shape animation + \inqmlmodule Qt3D.Animation + \since 5.9 + \inherits QtObject + \instantiates Qt3DAnimation::QMorphTarget + + A MorphTarget type is a convenience type, which provides a list + of \l {Qt3D.Render::Attribute} {Attributes}, which the MorphingAnimation uses + to animate geometry. A MorphTarget can also be created based on existing + \l {Qt3D.Render::Geometry}{Geometry}. + +*/ + +/*! + \property Qt3DAnimation::QMorphTarget::attributeNames + Holds a list of attribute names contained in the morph target. + \readonly +*/ + +/*! + \qmlproperty list MorphTarget::attributeNames + Holds a list of attribute names contained in the morph target. + \readonly +*/ +/*! + \qmlproperty list MorphTarget::attributes + Holds the list of attributes in the morph target. +*/ +/*! + \qmlmethod MorphTarget Qt3D.Animation::MorphTarget::fromGeometry(geometry, stringList) + Returns a morph target based on the attributes defined by the given stringList from + the given geometry. +*/ + QMorphTargetPrivate::QMorphTargetPrivate() : QObjectPrivate() { @@ -54,12 +103,18 @@ void QMorphTargetPrivate::updateAttributeNames() m_attributeNames.push_back(attr->name()); } +/*! + Constructs a QMorphTarget with given \a parent. +*/ QMorphTarget::QMorphTarget(QObject *parent) : QObject(*new QMorphTargetPrivate, parent) { } +/*! + Returns a list of attributes contained in the morph target. +*/ QVector QMorphTarget::attributeList() const { Q_D(const QMorphTarget); @@ -72,6 +127,9 @@ QStringList QMorphTarget::attributeNames() const return d->m_attributeNames; } +/*! + Sets \a attributes to the morph target. Old attributes are cleared. +*/ void QMorphTarget::setAttributes(const QVector &attributes) { Q_D(QMorphTarget); @@ -83,6 +141,10 @@ void QMorphTarget::setAttributes(const QVector &attrib emit attributeNamesChanged(d->m_attributeNames); } +/*! + Adds an \a attribute the morph target. An attribute with the same + name must not have been added previously to the morph target. +*/ void QMorphTarget::addAttribute(Qt3DRender::QAttribute *attribute) { Q_D(QMorphTarget); @@ -95,6 +157,9 @@ void QMorphTarget::addAttribute(Qt3DRender::QAttribute *attribute) emit attributeNamesChanged(d->m_attributeNames); } +/*! + Removes an \a attribute from the morph target. +*/ void QMorphTarget::removeAttribute(Qt3DRender::QAttribute *attribute) { Q_D(QMorphTarget); @@ -105,6 +170,9 @@ void QMorphTarget::removeAttribute(Qt3DRender::QAttribute *attribute) } } +/*! + Returns a morph target based on the \a attributes in the given \a geometry. +*/ QMorphTarget *QMorphTarget::fromGeometry(Qt3DRender::QGeometry *geometry, const QStringList &attributes) { QMorphTarget *target = new QMorphTarget(); diff --git a/src/animation/frontend/qvertexblendanimation.cpp b/src/animation/frontend/qvertexblendanimation.cpp index 8eb0e5751..efc36e45c 100644 --- a/src/animation/frontend/qvertexblendanimation.cpp +++ b/src/animation/frontend/qvertexblendanimation.cpp @@ -42,6 +42,100 @@ QT_BEGIN_NAMESPACE namespace Qt3DAnimation { +/*! + \class Qt3DAnimation::QVertexBlendAnimation + \brief A class implementing vertex-blend morphing animation + \inmodule Qt3DAnimation + \since 5.9 + \inherits Qt3DAnimation::QAbstractAnimation + + A Qt3DAnimation::QVertexBlendAnimation class implements vertex-blend morphing animation + to a target \l {Qt3DRender::QGeometryRenderer}{QGeometryRenderer}. The QVertexBlendAnimation + sets the correct \l {Qt3DRender::QAttribute}{QAttributes} from the + \l {Qt3DAnimation::QMorphTarget}{morph targets} to the target + \l {Qt3DRender::QGeometryRenderer::geometry} {QGeometryRenderer::geometry} and calculates + interpolator for the current position. Unlike with QMorphingAnimation, where the blending is + controller with blend weights, the blending occurs between sequential morph targets. + The actual blending between the attributes must be implemented in the material. + Qt3DAnimation::QMorphPhongMaterial implements material with morphing support for phong + lighting model. The blending happens between 2 attributes - 'base' and 'target'. + The names for the base and target attributes are taken from the morph target names, + where the base attribute retains the name it already has and the target attribute name + gets 'Target' appended to the name. The interpolator can be set as + a \l {Qt3DRender::QParameter}{QParameter} to the used material. + All morph targets in the animation should contain the attributes with same names as those + in the base geometry. + +*/ +/*! + \qmltype VertexBlendAnimation + \brief A type implementing vertex-blend morphing animation + \inqmlmodule Qt3D.Animation + \since 5.9 + \inherits AbstractAnimation + \instantiates Qt3DAnimation::QVertexBlendAnimation + + A VertexBlendAnimation type implements vertex-blend morphing animation + to a target \l GeometryRenderer. The VertexBlendAnimation sets the correct + \l {Attribute}{Attributes} from the morph targets to the target + \l {Qt3D.Render::GeometryRenderer::geometry}{GeometryRenderer::geometry} and calculates + interpolator for the current position. Unlike with MorphingAnimation, where the blending is + controller with blend weights, the blending occurs between sequential morph targets. + The actual blending between the attributes must be implemented in the material. + MorphPhongMaterial implements material with morphing support for phong lighting model. + The blending happens between 2 attributes - 'base' and 'target'. The names for the base + and target attributes are taken from the morph target names, where the base attribute + retains the name it already has and the target attribute name gets 'Target' appended to + the name. All morph targets in the animation should contain the attributes with same names + as those in the base geometry. + +*/ +/*! + \property Qt3DAnimation::QVertexBlendAnimation::targetPositions + Holds the position values of the morph target. Each position in the list specifies the position + of the corresponding morph target with the same index. The values must be in an ascending order. + Values can be positive or negative and do not have any predefined unit. +*/ +/*! + \property Qt3DAnimation::QVertexBlendAnimation::interpolator + Holds the interpolator between base and target attributes. + \readonly +*/ +/*! + \property Qt3DAnimation::QVertexBlendAnimation::target + Holds the target QGeometryRenderer the morphing animation is applied to. +*/ +/*! + \property Qt3DAnimation::QVertexBlendAnimation::targetName + Holds the name of the target geometry. This is a convenience property making it + easier to match the target geometry to the morphing animation. The name + is usually same as the name of the parent entity of the target QGeometryRenderer, but + does not have to be. +*/ + +/*! + \qmlproperty list VertexBlendAnimation::targetPositions + Holds the position values of the morph target. Each position in the list specifies the position + of the corresponding morph target with the same index. The values must be in an ascending order. + Values can be positive or negative and do not have any predefined unit. +*/ +/*! + \qmlproperty real VertexBlendAnimation::interpolator + Holds the interpolator between base and target attributes. + \readonly +*/ +/*! + \qmlproperty VertexBlendAnimation::target + Holds the target GeometryRenderer the morphing animation is applied to. +*/ +/*! + \qmlproperty string VertexBlendAnimation::targetName + Holds the name of the target geometry. This is a convenience property making it + easier to match the target geometry to the morphing animation. The name + is usually same as the name of the parent entity of the target GeometryRenderer, but + does not have to be. +*/ + QVertexBlendAnimationPrivate::QVertexBlendAnimationPrivate() : QAbstractAnimationPrivate(QAbstractAnimation::VertexBlendAnimation) , m_interpolator(0.0f) @@ -130,6 +224,9 @@ void QVertexBlendAnimationPrivate::updateAnimation(float position) } } +/*! + Construct a new QVertexBlendAnimation with \a parent. + */ QVertexBlendAnimation::QVertexBlendAnimation(QObject *parent) : QAbstractAnimation(*new QVertexBlendAnimationPrivate, parent) { @@ -162,12 +259,18 @@ QString QVertexBlendAnimation::targetName() const return d->m_targetName; } +/*! + Set morph \a targets to animation. Old targets are cleared. +*/ void QVertexBlendAnimation::setMorphTargets(const QVector &targets) { Q_D(QVertexBlendAnimation); d->m_morphTargets = targets; } +/*! + Add new morph \a target at the end of the animation. +*/ void QVertexBlendAnimation::addMorphTarget(Qt3DAnimation::QMorphTarget *target) { Q_D(QVertexBlendAnimation); @@ -175,6 +278,9 @@ void QVertexBlendAnimation::addMorphTarget(Qt3DAnimation::QMorphTarget *target) d->m_morphTargets.push_back(target); } +/*! + Remove morph \a target from the animation. +*/ void QVertexBlendAnimation::removeMorphTarget(Qt3DAnimation::QMorphTarget *target) { Q_D(QVertexBlendAnimation); @@ -200,6 +306,9 @@ void QVertexBlendAnimation::setTarget(Qt3DRender::QGeometryRenderer *target) } } +/*! + Return morph target list. +*/ QVector QVertexBlendAnimation::morphTargetList() { Q_D(QVertexBlendAnimation); -- cgit v1.2.3 From 6a5838c8e819c462404cf74c98c5e433be26d1b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Wed, 8 Feb 2017 13:10:48 +0200 Subject: Enable animations doc generation Change-Id: Ia7e725b34b7a180dfbc920e7a65db70dac9ddd66 Reviewed-by: Sean Harmer --- src/doc/qt3d.qdocconf | 9 ++-- src/doc/src/qt3d-index.qdoc | 5 +- src/doc/src/qt3d-module.qdoc | 8 +++ src/doc/src/qt3danimation-module.qdoc | 96 +++++++++++++++++++++++++++++++++++ 4 files changed, 113 insertions(+), 5 deletions(-) create mode 100644 src/doc/src/qt3danimation-module.qdoc diff --git a/src/doc/qt3d.qdocconf b/src/doc/qt3d.qdocconf index 623a2c5d5..941c9e3f6 100644 --- a/src/doc/qt3d.qdocconf +++ b/src/doc/qt3d.qdocconf @@ -47,7 +47,8 @@ headerdirs += . \ ../plugins \ ../quick3d/quick3d \ ../input \ - ../extras + ../extras \ + ../animation # Exclude private header files from the documentation build excludefiles += "*_p.h" @@ -59,7 +60,8 @@ sourcedirs += . \ ../plugins \ ../quick3d/quick3d \ ../input \ - ../extras + ../extras \ + ../animation exampledirs += ../../examples/qt3d \ snippets @@ -83,7 +85,8 @@ Cpp.ignoretokens += QT3DINPUTSHARED_EXPORT \ QT3DRENDERSHARED_EXPORT \ QT3DRENDERSHARED_PRIVATE_EXPORT \ QT3DQUICKSHARED_PRIVATE_EXPORT \ - QT3DEXTRASSHARED_EXPORT + QT3DEXTRASSHARED_EXPORT \ + QT3DANIMATIONSHARED_EXPORT Cpp.ignoredirectives += Q_DECLARE_LOGGING_CATEGORY diff --git a/src/doc/src/qt3d-index.qdoc b/src/doc/src/qt3d-index.qdoc index f14909cec..2031fcfdc 100644 --- a/src/doc/src/qt3d-index.qdoc +++ b/src/doc/src/qt3d-index.qdoc @@ -61,7 +61,7 @@ \l qmake \c .pro file: \badcode - QT += 3dcore 3drender 3dinput 3dlogic 3dextras + QT += 3dcore 3drender 3dinput 3dlogic 3dextras 3danimation \endcode To include the definitions of the modules' classes, use the following @@ -73,12 +73,13 @@ #include #include #include + #include \endcode A Qt Quick application requires also additional dependencies: \badcode - QT += 3dcore 3drender 3dinput 3dlogic 3dextras qml quick 3dquick + QT += 3dcore 3drender 3dinput 3dlogic 3dextras qml quick 3dquick 3danimation \endcode \section1 Overview diff --git a/src/doc/src/qt3d-module.qdoc b/src/doc/src/qt3d-module.qdoc index c82c528f1..0c3d14b56 100644 --- a/src/doc/src/qt3d-module.qdoc +++ b/src/doc/src/qt3d-module.qdoc @@ -77,6 +77,9 @@ \section2 Qt 3D Extras Module \generatelist {classesbymodule Qt3DExtras} + + \section2 Qt 3D Animation Module + \generatelist {classesbymodule Qt3DAnimation} */ /*! @@ -111,6 +114,7 @@ import Qt3D.Input 2.0 import Qt3D.Logic 2.0 import Qt3D.Extras 2.0 + import Qt3D.Animation 2.0 \endcode \section1 QML Types @@ -131,4 +135,8 @@ \section2 Qt 3D Extras Module \generatelist {qmltypesbymodule Qt3D.Extras} \noautolist + + \section2 Qt 3D Animation Module + \generatelist {qmltypesbymodule Qt3D.Animation} + \noautolist */ diff --git a/src/doc/src/qt3danimation-module.qdoc b/src/doc/src/qt3danimation-module.qdoc new file mode 100644 index 000000000..294edb0e7 --- /dev/null +++ b/src/doc/src/qt3danimation-module.qdoc @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** 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 Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: https://www.gnu.org/licenses/fdl-1.3.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \module Qt3DAnimation + \title Qt 3D Animation C++ Classes + + \brief The Qt 3D Animation modules provides a set of prebuilt elements to help + you get started with Qt 3D. + + This module is still in tech preview. This means it is unstable, likely to + change and provided as a convenience only. + + \ingroup modules + \ingroup qt3d-modules + \qtvariable 3danimation + + \code + #include + \endcode + + To link against the corresponding C++ library, add the following to your qmake project file: + + \badcode + QT += 3danimation + \endcode + + Classes, types, and functions are declared under the \l [Qt3DAnimation]{Qt3DAnimation} namespace. + + \section1 Overview + + \section2 Animations + + \list + \li Qt3DAnimation::QKeyframeAnimation + \endlist + + \section2 Clip animations + + \list + \li Qt3DAnimation::QAnimationClip + \endlist + + \section1 Reference + \list + \li \l {Qt 3D Animation C++ Classes} + \li \l {Qt 3D Examples} + \endlist + */ + +/*! + \namespace Qt3DAnimation + \inmodule Qt3DAnimation + \ingroup qt3d-namespaces + + \brief Contains classes from the Qt3DAnimation module. +*/ + +/*! + \qmlmodule Qt3D.Animation 2.0 + \title Qt 3D Qt3DAnimation QML Types + \ingroup qmlmodules + \ingroup qt3d-qmlmodules + + \brief Provides Qt 3D QML types for the animation module. + + To import and use the module's QML types, use the following statement: + + \badcode + import Qt3D.Animation 2.0 + \endcode +*/ -- cgit v1.2.3 From 88b24df43916442785238966d5a3c3eb77b2d097 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Mon, 13 Feb 2017 12:10:32 +0200 Subject: Fix crash when running 3d-text example Change the text geometry to use 32-bit index buffer. qTriangulate is using them, which causes the index buffer copy to cause a mess. Also long texts could easily cause vertex buffers with more than 65536 vertices to be generated. Also add check for empty outlines. Task-number: QTBUG-58833 Change-Id: I5ad84081000e6b178a81d6d107aa013f29a95ac5 Reviewed-by: Sean Harmer --- src/extras/3dtext/qtext3dgeometry.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/extras/3dtext/qtext3dgeometry.cpp b/src/extras/3dtext/qtext3dgeometry.cpp index 529c93b79..49db6e4a6 100644 --- a/src/extras/3dtext/qtext3dgeometry.cpp +++ b/src/extras/3dtext/qtext3dgeometry.cpp @@ -65,7 +65,7 @@ namespace Qt3DExtras { namespace { -using IndexType = unsigned short; +using IndexType = unsigned int; struct TriangulationData { struct Outline { @@ -190,7 +190,7 @@ void QText3DGeometryPrivate::init() m_normalAttribute->setCount(0); m_indexAttribute->setAttributeType(Qt3DRender::QAttribute::IndexAttribute); - m_indexAttribute->setVertexBaseType(Qt3DRender::QAttribute::UnsignedShort); + m_indexAttribute->setVertexBaseType(Qt3DRender::QAttribute::UnsignedInt); m_indexAttribute->setBuffer(m_indexBuffer); m_indexAttribute->setCount(0); @@ -328,6 +328,9 @@ void QText3DGeometryPrivate::update() const int end = data.outlines[i].end; const int verticesIndexBegin = verticesIndex; + if (begin == end) + continue; + QVector3D prevNormal = QVector3D::crossProduct( vertices[data.outlineIndices[end - 1] + numVertices].position - vertices[data.outlineIndices[end - 1]].position, vertices[data.outlineIndices[begin]].position - vertices[data.outlineIndices[end - 1]].position).normalized(); -- cgit v1.2.3 From a6297cdbc6025cd676691d67e6c8e34ebbab5c29 Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Sun, 12 Feb 2017 16:10:12 +0000 Subject: Initialize member in DependencyHandler Change-Id: I2f55f5e0ddc35a6e992b13f6729ae34199877a45 Coverity-Id: 154601 Reviewed-by: Paul Lemire --- src/core/jobs/dependencyhandler.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/jobs/dependencyhandler.cpp b/src/core/jobs/dependencyhandler.cpp index dcea66a62..3ccbbf059 100644 --- a/src/core/jobs/dependencyhandler.cpp +++ b/src/core/jobs/dependencyhandler.cpp @@ -104,6 +104,7 @@ namespace { } DependencyHandler::DependencyHandler() + : m_mutex() { } -- cgit v1.2.3 From c668bde4982ff7340de4e882aa45cf1db93bea98 Mon Sep 17 00:00:00 2001 From: Nico Vertriest Date: Tue, 24 Jan 2017 16:20:11 +0100 Subject: Doc: added doc for parameters QPaintedTextureImage Undocumented parameter h,size,w,rect in Qt3DRender::QPaintedTextureImage::setHeight() Change-Id: I7108b71ac84928b37db4f01218b83e908860e200 Reviewed-by: Venugopal Shivashankar --- src/render/texture/qpaintedtextureimage.cpp | 38 ++++++++++------------------- 1 file changed, 13 insertions(+), 25 deletions(-) diff --git a/src/render/texture/qpaintedtextureimage.cpp b/src/render/texture/qpaintedtextureimage.cpp index 9ae43378a..52c5706d8 100644 --- a/src/render/texture/qpaintedtextureimage.cpp +++ b/src/render/texture/qpaintedtextureimage.cpp @@ -104,14 +104,9 @@ QPaintedTextureImage::~QPaintedTextureImage() /*! \property QPaintedTextureImage::width - Holds the width of the texture image - */ - -/*! - \property QPaintedTextureImage::width - - \return the width of the texture image. - */ + This property holds the width of the texture image. + The width must be greater than or equal to 1. +*/ int QPaintedTextureImage::width() const { Q_D(const QPaintedTextureImage); @@ -121,14 +116,9 @@ int QPaintedTextureImage::width() const /*! \property QPaintedTextureImage::height - Holds the height of the texture image - */ - -/*! - \property QPaintedTextureImage::height - - \return the height of the texture image. - */ + This property holds the height of the texture image. + The height must be greater than or equal to 1. +*/ int QPaintedTextureImage::height() const { Q_D(const QPaintedTextureImage); @@ -138,14 +128,11 @@ int QPaintedTextureImage::height() const /*! \property QPaintedTextureImage::size - Holds the width and height of the texture image - */ + This property holds the size of the texture image. -/*! - \property QPaintedTextureImage::size + \sa height, width - \return the size of the texture image. - */ +*/ QSize QPaintedTextureImage::size() const { Q_D(const QPaintedTextureImage); @@ -206,9 +193,10 @@ void QPaintedTextureImage::setSize(QSize size) } /*! - Will trigger an update of the texture image, meaning the paint() method will - be invoked. - */ + Schedules the painted texture's paint() function to be called, + which in turn uploads the new image to the GPU. + Parameter \a rect is currently unused. +*/ void QPaintedTextureImage::update(const QRect &rect) { Q_UNUSED(rect) -- cgit v1.2.3 From 9dd10069ad84a7d51bb890d78f7f5e1e79b94906 Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Wed, 15 Feb 2017 10:19:23 +0000 Subject: Remove QConductedClipAnimator and defer to later MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Too much to fix up for 5.9 so remove and defer for 5.10. Task-number: QTBUG-58905 Change-Id: Ie5b4f172e57beac12933fa0db5f102b4dc9346fc Reviewed-by: Antti Määttä --- src/animation/backend/backend.pri | 2 - src/animation/backend/conductedclipanimator.cpp | 80 ------------------ src/animation/backend/conductedclipanimator_p.h | 79 ----------------- src/animation/backend/handle_types_p.h | 2 - src/animation/backend/handler.cpp | 1 - src/animation/backend/handler_p.h | 4 - src/animation/backend/managers_p.h | 12 --- src/animation/frontend/frontend.pri | 3 - src/animation/frontend/qanimationaspect.cpp | 4 - src/animation/frontend/qconductedclipanimator.cpp | 76 ----------------- src/animation/frontend/qconductedclipanimator.h | 76 ----------------- src/animation/frontend/qconductedclipanimator_p.h | 80 ------------------ .../animation/qt3dquick3danimationplugin.cpp | 2 - tests/auto/animation/animation.pro | 2 - .../conductedclipanimator.pro | 12 --- .../tst_conductedclipanimator.cpp | 98 ---------------------- .../qconductedclipanimator.pro | 12 --- .../tst_qconductedclipanimator.cpp | 64 -------------- 18 files changed, 609 deletions(-) delete mode 100644 src/animation/backend/conductedclipanimator.cpp delete mode 100644 src/animation/backend/conductedclipanimator_p.h delete mode 100644 src/animation/frontend/qconductedclipanimator.cpp delete mode 100644 src/animation/frontend/qconductedclipanimator.h delete mode 100644 src/animation/frontend/qconductedclipanimator_p.h delete mode 100644 tests/auto/animation/conductedclipanimator/conductedclipanimator.pro delete mode 100644 tests/auto/animation/conductedclipanimator/tst_conductedclipanimator.cpp delete mode 100644 tests/auto/animation/qconductedclipanimator/qconductedclipanimator.pro delete mode 100644 tests/auto/animation/qconductedclipanimator/tst_qconductedclipanimator.cpp diff --git a/src/animation/backend/backend.pri b/src/animation/backend/backend.pri index cc405fd79..7eb8913c8 100644 --- a/src/animation/backend/backend.pri +++ b/src/animation/backend/backend.pri @@ -13,7 +13,6 @@ HEADERS += \ $$PWD/functionrangefinder_p.h \ $$PWD/clipanimator_p.h \ $$PWD/blendedclipanimator_p.h \ - $$PWD/conductedclipanimator_p.h \ $$PWD/backendnode_p.h \ $$PWD/loadanimationclipjob_p.h \ $$PWD/channelmapping_p.h \ @@ -36,7 +35,6 @@ SOURCES += \ $$PWD/functionrangefinder.cpp \ $$PWD/clipanimator.cpp \ $$PWD/blendedclipanimator.cpp \ - $$PWD/conductedclipanimator.cpp \ $$PWD/backendnode.cpp \ $$PWD/loadanimationclipjob.cpp \ $$PWD/channelmapping.cpp \ diff --git a/src/animation/backend/conductedclipanimator.cpp b/src/animation/backend/conductedclipanimator.cpp deleted file mode 100644 index 32db1b7ea..000000000 --- a/src/animation/backend/conductedclipanimator.cpp +++ /dev/null @@ -1,80 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). -** Contact: http://www.qt-project.org/legal -** -** 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 "conductedclipanimator_p.h" -#include -#include -#include - -QT_BEGIN_NAMESPACE - -namespace Qt3DAnimation { -namespace Animation { - -ConductedClipAnimator::ConductedClipAnimator() - : BackendNode(ReadOnly) -{ -} - -void ConductedClipAnimator::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) -{ - const auto typedChange = qSharedPointerCast>(change); - const auto &data = typedChange->data; -} - -void ConductedClipAnimator::cleanup() -{ - setEnabled(false); - m_handler = nullptr; -} - -void ConductedClipAnimator::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) -{ - switch (e->type()) { - case Qt3DCore::PropertyUpdated: { - break; - } - - default: - break; - } - QBackendNode::sceneChangeEvent(e); -} - -} // namespace Animation -} // namespace Qt3DAnimation - -QT_END_NAMESPACE diff --git a/src/animation/backend/conductedclipanimator_p.h b/src/animation/backend/conductedclipanimator_p.h deleted file mode 100644 index d4534447e..000000000 --- a/src/animation/backend/conductedclipanimator_p.h +++ /dev/null @@ -1,79 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). -** Contact: http://www.qt-project.org/legal -** -** 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$ -** -****************************************************************************/ - -#ifndef QT3DANIMATION_ANIMATION_CONDUCTEDCLIPANIMATOR_P_H -#define QT3DANIMATION_ANIMATION_CONDUCTEDCLIPANIMATOR_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of other Qt classes. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include - -QT_BEGIN_NAMESPACE - -namespace Qt3DAnimation { -namespace Animation { - -class Handler; - -class Q_AUTOTEST_EXPORT ConductedClipAnimator : public BackendNode -{ -public: - ConductedClipAnimator(); - - void cleanup(); - - void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_OVERRIDE; - -private: - void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL; -}; - -} // namespace Animation -} // namespace Qt3DAnimation - - -QT_END_NAMESPACE - -#endif // QT3DANIMATION_ANIMATION_CONDUCTEDCLIPANIMATOR_P_H diff --git a/src/animation/backend/handle_types_p.h b/src/animation/backend/handle_types_p.h index f2c6774d2..f6f77eb20 100644 --- a/src/animation/backend/handle_types_p.h +++ b/src/animation/backend/handle_types_p.h @@ -61,14 +61,12 @@ namespace Animation { class AnimationClip; class ClipAnimator; class BlendedClipAnimator; -class ConductedClipAnimator; class ChannelMapping; class ChannelMapper; typedef Qt3DCore::QHandle HAnimationClip; typedef Qt3DCore::QHandle HClipAnimator; typedef Qt3DCore::QHandle HBlendedClipAnimator; -typedef Qt3DCore::QHandle HConductedClipAnimator; typedef Qt3DCore::QHandle HChannelMapping; typedef Qt3DCore::QHandle HChannelMapper; diff --git a/src/animation/backend/handler.cpp b/src/animation/backend/handler.cpp index e17227431..87146aa63 100644 --- a/src/animation/backend/handler.cpp +++ b/src/animation/backend/handler.cpp @@ -54,7 +54,6 @@ Handler::Handler() : m_animationClipManager(new AnimationClipManager) , m_clipAnimatorManager(new ClipAnimatorManager) , m_blendedClipAnimatorManager(new BlendedClipAnimatorManager) - , m_conductedClipAnimatorManager(new ConductedClipAnimatorManager) , m_channelMappingManager(new ChannelMappingManager) , m_channelMapperManager(new ChannelMapperManager) , m_clipBlendNodeManager(new ClipBlendNodeManager) diff --git a/src/animation/backend/handler_p.h b/src/animation/backend/handler_p.h index 25286fb45..91640c477 100644 --- a/src/animation/backend/handler_p.h +++ b/src/animation/backend/handler_p.h @@ -69,8 +69,6 @@ class ClipAnimator; class ClipAnimatorManager; class BlendedClipAnimator; class BlendedClipAnimatorManager; -class ConductedClipAnimator; -class ConductedClipAnimatorManager; class ChannelMapping; class ChannelMappingManager; class ChannelMapper; @@ -112,7 +110,6 @@ public: AnimationClipManager *animationClipManager() const Q_DECL_NOTHROW { return m_animationClipManager.data(); } ClipAnimatorManager *clipAnimatorManager() const Q_DECL_NOTHROW { return m_clipAnimatorManager.data(); } BlendedClipAnimatorManager *blendedClipAnimatorManager() const Q_DECL_NOTHROW { return m_blendedClipAnimatorManager.data(); } - ConductedClipAnimatorManager *conductedClipAnimatorManager() const Q_DECL_NOTHROW { return m_conductedClipAnimatorManager.data(); } ChannelMappingManager *channelMappingManager() const Q_DECL_NOTHROW { return m_channelMappingManager.data(); } ChannelMapperManager *channelMapperManager() const Q_DECL_NOTHROW { return m_channelMapperManager.data(); } ClipBlendNodeManager *clipBlendNodeManager() const Q_DECL_NOTHROW { return m_clipBlendNodeManager.data(); } @@ -123,7 +120,6 @@ private: QScopedPointer m_animationClipManager; QScopedPointer m_clipAnimatorManager; QScopedPointer m_blendedClipAnimatorManager; - QScopedPointer m_conductedClipAnimatorManager; QScopedPointer m_channelMappingManager; QScopedPointer m_channelMapperManager; QScopedPointer m_clipBlendNodeManager; diff --git a/src/animation/backend/managers_p.h b/src/animation/backend/managers_p.h index 42484921f..3b811121a 100644 --- a/src/animation/backend/managers_p.h +++ b/src/animation/backend/managers_p.h @@ -56,7 +56,6 @@ #include #include #include -#include #include #include #include @@ -98,16 +97,6 @@ public: BlendedClipAnimatorManager() {} }; -class ConductedClipAnimatorManager : public Qt3DCore::QResourceManager< - ConductedClipAnimator, - Qt3DCore::QNodeId, - 8, - Qt3DCore::ArrayAllocatingPolicy> -{ -public: - ConductedClipAnimatorManager() {} -}; - class ChannelMappingManager : public Qt3DCore::QResourceManager< ChannelMapping, Qt3DCore::QNodeId, @@ -149,7 +138,6 @@ private: Q_DECLARE_RESOURCE_INFO(Qt3DAnimation::Animation::AnimationClip, Q_REQUIRES_CLEANUP) Q_DECLARE_RESOURCE_INFO(Qt3DAnimation::Animation::ClipAnimator, Q_REQUIRES_CLEANUP) Q_DECLARE_RESOURCE_INFO(Qt3DAnimation::Animation::BlendedClipAnimator, Q_REQUIRES_CLEANUP) -Q_DECLARE_RESOURCE_INFO(Qt3DAnimation::Animation::ConductedClipAnimator, Q_REQUIRES_CLEANUP) Q_DECLARE_RESOURCE_INFO(Qt3DAnimation::Animation::ChannelMapping, Q_REQUIRES_CLEANUP) Q_DECLARE_RESOURCE_INFO(Qt3DAnimation::Animation::ChannelMapper, Q_REQUIRES_CLEANUP) diff --git a/src/animation/frontend/frontend.pri b/src/animation/frontend/frontend.pri index 0feeb2e42..c6aec043f 100644 --- a/src/animation/frontend/frontend.pri +++ b/src/animation/frontend/frontend.pri @@ -9,8 +9,6 @@ HEADERS += \ $$PWD/qclipanimator_p.h \ $$PWD/qblendedclipanimator.h \ $$PWD/qblendedclipanimator_p.h \ - $$PWD/qconductedclipanimator.h \ - $$PWD/qconductedclipanimator_p.h \ $$PWD/qchannelmapper.h \ $$PWD/qchannelmapper_p.h \ $$PWD/qchannelmapping.h \ @@ -42,7 +40,6 @@ SOURCES += \ $$PWD/qabstractclipblendnode.cpp \ $$PWD/qclipanimator.cpp \ $$PWD/qblendedclipanimator.cpp \ - $$PWD/qconductedclipanimator.cpp \ $$PWD/qchannelmapper.cpp \ $$PWD/qchannelmapping.cpp \ $$PWD/qlerpblend.cpp \ diff --git a/src/animation/frontend/qanimationaspect.cpp b/src/animation/frontend/qanimationaspect.cpp index b40077fd4..a47a18552 100644 --- a/src/animation/frontend/qanimationaspect.cpp +++ b/src/animation/frontend/qanimationaspect.cpp @@ -42,7 +42,6 @@ #include #include #include -#include #include #include #include @@ -101,9 +100,6 @@ QAnimationAspect::QAnimationAspect(QAnimationAspectPrivate &dd, QObject *parent) registerBackendType( QSharedPointer>::create(d->m_handler.data(), d->m_handler->blendedClipAnimatorManager())); - registerBackendType( - QSharedPointer>::create(d->m_handler.data(), - d->m_handler->conductedClipAnimatorManager())); registerBackendType( QSharedPointer>::create(d->m_handler.data(), d->m_handler->channelMappingManager())); diff --git a/src/animation/frontend/qconductedclipanimator.cpp b/src/animation/frontend/qconductedclipanimator.cpp deleted file mode 100644 index 29bdefe37..000000000 --- a/src/animation/frontend/qconductedclipanimator.cpp +++ /dev/null @@ -1,76 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB). -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt3D module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** 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-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ -#include "qconductedclipanimator.h" -#include "qconductedclipanimator_p.h" - -QT_BEGIN_NAMESPACE - -namespace Qt3DAnimation { - -QConductedClipAnimatorPrivate::QConductedClipAnimatorPrivate() - : Qt3DCore::QComponentPrivate() -{ -} - -QConductedClipAnimator::QConductedClipAnimator(Qt3DCore::QNode *parent) - : Qt3DCore::QComponent(*new QConductedClipAnimatorPrivate, parent) -{ -} - -QConductedClipAnimator::QConductedClipAnimator(QConductedClipAnimatorPrivate &dd, Qt3DCore::QNode *parent) - : Qt3DCore::QComponent(dd, parent) -{ -} - -QConductedClipAnimator::~QConductedClipAnimator() -{ -} - -Qt3DCore::QNodeCreatedChangeBasePtr QConductedClipAnimator::createNodeCreationChange() const -{ - auto creationChange = Qt3DCore::QNodeCreatedChangePtr::create(this); - auto &data = creationChange->data; - Q_D(const QConductedClipAnimator); - // TODO: Send data members in creation change - return creationChange; -} - -} // namespace Qt3DAnimation - -QT_END_NAMESPACE diff --git a/src/animation/frontend/qconductedclipanimator.h b/src/animation/frontend/qconductedclipanimator.h deleted file mode 100644 index 4364f6774..000000000 --- a/src/animation/frontend/qconductedclipanimator.h +++ /dev/null @@ -1,76 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB). -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt3D module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** 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-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QT3DANIMATION_QCONDUCTEDCLIPANIMATOR_H -#define QT3DANIMATION_QCONDUCTEDCLIPANIMATOR_H - -#include -#include - -QT_BEGIN_NAMESPACE - -namespace Qt3DAnimation { - -class QConductedClipAnimatorPrivate; - -class QT3DANIMATIONSHARED_EXPORT QConductedClipAnimator : public Qt3DCore::QComponent -{ - Q_OBJECT - // TODO: Add property declarations -public: - explicit QConductedClipAnimator(Qt3DCore::QNode *parent = nullptr); - ~QConductedClipAnimator(); - -public Q_SLOTS: - -Q_SIGNALS: - -protected: - QConductedClipAnimator(QConductedClipAnimatorPrivate &dd, Qt3DCore::QNode *parent = nullptr); - -private: - Q_DECLARE_PRIVATE(QConductedClipAnimator) - Qt3DCore::QNodeCreatedChangeBasePtr createNodeCreationChange() const Q_DECL_OVERRIDE; -}; - -} // namespace Qt3DAnimation - -QT_END_NAMESPACE - -#endif // QT3DANIMATION_QCONDUCTEDCLIPANIMATOR_H diff --git a/src/animation/frontend/qconductedclipanimator_p.h b/src/animation/frontend/qconductedclipanimator_p.h deleted file mode 100644 index c50247fa2..000000000 --- a/src/animation/frontend/qconductedclipanimator_p.h +++ /dev/null @@ -1,80 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB). -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt3D module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** 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-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QT3DANIMATION_QCONDUCTEDCLIPANIMATOR_P_H -#define QT3DANIMATION_QCONDUCTEDCLIPANIMATOR_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of other Qt classes. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include - -QT_BEGIN_NAMESPACE - -namespace Qt3DAnimation { - -class QConductedClipAnimatorPrivate : public Qt3DCore::QComponentPrivate -{ -public: - QConductedClipAnimatorPrivate(); - - Q_DECLARE_PUBLIC(QConductedClipAnimator) - - // TODO Add member variables -}; - -struct QConductedClipAnimatorData -{ - // TODO: Add members that should be sent to the backend -}; - -} // namespace Qt3DAnimation - - -QT_END_NAMESPACE - -#endif // QT3DANIMATION_QCONDUCTEDCLIPANIMATOR_P_H diff --git a/src/quick3d/imports/animation/qt3dquick3danimationplugin.cpp b/src/quick3d/imports/animation/qt3dquick3danimationplugin.cpp index bd54f73e8..334bf378f 100644 --- a/src/quick3d/imports/animation/qt3dquick3danimationplugin.cpp +++ b/src/quick3d/imports/animation/qt3dquick3danimationplugin.cpp @@ -41,7 +41,6 @@ #include #include #include -#include #include #include #include @@ -72,7 +71,6 @@ void Qt3DQuick3DAnimationPlugin::registerTypes(const char *uri) qmlRegisterType(uri, 2, 2, "AnimationClip"); qmlRegisterType(uri, 2, 2, "ClipAnimator"); qmlRegisterType(uri, 2, 2, "BlendedClipAnimator"); - qmlRegisterType(uri, 2, 2, "ConductedClipAnimator"); qmlRegisterType(uri, 2, 2, "ChannelMapping"); qmlRegisterExtendedType(uri, 2, 2, "ChannelMapper"); diff --git a/tests/auto/animation/animation.pro b/tests/auto/animation/animation.pro index 43a00cd12..2f3776aaf 100644 --- a/tests/auto/animation/animation.pro +++ b/tests/auto/animation/animation.pro @@ -5,7 +5,6 @@ SUBDIRS += \ qanimationclip \ qclipanimator \ qblendedclipanimator \ - qconductedclipanimator \ qchannelmapping \ qchannelmapper @@ -18,7 +17,6 @@ qtConfig(private_tests) { bezierevaluator \ clipanimator \ blendedclipanimator \ - conductedclipanimator \ channelmapper \ channelmapping \ qlerpblend \ diff --git a/tests/auto/animation/conductedclipanimator/conductedclipanimator.pro b/tests/auto/animation/conductedclipanimator/conductedclipanimator.pro deleted file mode 100644 index 61a1106d9..000000000 --- a/tests/auto/animation/conductedclipanimator/conductedclipanimator.pro +++ /dev/null @@ -1,12 +0,0 @@ -TEMPLATE = app - -TARGET = tst_conductedclipanimator - -QT += core-private 3dcore 3dcore-private 3danimation 3danimation-private testlib - -CONFIG += testcase - -SOURCES += \ - tst_conductedclipanimator.cpp - -include(../../core/common/common.pri) diff --git a/tests/auto/animation/conductedclipanimator/tst_conductedclipanimator.cpp b/tests/auto/animation/conductedclipanimator/tst_conductedclipanimator.cpp deleted file mode 100644 index 8536ab7e7..000000000 --- a/tests/auto/animation/conductedclipanimator/tst_conductedclipanimator.cpp +++ /dev/null @@ -1,98 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt3D module of the Qt Toolkit. -** -** $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 -#include -#include -#include -#include -#include -#include -#include -#include -#include - -class tst_ConductedClipAnimator: public Qt3DCore::QBackendNodeTester -{ - Q_OBJECT - -private Q_SLOTS: - void checkPeerPropertyMirroring() - { - // GIVEN - Qt3DAnimation::Animation::ConductedClipAnimator backendAnimator; - Qt3DAnimation::QConductedClipAnimator animator; - - // WHEN - simulateInitialization(&animator, &backendAnimator); - - // THEN - QCOMPARE(backendAnimator.peerId(), animator.id()); - QCOMPARE(backendAnimator.isEnabled(), animator.isEnabled()); - } - - void checkInitialAndCleanedUpState() - { - // GIVEN - Qt3DAnimation::Animation::ConductedClipAnimator backendAnimator; - - // THEN - QVERIFY(backendAnimator.peerId().isNull()); - QCOMPARE(backendAnimator.isEnabled(), false); - - // GIVEN - Qt3DAnimation::QConductedClipAnimator animator; - - // WHEN - simulateInitialization(&animator, &backendAnimator); - backendAnimator.cleanup(); - - // THEN - QCOMPARE(backendAnimator.isEnabled(), false); - } - - void checkPropertyChanges() - { - // GIVEN - Qt3DAnimation::Animation::ConductedClipAnimator backendAnimator; - Qt3DCore::QPropertyUpdatedChangePtr updateChange; - - // WHEN - updateChange.reset(new Qt3DCore::QPropertyUpdatedChange(Qt3DCore::QNodeId())); - updateChange->setPropertyName("enabled"); - updateChange->setValue(true); - backendAnimator.sceneChangeEvent(updateChange); - - // THEN - QCOMPARE(backendAnimator.isEnabled(), true); - } -}; - -QTEST_APPLESS_MAIN(tst_ConductedClipAnimator) - -#include "tst_conductedclipanimator.moc" diff --git a/tests/auto/animation/qconductedclipanimator/qconductedclipanimator.pro b/tests/auto/animation/qconductedclipanimator/qconductedclipanimator.pro deleted file mode 100644 index ef04bb54c..000000000 --- a/tests/auto/animation/qconductedclipanimator/qconductedclipanimator.pro +++ /dev/null @@ -1,12 +0,0 @@ -TEMPLATE = app - -TARGET = tst_qconductedclipanimator - -QT += 3dcore 3dcore-private 3danimation 3danimation-private testlib - -CONFIG += testcase - -SOURCES += \ - tst_qconductedclipanimator.cpp - -include(../../core/common/common.pri) diff --git a/tests/auto/animation/qconductedclipanimator/tst_qconductedclipanimator.cpp b/tests/auto/animation/qconductedclipanimator/tst_qconductedclipanimator.cpp deleted file mode 100644 index 7e40e5033..000000000 --- a/tests/auto/animation/qconductedclipanimator/tst_qconductedclipanimator.cpp +++ /dev/null @@ -1,64 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt3D module of the Qt Toolkit. -** -** $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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -class tst_QConductedClipAnimator : public QObject -{ - Q_OBJECT - -private Q_SLOTS: - void initTestCase() - { - qRegisterMetaType(); - } - - void checkDefaultConstruction() - { - // GIVEN - Qt3DAnimation::QConductedClipAnimator animator; - - // THEN - // TODO: Check default property state - } -}; - -QTEST_MAIN(tst_QConductedClipAnimator) - -#include "tst_qconductedclipanimator.moc" -- cgit v1.2.3 From 5bceaee38908934078bbdb62b564daa68f7e182b Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Wed, 15 Feb 2017 10:33:28 +0000 Subject: Use QVector in level of detail APIs For consistency with rest of API and to avoid ambiguity inherent with qreal. Task-number: QTBUG-58888 Task-number: QTBUG-58889 Change-Id: Ib8729a11152165caf05ecea63f9e10c4d90689db Reviewed-by: Mike Krus --- src/quick3d/quick3dextras/items/quick3dlevelofdetailloader.cpp | 4 ++-- src/quick3d/quick3dextras/items/quick3dlevelofdetailloader_p.h | 6 +++--- src/render/backend/levelofdetail.cpp | 2 +- src/render/backend/levelofdetail_p.h | 4 ++-- src/render/frontend/qlevelofdetail.cpp | 8 ++++---- src/render/frontend/qlevelofdetail.h | 8 ++++---- src/render/frontend/qlevelofdetail_p.h | 4 ++-- src/render/jobs/updatelevelofdetailjob.cpp | 4 ++-- tests/auto/render/levelofdetail/tst_levelofdetail.cpp | 6 +++--- tests/auto/render/qlevelofdetail/tst_qlevelofdetail.cpp | 2 +- 10 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/quick3d/quick3dextras/items/quick3dlevelofdetailloader.cpp b/src/quick3d/quick3dextras/items/quick3dlevelofdetailloader.cpp index f3d3f4323..c4a35328d 100644 --- a/src/quick3d/quick3dextras/items/quick3dlevelofdetailloader.cpp +++ b/src/quick3d/quick3dextras/items/quick3dlevelofdetailloader.cpp @@ -144,13 +144,13 @@ void Quick3DLevelOfDetailLoader::setThresholdType(Qt3DRender::QLevelOfDetail::Th d->m_lod->setThresholdType(thresholdType); } -QVector Quick3DLevelOfDetailLoader::thresholds() const +QVector Quick3DLevelOfDetailLoader::thresholds() const { Q_D(const Quick3DLevelOfDetailLoader); return d->m_lod->thresholds(); } -void Quick3DLevelOfDetailLoader::setThresholds(const QVector &thresholds) +void Quick3DLevelOfDetailLoader::setThresholds(const QVector &thresholds) { Q_D(Quick3DLevelOfDetailLoader); d->m_lod->setThresholds(thresholds); diff --git a/src/quick3d/quick3dextras/items/quick3dlevelofdetailloader_p.h b/src/quick3d/quick3dextras/items/quick3dlevelofdetailloader_p.h index 1ef359fe7..6eb539e56 100644 --- a/src/quick3d/quick3dextras/items/quick3dlevelofdetailloader_p.h +++ b/src/quick3d/quick3dextras/items/quick3dlevelofdetailloader_p.h @@ -71,7 +71,7 @@ class QT3DQUICKEXTRASSHARED_PRIVATE_EXPORT Quick3DLevelOfDetailLoader : public Q Q_PROPERTY(Qt3DRender::QCamera *camera READ camera WRITE setCamera NOTIFY cameraChanged) Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged) Q_PROPERTY(Qt3DRender::QLevelOfDetail::ThresholdType thresholdType READ thresholdType WRITE setThresholdType NOTIFY thresholdTypeChanged) - Q_PROPERTY(QVector thresholds READ thresholds WRITE setThresholds NOTIFY thresholdsChanged) + Q_PROPERTY(QVector thresholds READ thresholds WRITE setThresholds NOTIFY thresholdsChanged) Q_PROPERTY(Qt3DRender::QBoundingSphere *volumeOverride READ volumeOverride WRITE setVolumeOverride NOTIFY volumeOverrideChanged) Q_PROPERTY(QObject *entity READ entity NOTIFY entityChanged) @@ -88,8 +88,8 @@ public: void setCurrentIndex(int currentIndex); Qt3DRender::QLevelOfDetail::ThresholdType thresholdType() const; void setThresholdType(Qt3DRender::QLevelOfDetail::ThresholdType thresholdType); - QVector thresholds() const; - void setThresholds(const QVector &thresholds); + QVector thresholds() const; + void setThresholds(const QVector &thresholds); Qt3DRender::QBoundingSphere *volumeOverride() const; void setVolumeOverride(Qt3DRender::QBoundingSphere *volumeOverride); diff --git a/src/render/backend/levelofdetail.cpp b/src/render/backend/levelofdetail.cpp index 9ff0ef532..9618cc9bb 100644 --- a/src/render/backend/levelofdetail.cpp +++ b/src/render/backend/levelofdetail.cpp @@ -93,7 +93,7 @@ void LevelOfDetail::sceneChangeEvent(const QSceneChangePtr &e) } else if (propertyChange->propertyName() == QByteArrayLiteral("thresholdType")) { m_thresholdType = propertyChange->value().value(); } else if (propertyChange->propertyName() == QByteArrayLiteral("thresholds")) { - m_thresholds = propertyChange->value().value>(); + m_thresholds = propertyChange->value().value>(); } else if (propertyChange->propertyName() == QByteArrayLiteral("center")) { m_center = propertyChange->value().value(); } else if (propertyChange->propertyName() == QByteArrayLiteral("radius")) { diff --git a/src/render/backend/levelofdetail_p.h b/src/render/backend/levelofdetail_p.h index 83809a631..c8d065883 100644 --- a/src/render/backend/levelofdetail_p.h +++ b/src/render/backend/levelofdetail_p.h @@ -78,7 +78,7 @@ public: Qt3DCore::QNodeId camera() const { return m_camera; } int currentIndex() const { return m_currentIndex; } QLevelOfDetail::ThresholdType thresholdType() const { return m_thresholdType; } - QVector thresholds() const { return m_thresholds; } + QVector thresholds() const { return m_thresholds; } float radius() const { return m_radius; } QVector3D center() const { return m_center; } @@ -89,7 +89,7 @@ private: Qt3DCore::QNodeId m_camera; int m_currentIndex; QLevelOfDetail::ThresholdType m_thresholdType; - QVector m_thresholds; + QVector m_thresholds; float m_radius; QVector3D m_center; }; diff --git a/src/render/frontend/qlevelofdetail.cpp b/src/render/frontend/qlevelofdetail.cpp index 0d70803ca..53f2357b4 100644 --- a/src/render/frontend/qlevelofdetail.cpp +++ b/src/render/frontend/qlevelofdetail.cpp @@ -106,7 +106,7 @@ void QLevelOfDetailPrivate::_q_centerChanged(const QVector3D ¢er) Qt3DRender::QGeometryRenderer *geometryRenderer = new Qt3DCore::QGeometryRenderer(renderableEntity); renderableEntity->addComponent(geometryRenderer); Qt3DRender::QLevelOfDetail* lod = new Qt3Render::QLevelOfDetail(renderableEntity); - QVector thresholds = {20, 35, 50, 65}; + QVector thresholds = {20, 35, 50, 65}; lod->setThresholds(thresholds); lod->setCamera(mainCamera); renderableEntity->addComponent(lod); @@ -267,7 +267,7 @@ void QLevelOfDetailPrivate::_q_centerChanged(const QVector3D ¢er) */ /*! - * \qmlproperty QVector LevelOfDetail::thresholds + * \qmlproperty QVector LevelOfDetail::thresholds * * Array of range values as float point numbers. The value for the most detailed representation * should be specified first. @@ -435,7 +435,7 @@ void QLevelOfDetail::setThresholdType(QLevelOfDetail::ThresholdType thresholdTyp } } -QVector QLevelOfDetail::thresholds() const +QVector QLevelOfDetail::thresholds() const { Q_D(const QLevelOfDetail); return d->m_thresholds; @@ -445,7 +445,7 @@ QVector QLevelOfDetail::thresholds() const * Sets the range values. * \sa Qt3DRender::QLevelOfDetail::thresholdType */ -void QLevelOfDetail::setThresholds(QVector thresholds) +void QLevelOfDetail::setThresholds(QVector thresholds) { Q_D(QLevelOfDetail); if (d->m_thresholds != thresholds) { diff --git a/src/render/frontend/qlevelofdetail.h b/src/render/frontend/qlevelofdetail.h index f3325aea0..39cc8448b 100644 --- a/src/render/frontend/qlevelofdetail.h +++ b/src/render/frontend/qlevelofdetail.h @@ -59,7 +59,7 @@ class QT3DRENDERSHARED_EXPORT QLevelOfDetail : public Qt3DCore::QComponent Q_PROPERTY(Qt3DRender::QCamera *camera READ camera WRITE setCamera NOTIFY cameraChanged) Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged) Q_PROPERTY(ThresholdType thresholdType READ thresholdType WRITE setThresholdType NOTIFY thresholdTypeChanged) - Q_PROPERTY(QVector thresholds READ thresholds WRITE setThresholds NOTIFY thresholdsChanged) + Q_PROPERTY(QVector thresholds READ thresholds WRITE setThresholds NOTIFY thresholdsChanged) Q_PROPERTY(Qt3DRender::QBoundingSphere *volumeOverride READ volumeOverride WRITE setVolumeOverride NOTIFY volumeOverrideChanged) public: @@ -75,21 +75,21 @@ public: QCamera *camera() const; int currentIndex() const; ThresholdType thresholdType() const; - QVector thresholds() const; + QVector thresholds() const; QBoundingSphere *volumeOverride() const; public Q_SLOTS: void setCamera(QCamera *camera); void setCurrentIndex(int currentIndex); void setThresholdType(ThresholdType thresholdType); - void setThresholds(QVector thresholds); + void setThresholds(QVector thresholds); void setVolumeOverride(QBoundingSphere *volumeOverride); Q_SIGNALS: void cameraChanged(QCamera *camera); void currentIndexChanged(int currentIndex); void thresholdTypeChanged(ThresholdType thresholdType); - void thresholdsChanged(QVector thresholds); + void thresholdsChanged(QVector thresholds); void volumeOverrideChanged(QBoundingSphere *volumeOverride); protected: diff --git a/src/render/frontend/qlevelofdetail_p.h b/src/render/frontend/qlevelofdetail_p.h index ab25e9ad3..808959220 100644 --- a/src/render/frontend/qlevelofdetail_p.h +++ b/src/render/frontend/qlevelofdetail_p.h @@ -73,7 +73,7 @@ public: QCamera *m_camera; int m_currentIndex; QLevelOfDetail::ThresholdType m_thresholdType; - QVector m_thresholds; + QVector m_thresholds; QPointer m_volumeOverride; }; @@ -82,7 +82,7 @@ struct QLevelOfDetailData Qt3DCore::QNodeId camera; int currentIndex; QLevelOfDetail::ThresholdType thresholdType; - QVector thresholds; + QVector thresholds; float radius; QVector3D center; }; diff --git a/src/render/jobs/updatelevelofdetailjob.cpp b/src/render/jobs/updatelevelofdetailjob.cpp index 940d26850..6993d2bc8 100644 --- a/src/render/jobs/updatelevelofdetailjob.cpp +++ b/src/render/jobs/updatelevelofdetailjob.cpp @@ -160,7 +160,7 @@ void UpdateLevelOfDetailJob::updateEntityLodByDistance(Entity *entity, LevelOfDe if (!viewMatrixForCamera(lod->camera(), viewMatrix, projectionMatrix)) return; - const QVector thresholds = lod->thresholds(); + const QVector thresholds = lod->thresholds(); QVector3D center = lod->center(); if (lod->radius() > 0.f || entity->worldBoundingVolume() == nullptr) { center = *entity->worldTransform() * center; @@ -196,7 +196,7 @@ void UpdateLevelOfDetailJob::updateEntityLodByScreenArea(Entity *entity, LevelOf const PickingUtils::ViewportCameraAreaTriplet &vca = vcaTriplets.front(); - const QVector thresholds = lod->thresholds(); + const QVector thresholds = lod->thresholds(); Sphere bv(lod->center(), lod->radius()); if (lod->radius() <= 0.f && entity->worldBoundingVolume() != nullptr) { bv = *(entity->worldBoundingVolume()); diff --git a/tests/auto/render/levelofdetail/tst_levelofdetail.cpp b/tests/auto/render/levelofdetail/tst_levelofdetail.cpp index ab0e8c4b8..731e36a36 100644 --- a/tests/auto/render/levelofdetail/tst_levelofdetail.cpp +++ b/tests/auto/render/levelofdetail/tst_levelofdetail.cpp @@ -112,7 +112,7 @@ private Q_SLOTS: } { - QVector thresholds = {20.f, 30.f, 40.f}; + QVector thresholds = {20.0f, 30.0f, 40.0f}; QVariant v; v.setValue(thresholds); @@ -129,12 +129,12 @@ private Q_SLOTS: { // WHEN Qt3DCore::QPropertyUpdatedChangePtr updateChange(new Qt3DCore::QPropertyUpdatedChange(Qt3DCore::QNodeId())); - updateChange->setValue(QVector3D(1., 2., 3.)); + updateChange->setValue(QVector3D(1.0f, 2.0f, 3.0f)); updateChange->setPropertyName("center"); renderLod.sceneChangeEvent(updateChange); // THEN - QCOMPARE(renderLod.center(), QVector3D(1., 2., 3.)); + QCOMPARE(renderLod.center(), QVector3D(1.0f, 2.0f, 3.0f)); } } }; diff --git a/tests/auto/render/qlevelofdetail/tst_qlevelofdetail.cpp b/tests/auto/render/qlevelofdetail/tst_qlevelofdetail.cpp index e2ffdd9da..2f8f6a957 100644 --- a/tests/auto/render/qlevelofdetail/tst_qlevelofdetail.cpp +++ b/tests/auto/render/qlevelofdetail/tst_qlevelofdetail.cpp @@ -103,7 +103,7 @@ private Q_SLOTS: { // WHEN - QVector thresholds = {10., 20., 30.}; + QVector thresholds = {10.0f, 20.0f, 30.0f}; lod->setThresholds(thresholds); QCoreApplication::processEvents(); -- cgit v1.2.3 From 0a399dbc2c0c8338522af0e106cea2d68c44c4b2 Mon Sep 17 00:00:00 2001 From: Paul Lemire Date: Wed, 15 Feb 2017 09:56:02 +0000 Subject: QMemoryBarrier cleanup -rename barriertypes to waitOperation -in QML introduce a waitFor property -remove the Barrier suffix for the enum values -rename BarrierType to Operation Task-number: QTBUG-58878 Change-Id: Idc65f44b09e632509cd74286de26fea02e6b6dee Reviewed-by: Sean Harmer --- .../qt3d/compute-particles/ComputeFrameGraph.qml | 2 +- .../quick3drender/items/quick3dmemorybarrier.cpp | 10 ++--- .../quick3drender/items/quick3dmemorybarrier_p.h | 6 +-- src/render/backend/renderview_p.h | 6 +-- src/render/framegraph/memorybarrier.cpp | 12 +++--- src/render/framegraph/memorybarrier_p.h | 4 +- src/render/framegraph/qmemorybarrier.cpp | 48 +++++++++++----------- src/render/framegraph/qmemorybarrier.h | 44 ++++++++++---------- src/render/framegraph/qmemorybarrier_p.h | 4 +- src/render/graphicshelpers/graphicscontext.cpp | 2 +- src/render/graphicshelpers/graphicscontext_p.h | 2 +- src/render/graphicshelpers/graphicshelperes2.cpp | 2 +- src/render/graphicshelpers/graphicshelperes2_p.h | 2 +- src/render/graphicshelpers/graphicshelpergl2.cpp | 2 +- src/render/graphicshelpers/graphicshelpergl2_p.h | 2 +- src/render/graphicshelpers/graphicshelpergl3_2.cpp | 2 +- src/render/graphicshelpers/graphicshelpergl3_2_p.h | 2 +- src/render/graphicshelpers/graphicshelpergl3_3.cpp | 2 +- src/render/graphicshelpers/graphicshelpergl3_3_p.h | 2 +- src/render/graphicshelpers/graphicshelpergl4.cpp | 34 +++++++-------- src/render/graphicshelpers/graphicshelpergl4_p.h | 2 +- .../graphicshelpers/graphicshelperinterface_p.h | 2 +- src/render/jobs/renderviewjobutils.cpp | 2 +- .../render/memorybarrier/tst_memorybarrier.cpp | 12 +++--- .../render/qmemorybarrier/tst_qmemorybarrier.cpp | 30 +++++++------- tests/auto/render/renderviews/tst_renderviews.cpp | 10 ++--- 26 files changed, 124 insertions(+), 124 deletions(-) diff --git a/examples/qt3d/compute-particles/ComputeFrameGraph.qml b/examples/qt3d/compute-particles/ComputeFrameGraph.qml index 902d8ef74..17b3b27db 100644 --- a/examples/qt3d/compute-particles/ComputeFrameGraph.qml +++ b/examples/qt3d/compute-particles/ComputeFrameGraph.qml @@ -77,7 +77,7 @@ Viewport { CameraSelector { id: selector TechniqueFilter { - MemoryBarrier { barrierTypes: MemoryBarrier.VertexAttributeArrayBarrier } + MemoryBarrier { waitFor: MemoryBarrier.VertexAttributeArray } matchAll: [ FilterKey { name: "type"; value: "draw"} ] diff --git a/src/quick3d/quick3drender/items/quick3dmemorybarrier.cpp b/src/quick3d/quick3drender/items/quick3dmemorybarrier.cpp index a899d36c5..0754a0cf5 100644 --- a/src/quick3d/quick3drender/items/quick3dmemorybarrier.cpp +++ b/src/quick3d/quick3drender/items/quick3dmemorybarrier.cpp @@ -55,16 +55,16 @@ Quick3DMemoryBarrier::~Quick3DMemoryBarrier() { } -void Quick3DMemoryBarrier::setBarrierTypesInt(int barrierTypes) +void Quick3DMemoryBarrier::setWaitFor(int barrierTypes) { - QMemoryBarrier::BarrierTypes types(QMemoryBarrier::AllBarrier); + QMemoryBarrier::Operations types(QMemoryBarrier::All); types &= barrierTypes; // Will only keep flags that are actually set - parentBarrier()->setBarrierTypes(types); + parentBarrier()->setWaitOperations(types); } -int Quick3DMemoryBarrier::barrierTypesInt() const +int Quick3DMemoryBarrier::waitFor() const { - return QMemoryBarrier::BarrierTypes::Int(parentBarrier()->barrierTypes()); + return QMemoryBarrier::Operations::Int(parentBarrier()->waitOperations()); } } // namespace Quick diff --git a/src/quick3d/quick3drender/items/quick3dmemorybarrier_p.h b/src/quick3d/quick3drender/items/quick3dmemorybarrier_p.h index 5e402f006..ab8f72a76 100644 --- a/src/quick3d/quick3drender/items/quick3dmemorybarrier_p.h +++ b/src/quick3d/quick3drender/items/quick3dmemorybarrier_p.h @@ -65,15 +65,15 @@ namespace Quick { class QT3DQUICKRENDERSHARED_PRIVATE_EXPORT Quick3DMemoryBarrier : public QObject { Q_OBJECT - Q_PROPERTY(int barrierTypes READ barrierTypesInt WRITE setBarrierTypesInt) + Q_PROPERTY(int waitFor READ waitFor WRITE setWaitFor) public: explicit Quick3DMemoryBarrier(QObject *parent = nullptr); ~Quick3DMemoryBarrier(); inline QMemoryBarrier *parentBarrier() const { return qobject_cast(parent()); } - void setBarrierTypesInt(int barrierTypes); - int barrierTypesInt() const; + void setWaitFor(int waitOperations); + int waitFor() const; }; } // namespace Quick diff --git a/src/render/backend/renderview_p.h b/src/render/backend/renderview_p.h index 92fb502d9..5c0f5971a 100644 --- a/src/render/backend/renderview_p.h +++ b/src/render/backend/renderview_p.h @@ -221,8 +221,8 @@ public: inline void setRenderCaptureNodeId(const Qt3DCore::QNodeId nodeId) Q_DECL_NOTHROW { m_renderCaptureNodeId = nodeId; } inline const Qt3DCore::QNodeId renderCaptureNodeId() const Q_DECL_NOTHROW { return m_renderCaptureNodeId; } - void setMemoryBarrier(QMemoryBarrier::BarrierTypes barrier) Q_DECL_NOTHROW { m_memoryBarrier = barrier; } - QMemoryBarrier::BarrierTypes memoryBarrier() const Q_DECL_NOTHROW { return m_memoryBarrier; } + void setMemoryBarrier(QMemoryBarrier::Operations barrier) Q_DECL_NOTHROW { m_memoryBarrier = barrier; } + QMemoryBarrier::Operations memoryBarrier() const Q_DECL_NOTHROW { return m_memoryBarrier; } // Helps making the size of RenderView smaller // Contains all the data needed for the actual building of the RenderView @@ -282,7 +282,7 @@ private: bool m_compute:1; bool m_frustumCulling:1; int m_workGroups[3]; - QMemoryBarrier::BarrierTypes m_memoryBarrier; + QMemoryBarrier::Operations m_memoryBarrier; // We do not use pointers to RenderNodes or Drawable's here so that the // render aspect is free to change the drawables on the next frame whilst diff --git a/src/render/framegraph/memorybarrier.cpp b/src/render/framegraph/memorybarrier.cpp index c82f6eae8..ee8f156e3 100644 --- a/src/render/framegraph/memorybarrier.cpp +++ b/src/render/framegraph/memorybarrier.cpp @@ -49,7 +49,7 @@ namespace Render { MemoryBarrier::MemoryBarrier() : FrameGraphNode(FrameGraphNode::MemoryBarrier) - , m_barrierTypes(QMemoryBarrier::None) + , m_waitOperations(QMemoryBarrier::None) { } @@ -57,17 +57,17 @@ MemoryBarrier::~MemoryBarrier() { } -QMemoryBarrier::BarrierTypes MemoryBarrier::barrierTypes() const +QMemoryBarrier::Operations MemoryBarrier::waitOperations() const { - return m_barrierTypes; + return m_waitOperations; } void MemoryBarrier::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) { if (e->type() == Qt3DCore::PropertyUpdated) { Qt3DCore::QPropertyUpdatedChangePtr propertyChange = qSharedPointerCast(e); - if (propertyChange->propertyName() == QByteArrayLiteral("barrierTypes")) { - m_barrierTypes = propertyChange->value().value(); + if (propertyChange->propertyName() == QByteArrayLiteral("waitOperations")) { + m_waitOperations = propertyChange->value().value(); markDirty(AbstractRenderer::AllDirty); } } @@ -79,7 +79,7 @@ void MemoryBarrier::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr FrameGraphNode::initializeFromPeer(change); const auto typedChange = qSharedPointerCast>(change); const QMemoryBarrierData &data = typedChange->data; - m_barrierTypes = data.barrierTypes; + m_waitOperations = data.waitOperations; } } // Render diff --git a/src/render/framegraph/memorybarrier_p.h b/src/render/framegraph/memorybarrier_p.h index 4c0242476..66a3ae823 100644 --- a/src/render/framegraph/memorybarrier_p.h +++ b/src/render/framegraph/memorybarrier_p.h @@ -66,12 +66,12 @@ public: MemoryBarrier(); ~MemoryBarrier(); - QMemoryBarrier::BarrierTypes barrierTypes() const; + QMemoryBarrier::Operations waitOperations() const; void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_OVERRIDE; private: void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL; - QMemoryBarrier::BarrierTypes m_barrierTypes; + QMemoryBarrier::Operations m_waitOperations; }; } // Render diff --git a/src/render/framegraph/qmemorybarrier.cpp b/src/render/framegraph/qmemorybarrier.cpp index 9aa3ba560..0633e203e 100644 --- a/src/render/framegraph/qmemorybarrier.cpp +++ b/src/render/framegraph/qmemorybarrier.cpp @@ -97,30 +97,30 @@ namespace Qt3DRender { */ /*! - \enum QMemoryBarrier::BarrierType + \enum QMemoryBarrier::Operation This enum type describes types of buffer to be cleared. \value None - \value ElementArrayBarrier - \value UniformBarrier - \value TextureFetchBarrier - \value ShaderImageAccessBarrier - \value CommandBarrier - \value PixelBufferBarrier - \value TextureUpdateBarrier - \value BufferUpdateBarrier - \value FrameBufferBarrier - \value TransformFeedbackBarrier - \value AtomicCounterBarrier - \value ShaderStorageBarrier - \value QueryBufferBarrier - \value AllBarrier + \value ElementArray + \value Uniform + \value TextureFetch + \value ShaderImageAccess + \value Command + \value PixelBuffer + \value TextureUpdate + \value BufferUpdate + \value FrameBuffer + \value TransformFeedback + \value AtomicCounter + \value ShaderStorage + \value QueryBuffer + \value All */ QMemoryBarrierPrivate::QMemoryBarrierPrivate() : QFrameGraphNodePrivate() - , m_barrierTypes(QMemoryBarrier::None) + , m_waitOperations(QMemoryBarrier::None) { } @@ -133,20 +133,20 @@ QMemoryBarrier::~QMemoryBarrier() { } -void QMemoryBarrier::setBarrierTypes(QMemoryBarrier::BarrierTypes barrierTypes) +void QMemoryBarrier::setWaitOperations(QMemoryBarrier::Operations waitOperations) { Q_D(QMemoryBarrier); - if (barrierTypes != d->m_barrierTypes) { - d->m_barrierTypes = barrierTypes; - emit barrierTypesChanged(barrierTypes); - d->notifyPropertyChange("barrierTypes", QVariant::fromValue(barrierTypes)); + if (waitOperations != d->m_waitOperations) { + d->m_waitOperations = waitOperations; + emit waitOperationsChanged(waitOperations); + d->notifyPropertyChange("waitOperations", QVariant::fromValue(waitOperations)); } } -QMemoryBarrier::BarrierTypes QMemoryBarrier::barrierTypes() const +QMemoryBarrier::Operations QMemoryBarrier::waitOperations() const { Q_D(const QMemoryBarrier); - return d->m_barrierTypes; + return d->m_waitOperations; } QMemoryBarrier::QMemoryBarrier(QMemoryBarrierPrivate &dd, Qt3DCore::QNode *parent) @@ -159,7 +159,7 @@ Qt3DCore::QNodeCreatedChangeBasePtr QMemoryBarrier::createNodeCreationChange() c auto creationChange = QFrameGraphNodeCreatedChangePtr::create(this); QMemoryBarrierData &data = creationChange->data; Q_D(const QMemoryBarrier); - data.barrierTypes = d->m_barrierTypes; + data.waitOperations = d->m_waitOperations; return creationChange; } diff --git a/src/render/framegraph/qmemorybarrier.h b/src/render/framegraph/qmemorybarrier.h index 8b73c86bf..aaeeac6bc 100644 --- a/src/render/framegraph/qmemorybarrier.h +++ b/src/render/framegraph/qmemorybarrier.h @@ -55,33 +55,33 @@ public: explicit QMemoryBarrier(Qt3DCore::QNode *parent = nullptr); ~QMemoryBarrier(); - enum BarrierType { + enum Operation { None = 0, - VertexAttributeArrayBarrier = (1 << 0), - ElementArrayBarrier = (1 << 1), - UniformBarrier = (1 << 2), - TextureFetchBarrier = (1 << 3), - ShaderImageAccessBarrier = (1 << 4), - CommandBarrier = (1 << 5), - PixelBufferBarrier = (1 << 6), - TextureUpdateBarrier = (1 << 7), - BufferUpdateBarrier = (1 << 8), - FrameBufferBarrier = (1 << 9), - TransformFeedbackBarrier = (1 << 10), - AtomicCounterBarrier = (1 << 11), - ShaderStorageBarrier = (1 << 12), - QueryBufferBarrier = (1 << 13), - AllBarrier = 0xFFFFFFFF + VertexAttributeArray = (1 << 0), + ElementArray = (1 << 1), + Uniform = (1 << 2), + TextureFetch = (1 << 3), + ShaderImageAccess = (1 << 4), + Command = (1 << 5), + PixelBuffer = (1 << 6), + TextureUpdate = (1 << 7), + BufferUpdate = (1 << 8), + FrameBuffer = (1 << 9), + TransformFeedback = (1 << 10), + AtomicCounter = (1 << 11), + ShaderStorage = (1 << 12), + QueryBuffer = (1 << 13), + All = 0xFFFFFFFF }; - Q_ENUM(BarrierType) - Q_DECLARE_FLAGS(BarrierTypes, BarrierType) + Q_ENUM(Operation) + Q_DECLARE_FLAGS(Operations, Operation) public Q_SLOTS: - void setBarrierTypes(QMemoryBarrier::BarrierTypes barrierTypes); - BarrierTypes barrierTypes() const; + void setWaitOperations(QMemoryBarrier::Operations operations); + Operations waitOperations() const; Q_SIGNALS: - void barrierTypesChanged(QMemoryBarrier::BarrierTypes barrierTypes); + void waitOperationsChanged(QMemoryBarrier::Operations barrierTypes); protected: explicit QMemoryBarrier(QMemoryBarrierPrivate &dd, Qt3DCore::QNode *parent = nullptr); @@ -95,6 +95,6 @@ private: QT_END_NAMESPACE -Q_DECLARE_METATYPE(Qt3DRender::QMemoryBarrier::BarrierTypes) +Q_DECLARE_METATYPE(Qt3DRender::QMemoryBarrier::Operations) #endif // QT3DRENDER_QMEMORYBARRIER_H diff --git a/src/render/framegraph/qmemorybarrier_p.h b/src/render/framegraph/qmemorybarrier_p.h index 09df0c89c..384dbee3d 100644 --- a/src/render/framegraph/qmemorybarrier_p.h +++ b/src/render/framegraph/qmemorybarrier_p.h @@ -63,12 +63,12 @@ public: QMemoryBarrierPrivate(); Q_DECLARE_PUBLIC(QMemoryBarrier) - QMemoryBarrier::BarrierTypes m_barrierTypes; + QMemoryBarrier::Operations m_waitOperations; }; struct QMemoryBarrierData { - QMemoryBarrier::BarrierTypes barrierTypes; + QMemoryBarrier::Operations waitOperations; }; } // namespace Qt3DRender diff --git a/src/render/graphicshelpers/graphicscontext.cpp b/src/render/graphicshelpers/graphicscontext.cpp index c6a7aaff3..875f619b8 100644 --- a/src/render/graphicshelpers/graphicscontext.cpp +++ b/src/render/graphicshelpers/graphicscontext.cpp @@ -1477,7 +1477,7 @@ bool GraphicsContext::hasGLBufferForBuffer(Buffer *buffer) return (it != m_renderBufferHash.end()); } -void GraphicsContext::memoryBarrier(QMemoryBarrier::BarrierTypes barriers) +void GraphicsContext::memoryBarrier(QMemoryBarrier::Operations barriers) { m_glHelper->memoryBarrier(barriers); } diff --git a/src/render/graphicshelpers/graphicscontext_p.h b/src/render/graphicshelpers/graphicscontext_p.h index 0d9b24b6e..4358da999 100644 --- a/src/render/graphicshelpers/graphicscontext_p.h +++ b/src/render/graphicshelpers/graphicscontext_p.h @@ -163,7 +163,7 @@ public: void releaseBuffer(Qt3DCore::QNodeId bufferId); bool hasGLBufferForBuffer(Buffer *buffer); - void memoryBarrier(QMemoryBarrier::BarrierTypes barriers); + void memoryBarrier(QMemoryBarrier::Operations barriers); void setParameters(ShaderParameterPack ¶meterPack); diff --git a/src/render/graphicshelpers/graphicshelperes2.cpp b/src/render/graphicshelpers/graphicshelperes2.cpp index 08331e192..3b821f804 100644 --- a/src/render/graphicshelpers/graphicshelperes2.cpp +++ b/src/render/graphicshelpers/graphicshelperes2.cpp @@ -498,7 +498,7 @@ GLint GraphicsHelperES2::maxClipPlaneCount() return 0; } -void GraphicsHelperES2::memoryBarrier(QMemoryBarrier::BarrierTypes barriers) +void GraphicsHelperES2::memoryBarrier(QMemoryBarrier::Operations barriers) { Q_UNUSED(barriers); qWarning() << "memory barrier is not supported by OpenGL ES 2.0 (since 4.3)"; diff --git a/src/render/graphicshelpers/graphicshelperes2_p.h b/src/render/graphicshelpers/graphicshelperes2_p.h index 25f6c8cd8..f34eb7f87 100644 --- a/src/render/graphicshelpers/graphicshelperes2_p.h +++ b/src/render/graphicshelpers/graphicshelperes2_p.h @@ -110,7 +110,7 @@ public: void initializeHelper(QOpenGLContext *context, QAbstractOpenGLFunctions *functions) Q_DECL_OVERRIDE; void pointSize(bool programmable, GLfloat value) Q_DECL_OVERRIDE; GLint maxClipPlaneCount() Q_DECL_OVERRIDE; - void memoryBarrier(QMemoryBarrier::BarrierTypes barriers) Q_DECL_OVERRIDE; + void memoryBarrier(QMemoryBarrier::Operations barriers) Q_DECL_OVERRIDE; QVector programUniformBlocks(GLuint programId) Q_DECL_OVERRIDE; QVector programAttributesAndLocations(GLuint programId) Q_DECL_OVERRIDE; QVector programUniformsAndLocations(GLuint programId) Q_DECL_OVERRIDE; diff --git a/src/render/graphicshelpers/graphicshelpergl2.cpp b/src/render/graphicshelpers/graphicshelpergl2.cpp index 4d5d17d11..5f798f94e 100644 --- a/src/render/graphicshelpers/graphicshelpergl2.cpp +++ b/src/render/graphicshelpers/graphicshelpergl2.cpp @@ -518,7 +518,7 @@ GLint GraphicsHelperGL2::maxClipPlaneCount() return max; } -void GraphicsHelperGL2::memoryBarrier(QMemoryBarrier::BarrierTypes barriers) +void GraphicsHelperGL2::memoryBarrier(QMemoryBarrier::Operations barriers) { Q_UNUSED(barriers); qWarning() << "memory barrier is not supported by OpenGL 2.0 (since 4.3)"; diff --git a/src/render/graphicshelpers/graphicshelpergl2_p.h b/src/render/graphicshelpers/graphicshelpergl2_p.h index 8652b2bef..8966e48b2 100644 --- a/src/render/graphicshelpers/graphicshelpergl2_p.h +++ b/src/render/graphicshelpers/graphicshelpergl2_p.h @@ -110,7 +110,7 @@ public: void initializeHelper(QOpenGLContext *context, QAbstractOpenGLFunctions *functions) Q_DECL_OVERRIDE; void pointSize(bool programmable, GLfloat value) Q_DECL_OVERRIDE; GLint maxClipPlaneCount() Q_DECL_OVERRIDE; - void memoryBarrier(QMemoryBarrier::BarrierTypes barriers) Q_DECL_OVERRIDE; + void memoryBarrier(QMemoryBarrier::Operations barriers) Q_DECL_OVERRIDE; QVector programUniformBlocks(GLuint programId) Q_DECL_OVERRIDE; QVector programAttributesAndLocations(GLuint programId) Q_DECL_OVERRIDE; QVector programUniformsAndLocations(GLuint programId) Q_DECL_OVERRIDE; diff --git a/src/render/graphicshelpers/graphicshelpergl3_2.cpp b/src/render/graphicshelpers/graphicshelpergl3_2.cpp index 7599513fa..6c768e94e 100644 --- a/src/render/graphicshelpers/graphicshelpergl3_2.cpp +++ b/src/render/graphicshelpers/graphicshelpergl3_2.cpp @@ -797,7 +797,7 @@ GLint GraphicsHelperGL3_2::maxClipPlaneCount() return max; } -void GraphicsHelperGL3_2::memoryBarrier(QMemoryBarrier::BarrierTypes barriers) +void GraphicsHelperGL3_2::memoryBarrier(QMemoryBarrier::Operations barriers) { Q_UNUSED(barriers); qWarning() << "memory barrier is not supported by OpenGL 3.0 (since 4.3)"; diff --git a/src/render/graphicshelpers/graphicshelpergl3_2_p.h b/src/render/graphicshelpers/graphicshelpergl3_2_p.h index e12a65801..fbca14361 100644 --- a/src/render/graphicshelpers/graphicshelpergl3_2_p.h +++ b/src/render/graphicshelpers/graphicshelpergl3_2_p.h @@ -112,7 +112,7 @@ public: void initializeHelper(QOpenGLContext *context, QAbstractOpenGLFunctions *functions) Q_DECL_OVERRIDE; void pointSize(bool programmable, GLfloat value) Q_DECL_OVERRIDE; GLint maxClipPlaneCount() Q_DECL_OVERRIDE; - void memoryBarrier(QMemoryBarrier::BarrierTypes barriers) Q_DECL_OVERRIDE; + void memoryBarrier(QMemoryBarrier::Operations barriers) Q_DECL_OVERRIDE; QVector programUniformBlocks(GLuint programId) Q_DECL_OVERRIDE; QVector programAttributesAndLocations(GLuint programId) Q_DECL_OVERRIDE; QVector programUniformsAndLocations(GLuint programId) Q_DECL_OVERRIDE; diff --git a/src/render/graphicshelpers/graphicshelpergl3_3.cpp b/src/render/graphicshelpers/graphicshelpergl3_3.cpp index 4f6e38bf4..6959bdc6b 100644 --- a/src/render/graphicshelpers/graphicshelpergl3_3.cpp +++ b/src/render/graphicshelpers/graphicshelpergl3_3.cpp @@ -794,7 +794,7 @@ GLint GraphicsHelperGL3_3::maxClipPlaneCount() return max; } -void GraphicsHelperGL3_3::memoryBarrier(QMemoryBarrier::BarrierTypes barriers) +void GraphicsHelperGL3_3::memoryBarrier(QMemoryBarrier::Operations barriers) { Q_UNUSED(barriers); qWarning() << "memory barrier is not supported by OpenGL 3.3 (since 4.3)"; diff --git a/src/render/graphicshelpers/graphicshelpergl3_3_p.h b/src/render/graphicshelpers/graphicshelpergl3_3_p.h index 6d87c99b7..c093c801e 100644 --- a/src/render/graphicshelpers/graphicshelpergl3_3_p.h +++ b/src/render/graphicshelpers/graphicshelpergl3_3_p.h @@ -112,7 +112,7 @@ public: void initializeHelper(QOpenGLContext *context, QAbstractOpenGLFunctions *functions) Q_DECL_OVERRIDE; void pointSize(bool programmable, GLfloat value) Q_DECL_OVERRIDE; GLint maxClipPlaneCount() Q_DECL_OVERRIDE; - void memoryBarrier(QMemoryBarrier::BarrierTypes barriers) Q_DECL_OVERRIDE; + void memoryBarrier(QMemoryBarrier::Operations barriers) Q_DECL_OVERRIDE; QVector programUniformBlocks(GLuint programId) Q_DECL_OVERRIDE; QVector programAttributesAndLocations(GLuint programId) Q_DECL_OVERRIDE; QVector programUniformsAndLocations(GLuint programId) Q_DECL_OVERRIDE; diff --git a/src/render/graphicshelpers/graphicshelpergl4.cpp b/src/render/graphicshelpers/graphicshelpergl4.cpp index 682b3ac3b..26f03ac8a 100644 --- a/src/render/graphicshelpers/graphicshelpergl4.cpp +++ b/src/render/graphicshelpers/graphicshelpergl4.cpp @@ -88,42 +88,42 @@ namespace Render { namespace { -GLbitfield memoryBarrierGLBitfield(QMemoryBarrier::BarrierTypes barriers) +GLbitfield memoryBarrierGLBitfield(QMemoryBarrier::Operations barriers) { GLbitfield bits = 0; - if (barriers.testFlag(QMemoryBarrier::AllBarrier)) { + if (barriers.testFlag(QMemoryBarrier::All)) { bits |= GL_ALL_BARRIER_BITS; return bits; } - if (barriers.testFlag(QMemoryBarrier::VertexAttributeArrayBarrier)) + if (barriers.testFlag(QMemoryBarrier::VertexAttributeArray)) bits |= GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT; - if (barriers.testFlag(QMemoryBarrier::ElementArrayBarrier)) + if (barriers.testFlag(QMemoryBarrier::ElementArray)) bits |= GL_ELEMENT_ARRAY_BARRIER_BIT; - if (barriers.testFlag(QMemoryBarrier::UniformBarrier)) + if (barriers.testFlag(QMemoryBarrier::Uniform)) bits |= GL_UNIFORM_BARRIER_BIT; - if (barriers.testFlag(QMemoryBarrier::TextureFetchBarrier)) + if (barriers.testFlag(QMemoryBarrier::TextureFetch)) bits |= GL_TEXTURE_FETCH_BARRIER_BIT; - if (barriers.testFlag(QMemoryBarrier::ShaderImageAccessBarrier)) + if (barriers.testFlag(QMemoryBarrier::ShaderImageAccess)) bits |= GL_SHADER_IMAGE_ACCESS_BARRIER_BIT; - if (barriers.testFlag(QMemoryBarrier::CommandBarrier)) + if (barriers.testFlag(QMemoryBarrier::Command)) bits |= GL_COMMAND_BARRIER_BIT; - if (barriers.testFlag(QMemoryBarrier::PixelBufferBarrier)) + if (barriers.testFlag(QMemoryBarrier::PixelBuffer)) bits |= GL_PIXEL_BUFFER_BARRIER_BIT; - if (barriers.testFlag(QMemoryBarrier::TextureUpdateBarrier)) + if (barriers.testFlag(QMemoryBarrier::TextureUpdate)) bits |= GL_TEXTURE_UPDATE_BARRIER_BIT; - if (barriers.testFlag(QMemoryBarrier::BufferUpdateBarrier)) + if (barriers.testFlag(QMemoryBarrier::BufferUpdate)) bits |= GL_BUFFER_UPDATE_BARRIER_BIT; - if (barriers.testFlag(QMemoryBarrier::FrameBufferBarrier)) + if (barriers.testFlag(QMemoryBarrier::FrameBuffer)) bits |= GL_FRAMEBUFFER_BARRIER_BIT; - if (barriers.testFlag(QMemoryBarrier::TransformFeedbackBarrier)) + if (barriers.testFlag(QMemoryBarrier::TransformFeedback)) bits |= GL_TRANSFORM_FEEDBACK_BARRIER_BIT; - if (barriers.testFlag(QMemoryBarrier::AtomicCounterBarrier)) + if (barriers.testFlag(QMemoryBarrier::AtomicCounter)) bits |= GL_ATOMIC_COUNTER_BARRIER_BIT; - if (barriers.testFlag(QMemoryBarrier::ShaderStorageBarrier)) + if (barriers.testFlag(QMemoryBarrier::ShaderStorage)) bits |= GL_SHADER_STORAGE_BARRIER_BIT; - if (barriers.testFlag(QMemoryBarrier::QueryBufferBarrier)) + if (barriers.testFlag(QMemoryBarrier::QueryBuffer)) bits |= GL_QUERY_BUFFER_BARRIER_BIT; return bits; @@ -1047,7 +1047,7 @@ GLint GraphicsHelperGL4::maxClipPlaneCount() return max; } -void GraphicsHelperGL4::memoryBarrier(QMemoryBarrier::BarrierTypes barriers) +void GraphicsHelperGL4::memoryBarrier(QMemoryBarrier::Operations barriers) { m_funcs->glMemoryBarrier(memoryBarrierGLBitfield(barriers)); } diff --git a/src/render/graphicshelpers/graphicshelpergl4_p.h b/src/render/graphicshelpers/graphicshelpergl4_p.h index 5d464e116..6b3385838 100644 --- a/src/render/graphicshelpers/graphicshelpergl4_p.h +++ b/src/render/graphicshelpers/graphicshelpergl4_p.h @@ -110,7 +110,7 @@ public: void initializeHelper(QOpenGLContext *context, QAbstractOpenGLFunctions *functions) Q_DECL_OVERRIDE; void pointSize(bool programmable, GLfloat value) Q_DECL_OVERRIDE; GLint maxClipPlaneCount() Q_DECL_OVERRIDE; - void memoryBarrier(QMemoryBarrier::BarrierTypes barriers) Q_DECL_OVERRIDE; + void memoryBarrier(QMemoryBarrier::Operations barriers) Q_DECL_OVERRIDE; QVector programUniformBlocks(GLuint programId) Q_DECL_OVERRIDE; QVector programAttributesAndLocations(GLuint programId) Q_DECL_OVERRIDE; QVector programUniformsAndLocations(GLuint programId) Q_DECL_OVERRIDE; diff --git a/src/render/graphicshelpers/graphicshelperinterface_p.h b/src/render/graphicshelpers/graphicshelperinterface_p.h index 1048e1b26..4b2569263 100644 --- a/src/render/graphicshelpers/graphicshelperinterface_p.h +++ b/src/render/graphicshelpers/graphicshelperinterface_p.h @@ -125,7 +125,7 @@ public: virtual QSize getTextureDimensions(GLuint textureId, GLenum target, uint level = 0) = 0; virtual void initializeHelper(QOpenGLContext *context, QAbstractOpenGLFunctions *functions) = 0; virtual GLint maxClipPlaneCount() = 0; - virtual void memoryBarrier(QMemoryBarrier::BarrierTypes barriers) = 0; + virtual void memoryBarrier(QMemoryBarrier::Operations barriers) = 0; virtual void pointSize(bool programmable, GLfloat value) = 0; virtual QVector programAttributesAndLocations(GLuint programId) = 0; virtual QVector programUniformsAndLocations(GLuint programId) = 0; diff --git a/src/render/jobs/renderviewjobutils.cpp b/src/render/jobs/renderviewjobutils.cpp index 694c4b8ac..f75ea3f0c 100644 --- a/src/render/jobs/renderviewjobutils.cpp +++ b/src/render/jobs/renderviewjobutils.cpp @@ -240,7 +240,7 @@ void setRenderViewConfigFromFrameGraphLeafNode(RenderView *rv, const FrameGraphN case FrameGraphNode::MemoryBarrier: { const Render::MemoryBarrier *barrier = static_cast(node); - rv->setMemoryBarrier(barrier->barrierTypes()|rv->memoryBarrier()); + rv->setMemoryBarrier(barrier->waitOperations()|rv->memoryBarrier()); break; } diff --git a/tests/auto/render/memorybarrier/tst_memorybarrier.cpp b/tests/auto/render/memorybarrier/tst_memorybarrier.cpp index d4f54f3af..f0d4931d9 100644 --- a/tests/auto/render/memorybarrier/tst_memorybarrier.cpp +++ b/tests/auto/render/memorybarrier/tst_memorybarrier.cpp @@ -50,14 +50,14 @@ private Q_SLOTS: QCOMPARE(backendMemoryBarrier.nodeType(), Qt3DRender::Render::FrameGraphNode::MemoryBarrier); QCOMPARE(backendMemoryBarrier.isEnabled(), false); QVERIFY(backendMemoryBarrier.peerId().isNull()); - QCOMPARE(backendMemoryBarrier.barrierTypes(), Qt3DRender::QMemoryBarrier::None); + QCOMPARE(backendMemoryBarrier.waitOperations(), Qt3DRender::QMemoryBarrier::None); } void checkInitializeFromPeer() { // GIVEN Qt3DRender::QMemoryBarrier memoryBarrier; - memoryBarrier.setBarrierTypes(Qt3DRender::QMemoryBarrier::VertexAttributeArrayBarrier); + memoryBarrier.setWaitOperations(Qt3DRender::QMemoryBarrier::VertexAttributeArray); { // WHEN @@ -67,7 +67,7 @@ private Q_SLOTS: // THEN QCOMPARE(backendMemoryBarrier.isEnabled(), true); QCOMPARE(backendMemoryBarrier.peerId(), memoryBarrier.id()); - QCOMPARE(backendMemoryBarrier.barrierTypes(), Qt3DRender::QMemoryBarrier::VertexAttributeArrayBarrier); + QCOMPARE(backendMemoryBarrier.waitOperations(), Qt3DRender::QMemoryBarrier::VertexAttributeArray); } { // WHEN @@ -101,14 +101,14 @@ private Q_SLOTS: } { // WHEN - const Qt3DRender::QMemoryBarrier::BarrierTypes newValue(Qt3DRender::QMemoryBarrier::AtomicCounterBarrier|Qt3DRender::QMemoryBarrier::ElementArrayBarrier); + const Qt3DRender::QMemoryBarrier::Operations newValue(Qt3DRender::QMemoryBarrier::AtomicCounter|Qt3DRender::QMemoryBarrier::ElementArray); const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId()); - change->setPropertyName("barrierTypes"); + change->setPropertyName("waitOperations"); change->setValue(QVariant::fromValue(newValue)); backendMemoryBarrier.sceneChangeEvent(change); // THEN - QCOMPARE(backendMemoryBarrier.barrierTypes(), newValue); + QCOMPARE(backendMemoryBarrier.waitOperations(), newValue); } } diff --git a/tests/auto/render/qmemorybarrier/tst_qmemorybarrier.cpp b/tests/auto/render/qmemorybarrier/tst_qmemorybarrier.cpp index 87c813a03..25ee10cad 100644 --- a/tests/auto/render/qmemorybarrier/tst_qmemorybarrier.cpp +++ b/tests/auto/render/qmemorybarrier/tst_qmemorybarrier.cpp @@ -45,7 +45,7 @@ private Q_SLOTS: void initTestCase() { - qRegisterMetaType("QMemoryBarrier::BarrierTypes"); + qRegisterMetaType("QMemoryBarrier::Operations"); } void checkDefaultConstruction() @@ -54,7 +54,7 @@ private Q_SLOTS: Qt3DRender::QMemoryBarrier memoryBarrier; // THEN - QCOMPARE(memoryBarrier.barrierTypes(), Qt3DRender::QMemoryBarrier::None); + QCOMPARE(memoryBarrier.waitOperations(), Qt3DRender::QMemoryBarrier::None); } void checkPropertyChanges() @@ -64,21 +64,21 @@ private Q_SLOTS: { // WHEN - QSignalSpy spy(&memoryBarrier, SIGNAL(barrierTypesChanged(QMemoryBarrier::BarrierTypes))); - const Qt3DRender::QMemoryBarrier::BarrierTypes newValue(Qt3DRender::QMemoryBarrier::ShaderStorageBarrier|Qt3DRender::QMemoryBarrier::VertexAttributeArrayBarrier); - memoryBarrier.setBarrierTypes(newValue); + QSignalSpy spy(&memoryBarrier, SIGNAL(waitOperationsChanged(QMemoryBarrier::Operations))); + const Qt3DRender::QMemoryBarrier::Operations newValue(Qt3DRender::QMemoryBarrier::ShaderStorage|Qt3DRender::QMemoryBarrier::VertexAttributeArray); + memoryBarrier.setWaitOperations(newValue); // THEN QVERIFY(spy.isValid()); - QCOMPARE(memoryBarrier.barrierTypes(), newValue); + QCOMPARE(memoryBarrier.waitOperations(), newValue); QCOMPARE(spy.count(), 1); // WHEN spy.clear(); - memoryBarrier.setBarrierTypes(newValue); + memoryBarrier.setWaitOperations(newValue); // THEN - QCOMPARE(memoryBarrier.barrierTypes(), newValue); + QCOMPARE(memoryBarrier.waitOperations(), newValue); QCOMPARE(spy.count(), 0); } } @@ -88,7 +88,7 @@ private Q_SLOTS: // GIVEN Qt3DRender::QMemoryBarrier memoryBarrier; - memoryBarrier.setBarrierTypes(Qt3DRender::QMemoryBarrier::CommandBarrier); + memoryBarrier.setWaitOperations(Qt3DRender::QMemoryBarrier::Command); // WHEN QVector creationChanges; @@ -105,7 +105,7 @@ private Q_SLOTS: const auto creationChangeData = qSharedPointerCast>(creationChanges.first()); const Qt3DRender::QMemoryBarrierData cloneData = creationChangeData->data; - QCOMPARE(memoryBarrier.barrierTypes(), cloneData.barrierTypes); + QCOMPARE(memoryBarrier.waitOperations(), cloneData.waitOperations); QCOMPARE(memoryBarrier.id(), creationChangeData->subjectId()); QCOMPARE(memoryBarrier.isEnabled(), true); QCOMPARE(memoryBarrier.isEnabled(), creationChangeData->isNodeEnabled()); @@ -127,7 +127,7 @@ private Q_SLOTS: const auto creationChangeData = qSharedPointerCast>(creationChanges.first()); const Qt3DRender::QMemoryBarrierData cloneData = creationChangeData->data; - QCOMPARE(memoryBarrier.barrierTypes(), cloneData.barrierTypes); + QCOMPARE(memoryBarrier.waitOperations(), cloneData.waitOperations); QCOMPARE(memoryBarrier.id(), creationChangeData->subjectId()); QCOMPARE(memoryBarrier.isEnabled(), false); QCOMPARE(memoryBarrier.isEnabled(), creationChangeData->isNodeEnabled()); @@ -144,14 +144,14 @@ private Q_SLOTS: { // WHEN - memoryBarrier.setBarrierTypes(Qt3DRender::QMemoryBarrier::ShaderStorageBarrier); + memoryBarrier.setWaitOperations(Qt3DRender::QMemoryBarrier::ShaderStorage); QCoreApplication::processEvents(); // THEN QCOMPARE(arbiter.events.size(), 1); auto change = arbiter.events.first().staticCast(); - QCOMPARE(change->propertyName(), "barrierTypes"); - QCOMPARE(change->value().value(), memoryBarrier.barrierTypes()); + QCOMPARE(change->propertyName(), "waitOperations"); + QCOMPARE(change->value().value(), memoryBarrier.waitOperations()); QCOMPARE(change->type(), Qt3DCore::PropertyUpdated); arbiter.events.clear(); @@ -159,7 +159,7 @@ private Q_SLOTS: { // WHEN - memoryBarrier.setBarrierTypes(Qt3DRender::QMemoryBarrier::ShaderStorageBarrier); + memoryBarrier.setWaitOperations(Qt3DRender::QMemoryBarrier::ShaderStorage); QCoreApplication::processEvents(); // THEN diff --git a/tests/auto/render/renderviews/tst_renderviews.cpp b/tests/auto/render/renderviews/tst_renderviews.cpp index 70109d718..d469298f4 100644 --- a/tests/auto/render/renderviews/tst_renderviews.cpp +++ b/tests/auto/render/renderviews/tst_renderviews.cpp @@ -93,7 +93,7 @@ private Q_SLOTS: QCOMPARE(renderView.memoryBarrier(), QMemoryBarrier::None); // WHEN - const QMemoryBarrier::BarrierTypes barriers(QMemoryBarrier::BufferUpdateBarrier|QMemoryBarrier::ShaderImageAccessBarrier); + const QMemoryBarrier::Operations barriers(QMemoryBarrier::BufferUpdate|QMemoryBarrier::ShaderImageAccess); renderView.setMemoryBarrier(barriers); // THEN @@ -104,7 +104,7 @@ private Q_SLOTS: { { // GIVEN - const QMemoryBarrier::BarrierTypes barriers(QMemoryBarrier::AtomicCounterBarrier|QMemoryBarrier::ShaderStorageBarrier); + const QMemoryBarrier::Operations barriers(QMemoryBarrier::AtomicCounter|QMemoryBarrier::ShaderStorage); Qt3DRender::QMemoryBarrier frontendBarrier; FrameGraphManager frameGraphManager; MemoryBarrier backendBarrier; @@ -113,18 +113,18 @@ private Q_SLOTS: backendBarrier.setFrameGraphManager(&frameGraphManager); // WHEN - frontendBarrier.setBarrierTypes(barriers); + frontendBarrier.setWaitOperations(barriers); simulateInitialization(&frontendBarrier, &backendBarrier); // THEN QCOMPARE(renderView.memoryBarrier(), QMemoryBarrier::None); - QCOMPARE(backendBarrier.barrierTypes(), barriers); + QCOMPARE(backendBarrier.waitOperations(), barriers); // WHEN Qt3DRender::Render::setRenderViewConfigFromFrameGraphLeafNode(&renderView, &backendBarrier); // THEN - QCOMPARE(backendBarrier.barrierTypes(), renderView.memoryBarrier()); + QCOMPARE(backendBarrier.waitOperations(), renderView.memoryBarrier()); } // TO DO: Complete tests for other framegraph node types } -- cgit v1.2.3 From ec787715a7cb7af5a34972356009642da45e2950 Mon Sep 17 00:00:00 2001 From: Paul Lemire Date: Wed, 15 Feb 2017 10:24:34 +0000 Subject: Extruded Text cleanup -rename QText3DGeometry to QExtrudedTextGeometry -rename QText3DMesh to QExtrudedTextMesh -rename the depth property to extrusionLength -removed the edgeSplitAngle property -updated the example Task-number: QTBUG-58880 Change-Id: Ib2d1a58e62b34949db12b9245f1474baf9cf9b91 Reviewed-by: Sean Harmer --- examples/qt3d/3d-text/main.cpp | 13 +- src/extras/3dtext/3dtext.pri | 10 +- src/extras/3dtext/qextrudedtextgeometry.cpp | 503 ++++++++++++++++++++ src/extras/3dtext/qextrudedtextgeometry.h | 113 +++++ src/extras/3dtext/qextrudedtextgeometry_p.h | 106 +++++ src/extras/3dtext/qextrudedtextmesh.cpp | 157 ++++++ src/extras/3dtext/qextrudedtextmesh.h | 93 ++++ src/extras/3dtext/qtext3dgeometry.cpp | 528 --------------------- src/extras/3dtext/qtext3dgeometry.h | 117 ----- src/extras/3dtext/qtext3dgeometry_p.h | 106 ----- src/extras/3dtext/qtext3dmesh.cpp | 179 ------- src/extras/3dtext/qtext3dmesh.h | 97 ---- .../imports/extras/qt3dquick3dextrasplugin.cpp | 8 +- 13 files changed, 986 insertions(+), 1044 deletions(-) create mode 100644 src/extras/3dtext/qextrudedtextgeometry.cpp create mode 100644 src/extras/3dtext/qextrudedtextgeometry.h create mode 100644 src/extras/3dtext/qextrudedtextgeometry_p.h create mode 100644 src/extras/3dtext/qextrudedtextmesh.cpp create mode 100644 src/extras/3dtext/qextrudedtextmesh.h delete mode 100644 src/extras/3dtext/qtext3dgeometry.cpp delete mode 100644 src/extras/3dtext/qtext3dgeometry.h delete mode 100644 src/extras/3dtext/qtext3dgeometry_p.h delete mode 100644 src/extras/3dtext/qtext3dmesh.cpp delete mode 100644 src/extras/3dtext/qtext3dmesh.h diff --git a/examples/qt3d/3d-text/main.cpp b/examples/qt3d/3d-text/main.cpp index 40ae8b80a..17d749f94 100644 --- a/examples/qt3d/3d-text/main.cpp +++ b/examples/qt3d/3d-text/main.cpp @@ -51,8 +51,7 @@ #include #include #include -#include -#include +#include int main(int argc, char *argv[]) { @@ -85,17 +84,15 @@ int main(int argc, char *argv[]) for (QString family : fonts) { auto *text = new Qt3DCore::QEntity(root); - auto *textMesh = new Qt3DExtras::QText3DMesh(); - Qt3DExtras::QText3DGeometry *textGeometry = static_cast(textMesh->geometry()); + auto *textMesh = new Qt3DExtras::QExtrudedTextMesh(); auto *textTransform = new Qt3DCore::QTransform(); QFont font(family, 32, -1, false); textTransform->setTranslation(QVector3D(-2.45f, i * .5f, 0)); textTransform->setScale(.2f); - textGeometry->setDepth(.45f); - textGeometry->setFont(font); - textGeometry->setEdgeSplitAngle(90.f * .15f); - textGeometry->setText(QString(family)); + textMesh->setDepth(.45f); + textMesh->setFont(font); + textMesh->setText(QString(family)); textMaterial->setDiffuse(QColor(111, 150, 255)); text->addComponent(textMaterial); diff --git a/src/extras/3dtext/3dtext.pri b/src/extras/3dtext/3dtext.pri index bcf2ce948..d7855f1b0 100644 --- a/src/extras/3dtext/3dtext.pri +++ b/src/extras/3dtext/3dtext.pri @@ -1,11 +1,11 @@ SOURCES += \ - $$PWD/qtext3dgeometry.cpp \ - $$PWD/qtext3dmesh.cpp + $$PWD/qextrudedtextgeometry.cpp \ + $$PWD/qextrudedtextmesh.cpp HEADERS += \ - $$PWD/qtext3dgeometry.h \ - $$PWD/qtext3dgeometry_p.h \ - $$PWD/qtext3dmesh.h + $$PWD/qextrudedtextgeometry.h \ + $$PWD/qextrudedtextgeometry_p.h \ + $$PWD/qextrudedtextmesh.h INCLUDEPATH += $$PWD diff --git a/src/extras/3dtext/qextrudedtextgeometry.cpp b/src/extras/3dtext/qextrudedtextgeometry.cpp new file mode 100644 index 000000000..82bdb464b --- /dev/null +++ b/src/extras/3dtext/qextrudedtextgeometry.cpp @@ -0,0 +1,503 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qextrudedtextgeometry.h" +#include "qextrudedtextgeometry_p.h" +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DExtras { + +namespace { + +static float edgeSplitAngle = 90.f * 0.1f; + +using IndexType = unsigned int; + +struct TriangulationData { + struct Outline { + int begin; + int end; + }; + + QVector vertices; + QVector indices; + QVector outlines; + QVector outlineIndices; + bool inverted; +}; + +TriangulationData triangulate(const QString &text, const QFont &font) +{ + TriangulationData result; + int beginOutline = 0; + + // Initialize path with text and extract polygons + QPainterPath path; + path.setFillRule(Qt::WindingFill); + path.addText(0, 0, font, text); + QList polygons = path.toSubpathPolygons(QTransform().scale(1.f, -1.f)); + + // maybe glyph has no geometry + if (polygons.size() == 0) + return result; + + const int prevNumIndices = result.indices.size(); + + // Reset path and add previously extracted polygons (which where spatially transformed) + path = QPainterPath(); + path.setFillRule(Qt::WindingFill); + for (QPolygonF &p : polygons) + path.addPolygon(p); + + // Extract polylines out of the path, this allows us to retrive indicies for each glyph outline + QPolylineSet polylines = qPolyline(path); + QVector tmpIndices; + tmpIndices.resize(polylines.indices.size()); + memcpy(tmpIndices.data(), polylines.indices.data(), polylines.indices.size() * sizeof(IndexType)); + + int lastIndex = 0; + for (const IndexType idx : tmpIndices) { + if (idx == std::numeric_limits::max()) { + const int endOutline = lastIndex; + result.outlines.push_back({beginOutline, endOutline}); + beginOutline = endOutline; + } else { + result.outlineIndices.push_back(idx); + ++lastIndex; + } + } + + // Triangulate path + const QTriangleSet triangles = qTriangulate(path); + + // Append new indices to result.indices buffer + result.indices.resize(result.indices.size() + triangles.indices.size()); + memcpy(&result.indices[prevNumIndices], triangles.indices.data(), triangles.indices.size() * sizeof(IndexType)); + for (int i = prevNumIndices, m = result.indices.size(); i < m; ++i) + result.indices[i] += result.vertices.size(); + + // Append new triangles to result.vertices + result.vertices.reserve(triangles.vertices.size() / 2); + for (int i = 0, m = triangles.vertices.size(); i < m; i += 2) + result.vertices.push_back(QVector3D(triangles.vertices[i] / font.pointSizeF(), triangles.vertices[i + 1] / font.pointSizeF(), 0.0f)); + + return result; +} + +inline QVector3D mix(const QVector3D &a, const QVector3D &b, float ratio) +{ + return a + (b - a) * ratio; +} + +} // anonymous namespace + +QExtrudedTextGeometryPrivate::QExtrudedTextGeometryPrivate() + : QGeometryPrivate() + , m_font(QFont(QStringLiteral("Arial"))) + , m_depth(1.f) + , m_positionAttribute(nullptr) + , m_normalAttribute(nullptr) + , m_indexAttribute(nullptr) + , m_vertexBuffer(nullptr) + , m_indexBuffer(nullptr) +{ + m_font.setPointSize(4); +} + +void QExtrudedTextGeometryPrivate::init() +{ + Q_Q(QExtrudedTextGeometry); + m_positionAttribute = new Qt3DRender::QAttribute(q); + m_normalAttribute = new Qt3DRender::QAttribute(q); + m_indexAttribute = new Qt3DRender::QAttribute(q); + m_vertexBuffer = new Qt3DRender::QBuffer(Qt3DRender::QBuffer::VertexBuffer, q); + m_indexBuffer = new Qt3DRender::QBuffer(Qt3DRender::QBuffer::IndexBuffer, q); + + const quint32 elementSize = 3 + 3; + const quint32 stride = elementSize * sizeof(float); + + m_positionAttribute->setName(Qt3DRender::QAttribute::defaultPositionAttributeName()); + m_positionAttribute->setVertexBaseType(Qt3DRender::QAttribute::Float); + m_positionAttribute->setVertexSize(3); + m_positionAttribute->setAttributeType(Qt3DRender::QAttribute::VertexAttribute); + m_positionAttribute->setBuffer(m_vertexBuffer); + m_positionAttribute->setByteStride(stride); + m_positionAttribute->setByteOffset(0); + m_positionAttribute->setCount(0); + + m_normalAttribute->setName(Qt3DRender::QAttribute::defaultNormalAttributeName()); + m_normalAttribute->setVertexBaseType(Qt3DRender::QAttribute::Float); + m_normalAttribute->setVertexSize(3); + m_normalAttribute->setAttributeType(Qt3DRender::QAttribute::VertexAttribute); + m_normalAttribute->setBuffer(m_vertexBuffer); + m_normalAttribute->setByteStride(stride); + m_normalAttribute->setByteOffset(3 * sizeof(float)); + m_normalAttribute->setCount(0); + + m_indexAttribute->setAttributeType(Qt3DRender::QAttribute::IndexAttribute); + m_indexAttribute->setVertexBaseType(Qt3DRender::QAttribute::UnsignedInt); + m_indexAttribute->setBuffer(m_indexBuffer); + m_indexAttribute->setCount(0); + + q->addAttribute(m_positionAttribute); + q->addAttribute(m_normalAttribute); + q->addAttribute(m_indexAttribute); + + update(); +} + +/*! + * \qmltype ExtrudedTextGeometry + * \instantiates Qt3DExtras::QExtrudedTextGeometry + * \inqmlmodule Qt3D.Extras + * \brief ExtrudedTextGeometry allows creation of a 3D text in 3D space. + * + * The ExtrudedTextGeometry type is most commonly used internally by the + * ExtrudedTextMesh type but can also be used in custom GeometryRenderer types. + */ + +/*! + * \qmlproperty QString ExtrudedTextGeometry::text + * + * Holds the text used for the mesh. + */ + +/*! + * \qmlproperty QFont ExtrudedTextGeometry::font + * + * Holds the font of the text. + */ + +/*! + * \qmlproperty float ExtrudedTextGeometry::depth + * + * Holds the extrusion depth of the text. + */ + +/*! + * \qmlproperty Attribute ExtrudedTextGeometry::positionAttribute + * + * Holds the geometry position attribute. + */ + +/*! + * \qmlproperty Attribute ExtrudedTextGeometry::normalAttribute + * + * Holds the geometry normal attribute. + */ + +/*! + * \qmlproperty Attribute ExtrudedTextGeometry::indexAttribute + * + * Holds the geometry index attribute. + */ + +/*! + * \class Qt3DExtras::QExtrudedTextGeometry + * \inheaderfile Qt3DExtras/QExtrudedTextGeometry + * \inmodule Qt3DExtras + * \brief The QExtrudedTextGeometry class allows creation of a 3D extruded text + * in 3D space. + * \since 5.9 + * \ingroup geometries + * \inherits Qt3DRender::QGeometry + * + * The QExtrudedTextGeometry class is most commonly used internally by the QText3DMesh + * but can also be used in custom Qt3DRender::QGeometryRenderer subclasses. + */ + +/*! + * Constructs a new QExtrudedTextGeometry with \a parent. + */ +QExtrudedTextGeometry::QExtrudedTextGeometry(Qt3DCore::QNode *parent) + : QGeometry(*new QExtrudedTextGeometryPrivate(), parent) +{ + Q_D(QExtrudedTextGeometry); + d->init(); +} + +/*! + * \internal + */ +QExtrudedTextGeometry::QExtrudedTextGeometry(QExtrudedTextGeometryPrivate &dd, Qt3DCore::QNode *parent) + : QGeometry(dd, parent) +{ + Q_D(QExtrudedTextGeometry); + d->init(); +} + +/*! + * \internal + */ +QExtrudedTextGeometry::~QExtrudedTextGeometry() +{} + +/*! + * \internal + * Updates vertices based on text, font, extrusionLength and smoothAngle properties. + */ +void QExtrudedTextGeometryPrivate::update() +{ + if (m_text.trimmed().isEmpty()) // save enough? + return; + + TriangulationData data = triangulate(m_text, m_font); + + const int numVertices = data.vertices.size(); + const int numIndices = data.indices.size(); + + struct Vertex { + QVector3D position; + QVector3D normal; + }; + + QVector indices; + QVector vertices; + + // TODO: keep 'vertices.size()' small when extruding + vertices.reserve(data.vertices.size() * 2); + for (QVector3D &v : data.vertices) // front face + vertices.push_back({ v, // vertex + QVector3D(0.0f, 0.0f, -1.0f) }); // normal + for (QVector3D &v : data.vertices) // front face + vertices.push_back({ QVector3D(v.x(), v.y(), m_depth), // vertex + QVector3D(0.0f, 0.0f, 1.0f) }); // normal + + for (int i = 0, verticesIndex = vertices.size(); i < data.outlines.size(); ++i) { + const int begin = data.outlines[i].begin; + const int end = data.outlines[i].end; + const int verticesIndexBegin = verticesIndex; + + if (begin == end) + continue; + + QVector3D prevNormal = QVector3D::crossProduct( + vertices[data.outlineIndices[end - 1] + numVertices].position - vertices[data.outlineIndices[end - 1]].position, + vertices[data.outlineIndices[begin]].position - vertices[data.outlineIndices[end - 1]].position).normalized(); + + for (int j = begin; j < end; ++j) { + const bool isLastIndex = (j == end - 1); + const IndexType cur = data.outlineIndices[j]; + const IndexType next = data.outlineIndices[((j - begin + 1) % (end - begin)) + begin]; // normalize, bring in range and adjust + const QVector3D normal = QVector3D::crossProduct(vertices[cur + numVertices].position - vertices[cur].position, vertices[next].position - vertices[cur].position).normalized(); + + // use smooth normals in case of a short angle + const bool smooth = QVector3D::dotProduct(prevNormal, normal) > (90.0f - edgeSplitAngle) / 90.0f; + const QVector3D resultNormal = smooth ? mix(prevNormal, normal, 0.5f) : normal; + if (!smooth) { + vertices.push_back({vertices[cur].position, prevNormal}); + vertices.push_back({vertices[cur + numVertices].position, prevNormal}); + verticesIndex += 2; + } + + vertices.push_back({vertices[cur].position, resultNormal}); + vertices.push_back({vertices[cur + numVertices].position, resultNormal}); + + const int v0 = verticesIndex; + const int v1 = verticesIndex + 1; + const int v2 = isLastIndex ? verticesIndexBegin : verticesIndex + 2; + const int v3 = isLastIndex ? verticesIndexBegin + 1 : verticesIndex + 3; + + indices.push_back(v0); + indices.push_back(v1); + indices.push_back(v2); + indices.push_back(v2); + indices.push_back(v1); + indices.push_back(v3); + + verticesIndex += 2; + prevNormal = normal; + } + } + + { // upload vertices + QByteArray data; + data.resize(vertices.size() * sizeof(Vertex)); + memcpy(data.data(), vertices.data(), vertices.size() * sizeof(Vertex)); + + m_vertexBuffer->setData(data); + m_positionAttribute->setCount(vertices.size()); + m_normalAttribute->setCount(vertices.size()); + } + + // resize for following insertions + const int indicesOffset = indices.size(); + indices.resize(indices.size() + numIndices * 2); + + // copy values for back faces + IndexType *indicesFaces = indices.data() + indicesOffset; + memcpy(indicesFaces, data.indices.data(), numIndices * sizeof(IndexType)); + + // insert values for front face and flip triangles + for (int j = 0; j < numIndices; j += 3) + { + indicesFaces[numIndices + j ] = indicesFaces[j ] + numVertices; + indicesFaces[numIndices + j + 1] = indicesFaces[j + 2] + numVertices; + indicesFaces[numIndices + j + 2] = indicesFaces[j + 1] + numVertices; + } + + { // upload indices + QByteArray data; + data.resize(indices.size() * sizeof(IndexType)); + memcpy(data.data(), indices.data(), indices.size() * sizeof(IndexType)); + + m_indexBuffer->setData(data); + m_indexAttribute->setCount(indices.size()); + } +} + +void QExtrudedTextGeometry::setText(QString text) +{ + Q_D(QExtrudedTextGeometry); + if (d->m_text != text) { + d->m_text = text; + d->update(); + emit textChanged(text); + } +} + +void QExtrudedTextGeometry::setFont(QFont font) +{ + Q_D(QExtrudedTextGeometry); + if (d->m_font != font) { + d->m_font = font; + d->update(); + emit fontChanged(font); + } +} + +void QExtrudedTextGeometry::setDepth(float depth) +{ + Q_D(QExtrudedTextGeometry); + if (d->m_depth != depth) { + d->m_depth = depth; + d->update(); + emit depthChanged(depth); + } +} + +/*! + * \property QString QExtrudedTextGeometry::text + * + * Holds the text used for the mesh. + */ +QString QExtrudedTextGeometry::text() const +{ + Q_D(const QExtrudedTextGeometry); + return d->m_text; +} + +/*! + * \property QFont QExtrudedTextGeometry::font + * + * Holds the font of the text. + */ +QFont QExtrudedTextGeometry::font() const +{ + Q_D(const QExtrudedTextGeometry); + return d->m_font; +} + +/*! + * \property float QExtrudedTextGeometry::extrusionLength + * + * Holds the extrusion length of the text. + */ +float QExtrudedTextGeometry::extrusionLength() const +{ + Q_D(const QExtrudedTextGeometry); + return d->m_depth; +} + +/*! + * \property QExtrudedTextGeometry::positionAttribute + * + * Holds the geometry position attribute. + */ +Qt3DRender::QAttribute *QExtrudedTextGeometry::positionAttribute() const +{ + Q_D(const QExtrudedTextGeometry); + return d->m_positionAttribute; +} + +/*! + * \property QExtrudedTextMesh::normalAttribute + * + * Holds the geometry normal attribute. + */ +Qt3DRender::QAttribute *QExtrudedTextGeometry::normalAttribute() const +{ + Q_D(const QExtrudedTextGeometry); + return d->m_normalAttribute; +} + +/*! + * \property QExtrudedTextMesh::indexAttribute + * + * Holds the geometry index attribute. + */ +Qt3DRender::QAttribute *QExtrudedTextGeometry::indexAttribute() const +{ + Q_D(const QExtrudedTextGeometry); + return d->m_indexAttribute; +} + +} // Qt3DExtras + +QT_END_NAMESPACE diff --git a/src/extras/3dtext/qextrudedtextgeometry.h b/src/extras/3dtext/qextrudedtextgeometry.h new file mode 100644 index 000000000..594e20dee --- /dev/null +++ b/src/extras/3dtext/qextrudedtextgeometry.h @@ -0,0 +1,113 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3DEXTRAS_QEXTRUDEDTEXTGEOMETRY_H +#define QT3DEXTRAS_QEXTRUDEDTEXTGEOMETRY_H + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +class QAttribute; + +} // namespace Qt3DRender + +namespace Qt3DExtras { + +class QExtrudedTextGeometryPrivate; + +class QT3DEXTRASSHARED_EXPORT QExtrudedTextGeometry : public Qt3DRender::QGeometry +{ + Q_OBJECT + Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged) + Q_PROPERTY(QFont font READ font WRITE setFont NOTIFY fontChanged) + Q_PROPERTY(float extrusionLength READ extrusionLength WRITE setDepth NOTIFY depthChanged) + Q_PROPERTY(Qt3DRender::QAttribute *positionAttribute READ positionAttribute CONSTANT) + Q_PROPERTY(Qt3DRender::QAttribute *normalAttribute READ normalAttribute CONSTANT) + Q_PROPERTY(Qt3DRender::QAttribute *indexAttribute READ indexAttribute CONSTANT) + +public: + explicit QExtrudedTextGeometry(Qt3DCore::QNode *parent = nullptr); + ~QExtrudedTextGeometry(); + + Qt3DRender::QAttribute *positionAttribute() const; + Qt3DRender::QAttribute *normalAttribute() const; + Qt3DRender::QAttribute *indexAttribute() const; + QString text() const; + QFont font() const; + float extrusionLength() const; + +public Q_SLOTS: + void setText(QString text); + void setFont(QFont font); + void setDepth(float extrusionLength); + +Q_SIGNALS: + void textChanged(QString text); + void fontChanged(QFont font); + void depthChanged(float extrusionLength); + +protected: + QExtrudedTextGeometry(QExtrudedTextGeometryPrivate &dd, QNode *parent = nullptr); + +private: + Q_DECLARE_PRIVATE(QExtrudedTextGeometry) +}; + +} // namespace Qt3DExtras + +QT_END_NAMESPACE + +#endif // QT3DEXTRAS_QEXTRUDEDTEXTGEOMETRY_H diff --git a/src/extras/3dtext/qextrudedtextgeometry_p.h b/src/extras/3dtext/qextrudedtextgeometry_p.h new file mode 100644 index 000000000..0bfa45e17 --- /dev/null +++ b/src/extras/3dtext/qextrudedtextgeometry_p.h @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3DEXTRAS_QEXTRUDEDTEXTGEOMETRY_P_H +#define QT3DEXTRAS_QEXTRUDEDTEXTGEOMETRY_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +class QAttribute; +class QBuffer; + +} // namespace Qt3DRender + +namespace Qt3DExtras { + +class QExtrudedTextGeometry; + +class QExtrudedTextGeometryPrivate : public Qt3DRender::QGeometryPrivate +{ +public: + QExtrudedTextGeometryPrivate(); + void init(); + void update(); + + QString m_text; + QFont m_font; + float m_depth; + float m_edgeSplitAngle; + + Qt3DRender::QAttribute *m_positionAttribute; + Qt3DRender::QAttribute *m_normalAttribute; + Qt3DRender::QAttribute *m_indexAttribute; + Qt3DRender::QBuffer *m_vertexBuffer; + Qt3DRender::QBuffer *m_indexBuffer; + + Q_DECLARE_PUBLIC(QExtrudedTextGeometry) +}; + +} // namespace Qt3DExtras + +QT_END_NAMESPACE + +#endif // QT3DEXTRAS_QEXTRUDEDTEXTGEOMETRY_P_H diff --git a/src/extras/3dtext/qextrudedtextmesh.cpp b/src/extras/3dtext/qextrudedtextmesh.cpp new file mode 100644 index 000000000..ef31989ab --- /dev/null +++ b/src/extras/3dtext/qextrudedtextmesh.cpp @@ -0,0 +1,157 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qextrudedtextmesh.h" +#include "qextrudedtextgeometry.h" + +QT_BEGIN_NAMESPACE + +namespace Qt3DExtras { + +/*! + * \qmltype ExtrudedTextMesh + * \instantiates Qt3DExtras::QExtrudedTextMesh + * \inqmlmodule Qt3D.Extras + * \brief A 3D extruded Text mesh. + */ + +/*! + * \qmlproperty QString ExtrudedTextMesh::text + * + * Holds the text used for the mesh. + */ + +/*! + * \qmlproperty QFont ExtrudedTextMesh::font + * + * Holds the font of the text. + */ + +/*! + * \qmlproperty float ExtrudedTextMesh::depth + * + * Holds the extrusion depth of the text. + */ + +/*! + * \class Qt3DExtras::QExtrudedTextMesh + * \inheaderfile Qt3DExtras/QExtrudedTextMesh + * \inmodule Qt3DExtras + * + * \inherits Qt3DRender::QGeometryRenderer + * + * \brief A 3D extruded Text mesh. + */ + +/*! + * Constructs a new QText3DMesh with \a parent. + */ +QExtrudedTextMesh::QExtrudedTextMesh(Qt3DCore::QNode *parent) + : QGeometryRenderer(parent) +{ + QExtrudedTextGeometry *geometry = new QExtrudedTextGeometry(); + QObject::connect(geometry, &QExtrudedTextGeometry::depthChanged, this, &QExtrudedTextMesh::depthChanged); + QObject::connect(geometry, &QExtrudedTextGeometry::textChanged, this, &QExtrudedTextMesh::textChanged); + QObject::connect(geometry, &QExtrudedTextGeometry::fontChanged, this, &QExtrudedTextMesh::fontChanged); + QGeometryRenderer::setGeometry(geometry); +} + +/*! \internal */ +QExtrudedTextMesh::~QExtrudedTextMesh() +{} + +void QExtrudedTextMesh::setText(QString text) +{ + static_cast(geometry())->setText(text); +} + +void QExtrudedTextMesh::setFont(QFont font) +{ + static_cast(geometry())->setFont(font); +} + +void QExtrudedTextMesh::setDepth(float depth) +{ + static_cast(geometry())->setDepth(depth); +} + +/*! + * \property QString QExtrudedTextMesh::text + * + * Holds the text used for the mesh. + */ +QString QExtrudedTextMesh::text() +{ + return static_cast(geometry())->text(); +} + +/*! + * \property QFont QExtrudedTextMesh::font + * + * Holds the font of the text. + */ +QFont QExtrudedTextMesh::font() +{ + return static_cast(geometry())->font(); +} + +/*! + * \property float QExtrudedTextMesh::depth + * + * Holds the extrusion depth of the text. + */ +float QExtrudedTextMesh::depth() +{ + return static_cast(geometry())->extrusionLength(); +} + +} // namespace Qt3DExtras + +QT_END_NAMESPACE diff --git a/src/extras/3dtext/qextrudedtextmesh.h b/src/extras/3dtext/qextrudedtextmesh.h new file mode 100644 index 000000000..9e14cca13 --- /dev/null +++ b/src/extras/3dtext/qextrudedtextmesh.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3DEXTRAS_QEXTRUDEDTEXTMESH_H +#define QT3DEXTRAS_QEXTRUDEDTEXTMESH_H + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DExtras { + +class QT3DEXTRASSHARED_EXPORT QExtrudedTextMesh : public Qt3DRender::QGeometryRenderer +{ + Q_OBJECT + Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged) + Q_PROPERTY(QFont font READ font WRITE setFont NOTIFY fontChanged) + Q_PROPERTY(float depth READ depth WRITE setDepth NOTIFY depthChanged) + +public: + QExtrudedTextMesh(Qt3DCore::QNode *parent = nullptr); + ~QExtrudedTextMesh(); + + QString text(); + QFont font(); + float depth(); + +public Q_SLOTS: + void setText(QString text); + void setFont(QFont font); + void setDepth(float depth); + +Q_SIGNALS: + void textChanged(QString text); + void fontChanged(QFont font); + void depthChanged(float depth); +}; + +} // namespace Qt3DExtras + +QT_END_NAMESPACE + +#endif // QT3DEXTRAS_QEXTRUDEDTEXTMESH_H diff --git a/src/extras/3dtext/qtext3dgeometry.cpp b/src/extras/3dtext/qtext3dgeometry.cpp deleted file mode 100644 index 49db6e4a6..000000000 --- a/src/extras/3dtext/qtext3dgeometry.cpp +++ /dev/null @@ -1,528 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt3D module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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. -** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qtext3dgeometry.h" -#include "qtext3dgeometry_p.h" -#include -#include -#include -#include -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE - -namespace Qt3DExtras { - -namespace { - -using IndexType = unsigned int; - -struct TriangulationData { - struct Outline { - int begin; - int end; - }; - - QVector vertices; - QVector indices; - QVector outlines; - QVector outlineIndices; - bool inverted; -}; - -TriangulationData triangulate(const QString &text, const QFont &font) -{ - TriangulationData result; - int beginOutline = 0; - - // Initialize path with text and extract polygons - QPainterPath path; - path.setFillRule(Qt::WindingFill); - path.addText(0, 0, font, text); - QList polygons = path.toSubpathPolygons(QTransform().scale(1.f, -1.f)); - - // maybe glyph has no geometry - if (polygons.size() == 0) - return result; - - const int prevNumIndices = result.indices.size(); - - // Reset path and add previously extracted polygons (which where spatially transformed) - path = QPainterPath(); - path.setFillRule(Qt::WindingFill); - for (QPolygonF &p : polygons) - path.addPolygon(p); - - // Extract polylines out of the path, this allows us to retrive indicies for each glyph outline - QPolylineSet polylines = qPolyline(path); - QVector tmpIndices; - tmpIndices.resize(polylines.indices.size()); - memcpy(tmpIndices.data(), polylines.indices.data(), polylines.indices.size() * sizeof(IndexType)); - - int lastIndex = 0; - for (const IndexType idx : tmpIndices) { - if (idx == std::numeric_limits::max()) { - const int endOutline = lastIndex; - result.outlines.push_back({beginOutline, endOutline}); - beginOutline = endOutline; - } else { - result.outlineIndices.push_back(idx); - ++lastIndex; - } - } - - // Triangulate path - const QTriangleSet triangles = qTriangulate(path); - - // Append new indices to result.indices buffer - result.indices.resize(result.indices.size() + triangles.indices.size()); - memcpy(&result.indices[prevNumIndices], triangles.indices.data(), triangles.indices.size() * sizeof(IndexType)); - for (int i = prevNumIndices, m = result.indices.size(); i < m; ++i) - result.indices[i] += result.vertices.size(); - - // Append new triangles to result.vertices - result.vertices.reserve(triangles.vertices.size() / 2); - for (int i = 0, m = triangles.vertices.size(); i < m; i += 2) - result.vertices.push_back(QVector3D(triangles.vertices[i] / font.pointSizeF(), triangles.vertices[i + 1] / font.pointSizeF(), 0.0f)); - - return result; -} - -inline QVector3D mix(const QVector3D &a, const QVector3D &b, float ratio) -{ - return a + (b - a) * ratio; -} - -} // anonymous namespace - -QText3DGeometryPrivate::QText3DGeometryPrivate() - : QGeometryPrivate() - , m_font(QFont(QStringLiteral("Arial"))) - , m_depth(1.f) - , m_edgeSplitAngle(90.f * 0.1f) - , m_positionAttribute(nullptr) - , m_normalAttribute(nullptr) - , m_indexAttribute(nullptr) - , m_vertexBuffer(nullptr) - , m_indexBuffer(nullptr) -{ - m_font.setPointSize(4); -} - -void QText3DGeometryPrivate::init() -{ - Q_Q(QText3DGeometry); - m_positionAttribute = new Qt3DRender::QAttribute(q); - m_normalAttribute = new Qt3DRender::QAttribute(q); - m_indexAttribute = new Qt3DRender::QAttribute(q); - m_vertexBuffer = new Qt3DRender::QBuffer(Qt3DRender::QBuffer::VertexBuffer, q); - m_indexBuffer = new Qt3DRender::QBuffer(Qt3DRender::QBuffer::IndexBuffer, q); - - const quint32 elementSize = 3 + 3; - const quint32 stride = elementSize * sizeof(float); - - m_positionAttribute->setName(Qt3DRender::QAttribute::defaultPositionAttributeName()); - m_positionAttribute->setVertexBaseType(Qt3DRender::QAttribute::Float); - m_positionAttribute->setVertexSize(3); - m_positionAttribute->setAttributeType(Qt3DRender::QAttribute::VertexAttribute); - m_positionAttribute->setBuffer(m_vertexBuffer); - m_positionAttribute->setByteStride(stride); - m_positionAttribute->setByteOffset(0); - m_positionAttribute->setCount(0); - - m_normalAttribute->setName(Qt3DRender::QAttribute::defaultNormalAttributeName()); - m_normalAttribute->setVertexBaseType(Qt3DRender::QAttribute::Float); - m_normalAttribute->setVertexSize(3); - m_normalAttribute->setAttributeType(Qt3DRender::QAttribute::VertexAttribute); - m_normalAttribute->setBuffer(m_vertexBuffer); - m_normalAttribute->setByteStride(stride); - m_normalAttribute->setByteOffset(3 * sizeof(float)); - m_normalAttribute->setCount(0); - - m_indexAttribute->setAttributeType(Qt3DRender::QAttribute::IndexAttribute); - m_indexAttribute->setVertexBaseType(Qt3DRender::QAttribute::UnsignedInt); - m_indexAttribute->setBuffer(m_indexBuffer); - m_indexAttribute->setCount(0); - - q->addAttribute(m_positionAttribute); - q->addAttribute(m_normalAttribute); - q->addAttribute(m_indexAttribute); - - update(); -} - -/*! - * \qmltype Text3DGeometry - * \instantiates Qt3DExtras::QText3DGeometry - * \inqmlmodule Qt3D.Extras - * \brief Text3DGeometry allows creation of a 3D text in 3D space. - * - * The Text3DGeometry type is most commonly used internally by the Text3DMesh type - * but can also be used in custom GeometryRenderer types. - */ - -/*! - * \qmlproperty QString Text3DGeometry::text - * - * Holds the text used for the mesh. - */ - -/*! - * \qmlproperty QFont Text3DGeometry::font - * - * Holds the font of the text. - */ - -/*! - * \qmlproperty float Text3DGeometry::depth - * - * Holds the extrusion depth of the text. - */ - -/*! - * \qmlproperty float Text3DGeometry::edgeSplitAngle - * - * Holds the threshold angle for smooth normals. - */ - -/*! - * \qmlproperty Attribute Text3DGeometry::positionAttribute - * - * Holds the geometry position attribute. - */ - -/*! - * \qmlproperty Attribute Text3DGeometry::normalAttribute - * - * Holds the geometry normal attribute. - */ - -/*! - * \qmlproperty Attribute Text3DGeometry::indexAttribute - * - * Holds the geometry index attribute. - */ - -/*! - * \class Qt3DExtras::QText3DGeometry - * \inheaderfile Qt3DExtras/QText3DGeometry - * \inmodule Qt3DExtras - * \brief The QText3DGeometry class allows creation of a 3D text in 3D space. - * \since 5.8 - * \ingroup geometries - * \inherits Qt3DRender::QGeometry - * - * The QText3DGeometry class is most commonly used internally by the QText3DMesh - * but can also be used in custom Qt3DRender::QGeometryRenderer subclasses. - */ - -/*! - * Constructs a new QText3DGeometry with \a parent. - */ -QText3DGeometry::QText3DGeometry(Qt3DCore::QNode *parent) - : QGeometry(*new QText3DGeometryPrivate(), parent) -{ - Q_D(QText3DGeometry); - d->init(); -} - -/*! - * \internal - */ -QText3DGeometry::QText3DGeometry(QText3DGeometryPrivate &dd, Qt3DCore::QNode *parent) - : QGeometry(dd, parent) -{ - Q_D(QText3DGeometry); - d->init(); -} - -/*! - * \internal - */ -QText3DGeometry::~QText3DGeometry() -{} - -/*! - * \internal - * Updates vertices based on text, font, depth and smoothAngle properties. - */ -void QText3DGeometryPrivate::update() -{ - if (m_text.trimmed().isEmpty()) // save enough? - return; - - TriangulationData data = triangulate(m_text, m_font); - - const int numVertices = data.vertices.size(); - const int numIndices = data.indices.size(); - - struct Vertex { - QVector3D position; - QVector3D normal; - }; - - QVector indices; - QVector vertices; - - // TODO: keep 'vertices.size()' small when extruding - vertices.reserve(data.vertices.size() * 2); - for (QVector3D &v : data.vertices) // front face - vertices.push_back({ v, // vertex - QVector3D(0.0f, 0.0f, -1.0f) }); // normal - for (QVector3D &v : data.vertices) // front face - vertices.push_back({ QVector3D(v.x(), v.y(), m_depth), // vertex - QVector3D(0.0f, 0.0f, 1.0f) }); // normal - - for (int i = 0, verticesIndex = vertices.size(); i < data.outlines.size(); ++i) { - const int begin = data.outlines[i].begin; - const int end = data.outlines[i].end; - const int verticesIndexBegin = verticesIndex; - - if (begin == end) - continue; - - QVector3D prevNormal = QVector3D::crossProduct( - vertices[data.outlineIndices[end - 1] + numVertices].position - vertices[data.outlineIndices[end - 1]].position, - vertices[data.outlineIndices[begin]].position - vertices[data.outlineIndices[end - 1]].position).normalized(); - - for (int j = begin; j < end; ++j) { - const bool isLastIndex = (j == end - 1); - const IndexType cur = data.outlineIndices[j]; - const IndexType next = data.outlineIndices[((j - begin + 1) % (end - begin)) + begin]; // normalize, bring in range and adjust - const QVector3D normal = QVector3D::crossProduct(vertices[cur + numVertices].position - vertices[cur].position, vertices[next].position - vertices[cur].position).normalized(); - - // use smooth normals in case of a short angle - const bool smooth = QVector3D::dotProduct(prevNormal, normal) > (90.0f - m_edgeSplitAngle) / 90.0f; - const QVector3D resultNormal = smooth ? mix(prevNormal, normal, 0.5f) : normal; - if (!smooth) { - vertices.push_back({vertices[cur].position, prevNormal}); - vertices.push_back({vertices[cur + numVertices].position, prevNormal}); - verticesIndex += 2; - } - - vertices.push_back({vertices[cur].position, resultNormal}); - vertices.push_back({vertices[cur + numVertices].position, resultNormal}); - - const int v0 = verticesIndex; - const int v1 = verticesIndex + 1; - const int v2 = isLastIndex ? verticesIndexBegin : verticesIndex + 2; - const int v3 = isLastIndex ? verticesIndexBegin + 1 : verticesIndex + 3; - - indices.push_back(v0); - indices.push_back(v1); - indices.push_back(v2); - indices.push_back(v2); - indices.push_back(v1); - indices.push_back(v3); - - verticesIndex += 2; - prevNormal = normal; - } - } - - { // upload vertices - QByteArray data; - data.resize(vertices.size() * sizeof(Vertex)); - memcpy(data.data(), vertices.data(), vertices.size() * sizeof(Vertex)); - - m_vertexBuffer->setData(data); - m_positionAttribute->setCount(vertices.size()); - m_normalAttribute->setCount(vertices.size()); - } - - // resize for following insertions - const int indicesOffset = indices.size(); - indices.resize(indices.size() + numIndices * 2); - - // copy values for back faces - IndexType *indicesFaces = indices.data() + indicesOffset; - memcpy(indicesFaces, data.indices.data(), numIndices * sizeof(IndexType)); - - // insert values for front face and flip triangles - for (int j = 0; j < numIndices; j += 3) - { - indicesFaces[numIndices + j ] = indicesFaces[j ] + numVertices; - indicesFaces[numIndices + j + 1] = indicesFaces[j + 2] + numVertices; - indicesFaces[numIndices + j + 2] = indicesFaces[j + 1] + numVertices; - } - - { // upload indices - QByteArray data; - data.resize(indices.size() * sizeof(IndexType)); - memcpy(data.data(), indices.data(), indices.size() * sizeof(IndexType)); - - m_indexBuffer->setData(data); - m_indexAttribute->setCount(indices.size()); - } -} - -void QText3DGeometry::setText(QString text) -{ - Q_D(QText3DGeometry); - if (d->m_text != text) { - d->m_text = text; - d->update(); - emit textChanged(text); - } -} - -void QText3DGeometry::setFont(QFont font) -{ - Q_D(QText3DGeometry); - if (d->m_font != font) { - d->m_font = font; - d->update(); - emit fontChanged(font); - } -} - -void QText3DGeometry::setDepth(float depth) -{ - Q_D(QText3DGeometry); - if (d->m_depth != depth) { - d->m_depth = depth; - d->update(); - emit depthChanged(depth); - } -} - -void QText3DGeometry::setEdgeSplitAngle(float smoothAngle) -{ - Q_D(QText3DGeometry); - if (d->m_edgeSplitAngle != smoothAngle) { - d->m_edgeSplitAngle = smoothAngle; - d->update(); - emit edgeSplitAngleChanged(smoothAngle); - } -} - -/*! - * \property QString Text3DGeometry::text - * - * Holds the text used for the mesh. - */ -QString QText3DGeometry::text() const -{ - Q_D(const QText3DGeometry); - return d->m_text; -} - -/*! - * \property QFont Text3DGeometry::font - * - * Holds the font of the text. - */ -QFont QText3DGeometry::font() const -{ - Q_D(const QText3DGeometry); - return d->m_font; -} - -/*! - * \property float Text3DGeometry::depth - * - * Holds the extrusion depth of the text. - */ -float QText3DGeometry::depth() const -{ - Q_D(const QText3DGeometry); - return d->m_depth; -} - -/*! - * \property float Text3DGeometry::edgeSplitAngle - * - * Holds the threshold angle for smooth normals. - */ -float QText3DGeometry::edgeSplitAngle() const -{ - Q_D(const QText3DGeometry); - return d->m_edgeSplitAngle; -} - -/*! - * \property Text3DGeometry::positionAttribute - * - * Holds the geometry position attribute. - */ -Qt3DRender::QAttribute *QText3DGeometry::positionAttribute() const -{ - Q_D(const QText3DGeometry); - return d->m_positionAttribute; -} - -/*! - * \property Text3DGeometry::normalAttribute - * - * Holds the geometry normal attribute. - */ -Qt3DRender::QAttribute *QText3DGeometry::normalAttribute() const -{ - Q_D(const QText3DGeometry); - return d->m_normalAttribute; -} - -/*! - * \property Text3DGeometry::indexAttribute - * - * Holds the geometry index attribute. - */ -Qt3DRender::QAttribute *QText3DGeometry::indexAttribute() const -{ - Q_D(const QText3DGeometry); - return d->m_indexAttribute; -} - -} // Qt3DExtras - -QT_END_NAMESPACE diff --git a/src/extras/3dtext/qtext3dgeometry.h b/src/extras/3dtext/qtext3dgeometry.h deleted file mode 100644 index 4cd89b112..000000000 --- a/src/extras/3dtext/qtext3dgeometry.h +++ /dev/null @@ -1,117 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt3D module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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. -** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QT3DEXTRAS_QTEXT3DGEOMETRY_H -#define QT3DEXTRAS_QTEXT3DGEOMETRY_H - -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE - -namespace Qt3DRender { - -class QAttribute; - -} // namespace Qt3DRender - -namespace Qt3DExtras { - -class QText3DGeometryPrivate; - -class QT3DEXTRASSHARED_EXPORT QText3DGeometry : public Qt3DRender::QGeometry -{ - Q_OBJECT - Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged) - Q_PROPERTY(QFont font READ font WRITE setFont NOTIFY fontChanged) - Q_PROPERTY(float depth READ depth WRITE setDepth NOTIFY depthChanged) - Q_PROPERTY(float edgeSplitAngle READ edgeSplitAngle WRITE setEdgeSplitAngle NOTIFY edgeSplitAngleChanged) - Q_PROPERTY(Qt3DRender::QAttribute *positionAttribute READ positionAttribute CONSTANT) - Q_PROPERTY(Qt3DRender::QAttribute *normalAttribute READ normalAttribute CONSTANT) - Q_PROPERTY(Qt3DRender::QAttribute *indexAttribute READ indexAttribute CONSTANT) - -public: - explicit QText3DGeometry(Qt3DCore::QNode *parent = nullptr); - ~QText3DGeometry(); - - Qt3DRender::QAttribute *positionAttribute() const; - Qt3DRender::QAttribute *normalAttribute() const; - Qt3DRender::QAttribute *indexAttribute() const; - QString text() const; - QFont font() const; - float depth() const; - float edgeSplitAngle() const; - -public Q_SLOTS: - void setText(QString text); - void setFont(QFont font); - void setDepth(float depth); - void setEdgeSplitAngle(float edgeSplitAngle); - -Q_SIGNALS: - void textChanged(QString text); - void fontChanged(QFont font); - void depthChanged(float depth); - void edgeSplitAngleChanged(float edgeSplitAngle); - -protected: - QText3DGeometry(QText3DGeometryPrivate &dd, QNode *parent = nullptr); - -private: - Q_DECLARE_PRIVATE(QText3DGeometry) -}; - -} // namespace Qt3DExtras - -QT_END_NAMESPACE - -#endif // QT3DEXTRAS_QTEXT3DGEOMETRY_H diff --git a/src/extras/3dtext/qtext3dgeometry_p.h b/src/extras/3dtext/qtext3dgeometry_p.h deleted file mode 100644 index dc5e2f6a7..000000000 --- a/src/extras/3dtext/qtext3dgeometry_p.h +++ /dev/null @@ -1,106 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt3D module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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. -** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QT3DEXTRAS_QTEXT3DGEOMETRY_P_H -#define QT3DEXTRAS_QTEXT3DGEOMETRY_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include -#include - -QT_BEGIN_NAMESPACE - -namespace Qt3DRender { - -class QAttribute; -class QBuffer; - -} // namespace Qt3DRender - -namespace Qt3DExtras { - -class QText3DGeometry; - -class QText3DGeometryPrivate : public Qt3DRender::QGeometryPrivate -{ -public: - QText3DGeometryPrivate(); - void init(); - void update(); - - QString m_text; - QFont m_font; - float m_depth; - float m_edgeSplitAngle; - - Qt3DRender::QAttribute *m_positionAttribute; - Qt3DRender::QAttribute *m_normalAttribute; - Qt3DRender::QAttribute *m_indexAttribute; - Qt3DRender::QBuffer *m_vertexBuffer; - Qt3DRender::QBuffer *m_indexBuffer; - - Q_DECLARE_PUBLIC(QText3DGeometry) -}; - -} // namespace Qt3DExtras - -QT_END_NAMESPACE - -#endif // QT3DEXTRAS_QTEXT3DGEOMETRY_P_H diff --git a/src/extras/3dtext/qtext3dmesh.cpp b/src/extras/3dtext/qtext3dmesh.cpp deleted file mode 100644 index a89c01a4d..000000000 --- a/src/extras/3dtext/qtext3dmesh.cpp +++ /dev/null @@ -1,179 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt3D module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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. -** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qtext3dmesh.h" -#include "qtext3dgeometry.h" - -QT_BEGIN_NAMESPACE - -namespace Qt3DExtras { - -/*! - * \qmltype Text3DMesh - * \instantiates Qt3DExtras::QText3DMesh - * \inqmlmodule Qt3D.Extras - * \brief A 3D Text mesh. - */ - -/*! - * \qmlproperty QString Text3DMesh::text - * - * Holds the text used for the mesh. - */ - -/*! - * \qmlproperty QFont Text3DMesh::font - * - * Holds the font of the text. - */ - -/*! - * \qmlproperty float Text3DMesh::depth - * - * Holds the extrusion depth of the text. - */ - -/*! - * \qmlproperty float Text3DMesh::edgeSplitAngle - * - * Holds the threshold angle for smooth normals. - */ - -/*! - * \class Qt3DExtras::QText3DMesh - * \inheaderfile Qt3DExtras/QText3DMesh - * \inmodule Qt3DExtras - * - * \inherits Qt3DRender::QGeometryRenderer - * - * \brief A 3D Text mesh. - */ - -/*! - * Constructs a new QText3DMesh with \a parent. - */ -QText3DMesh::QText3DMesh(Qt3DCore::QNode *parent) - : QGeometryRenderer(parent) -{ - QText3DGeometry *geometry = new QText3DGeometry(); - QObject::connect(geometry, &QText3DGeometry::depthChanged, this, &QText3DMesh::depthChanged); - QObject::connect(geometry, &QText3DGeometry::textChanged, this, &QText3DMesh::textChanged); - QObject::connect(geometry, &QText3DGeometry::fontChanged, this, &QText3DMesh::fontChanged); - QObject::connect(geometry, &QText3DGeometry::edgeSplitAngleChanged, this, &QText3DMesh::edgeSplitAngleChanged); - QGeometryRenderer::setGeometry(geometry); -} - -/*! \internal */ -QText3DMesh::~QText3DMesh() -{} - -void QText3DMesh::setText(QString text) -{ - static_cast(geometry())->setText(text); -} - -void QText3DMesh::setFont(QFont font) -{ - static_cast(geometry())->setFont(font); -} - -void QText3DMesh::setDepth(float depth) -{ - static_cast(geometry())->setDepth(depth); -} - -void QText3DMesh::setEdgeSplitAngle(float smoothAngle) -{ - static_cast(geometry())->setEdgeSplitAngle(smoothAngle); -} - -/*! - * \property QString QText3DMesh::text - * - * Holds the text used for the mesh. - */ -QString QText3DMesh::text() -{ - return static_cast(geometry())->text(); -} - -/*! - * \property QFont QText3DMesh::font - * - * Holds the font of the text. - */ -QFont QText3DMesh::font() -{ - return static_cast(geometry())->font(); -} - -/*! - * \property float QText3DMesh::depth - * - * Holds the extrusion depth of the text. - */ -float QText3DMesh::depth() -{ - return static_cast(geometry())->depth(); -} - -/*! - * \property float QText3DMesh::edgeSplitAngle - * - * Holds the threshold angle for smooth normals. - */ -float QText3DMesh::edgeSplitAngle() -{ - return static_cast(geometry())->edgeSplitAngle(); -} - -} // namespace Qt3DExtras - -QT_END_NAMESPACE diff --git a/src/extras/3dtext/qtext3dmesh.h b/src/extras/3dtext/qtext3dmesh.h deleted file mode 100644 index 6bb546675..000000000 --- a/src/extras/3dtext/qtext3dmesh.h +++ /dev/null @@ -1,97 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt3D module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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. -** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QT3DEXTRAS_QTEXT3DMESH_H -#define QT3DEXTRAS_QTEXT3DMESH_H - -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE - -namespace Qt3DExtras { - -class QT3DEXTRASSHARED_EXPORT QText3DMesh : public Qt3DRender::QGeometryRenderer -{ - Q_OBJECT - Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged) - Q_PROPERTY(QFont font READ font WRITE setFont NOTIFY fontChanged) - Q_PROPERTY(float depth READ depth WRITE setDepth NOTIFY depthChanged) - Q_PROPERTY(float edgeSplitAngle READ edgeSplitAngle WRITE setEdgeSplitAngle NOTIFY edgeSplitAngleChanged) - -public: - QText3DMesh(Qt3DCore::QNode *parent = nullptr); - ~QText3DMesh(); - - QString text(); - QFont font(); - float depth(); - float edgeSplitAngle(); - -public Q_SLOTS: - void setText(QString text); - void setFont(QFont font); - void setDepth(float depth); - void setEdgeSplitAngle(float edgeSplitAngle); - -Q_SIGNALS: - void textChanged(QString text); - void fontChanged(QFont font); - void depthChanged(float depth); - void edgeSplitAngleChanged(float edgeSplitAngle); -}; - -} // namespace Qt3DExtras - -QT_END_NAMESPACE - -#endif // QT3DEXTRAS_QTEXT3DMESH_H diff --git a/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp b/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp index 62cb1f55e..7bf41828b 100644 --- a/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp +++ b/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp @@ -66,8 +66,8 @@ #include #include #include -#include -#include +#include +#include #include #include #include @@ -121,8 +121,8 @@ void Qt3DQuick3DExtrasPlugin::registerTypes(const char *uri) qmlRegisterType(uri, 2, 0, "SphereGeometry"); // 3D Text - qmlRegisterType(uri, 2, 2, "Text3DGeometry"); - qmlRegisterType(uri, 2, 2, "Text3DMesh"); + qmlRegisterType(uri, 2, 2, "ExtrudedTextGeometry"); + qmlRegisterType(uri, 2, 2, "ExtrudedTextMesh"); qmlRegisterType(uri, 2, 2, "DistanceFieldGlyphCache"); qmlRegisterType(uri, 2, 2, "DistanceFieldText"); -- cgit v1.2.3 From 4908bb231e32ecf0673f9f2dfa651e23fb3d325f Mon Sep 17 00:00:00 2001 From: Paul Lemire Date: Wed, 15 Feb 2017 10:36:48 +0000 Subject: QShaderProgram: rename enum ShaderStatus to Status Task-number: QTBUG-58896 Change-Id: I39be12a9fe00d3fd2e2f6074dd7f8df728ac1b7a Reviewed-by: Sean Harmer --- src/render/materialsystem/qshaderprogram.cpp | 6 +++--- src/render/materialsystem/qshaderprogram.h | 10 +++++----- src/render/materialsystem/qshaderprogram_p.h | 4 ++-- src/render/materialsystem/shader.cpp | 2 +- src/render/materialsystem/shader_p.h | 6 +++--- tests/auto/render/qshaderprogram/tst_qshaderprogram.cpp | 6 +++--- 6 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/render/materialsystem/qshaderprogram.cpp b/src/render/materialsystem/qshaderprogram.cpp index 35e8e25aa..2a65d257c 100644 --- a/src/render/materialsystem/qshaderprogram.cpp +++ b/src/render/materialsystem/qshaderprogram.cpp @@ -111,7 +111,7 @@ void QShaderProgramPrivate::setLog(const QString &log) } } -void QShaderProgramPrivate::setStatus(QShaderProgram::ShaderStatus status) +void QShaderProgramPrivate::setStatus(QShaderProgram::Status status) { Q_Q(QShaderProgram); if (status != m_status) { @@ -145,7 +145,7 @@ void QShaderProgram::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) if (e->propertyName() == QByteArrayLiteral("log")) d->setLog(e->value().toString()); else if (e->propertyName() == QByteArrayLiteral("status")) - d->setStatus(static_cast(e->value().toInt())); + d->setStatus(static_cast(e->value().toInt())); } } @@ -381,7 +381,7 @@ QString QShaderProgram::log() const Holds the status of the current shader program. */ -QShaderProgram::ShaderStatus QShaderProgram::status() const +QShaderProgram::Status QShaderProgram::status() const { Q_D(const QShaderProgram); return d->m_status; diff --git a/src/render/materialsystem/qshaderprogram.h b/src/render/materialsystem/qshaderprogram.h index dd90a7d07..a5bee7d5f 100644 --- a/src/render/materialsystem/qshaderprogram.h +++ b/src/render/materialsystem/qshaderprogram.h @@ -59,7 +59,7 @@ class QT3DRENDERSHARED_EXPORT QShaderProgram : public Qt3DCore::QNode Q_PROPERTY(QByteArray fragmentShaderCode READ fragmentShaderCode WRITE setFragmentShaderCode NOTIFY fragmentShaderCodeChanged) Q_PROPERTY(QByteArray computeShaderCode READ computeShaderCode WRITE setComputeShaderCode NOTIFY computeShaderCodeChanged) Q_PROPERTY(QString log READ log NOTIFY logChanged) - Q_PROPERTY(ShaderStatus status READ status NOTIFY statusChanged) + Q_PROPERTY(Status status READ status NOTIFY statusChanged) public: explicit QShaderProgram(Qt3DCore::QNode *parent = nullptr); @@ -75,12 +75,12 @@ public: }; Q_ENUM(ShaderType) // LCOV_EXCL_LINE - enum ShaderStatus { + enum Status { NotReady = 0, Ready, Error }; - Q_ENUM(ShaderStatus) // LCOV_EXCL_LINE + Q_ENUM(Status) // LCOV_EXCL_LINE // Source code in-line QByteArray vertexShaderCode() const; @@ -94,7 +94,7 @@ public: QByteArray shaderCode(ShaderType type) const; QString log() const; - ShaderStatus status() const; + Status status() const; Q_INVOKABLE static QByteArray loadSource(const QUrl &sourceUrl); @@ -114,7 +114,7 @@ Q_SIGNALS: void fragmentShaderCodeChanged(const QByteArray &fragmentShaderCode); void computeShaderCodeChanged(const QByteArray &computeShaderCode); void logChanged(const QString &log); - void statusChanged(ShaderStatus status); + void statusChanged(Status status); protected: explicit QShaderProgram(QShaderProgramPrivate &dd, Qt3DCore::QNode *parent = nullptr); diff --git a/src/render/materialsystem/qshaderprogram_p.h b/src/render/materialsystem/qshaderprogram_p.h index 171cd8724..6bdde68f1 100644 --- a/src/render/materialsystem/qshaderprogram_p.h +++ b/src/render/materialsystem/qshaderprogram_p.h @@ -77,10 +77,10 @@ public: QByteArray m_fragmentShaderCode; QByteArray m_computeShaderCode; QString m_log; - QShaderProgram::ShaderStatus m_status; + QShaderProgram::Status m_status; void setLog(const QString &log); - void setStatus(QShaderProgram::ShaderStatus status); + void setStatus(QShaderProgram::Status status); }; struct QShaderProgramData diff --git a/src/render/materialsystem/shader.cpp b/src/render/materialsystem/shader.cpp index 02f58dfbc..69d22297a 100644 --- a/src/render/materialsystem/shader.cpp +++ b/src/render/materialsystem/shader.cpp @@ -447,7 +447,7 @@ void Shader::setLog(const QString &log) } } -void Shader::setStatus(QShaderProgram::ShaderStatus status) +void Shader::setStatus(QShaderProgram::Status status) { if (status != m_status) { m_status = status; diff --git a/src/render/materialsystem/shader_p.h b/src/render/materialsystem/shader_p.h index 625abe847..b5127f5ec 100644 --- a/src/render/materialsystem/shader_p.h +++ b/src/render/materialsystem/shader_p.h @@ -119,7 +119,7 @@ public: ShaderStorageBlock storageBlockForBlockName(const QString &blockName); inline QString log() const { return m_log; } - inline QShaderProgram::ShaderStatus status() const { return m_status; } + inline QShaderProgram::Status status() const { return m_status; } void submitPendingNotifications(); inline bool hasPendingNotifications() const { return !m_pendingNotifications.empty(); } @@ -155,7 +155,7 @@ private: GraphicsContext *m_graphicsContext; QMetaObject::Connection m_contextConnection; QString m_log; - QShaderProgram::ShaderStatus m_status; + QShaderProgram::Status m_status; QVector m_pendingNotifications; @@ -169,7 +169,7 @@ private: void initializeFromReference(const Shader &other); void setLog(const QString &log); - void setStatus(QShaderProgram::ShaderStatus status); + void setStatus(QShaderProgram::Status status); friend class GraphicsContext; }; diff --git a/tests/auto/render/qshaderprogram/tst_qshaderprogram.cpp b/tests/auto/render/qshaderprogram/tst_qshaderprogram.cpp index e5d001759..901ee7349 100644 --- a/tests/auto/render/qshaderprogram/tst_qshaderprogram.cpp +++ b/tests/auto/render/qshaderprogram/tst_qshaderprogram.cpp @@ -481,11 +481,11 @@ private Q_SLOTS: void checkStatusPropertyUpdate() { // GIVEN - qRegisterMetaType("ShaderStatus"); + qRegisterMetaType("Status"); TestArbiter arbiter; arbiter.setArbiterOnNode(this); - QSignalSpy spy(this, SIGNAL(statusChanged(ShaderStatus))); - const Qt3DRender::QShaderProgram::ShaderStatus newStatus = Qt3DRender::QShaderProgram::Error; + QSignalSpy spy(this, SIGNAL(statusChanged(Status))); + const Qt3DRender::QShaderProgram::Status newStatus = Qt3DRender::QShaderProgram::Error; // THEN QVERIFY(spy.isValid()); -- cgit v1.2.3 From b3e5096537007b110536d1d9b6dcd895d1d26f22 Mon Sep 17 00:00:00 2001 From: Paul Lemire Date: Thu, 16 Feb 2017 08:17:29 +0000 Subject: Quick3DChannelMapper: make mappings the default property Task-number: QTBUG-58900 Change-Id: Ie3bdb17d03242c22bf899aa4addcace03927bac9 Reviewed-by: Sean Harmer --- src/quick3d/quick3danimation/items/quick3dchannelmapper_p.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/quick3d/quick3danimation/items/quick3dchannelmapper_p.h b/src/quick3d/quick3danimation/items/quick3dchannelmapper_p.h index fddaae72d..e44efad68 100644 --- a/src/quick3d/quick3danimation/items/quick3dchannelmapper_p.h +++ b/src/quick3d/quick3danimation/items/quick3dchannelmapper_p.h @@ -66,6 +66,8 @@ class QT3DQUICKANIMATIONSHARED_PRIVATE_EXPORT Quick3DChannelMapper : public QOb { Q_OBJECT Q_PROPERTY(QQmlListProperty mappings READ qmlMappings CONSTANT) + Q_CLASSINFO("DefaultProperty", "mappings") + public: explicit Quick3DChannelMapper(QObject *parent = nullptr); -- cgit v1.2.3 From a8b868918beaa7349bdcfc42f688553a3007ffdb Mon Sep 17 00:00:00 2001 From: Paul Lemire Date: Wed, 15 Feb 2017 09:09:05 +0000 Subject: QBuffer: change access type enum values Task-number: QTBUG-58875 Change-Id: If764f69a7b47bd97a30eb9582c639a3cde7382d4 Reviewed-by: Kevin Ottens --- src/render/geometry/qbuffer.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/render/geometry/qbuffer.h b/src/render/geometry/qbuffer.h index a3facba39..c3ed650f0 100644 --- a/src/render/geometry/qbuffer.h +++ b/src/render/geometry/qbuffer.h @@ -89,9 +89,9 @@ public: Q_ENUM(UsageType) // LCOV_EXCL_LINE enum AccessType { - Write = 0x0, - Read = 0x1, - ReadWrite = 0x2 + Write = 0x1, + Read = 0x2, + ReadWrite = Write|Read }; Q_ENUM(AccessType) // LCOV_EXCL_LINE -- cgit v1.2.3 From 0b9f985454da517b0da01cb7df09cbe1d86e04ff Mon Sep 17 00:00:00 2001 From: Paul Lemire Date: Wed, 15 Feb 2017 09:15:33 +0000 Subject: Improve buffercapture-qml manual test Task-number: QTBUG-58875 Change-Id: Ic030e6b9ab5e40d1131b80aa0d0a5d30d74d72b6 Reviewed-by: Kevin Ottens --- tests/manual/buffercapture-qml/BufferSetterScene.qml | 6 +++--- tests/manual/buffercapture-qml/bufferSetter.comp | 2 +- tests/manual/buffercapture-qml/main.cpp | 5 ++--- tests/manual/buffercapture-qml/main.qml | 2 ++ 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/tests/manual/buffercapture-qml/BufferSetterScene.qml b/tests/manual/buffercapture-qml/BufferSetterScene.qml index 37f2858d6..530b73d43 100644 --- a/tests/manual/buffercapture-qml/BufferSetterScene.qml +++ b/tests/manual/buffercapture-qml/BufferSetterScene.qml @@ -60,8 +60,9 @@ Entity { Camera { id: sceneCamera projectionType: CameraLens.PerspectiveProjection - viewCenter: Qt.vector3d(0, 0, 0) + upVector: Qt.vector3d(0, 1, 0) position: Qt.vector3d(0, 0, -800) + viewCenter: Qt.vector3d(0, 0, 0) nearPlane: 0.1 farPlane: 1000 fieldOfView: 25 @@ -93,8 +94,7 @@ Entity { objectName: "buffer" type: Buffer.VertexBuffer data: initGraphBuffer() - access: Buffer.Read - onDataAvailable: access = Buffer.Write + access: Buffer.ReadWrite } ComputeMaterial { diff --git a/tests/manual/buffercapture-qml/bufferSetter.comp b/tests/manual/buffercapture-qml/bufferSetter.comp index 4fd99bf33..d7c383669 100755 --- a/tests/manual/buffercapture-qml/bufferSetter.comp +++ b/tests/manual/buffercapture-qml/bufferSetter.comp @@ -62,5 +62,5 @@ layout (location=1) uniform int inputSize; void main() { if (gl_GlobalInvocationID.x < inputSize) - d[gl_GlobalInvocationID.x] = gl_GlobalInvocationID.x; + d[gl_GlobalInvocationID.x] = d[gl_GlobalInvocationID.x] + gl_GlobalInvocationID.x * 2; } diff --git a/tests/manual/buffercapture-qml/main.cpp b/tests/manual/buffercapture-qml/main.cpp index cb6d6a489..6928c5724 100644 --- a/tests/manual/buffercapture-qml/main.cpp +++ b/tests/manual/buffercapture-qml/main.cpp @@ -66,7 +66,6 @@ int main(int argc, char* argv[]) view.setSource(QUrl("qrc:/main.qml")); - QObject *rootObject = view.rootObject(); Qt3DRender::QBuffer *buffer = rootObject->findChild("buffer"); @@ -74,9 +73,9 @@ int main(int argc, char* argv[]) [=](const QByteArray &bytes) { //I know I'm receiving int data const uint *data = reinterpret_cast(bytes.data()); - std::cout << "Data received" << std::endl; + qDebug() << "Data received"; for (uint i = 0; i < 1024; ++i) - std::cout << data[i] << std::endl; + qDebug() << data[i]; } ); diff --git a/tests/manual/buffercapture-qml/main.qml b/tests/manual/buffercapture-qml/main.qml index 95859b576..a2680e921 100644 --- a/tests/manual/buffercapture-qml/main.qml +++ b/tests/manual/buffercapture-qml/main.qml @@ -54,6 +54,8 @@ import Qt3D.Render 2.0 import QtQuick.Scene3D 2.0 Item { + width: 128 + height: width Scene3D { anchors.fill: parent BufferSetterScene { -- cgit v1.2.3 From b5f76df191c10dfcd0688fc79bd3af12dbe74bbb Mon Sep 17 00:00:00 2001 From: Kevin Ottens Date: Thu, 16 Feb 2017 11:15:54 +0100 Subject: Metal/Rough materials: metallic -> metalness Rename decided during API review in order to match with roughness. Change-Id: I4b1a13e6028ba410fb31a80e6c64f9539581f8c4 Task-Id: QTBUG-58894 Reviewed-by: Paul Lemire --- src/extras/defaults/qmetalroughmaterial.cpp | 20 ++++++------- src/extras/defaults/qmetalroughmaterial.h | 8 ++--- src/extras/defaults/qmetalroughmaterial_p.h | 2 +- .../defaults/qtexturedmetalroughmaterial.cpp | 34 +++++++++++----------- src/extras/defaults/qtexturedmetalroughmaterial.h | 8 ++--- .../defaults/qtexturedmetalroughmaterial_p.h | 4 +-- src/extras/shaders/gl3/metalrough.frag | 12 ++++---- src/extras/shaders/gl3/metalroughuniform.frag | 10 +++---- src/quick3d/imports/extras/plugins.qmltypes | 20 ++++++------- 9 files changed, 59 insertions(+), 59 deletions(-) diff --git a/src/extras/defaults/qmetalroughmaterial.cpp b/src/extras/defaults/qmetalroughmaterial.cpp index ee43993c9..b988e11ce 100644 --- a/src/extras/defaults/qmetalroughmaterial.cpp +++ b/src/extras/defaults/qmetalroughmaterial.cpp @@ -63,7 +63,7 @@ QMetalRoughMaterialPrivate::QMetalRoughMaterialPrivate() , m_environmentIrradianceTexture(new QTexture2D()) , m_environmentSpecularTexture(new QTexture2D()) , m_baseColorParameter(new QParameter(QStringLiteral("baseColor"), QColor("grey"))) - , m_metallicParameter(new QParameter(QStringLiteral("metallic"), 0.0f)) + , m_metalnessParameter(new QParameter(QStringLiteral("metalness"), 0.0f)) , m_roughnessParameter(new QParameter(QStringLiteral("roughness"), 0.0f)) , m_environmentIrradianceParameter(new QParameter(QStringLiteral("skyIrradiance"), m_environmentIrradianceTexture)) , m_environmentSpecularParameter(new QParameter(QStringLiteral("skySpecular"), m_environmentSpecularTexture)) @@ -90,7 +90,7 @@ void QMetalRoughMaterialPrivate::init() { connect(m_baseColorParameter, &Qt3DRender::QParameter::valueChanged, this, &QMetalRoughMaterialPrivate::handleBaseColorChanged); - connect(m_metallicParameter, &Qt3DRender::QParameter::valueChanged, + connect(m_metalnessParameter, &Qt3DRender::QParameter::valueChanged, this, &QMetalRoughMaterialPrivate::handleMetallicChanged); connect(m_roughnessParameter, &Qt3DRender::QParameter::valueChanged, this, &QMetalRoughMaterialPrivate::handleRoughnessChanged); @@ -118,7 +118,7 @@ void QMetalRoughMaterialPrivate::init() m_metalRoughEffect->addTechnique(m_metalRoughGL3Technique); m_metalRoughEffect->addParameter(m_baseColorParameter); - m_metalRoughEffect->addParameter(m_metallicParameter); + m_metalRoughEffect->addParameter(m_metalnessParameter); m_metalRoughEffect->addParameter(m_roughnessParameter); m_metalRoughEffect->addParameter(m_environmentIrradianceParameter); m_metalRoughEffect->addParameter(m_environmentSpecularParameter); @@ -135,7 +135,7 @@ void QMetalRoughMaterialPrivate::handleBaseColorChanged(const QVariant &var) void QMetalRoughMaterialPrivate::handleMetallicChanged(const QVariant &var) { Q_Q(QMetalRoughMaterial); - emit q->metallicChanged(var.toFloat()); + emit q->metalnessChanged(var.toFloat()); } void QMetalRoughMaterialPrivate::handleRoughnessChanged(const QVariant &var) { @@ -204,15 +204,15 @@ QColor QMetalRoughMaterial::baseColor() const } /*! - \property QMetalRoughMaterial::metallic + \property QMetalRoughMaterial::metalness - Holds the current metallic level of the material, since is a value between 0 (purely dielectric, the default) + Holds the current metalness level of the material, since is a value between 0 (purely dielectric, the default) and 1 (purely metallic). */ -float QMetalRoughMaterial::metallic() const +float QMetalRoughMaterial::metalness() const { Q_D(const QMetalRoughMaterial); - return d->m_metallicParameter->value().toFloat(); + return d->m_metalnessParameter->value().toFloat(); } /*! @@ -272,10 +272,10 @@ void QMetalRoughMaterial::setBaseColor(const QColor &baseColor) d->m_baseColorParameter->setValue(QVariant::fromValue(baseColor)); } -void QMetalRoughMaterial::setMetallic(float metallic) +void QMetalRoughMaterial::setMetalness(float metalness) { Q_D(QMetalRoughMaterial); - d->m_metallicParameter->setValue(QVariant::fromValue(metallic)); + d->m_metalnessParameter->setValue(QVariant::fromValue(metalness)); } void QMetalRoughMaterial::setRoughness(float roughness) diff --git a/src/extras/defaults/qmetalroughmaterial.h b/src/extras/defaults/qmetalroughmaterial.h index a7fbfba59..e13d6c1e9 100644 --- a/src/extras/defaults/qmetalroughmaterial.h +++ b/src/extras/defaults/qmetalroughmaterial.h @@ -58,7 +58,7 @@ class QT3DEXTRASSHARED_EXPORT QMetalRoughMaterial : public Qt3DRender::QMaterial { Q_OBJECT Q_PROPERTY(QColor baseColor READ baseColor WRITE setBaseColor NOTIFY baseColorChanged) - Q_PROPERTY(float metallic READ metallic WRITE setMetallic NOTIFY metallicChanged) + Q_PROPERTY(float metalness READ metalness WRITE setMetalness NOTIFY metalnessChanged) Q_PROPERTY(float roughness READ roughness WRITE setRoughness NOTIFY roughnessChanged) Q_PROPERTY(Qt3DRender::QAbstractTexture *environmentIrradiance READ environmentIrradiance WRITE setEnvironmentIrradiance NOTIFY environmentIrradianceChanged) Q_PROPERTY(Qt3DRender::QAbstractTexture *environmentSpecular READ environmentSpecular WRITE setEnvironmentSpecular NOTIFY environmentSpecularChanged) @@ -68,21 +68,21 @@ public: ~QMetalRoughMaterial(); QColor baseColor() const; - float metallic() const; + float metalness() const; float roughness() const; Qt3DRender::QAbstractTexture *environmentIrradiance() const; Qt3DRender::QAbstractTexture *environmentSpecular() const; public Q_SLOTS: void setBaseColor(const QColor &baseColor); - void setMetallic(float metallic); + void setMetalness(float metalness); void setRoughness(float roughness); void setEnvironmentIrradiance(Qt3DRender::QAbstractTexture *environmentIrradiance); void setEnvironmentSpecular(Qt3DRender::QAbstractTexture *environmentSpecular); Q_SIGNALS: void baseColorChanged(const QColor &baseColor); - void metallicChanged(float metallic); + void metalnessChanged(float metalness); void roughnessChanged(float roughness); void environmentIrradianceChanged(Qt3DRender::QAbstractTexture *environmentIrradiance); void environmentSpecularChanged(Qt3DRender::QAbstractTexture *environmentSpecular); diff --git a/src/extras/defaults/qmetalroughmaterial_p.h b/src/extras/defaults/qmetalroughmaterial_p.h index e501867e1..b406df996 100644 --- a/src/extras/defaults/qmetalroughmaterial_p.h +++ b/src/extras/defaults/qmetalroughmaterial_p.h @@ -87,7 +87,7 @@ public: Qt3DRender::QAbstractTexture *m_environmentIrradianceTexture; Qt3DRender::QAbstractTexture *m_environmentSpecularTexture; Qt3DRender::QParameter *m_baseColorParameter; - Qt3DRender::QParameter *m_metallicParameter; + Qt3DRender::QParameter *m_metalnessParameter; Qt3DRender::QParameter *m_roughnessParameter; Qt3DRender::QParameter *m_environmentIrradianceParameter; Qt3DRender::QParameter *m_environmentSpecularParameter; diff --git a/src/extras/defaults/qtexturedmetalroughmaterial.cpp b/src/extras/defaults/qtexturedmetalroughmaterial.cpp index f50bc8ab8..ea7c7b9d7 100644 --- a/src/extras/defaults/qtexturedmetalroughmaterial.cpp +++ b/src/extras/defaults/qtexturedmetalroughmaterial.cpp @@ -61,14 +61,14 @@ namespace Qt3DExtras { QTexturedMetalRoughMaterialPrivate::QTexturedMetalRoughMaterialPrivate() : QMaterialPrivate() , m_baseColorTexture(new QTexture2D()) - , m_metallicTexture(new QTexture2D()) + , m_metalnessTexture(new QTexture2D()) , m_roughnessTexture(new QTexture2D()) , m_ambientOcclusionTexture(new QTexture2D()) , m_normalTexture(new QTexture2D()) , m_environmentIrradianceTexture(new QTexture2D()) , m_environmentSpecularTexture(new QTexture2D()) , m_baseColorParameter(new QParameter(QStringLiteral("baseColorMap"), m_baseColorTexture)) - , m_metallicParameter(new QParameter(QStringLiteral("metallicMap"), m_metallicTexture)) + , m_metalnessParameter(new QParameter(QStringLiteral("metalnessMap"), m_metalnessTexture)) , m_roughnessParameter(new QParameter(QStringLiteral("roughnessMap"), m_roughnessTexture)) , m_ambientOcclusionParameter(new QParameter(QStringLiteral("ambientOcclusionMap"), m_ambientOcclusionTexture)) , m_normalParameter(new QParameter(QStringLiteral("normalMap"), m_normalTexture)) @@ -86,11 +86,11 @@ QTexturedMetalRoughMaterialPrivate::QTexturedMetalRoughMaterialPrivate() m_baseColorTexture->setGenerateMipMaps(true); m_baseColorTexture->setMaximumAnisotropy(16.0f); - m_metallicTexture->setMagnificationFilter(QAbstractTexture::Linear); - m_metallicTexture->setMinificationFilter(QAbstractTexture::LinearMipMapLinear); - m_metallicTexture->setWrapMode(QTextureWrapMode(QTextureWrapMode::Repeat)); - m_metallicTexture->setGenerateMipMaps(true); - m_metallicTexture->setMaximumAnisotropy(16.0f); + m_metalnessTexture->setMagnificationFilter(QAbstractTexture::Linear); + m_metalnessTexture->setMinificationFilter(QAbstractTexture::LinearMipMapLinear); + m_metalnessTexture->setWrapMode(QTextureWrapMode(QTextureWrapMode::Repeat)); + m_metalnessTexture->setGenerateMipMaps(true); + m_metalnessTexture->setMaximumAnisotropy(16.0f); m_roughnessTexture->setMagnificationFilter(QAbstractTexture::Linear); m_roughnessTexture->setMinificationFilter(QAbstractTexture::LinearMipMapLinear); @@ -127,7 +127,7 @@ void QTexturedMetalRoughMaterialPrivate::init() { connect(m_baseColorParameter, &Qt3DRender::QParameter::valueChanged, this, &QTexturedMetalRoughMaterialPrivate::handleBaseColorChanged); - connect(m_metallicParameter, &Qt3DRender::QParameter::valueChanged, + connect(m_metalnessParameter, &Qt3DRender::QParameter::valueChanged, this, &QTexturedMetalRoughMaterialPrivate::handleMetallicChanged); connect(m_roughnessParameter, &Qt3DRender::QParameter::valueChanged, this, &QTexturedMetalRoughMaterialPrivate::handleRoughnessChanged); @@ -159,7 +159,7 @@ void QTexturedMetalRoughMaterialPrivate::init() m_metalRoughEffect->addTechnique(m_metalRoughGL3Technique); m_metalRoughEffect->addParameter(m_baseColorParameter); - m_metalRoughEffect->addParameter(m_metallicParameter); + m_metalRoughEffect->addParameter(m_metalnessParameter); m_metalRoughEffect->addParameter(m_roughnessParameter); m_metalRoughEffect->addParameter(m_ambientOcclusionParameter); m_metalRoughEffect->addParameter(m_normalParameter); @@ -178,7 +178,7 @@ void QTexturedMetalRoughMaterialPrivate::handleBaseColorChanged(const QVariant & void QTexturedMetalRoughMaterialPrivate::handleMetallicChanged(const QVariant &var) { Q_Q(QTexturedMetalRoughMaterial); - emit q->metallicChanged(var.value()); + emit q->metalnessChanged(var.value()); } void QTexturedMetalRoughMaterialPrivate::handleRoughnessChanged(const QVariant &var) { @@ -268,11 +268,11 @@ QAbstractTexture *QTexturedMetalRoughMaterial::baseColor() const } /*! - \property QTexturedMetalRoughMaterial::metallic + \property QTexturedMetalRoughMaterial::metalness - Holds the current metallic map texture. + Holds the current metalness map texture. - By default, the metallic texture has the following properties: + By default, the metalness texture has the following properties: \list \li Linear minification and magnification filters @@ -281,10 +281,10 @@ QAbstractTexture *QTexturedMetalRoughMaterial::baseColor() const \li Maximum anisotropy of 16.0 \endlist */ -QAbstractTexture *QTexturedMetalRoughMaterial::metallic() const +QAbstractTexture *QTexturedMetalRoughMaterial::metalness() const { Q_D(const QTexturedMetalRoughMaterial); - return d->m_metallicParameter->value().value(); + return d->m_metalnessParameter->value().value(); } /*! @@ -392,10 +392,10 @@ void QTexturedMetalRoughMaterial::setBaseColor(QAbstractTexture *baseColor) d->m_baseColorParameter->setValue(QVariant::fromValue(baseColor)); } -void QTexturedMetalRoughMaterial::setMetallic(QAbstractTexture *metallic) +void QTexturedMetalRoughMaterial::setMetalness(QAbstractTexture *metalness) { Q_D(QTexturedMetalRoughMaterial); - d->m_metallicParameter->setValue(QVariant::fromValue(metallic)); + d->m_metalnessParameter->setValue(QVariant::fromValue(metalness)); } void QTexturedMetalRoughMaterial::setRoughness(QAbstractTexture *roughness) diff --git a/src/extras/defaults/qtexturedmetalroughmaterial.h b/src/extras/defaults/qtexturedmetalroughmaterial.h index 2a667aea8..c5c3fce33 100644 --- a/src/extras/defaults/qtexturedmetalroughmaterial.h +++ b/src/extras/defaults/qtexturedmetalroughmaterial.h @@ -53,7 +53,7 @@ class QT3DEXTRASSHARED_EXPORT QTexturedMetalRoughMaterial : public Qt3DRender::Q { Q_OBJECT Q_PROPERTY(Qt3DRender::QAbstractTexture *baseColor READ baseColor WRITE setBaseColor NOTIFY baseColorChanged) - Q_PROPERTY(Qt3DRender::QAbstractTexture *metallic READ metallic WRITE setMetallic NOTIFY metallicChanged) + Q_PROPERTY(Qt3DRender::QAbstractTexture *metalness READ metalness WRITE setMetalness NOTIFY metalnessChanged) Q_PROPERTY(Qt3DRender::QAbstractTexture *roughness READ roughness WRITE setRoughness NOTIFY roughnessChanged) Q_PROPERTY(Qt3DRender::QAbstractTexture *ambientOcclusion READ ambientOcclusion WRITE setAmbientOcclusion NOTIFY ambientOcclusionChanged) Q_PROPERTY(Qt3DRender::QAbstractTexture *normal READ normal WRITE setNormal NOTIFY normalChanged) @@ -65,7 +65,7 @@ public: ~QTexturedMetalRoughMaterial(); Qt3DRender::QAbstractTexture *baseColor() const; - Qt3DRender::QAbstractTexture *metallic() const; + Qt3DRender::QAbstractTexture *metalness() const; Qt3DRender::QAbstractTexture *roughness() const; Qt3DRender::QAbstractTexture *ambientOcclusion() const; Qt3DRender::QAbstractTexture *normal() const; @@ -74,7 +74,7 @@ public: public Q_SLOTS: void setBaseColor(Qt3DRender::QAbstractTexture *baseColor); - void setMetallic(Qt3DRender::QAbstractTexture *metallic); + void setMetalness(Qt3DRender::QAbstractTexture *metalness); void setRoughness(Qt3DRender::QAbstractTexture *roughness); void setAmbientOcclusion(Qt3DRender::QAbstractTexture *ambientOcclusion); void setNormal(Qt3DRender::QAbstractTexture *normal); @@ -83,7 +83,7 @@ public Q_SLOTS: Q_SIGNALS: void baseColorChanged(Qt3DRender::QAbstractTexture *baseColor); - void metallicChanged(Qt3DRender::QAbstractTexture *metallic); + void metalnessChanged(Qt3DRender::QAbstractTexture *metalness); void roughnessChanged(Qt3DRender::QAbstractTexture *roughness); void ambientOcclusionChanged(Qt3DRender::QAbstractTexture *ambientOcclusion); void normalChanged(Qt3DRender::QAbstractTexture *normal); diff --git a/src/extras/defaults/qtexturedmetalroughmaterial_p.h b/src/extras/defaults/qtexturedmetalroughmaterial_p.h index 54fdb73b2..084824304 100644 --- a/src/extras/defaults/qtexturedmetalroughmaterial_p.h +++ b/src/extras/defaults/qtexturedmetalroughmaterial_p.h @@ -87,14 +87,14 @@ public: void handleEnvironmentSpecularChanged(const QVariant &var); Qt3DRender::QAbstractTexture *m_baseColorTexture; - Qt3DRender::QAbstractTexture *m_metallicTexture; + Qt3DRender::QAbstractTexture *m_metalnessTexture; Qt3DRender::QAbstractTexture *m_roughnessTexture; Qt3DRender::QAbstractTexture *m_ambientOcclusionTexture; Qt3DRender::QAbstractTexture *m_normalTexture; Qt3DRender::QAbstractTexture *m_environmentIrradianceTexture; Qt3DRender::QAbstractTexture *m_environmentSpecularTexture; Qt3DRender::QParameter *m_baseColorParameter; - Qt3DRender::QParameter *m_metallicParameter; + Qt3DRender::QParameter *m_metalnessParameter; Qt3DRender::QParameter *m_roughnessParameter; Qt3DRender::QParameter *m_ambientOcclusionParameter; Qt3DRender::QParameter *m_normalParameter; diff --git a/src/extras/shaders/gl3/metalrough.frag b/src/extras/shaders/gl3/metalrough.frag index 99624dd24..197d3eec7 100644 --- a/src/extras/shaders/gl3/metalrough.frag +++ b/src/extras/shaders/gl3/metalrough.frag @@ -67,7 +67,7 @@ uniform samplerCube skySpecular; // For specular contribution // PBR Material maps uniform sampler2D baseColorMap; -uniform sampler2D metallicMap; +uniform sampler2D metalnessMap; uniform sampler2D roughnessMap; uniform sampler2D normalMap; uniform sampler2D ambientOcclusionMap; @@ -157,7 +157,7 @@ vec3 specularModel(const in vec3 F0, vec3 pbrIblModel(const in vec3 wNormal, const in vec3 wView, const in vec3 baseColor, - const in float metallic, + const in float metalness, const in float roughness, const in float ambientOcclusion) { @@ -175,12 +175,12 @@ vec3 pbrIblModel(const in vec3 wNormal, float lDotH = dot(l, h); // Calculate diffuse component - vec3 diffuseColor = (1.0 - metallic) * baseColor; + vec3 diffuseColor = (1.0 - metalness) * baseColor; vec3 diffuse = diffuseColor * texture(skyIrradiance, l).rgb; // Calculate specular component vec3 dielectricColor = vec3(0.04); - vec3 F0 = mix(dielectricColor, baseColor, metallic); + vec3 F0 = mix(dielectricColor, baseColor, metalness); vec3 specularFactor = specularModel(F0, lDotH, lDotN, vDotN, n, h); float lod = roughnessToMipLevel(roughness); @@ -218,7 +218,7 @@ void main() // Sample the inputs needed for the metal-roughness PBR BRDF vec3 baseColor = texture(baseColorMap, texCoord).rgb; - float metallic = texture(metallicMap, texCoord).r * metalFactor; + float metalness = texture(metalnessMap, texCoord).r * metalFactor; float roughness = texture(roughnessMap, texCoord).r; float ambientOcclusion = texture(ambientOcclusionMap, texCoord).r; vec3 tNormal = 2.0 * texture(normalMap, texCoord).rgb - vec3(1.0); @@ -227,7 +227,7 @@ void main() vec3 cLinear = pbrIblModel(wNormal, wView, baseColor, - metallic, + metalness, roughness, ambientOcclusion); diff --git a/src/extras/shaders/gl3/metalroughuniform.frag b/src/extras/shaders/gl3/metalroughuniform.frag index 7ff061e12..66201513a 100644 --- a/src/extras/shaders/gl3/metalroughuniform.frag +++ b/src/extras/shaders/gl3/metalroughuniform.frag @@ -67,7 +67,7 @@ uniform samplerCube skySpecular; // For specular contribution // PBR Material maps uniform vec4 baseColor; -uniform float metallic; +uniform float metalness; uniform float roughness; // Roughness -> mip level mapping @@ -152,7 +152,7 @@ vec3 specularModel(const in vec3 F0, vec3 pbrIblModel(const in vec3 wNormal, const in vec3 wView, const in vec3 baseColor, - const in float metallic, + const in float metalness, const in float roughness) { // Calculate reflection direction of view vector about surface normal @@ -169,12 +169,12 @@ vec3 pbrIblModel(const in vec3 wNormal, float lDotH = dot(l, h); // Calculate diffuse component - vec3 diffuseColor = (1.0 - metallic) * baseColor; + vec3 diffuseColor = (1.0 - metalness) * baseColor; vec3 diffuse = diffuseColor * texture(skyIrradiance, l).rgb; // Calculate specular component vec3 dielectricColor = vec3(0.04); - vec3 F0 = mix(dielectricColor, baseColor, metallic); + vec3 F0 = mix(dielectricColor, baseColor, metalness); vec3 specularFactor = specularModel(F0, lDotH, lDotN, vDotN, n, h); float lod = roughnessToMipLevel(roughness); @@ -206,7 +206,7 @@ void main() vec3 cLinear = pbrIblModel(worldNormal, worldView, baseColor.rgb, - metallic, + metalness, roughness); // Apply simple (Reinhard) tonemap transform to get into LDR range [0, 1] diff --git a/src/quick3d/imports/extras/plugins.qmltypes b/src/quick3d/imports/extras/plugins.qmltypes index 843c9802b..cbe12c9ad 100644 --- a/src/quick3d/imports/extras/plugins.qmltypes +++ b/src/quick3d/imports/extras/plugins.qmltypes @@ -736,7 +736,7 @@ Module { exports: ["Qt3D.Extras/MetalRoughMaterial 2.2"] exportMetaObjectRevisions: [0] Property { name: "baseColor"; type: "QColor" } - Property { name: "metallic"; type: "float" } + Property { name: "metalness"; type: "float" } Property { name: "roughness"; type: "float" } Property { name: "environmentIrradiance" @@ -750,8 +750,8 @@ Module { Parameter { name: "baseColor"; type: "QColor" } } Signal { - name: "metallicChanged" - Parameter { name: "metallic"; type: "float" } + name: "metalnessChanged" + Parameter { name: "metalness"; type: "float" } } Signal { name: "roughnessChanged" @@ -778,8 +778,8 @@ Module { Parameter { name: "baseColor"; type: "QColor" } } Method { - name: "setMetallic" - Parameter { name: "metallic"; type: "float" } + name: "setMetalness" + Parameter { name: "metalness"; type: "float" } } Method { name: "setRoughness" @@ -1449,7 +1449,7 @@ Module { exports: ["Qt3D.Extras/TexturedMetalRoughMaterial 2.2"] exportMetaObjectRevisions: [0] Property { name: "baseColor"; type: "Qt3DRender::QAbstractTexture"; isPointer: true } - Property { name: "metallic"; type: "Qt3DRender::QAbstractTexture"; isPointer: true } + Property { name: "metalness"; type: "Qt3DRender::QAbstractTexture"; isPointer: true } Property { name: "roughness"; type: "Qt3DRender::QAbstractTexture"; isPointer: true } Property { name: "ambientOcclusion"; type: "Qt3DRender::QAbstractTexture"; isPointer: true } Property { name: "normal"; type: "Qt3DRender::QAbstractTexture"; isPointer: true } @@ -1465,8 +1465,8 @@ Module { Parameter { name: "baseColor"; type: "Qt3DRender::QAbstractTexture"; isPointer: true } } Signal { - name: "metallicChanged" - Parameter { name: "metallic"; type: "Qt3DRender::QAbstractTexture"; isPointer: true } + name: "metalnessChanged" + Parameter { name: "metalness"; type: "Qt3DRender::QAbstractTexture"; isPointer: true } } Signal { name: "roughnessChanged" @@ -1501,8 +1501,8 @@ Module { Parameter { name: "baseColor"; type: "Qt3DRender::QAbstractTexture"; isPointer: true } } Method { - name: "setMetallic" - Parameter { name: "metallic"; type: "Qt3DRender::QAbstractTexture"; isPointer: true } + name: "setMetalness" + Parameter { name: "metalness"; type: "Qt3DRender::QAbstractTexture"; isPointer: true } } Method { name: "setRoughness" -- cgit v1.2.3 From 6f10fdbd675c056a278744e7fc867a146cded82d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Wed, 15 Feb 2017 17:11:47 +0200 Subject: Cleanup scene2d console messages at startup Change warnings to debug messages so that hey won't be logged by default. Task-number: QTBUG-58534 Change-Id: Ib84986df2bde9325c0491d9ed0a32e7c40b5c8d8 Reviewed-by: Paul Lemire --- src/quick3d/quick3drender/scene2d/scene2d.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/quick3d/quick3drender/scene2d/scene2d.cpp b/src/quick3d/quick3drender/scene2d/scene2d.cpp index 51a4304af..9317dc2c5 100644 --- a/src/quick3d/quick3drender/scene2d/scene2d.cpp +++ b/src/quick3d/quick3drender/scene2d/scene2d.cpp @@ -196,7 +196,7 @@ void Scene2D::initializeRender() if (!m_renderInitialized && m_sharedObject.data() != nullptr) { m_shareContext = renderer()->shareContext(); if (!m_shareContext){ - qCWarning(Qt3DRender::Quick::Scene2D) << Q_FUNC_INFO << "Renderer not initialized."; + qCDebug(Qt3DRender::Quick::Scene2D) << Q_FUNC_INFO << "Renderer not initialized."; QCoreApplication::postEvent(m_sharedObject->m_renderObject, new QEvent(INITIALIZE)); return; } @@ -277,7 +277,7 @@ void Scene2D::render() // Need to call sync even if the texture is not in use syncRenderControl(); m_context->doneCurrent(); - qCWarning(Qt3DRender::Quick::Scene2D) << Q_FUNC_INFO << "Texture not in use."; + qCDebug(Qt3DRender::Quick::Scene2D) << Q_FUNC_INFO << "Texture not in use."; QCoreApplication::postEvent(m_sharedObject->m_renderObject, new QEvent(RENDER)); return; } -- cgit v1.2.3 From f22b372e812ee808ba2dd88bf345ef6f4fb635d1 Mon Sep 17 00:00:00 2001 From: Nico Vertriest Date: Mon, 13 Feb 2017 17:01:15 +0100 Subject: Doc: Corrected snippet quoting syntax MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Command '\snippet (//! [2])' failed at end of file 'planets-qml/PlanetsMain.qml' Change-Id: If30a8123aad2631de22731e5bbd51871166063c8 Reviewed-by: Tomi Korpipää Reviewed-by: Kevin Ottens --- examples/qt3d/planets-qml/PlanetsMain.qml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/qt3d/planets-qml/PlanetsMain.qml b/examples/qt3d/planets-qml/PlanetsMain.qml index a6fb3545f..c9d826784 100644 --- a/examples/qt3d/planets-qml/PlanetsMain.qml +++ b/examples/qt3d/planets-qml/PlanetsMain.qml @@ -417,8 +417,9 @@ Item { value: 1 minimumValue: 1 maximumValue: 2 - + //! [2] onValueChanged: solarsystem.changeCameraDistance(value) + //! [2] property bool panningEnabled: false signal swipeUp() -- cgit v1.2.3 From 7328700ee5622fbb635205592c97280a8f84817a Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Fri, 17 Feb 2017 15:15:50 +0000 Subject: Revert "Use QVector in level of detail APIs" This reverts commit 5bceaee38908934078bbdb62b564daa68f7e182b. QML uses doubles throughout and there is no good way or place to reliably switch to floats in the API. We tried extending QtDeclarative to work with QJSValues containing vectors/lists of floats and doubles (rather than qreal) but this introduces rounding errors that are difficult to control robustly. We also looked at removing the Q_PROPERTY in C++ and adding it to a QML extension object. But that would make it not work with animations bound to this property. So, in the end, it seems like qreal is the best of a bad set of alternatives. We should make a renewed effort to kill qreal for Qt 6. Change-Id: I9d61e58e7223eb5a6b848ba33fc760b3654bbddd Reviewed-by: Mike Krus --- src/quick3d/quick3dextras/items/quick3dlevelofdetailloader.cpp | 4 ++-- src/quick3d/quick3dextras/items/quick3dlevelofdetailloader_p.h | 6 +++--- src/render/backend/levelofdetail.cpp | 2 +- src/render/backend/levelofdetail_p.h | 4 ++-- src/render/frontend/qlevelofdetail.cpp | 8 ++++---- src/render/frontend/qlevelofdetail.h | 8 ++++---- src/render/frontend/qlevelofdetail_p.h | 4 ++-- src/render/jobs/updatelevelofdetailjob.cpp | 4 ++-- tests/auto/render/levelofdetail/tst_levelofdetail.cpp | 6 +++--- tests/auto/render/qlevelofdetail/tst_qlevelofdetail.cpp | 2 +- 10 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/quick3d/quick3dextras/items/quick3dlevelofdetailloader.cpp b/src/quick3d/quick3dextras/items/quick3dlevelofdetailloader.cpp index c4a35328d..f3d3f4323 100644 --- a/src/quick3d/quick3dextras/items/quick3dlevelofdetailloader.cpp +++ b/src/quick3d/quick3dextras/items/quick3dlevelofdetailloader.cpp @@ -144,13 +144,13 @@ void Quick3DLevelOfDetailLoader::setThresholdType(Qt3DRender::QLevelOfDetail::Th d->m_lod->setThresholdType(thresholdType); } -QVector Quick3DLevelOfDetailLoader::thresholds() const +QVector Quick3DLevelOfDetailLoader::thresholds() const { Q_D(const Quick3DLevelOfDetailLoader); return d->m_lod->thresholds(); } -void Quick3DLevelOfDetailLoader::setThresholds(const QVector &thresholds) +void Quick3DLevelOfDetailLoader::setThresholds(const QVector &thresholds) { Q_D(Quick3DLevelOfDetailLoader); d->m_lod->setThresholds(thresholds); diff --git a/src/quick3d/quick3dextras/items/quick3dlevelofdetailloader_p.h b/src/quick3d/quick3dextras/items/quick3dlevelofdetailloader_p.h index 6eb539e56..1ef359fe7 100644 --- a/src/quick3d/quick3dextras/items/quick3dlevelofdetailloader_p.h +++ b/src/quick3d/quick3dextras/items/quick3dlevelofdetailloader_p.h @@ -71,7 +71,7 @@ class QT3DQUICKEXTRASSHARED_PRIVATE_EXPORT Quick3DLevelOfDetailLoader : public Q Q_PROPERTY(Qt3DRender::QCamera *camera READ camera WRITE setCamera NOTIFY cameraChanged) Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged) Q_PROPERTY(Qt3DRender::QLevelOfDetail::ThresholdType thresholdType READ thresholdType WRITE setThresholdType NOTIFY thresholdTypeChanged) - Q_PROPERTY(QVector thresholds READ thresholds WRITE setThresholds NOTIFY thresholdsChanged) + Q_PROPERTY(QVector thresholds READ thresholds WRITE setThresholds NOTIFY thresholdsChanged) Q_PROPERTY(Qt3DRender::QBoundingSphere *volumeOverride READ volumeOverride WRITE setVolumeOverride NOTIFY volumeOverrideChanged) Q_PROPERTY(QObject *entity READ entity NOTIFY entityChanged) @@ -88,8 +88,8 @@ public: void setCurrentIndex(int currentIndex); Qt3DRender::QLevelOfDetail::ThresholdType thresholdType() const; void setThresholdType(Qt3DRender::QLevelOfDetail::ThresholdType thresholdType); - QVector thresholds() const; - void setThresholds(const QVector &thresholds); + QVector thresholds() const; + void setThresholds(const QVector &thresholds); Qt3DRender::QBoundingSphere *volumeOverride() const; void setVolumeOverride(Qt3DRender::QBoundingSphere *volumeOverride); diff --git a/src/render/backend/levelofdetail.cpp b/src/render/backend/levelofdetail.cpp index 9618cc9bb..9ff0ef532 100644 --- a/src/render/backend/levelofdetail.cpp +++ b/src/render/backend/levelofdetail.cpp @@ -93,7 +93,7 @@ void LevelOfDetail::sceneChangeEvent(const QSceneChangePtr &e) } else if (propertyChange->propertyName() == QByteArrayLiteral("thresholdType")) { m_thresholdType = propertyChange->value().value(); } else if (propertyChange->propertyName() == QByteArrayLiteral("thresholds")) { - m_thresholds = propertyChange->value().value>(); + m_thresholds = propertyChange->value().value>(); } else if (propertyChange->propertyName() == QByteArrayLiteral("center")) { m_center = propertyChange->value().value(); } else if (propertyChange->propertyName() == QByteArrayLiteral("radius")) { diff --git a/src/render/backend/levelofdetail_p.h b/src/render/backend/levelofdetail_p.h index c8d065883..83809a631 100644 --- a/src/render/backend/levelofdetail_p.h +++ b/src/render/backend/levelofdetail_p.h @@ -78,7 +78,7 @@ public: Qt3DCore::QNodeId camera() const { return m_camera; } int currentIndex() const { return m_currentIndex; } QLevelOfDetail::ThresholdType thresholdType() const { return m_thresholdType; } - QVector thresholds() const { return m_thresholds; } + QVector thresholds() const { return m_thresholds; } float radius() const { return m_radius; } QVector3D center() const { return m_center; } @@ -89,7 +89,7 @@ private: Qt3DCore::QNodeId m_camera; int m_currentIndex; QLevelOfDetail::ThresholdType m_thresholdType; - QVector m_thresholds; + QVector m_thresholds; float m_radius; QVector3D m_center; }; diff --git a/src/render/frontend/qlevelofdetail.cpp b/src/render/frontend/qlevelofdetail.cpp index 53f2357b4..0d70803ca 100644 --- a/src/render/frontend/qlevelofdetail.cpp +++ b/src/render/frontend/qlevelofdetail.cpp @@ -106,7 +106,7 @@ void QLevelOfDetailPrivate::_q_centerChanged(const QVector3D ¢er) Qt3DRender::QGeometryRenderer *geometryRenderer = new Qt3DCore::QGeometryRenderer(renderableEntity); renderableEntity->addComponent(geometryRenderer); Qt3DRender::QLevelOfDetail* lod = new Qt3Render::QLevelOfDetail(renderableEntity); - QVector thresholds = {20, 35, 50, 65}; + QVector thresholds = {20, 35, 50, 65}; lod->setThresholds(thresholds); lod->setCamera(mainCamera); renderableEntity->addComponent(lod); @@ -267,7 +267,7 @@ void QLevelOfDetailPrivate::_q_centerChanged(const QVector3D ¢er) */ /*! - * \qmlproperty QVector LevelOfDetail::thresholds + * \qmlproperty QVector LevelOfDetail::thresholds * * Array of range values as float point numbers. The value for the most detailed representation * should be specified first. @@ -435,7 +435,7 @@ void QLevelOfDetail::setThresholdType(QLevelOfDetail::ThresholdType thresholdTyp } } -QVector QLevelOfDetail::thresholds() const +QVector QLevelOfDetail::thresholds() const { Q_D(const QLevelOfDetail); return d->m_thresholds; @@ -445,7 +445,7 @@ QVector QLevelOfDetail::thresholds() const * Sets the range values. * \sa Qt3DRender::QLevelOfDetail::thresholdType */ -void QLevelOfDetail::setThresholds(QVector thresholds) +void QLevelOfDetail::setThresholds(QVector thresholds) { Q_D(QLevelOfDetail); if (d->m_thresholds != thresholds) { diff --git a/src/render/frontend/qlevelofdetail.h b/src/render/frontend/qlevelofdetail.h index 39cc8448b..f3325aea0 100644 --- a/src/render/frontend/qlevelofdetail.h +++ b/src/render/frontend/qlevelofdetail.h @@ -59,7 +59,7 @@ class QT3DRENDERSHARED_EXPORT QLevelOfDetail : public Qt3DCore::QComponent Q_PROPERTY(Qt3DRender::QCamera *camera READ camera WRITE setCamera NOTIFY cameraChanged) Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged) Q_PROPERTY(ThresholdType thresholdType READ thresholdType WRITE setThresholdType NOTIFY thresholdTypeChanged) - Q_PROPERTY(QVector thresholds READ thresholds WRITE setThresholds NOTIFY thresholdsChanged) + Q_PROPERTY(QVector thresholds READ thresholds WRITE setThresholds NOTIFY thresholdsChanged) Q_PROPERTY(Qt3DRender::QBoundingSphere *volumeOverride READ volumeOverride WRITE setVolumeOverride NOTIFY volumeOverrideChanged) public: @@ -75,21 +75,21 @@ public: QCamera *camera() const; int currentIndex() const; ThresholdType thresholdType() const; - QVector thresholds() const; + QVector thresholds() const; QBoundingSphere *volumeOverride() const; public Q_SLOTS: void setCamera(QCamera *camera); void setCurrentIndex(int currentIndex); void setThresholdType(ThresholdType thresholdType); - void setThresholds(QVector thresholds); + void setThresholds(QVector thresholds); void setVolumeOverride(QBoundingSphere *volumeOverride); Q_SIGNALS: void cameraChanged(QCamera *camera); void currentIndexChanged(int currentIndex); void thresholdTypeChanged(ThresholdType thresholdType); - void thresholdsChanged(QVector thresholds); + void thresholdsChanged(QVector thresholds); void volumeOverrideChanged(QBoundingSphere *volumeOverride); protected: diff --git a/src/render/frontend/qlevelofdetail_p.h b/src/render/frontend/qlevelofdetail_p.h index 808959220..ab25e9ad3 100644 --- a/src/render/frontend/qlevelofdetail_p.h +++ b/src/render/frontend/qlevelofdetail_p.h @@ -73,7 +73,7 @@ public: QCamera *m_camera; int m_currentIndex; QLevelOfDetail::ThresholdType m_thresholdType; - QVector m_thresholds; + QVector m_thresholds; QPointer m_volumeOverride; }; @@ -82,7 +82,7 @@ struct QLevelOfDetailData Qt3DCore::QNodeId camera; int currentIndex; QLevelOfDetail::ThresholdType thresholdType; - QVector thresholds; + QVector thresholds; float radius; QVector3D center; }; diff --git a/src/render/jobs/updatelevelofdetailjob.cpp b/src/render/jobs/updatelevelofdetailjob.cpp index 6993d2bc8..940d26850 100644 --- a/src/render/jobs/updatelevelofdetailjob.cpp +++ b/src/render/jobs/updatelevelofdetailjob.cpp @@ -160,7 +160,7 @@ void UpdateLevelOfDetailJob::updateEntityLodByDistance(Entity *entity, LevelOfDe if (!viewMatrixForCamera(lod->camera(), viewMatrix, projectionMatrix)) return; - const QVector thresholds = lod->thresholds(); + const QVector thresholds = lod->thresholds(); QVector3D center = lod->center(); if (lod->radius() > 0.f || entity->worldBoundingVolume() == nullptr) { center = *entity->worldTransform() * center; @@ -196,7 +196,7 @@ void UpdateLevelOfDetailJob::updateEntityLodByScreenArea(Entity *entity, LevelOf const PickingUtils::ViewportCameraAreaTriplet &vca = vcaTriplets.front(); - const QVector thresholds = lod->thresholds(); + const QVector thresholds = lod->thresholds(); Sphere bv(lod->center(), lod->radius()); if (lod->radius() <= 0.f && entity->worldBoundingVolume() != nullptr) { bv = *(entity->worldBoundingVolume()); diff --git a/tests/auto/render/levelofdetail/tst_levelofdetail.cpp b/tests/auto/render/levelofdetail/tst_levelofdetail.cpp index 731e36a36..ab0e8c4b8 100644 --- a/tests/auto/render/levelofdetail/tst_levelofdetail.cpp +++ b/tests/auto/render/levelofdetail/tst_levelofdetail.cpp @@ -112,7 +112,7 @@ private Q_SLOTS: } { - QVector thresholds = {20.0f, 30.0f, 40.0f}; + QVector thresholds = {20.f, 30.f, 40.f}; QVariant v; v.setValue(thresholds); @@ -129,12 +129,12 @@ private Q_SLOTS: { // WHEN Qt3DCore::QPropertyUpdatedChangePtr updateChange(new Qt3DCore::QPropertyUpdatedChange(Qt3DCore::QNodeId())); - updateChange->setValue(QVector3D(1.0f, 2.0f, 3.0f)); + updateChange->setValue(QVector3D(1., 2., 3.)); updateChange->setPropertyName("center"); renderLod.sceneChangeEvent(updateChange); // THEN - QCOMPARE(renderLod.center(), QVector3D(1.0f, 2.0f, 3.0f)); + QCOMPARE(renderLod.center(), QVector3D(1., 2., 3.)); } } }; diff --git a/tests/auto/render/qlevelofdetail/tst_qlevelofdetail.cpp b/tests/auto/render/qlevelofdetail/tst_qlevelofdetail.cpp index 2f8f6a957..e2ffdd9da 100644 --- a/tests/auto/render/qlevelofdetail/tst_qlevelofdetail.cpp +++ b/tests/auto/render/qlevelofdetail/tst_qlevelofdetail.cpp @@ -103,7 +103,7 @@ private Q_SLOTS: { // WHEN - QVector thresholds = {10.0f, 20.0f, 30.0f}; + QVector thresholds = {10., 20., 30.}; lod->setThresholds(thresholds); QCoreApplication::processEvents(); -- cgit v1.2.3 From 922078911d131358f91ec25b7366ff6ac5cb55a7 Mon Sep 17 00:00:00 2001 From: Mike Krus Date: Sat, 18 Feb 2017 22:45:43 +0000 Subject: Remove unnecessary widget dependency Found this when building for iOS using a custom build without widgets. Change-Id: If50e2d388aafacf9f8b3cfea20752c790e1fbc1d Reviewed-by: Sean Harmer --- examples/qt3d/planets-qml/planets-qml.pro | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/qt3d/planets-qml/planets-qml.pro b/examples/qt3d/planets-qml/planets-qml.pro index 39b93cb8c..18175823f 100644 --- a/examples/qt3d/planets-qml/planets-qml.pro +++ b/examples/qt3d/planets-qml/planets-qml.pro @@ -3,7 +3,6 @@ } QT += qml quick \ - widgets \ concurrent \ 3dcore 3drender 3dinput \ 3dquick 3dquickrender 3dquickinput 3dquickextras \ -- cgit v1.2.3 From 63ea9813791d62c18e7a5c1a1ce03e1318f8203c Mon Sep 17 00:00:00 2001 From: Mike Krus Date: Sun, 19 Feb 2017 15:55:24 +0000 Subject: Rename CoordinateVisitor to BufferVisitor Point picking will need a point/coordinate visitor to traverse coordinate in order. BufferVisitor traverses a single buffer irrespective of the draw order. It reveals (another, pre-existing) problem with bounding volume computations: it computes based on all the values in a buffer. In the case of indexed primitives, only a subset of those may be used and the bounding volume may be very different. Will fix this for 5.10 using proper coordinate visitor Change-Id: Ie86f26d7066260d69da9639eb1dab823c650333c Reviewed-by: Kevin Ottens --- src/render/backend/buffervisitor_p.h | 212 ++++++++++++++++++++++++++++++ src/render/backend/coordinatevisitor_p.h | 212 ------------------------------ src/render/backend/render-backend.pri | 2 +- src/render/jobs/calcboundingvolumejob.cpp | 10 +- 4 files changed, 218 insertions(+), 218 deletions(-) create mode 100644 src/render/backend/buffervisitor_p.h delete mode 100644 src/render/backend/coordinatevisitor_p.h diff --git a/src/render/backend/buffervisitor_p.h b/src/render/backend/buffervisitor_p.h new file mode 100644 index 000000000..7149e21ae --- /dev/null +++ b/src/render/backend/buffervisitor_p.h @@ -0,0 +1,212 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3DRENDER_RENDER_BUFFERVISITOR_P_H +#define QT3DRENDER_RENDER_BUFFERVISITOR_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DCore { +class QEntity; +} + +namespace Qt3DRender { +namespace Render { + + +template +class Q_AUTOTEST_EXPORT BufferVisitor +{ +public: + explicit BufferVisitor(NodeManagers *manager) + : m_manager(manager) + { + } + virtual ~BufferVisitor() { } + + virtual void visit(uint ndx, ValueType x) { + Q_UNUSED(ndx); Q_UNUSED(x); + } + virtual void visit(uint ndx, ValueType x, ValueType y) { + Q_UNUSED(ndx); Q_UNUSED(x); Q_UNUSED(y); + } + virtual void visit(uint ndx, ValueType x, ValueType y, ValueType z) { + Q_UNUSED(ndx); Q_UNUSED(x); Q_UNUSED(y); Q_UNUSED(z); + } + virtual void visit(uint ndx, ValueType x, ValueType y, ValueType z, ValueType w) { + Q_UNUSED(ndx); Q_UNUSED(x); Q_UNUSED(y); Q_UNUSED(z); Q_UNUSED(w); + } + + bool apply(const GeometryRenderer *renderer, const QString &attributeName) + { + if (renderer == nullptr || renderer->instanceCount() != 1) { + return false; + } + + Geometry *geom = m_manager->lookupResource(renderer->geometryId()); + + if (!geom) + return false; + + Attribute *attribute = nullptr; + + const auto attrIds = geom->attributes(); + for (const Qt3DCore::QNodeId attrId : attrIds) { + attribute = m_manager->lookupResource(attrId); + if (attribute){ + if (attribute->name() == attributeName + || (attributeName == QStringLiteral("default") + && attribute->name() == QAttribute::defaultTextureCoordinateAttributeName())) { + break; + } + } + attribute = nullptr; + } + + if (!attribute) + return false; + + return apply(attribute); + } + + bool apply(Qt3DRender::Render::Attribute *attribute) + { + if (attribute->vertexBaseType() != VertexBaseType) + return false; + if (attribute->vertexSize() < dataSize) + return false; + + auto data = m_manager->lookupResource(attribute->bufferId())->data(); + auto buffer = BufferTypeInfo::castToType(data, attribute->byteOffset()); + switch (dataSize) { + case 1: traverseCoordinates1(buffer, attribute->byteStride(), attribute->count()); break; + case 2: traverseCoordinates2(buffer, attribute->byteStride(), attribute->count()); break; + case 3: traverseCoordinates3(buffer, attribute->byteStride(), attribute->count()); break; + case 4: traverseCoordinates4(buffer, attribute->byteStride(), attribute->count()); break; + default: Q_UNREACHABLE(); + } + + return true; + } + +protected: + + template + void traverseCoordinates1(Coordinate *coordinates, + const uint byteStride, + const uint count) + { + const uint stride = byteStride / sizeof(Coordinate); + for (uint ndx = 0; ndx < count; ++ndx) { + visit(ndx, coordinates[0]); + coordinates += stride; + } + } + + template + void traverseCoordinates2(Coordinate *coordinates, + const uint byteStride, + const uint count) + { + const uint stride = byteStride / sizeof(Coordinate); + for (uint ndx = 0; ndx < count; ++ndx) { + visit(ndx, coordinates[0], coordinates[1]); + coordinates += stride; + } + } + + template + void traverseCoordinates3(Coordinate *coordinates, + const uint byteStride, + const uint count) + { + const uint stride = byteStride / sizeof(Coordinate); + for (uint ndx = 0; ndx < count; ++ndx) { + visit(ndx, coordinates[0], coordinates[1], coordinates[2]); + coordinates += stride; + } + } + + template + void traverseCoordinates4(Coordinate *coordinates, + const uint byteStride, + const uint count) + { + const uint stride = byteStride / sizeof(Coordinate); + for (uint ndx = 0; ndx < count; ++ndx) { + visit(ndx, coordinates[0], coordinates[1], coordinates[2], coordinates[3]); + coordinates += stride; + } + } + + NodeManagers *m_manager; +}; + +typedef BufferVisitor Buffer3fVisitor; + +} // namespace Render + +} // namespace Qt3DRender + +QT_END_NAMESPACE + + +#endif // QT3DRENDER_RENDER_BUFFERVISITOR_P_H diff --git a/src/render/backend/coordinatevisitor_p.h b/src/render/backend/coordinatevisitor_p.h deleted file mode 100644 index e7687ab3a..000000000 --- a/src/render/backend/coordinatevisitor_p.h +++ /dev/null @@ -1,212 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt3D module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** 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-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QT3DRENDER_RENDER_COORDINATEVISITOR_P_H -#define QT3DRENDER_RENDER_COORDINATEVISITOR_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of other Qt classes. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE - -namespace Qt3DCore { -class QEntity; -} - -namespace Qt3DRender { -namespace Render { - - -template -class Q_AUTOTEST_EXPORT CoordinateVisitor -{ -public: - explicit CoordinateVisitor(NodeManagers *manager) - : m_manager(manager) - { - } - virtual ~CoordinateVisitor() { } - - virtual void visit(uint ndx, ValueType x) { - Q_UNUSED(ndx); Q_UNUSED(x); - } - virtual void visit(uint ndx, ValueType x, ValueType y) { - Q_UNUSED(ndx); Q_UNUSED(x); Q_UNUSED(y); - } - virtual void visit(uint ndx, ValueType x, ValueType y, ValueType z) { - Q_UNUSED(ndx); Q_UNUSED(x); Q_UNUSED(y); Q_UNUSED(z); - } - virtual void visit(uint ndx, ValueType x, ValueType y, ValueType z, ValueType w) { - Q_UNUSED(ndx); Q_UNUSED(x); Q_UNUSED(y); Q_UNUSED(z); Q_UNUSED(w); - } - - bool apply(const GeometryRenderer *renderer, const QString &attributeName) - { - if (renderer == nullptr || renderer->instanceCount() != 1) { - return false; - } - - Geometry *geom = m_manager->lookupResource(renderer->geometryId()); - - if (!geom) - return false; - - Attribute *attribute = nullptr; - - const auto attrIds = geom->attributes(); - for (const Qt3DCore::QNodeId attrId : attrIds) { - attribute = m_manager->lookupResource(attrId); - if (attribute){ - if (attribute->name() == attributeName - || (attributeName == QStringLiteral("default") - && attribute->name() == QAttribute::defaultTextureCoordinateAttributeName())) { - break; - } - } - attribute = nullptr; - } - - if (!attribute) - return false; - - return apply(attribute); - } - - bool apply(Qt3DRender::Render::Attribute *attribute) - { - if (attribute->vertexBaseType() != VertexBaseType) - return false; - if (attribute->vertexSize() < dataSize) - return false; - - auto data = m_manager->lookupResource(attribute->bufferId())->data(); - auto buffer = BufferTypeInfo::castToType(data, attribute->byteOffset()); - switch (dataSize) { - case 1: traverseCoordinates1(buffer, attribute->byteStride(), attribute->count()); break; - case 2: traverseCoordinates2(buffer, attribute->byteStride(), attribute->count()); break; - case 3: traverseCoordinates3(buffer, attribute->byteStride(), attribute->count()); break; - case 4: traverseCoordinates4(buffer, attribute->byteStride(), attribute->count()); break; - default: Q_UNREACHABLE(); - } - - return true; - } - -protected: - - template - void traverseCoordinates1(Coordinate *coordinates, - const uint byteStride, - const uint count) - { - const uint stride = byteStride / sizeof(Coordinate); - for (uint ndx = 0; ndx < count; ++ndx) { - visit(ndx, coordinates[0]); - coordinates += stride; - } - } - - template - void traverseCoordinates2(Coordinate *coordinates, - const uint byteStride, - const uint count) - { - const uint stride = byteStride / sizeof(Coordinate); - for (uint ndx = 0; ndx < count; ++ndx) { - visit(ndx, coordinates[0], coordinates[1]); - coordinates += stride; - } - } - - template - void traverseCoordinates3(Coordinate *coordinates, - const uint byteStride, - const uint count) - { - const uint stride = byteStride / sizeof(Coordinate); - for (uint ndx = 0; ndx < count; ++ndx) { - visit(ndx, coordinates[0], coordinates[1], coordinates[2]); - coordinates += stride; - } - } - - template - void traverseCoordinates4(Coordinate *coordinates, - const uint byteStride, - const uint count) - { - const uint stride = byteStride / sizeof(Coordinate); - for (uint ndx = 0; ndx < count; ++ndx) { - visit(ndx, coordinates[0], coordinates[1], coordinates[2], coordinates[3]); - coordinates += stride; - } - } - - NodeManagers *m_manager; -}; - -typedef CoordinateVisitor Coordinate3fVisitor; - -} // namespace Render - -} // namespace Qt3DRender - -QT_END_NAMESPACE - - -#endif // QT3DRENDER_RENDER_COORDINATEVISITOR_P_H diff --git a/src/render/backend/render-backend.pri b/src/render/backend/render-backend.pri index f694e7cea..14e9c6370 100644 --- a/src/render/backend/render-backend.pri +++ b/src/render/backend/render-backend.pri @@ -29,7 +29,7 @@ HEADERS += \ $$PWD/triangleboundingvolume_p.h \ $$PWD/openglvertexarrayobject_p.h \ $$PWD/trianglesextractor_p.h \ - $$PWD/coordinatevisitor_p.h \ + $$PWD/buffervisitor_p.h \ $$PWD/bufferutils_p.h \ $$PWD/trianglesvisitor_p.h \ $$PWD/abstractrenderer_p.h \ diff --git a/src/render/jobs/calcboundingvolumejob.cpp b/src/render/jobs/calcboundingvolumejob.cpp index 2f2d471d6..7bbab307c 100644 --- a/src/render/jobs/calcboundingvolumejob.cpp +++ b/src/render/jobs/calcboundingvolumejob.cpp @@ -50,7 +50,7 @@ #include #include #include -#include +#include #include #include @@ -119,11 +119,11 @@ private: Sphere m_volume; NodeManagers *m_manager; - class FindExtremePoints : public Coordinate3fVisitor + class FindExtremePoints : public Buffer3fVisitor { public: FindExtremePoints(NodeManagers *manager) - : Coordinate3fVisitor(manager) + : Buffer3fVisitor(manager) , xMin(0.0f), xMax(0.0f), yMin(0.0f), yMax(0.0f), zMin(0.0f), zMax(0.0f) { } @@ -166,11 +166,11 @@ private: } }; - class ExpandSphere : public Coordinate3fVisitor + class ExpandSphere : public Buffer3fVisitor { public: ExpandSphere(NodeManagers *manager, Sphere& volume) - : Coordinate3fVisitor(manager), m_volume(volume) + : Buffer3fVisitor(manager), m_volume(volume) { } Sphere& m_volume; -- cgit v1.2.3 From e8251833651cf6a63b921eb35bc74d47c9b17d33 Mon Sep 17 00:00:00 2001 From: Mike Krus Date: Thu, 9 Feb 2017 11:29:06 +0000 Subject: Google Cardboard demo Change-Id: Iee998ffe7ddb67a03ed260db053f541e0138b837 Reviewed-by: Kevin Ottens --- examples/qt3d/qardboard/Info.plist | 35 ++++ examples/qt3d/qardboard/PlacedEntity.qml | 82 +++++++++ examples/qt3d/qardboard/QardboardCamera.qml | 124 +++++++++++++ examples/qt3d/qardboard/QardboardFrameGraph.qml | 90 +++++++++ examples/qt3d/qardboard/QardboardRootEntity.qml | 105 +++++++++++ examples/qt3d/qardboard/QardboardScene3D.qml | 68 +++++++ .../qt3d/qardboard/abstractdeviceorientation.cpp | 112 +++++++++++ .../qt3d/qardboard/abstractdeviceorientation.h | 96 ++++++++++ examples/qt3d/qardboard/dummydeviceorientation.cpp | 73 ++++++++ examples/qt3d/qardboard/dummydeviceorientation.h | 68 +++++++ examples/qt3d/qardboard/iosdeviceorientation.h | 68 +++++++ examples/qt3d/qardboard/iosdeviceorientation.mm | 77 ++++++++ examples/qt3d/qardboard/iosdeviceorientation_p.h | 63 +++++++ examples/qt3d/qardboard/iosdeviceorientation_p.mm | 154 ++++++++++++++++ examples/qt3d/qardboard/main.cpp | 85 +++++++++ examples/qt3d/qardboard/main.qml | 205 +++++++++++++++++++++ examples/qt3d/qardboard/qardboard.pro | 35 ++++ examples/qt3d/qardboard/resources.qrc | 10 + examples/qt3d/qt3d.pro | 3 +- 19 files changed, 1552 insertions(+), 1 deletion(-) create mode 100644 examples/qt3d/qardboard/Info.plist create mode 100644 examples/qt3d/qardboard/PlacedEntity.qml create mode 100644 examples/qt3d/qardboard/QardboardCamera.qml create mode 100644 examples/qt3d/qardboard/QardboardFrameGraph.qml create mode 100644 examples/qt3d/qardboard/QardboardRootEntity.qml create mode 100644 examples/qt3d/qardboard/QardboardScene3D.qml create mode 100644 examples/qt3d/qardboard/abstractdeviceorientation.cpp create mode 100644 examples/qt3d/qardboard/abstractdeviceorientation.h create mode 100644 examples/qt3d/qardboard/dummydeviceorientation.cpp create mode 100644 examples/qt3d/qardboard/dummydeviceorientation.h create mode 100644 examples/qt3d/qardboard/iosdeviceorientation.h create mode 100644 examples/qt3d/qardboard/iosdeviceorientation.mm create mode 100644 examples/qt3d/qardboard/iosdeviceorientation_p.h create mode 100644 examples/qt3d/qardboard/iosdeviceorientation_p.mm create mode 100644 examples/qt3d/qardboard/main.cpp create mode 100644 examples/qt3d/qardboard/main.qml create mode 100644 examples/qt3d/qardboard/qardboard.pro create mode 100644 examples/qt3d/qardboard/resources.qrc diff --git a/examples/qt3d/qardboard/Info.plist b/examples/qt3d/qardboard/Info.plist new file mode 100644 index 000000000..26c5fe5e2 --- /dev/null +++ b/examples/qt3d/qardboard/Info.plist @@ -0,0 +1,35 @@ + + + + + CFBundleIconFile + + CFBundlePackageType + APPL + CFBundleGetInfoString + Created by Qt/QMake + CFBundleSignature + ???? + CFBundleExecutable + qardboard + CFBundleIdentifier + com.kdab.${PRODUCT_NAME:rfc1034identifier} + CFBundleDisplayName + ${PRODUCT_NAME} + CFBundleName + ${PRODUCT_NAME} + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1.0 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UISupportedInterfaceOrientations + + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/examples/qt3d/qardboard/PlacedEntity.qml b/examples/qt3d/qardboard/PlacedEntity.qml new file mode 100644 index 000000000..b0d73634b --- /dev/null +++ b/examples/qt3d/qardboard/PlacedEntity.qml @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import Qt3D.Core 2.0 +import Qt3D.Render 2.0 +import Qt3D.Extras 2.0 + +Entity { + id: root + property double angle: 0 + property double radius: 10 + property var mesh + property alias color: material.diffuse + property vector3d center: Qt.vector3d(0, 0, 0) + + components: [ + Transform { + id: tr + matrix: { + var ra = 0// (root.angle) * Math.PI / 180 + var m = Qt.matrix4x4() + m.rotate(root.angle, Qt.vector3d(0, 1, 0)) + m.translate(Qt.vector3d(root.center.x + root.radius * Math.sin(ra), root.center.y, root.center.z - root.radius * Math.cos(ra))) + return m + } + } + ] + + Entity { + PhongMaterial { + id: material + } + components: [ material, mesh ] + } +} diff --git a/examples/qt3d/qardboard/QardboardCamera.qml b/examples/qt3d/qardboard/QardboardCamera.qml new file mode 100644 index 000000000..1912b8a22 --- /dev/null +++ b/examples/qt3d/qardboard/QardboardCamera.qml @@ -0,0 +1,124 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import Qt3D.Core 2.0 +import Qt3D.Render 2.0 + +Entity { + id: root + property real convergence: 2000.0 + property real eyeSeparation: 35.0 + property real aspectRatio: _window.width / _window.height + property real fieldOfView: 60.0 + property real nearPlane: 1. + property real farPlane: 1000.0 + + property vector3d position: Qt.vector3d(0.0, 0.0, 0.0) + property vector3d viewDirection: Qt.vector3d(0.0, 0.0, 1.0) + property vector3d viewUp: Qt.vector3d(0.0, 1.0, 0.0) + property alias viewMatrix: leftEyeTransform.matrix + + readonly property real _fov2: Math.tan(fieldOfView * Math.PI / 180 * 0.5) + readonly property real top: nearPlane * _fov2 + readonly property real a: aspectRatio * _fov2 * convergence + + CameraLens { + id: leftEyeLens + projectionType: CameraLens.FrustumProjection + nearPlane : root.nearPlane + farPlane : root.farPlane + left: -(a - eyeSeparation * 0.5) * nearPlane / convergence + right: (a + eyeSeparation * 0.5) * nearPlane / convergence + top: root.top + bottom: -root.top + } + + CameraLens { + id: rightEyeLens + projectionType: CameraLens.FrustumProjection + nearPlane : root.nearPlane + farPlane : root.farPlane + left: -(a + eyeSeparation * 0.5) * nearPlane / convergence + right: (a - eyeSeparation * 0.5) * nearPlane / convergence + top: root.top + bottom: -root.top + } + + Transform { + id: leftEyeTransform + + matrix: { + var m = Qt.matrix4x4(); + m.lookAt(root.position, root.position + root.viewDirection, root.viewUp); + return m; + } + } + + Transform { + id: rightEyeTransform + + matrix: leftEyeTransform.matrix + } + + property Entity leftCamera: Entity { + components: [ + leftEyeLens, + leftEyeTransform + ] + } + + property Entity rightCamera: Entity { + id: rightCameraEntity + components: [ + rightEyeLens, + rightEyeTransform + ] + } +} diff --git a/examples/qt3d/qardboard/QardboardFrameGraph.qml b/examples/qt3d/qardboard/QardboardFrameGraph.qml new file mode 100644 index 000000000..195076c70 --- /dev/null +++ b/examples/qt3d/qardboard/QardboardFrameGraph.qml @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import Qt3D.Core 2.0 +import Qt3D.Render 2.0 + +Viewport { + property alias leftCamera: leftCameraSelector.camera + property alias rightCamera: rightCameraSelector.camera + property alias window: surfaceSelector.surface + + RenderSurfaceSelector { + id: surfaceSelector + + // ColorMask is reset by default + // By default reset to the default if not specified + ClearBuffers { + clearColor: "white" + buffers: ClearBuffers.ColorDepthBuffer + NoDraw {} // We just want to clear the buffers + } + + // Draw with left eye + Viewport { + id: leftViewport + normalizedRect: Qt.rect(0, 0, .5, 1) + + CameraSelector { + id: leftCameraSelector + } + } + + // Draw with right eye + Viewport { + id: rightViewport + normalizedRect: Qt.rect(.5, 0, .5, 1) + + CameraSelector { + id: rightCameraSelector + } + } + } +} diff --git a/examples/qt3d/qardboard/QardboardRootEntity.qml b/examples/qt3d/qardboard/QardboardRootEntity.qml new file mode 100644 index 000000000..85e4fbc7e --- /dev/null +++ b/examples/qt3d/qardboard/QardboardRootEntity.qml @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import Qt3D.Core 2.0 +import Qt3D.Render 2.0 +import Qt3D.Input 2.0 +import Qardboard 1.0 + +Entity { + id: root + property alias fieldOfView: stereoCamera.fieldOfView + property alias cameraPosition: stereoCamera.position + property alias cameraDirection: stereoCamera.viewDirection + property alias headlightDirection: headLight.worldDirection + + components: [ + RenderSettings { + activeFrameGraph: QardboardFrameGraph { + id: stereoFrameGraph + leftCamera: stereoCamera.leftCamera + rightCamera: stereoCamera.rightCamera + } + }, + InputSettings { }, + DirectionalLight { + id: headLight + worldDirection: stereoCamera.viewDirection.times(-1) + } + ] + + DeviceOrientation { + id: orientation + enabled: true + } + + QardboardCamera { + id: stereoCamera + viewMatrix: computeMatrix(orientation.roll, orientation.pitch, orientation.yaw) + + property vector3d vc + property vector3d vd + property vector3d vu + + function computeMatrix(roll, pitch, yaw) { + var m = Qt.matrix4x4() + m.rotate(-roll, Qt.vector3d(1, 0, 0)) + m.rotate(yaw, Qt.vector3d(0, 1, 0)) + vd = m.times(stereoCamera.viewDirection) + vu = m.times(stereoCamera.viewUp) + var r = Qt.matrix4x4() + vc = stereoCamera.position.minus(vd) + r.lookAt(stereoCamera.position, vc, vu) +// console.log(roll.toFixed(2), pitch.toFixed(2), yaw.toFixed(2), stereoCamera.position, vd, vc, vu) +// console.log(r) + return r + } + } +} diff --git a/examples/qt3d/qardboard/QardboardScene3D.qml b/examples/qt3d/qardboard/QardboardScene3D.qml new file mode 100644 index 000000000..01c7ba771 --- /dev/null +++ b/examples/qt3d/qardboard/QardboardScene3D.qml @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import QtQuick.Scene3D 2.0 + +import Qt3D.Core 2.0 +import Qt3D.Render 2.0 +import Qt3D.Input 2.0 +import Qt3D.Extras 2.0 + +Scene3D { + id: scene3d + focus: true + aspects: ["input", "logic"] + cameraAspectRatioMode: Scene3D.UserAspectRatio + multisample: true + + QardboardRootEntity { + } +} diff --git a/examples/qt3d/qardboard/abstractdeviceorientation.cpp b/examples/qt3d/qardboard/abstractdeviceorientation.cpp new file mode 100644 index 000000000..d8e869439 --- /dev/null +++ b/examples/qt3d/qardboard/abstractdeviceorientation.cpp @@ -0,0 +1,112 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "abstractdeviceorientation.h" + +#include +#include +#include +#include + + +AbstractDeviceOrientation::AbstractDeviceOrientation(QObject *parent) + : QObject(parent) + , m_roll(0) + , m_pitch(0) + , m_yaw(0) + , m_enabled(false) +{ +} + +bool AbstractDeviceOrientation::enabled() const +{ + return m_enabled; +} + +void AbstractDeviceOrientation::stop() +{ + if (m_enabled) { + m_enabled = false; + emit enabledChanged(m_enabled); + } +} + +void AbstractDeviceOrientation::setRoll(qreal v) +{ + if (v != m_roll) { + m_roll = v; + emit rollChanged(v); + } +} + +void AbstractDeviceOrientation::setPitch(qreal v) +{ + if (v != m_pitch) { + m_pitch = v; + emit pitchChanged(v); + } +} + +void AbstractDeviceOrientation::setYaw(qreal v) +{ + if (v != m_yaw) { + m_yaw = v; + emit yawChanged(v); + } +} + +void AbstractDeviceOrientation::setEnabled(bool v) +{ + if (v && !m_enabled) { + start(); + } else if (!v && m_enabled) { + stop(); + } +} diff --git a/examples/qt3d/qardboard/abstractdeviceorientation.h b/examples/qt3d/qardboard/abstractdeviceorientation.h new file mode 100644 index 000000000..ea06c6cab --- /dev/null +++ b/examples/qt3d/qardboard/abstractdeviceorientation.h @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef ABSTRACT_DEVICEORIENTATION_H +#define ABSTRACT_DEVICEORIENTATION_H + +#include + +class AbstractDeviceOrientation : public QObject +{ + Q_OBJECT + Q_PROPERTY(qreal roll READ roll WRITE setRoll NOTIFY rollChanged) + Q_PROPERTY(qreal pitch READ pitch WRITE setPitch NOTIFY pitchChanged) + Q_PROPERTY(qreal yaw READ yaw WRITE setYaw NOTIFY yawChanged) + Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged) + +public: + AbstractDeviceOrientation(QObject* parent = 0); + + qreal roll() const { return m_roll; } + qreal pitch() const { return m_pitch; } + qreal yaw() const { return m_yaw; } + + bool enabled() const; + +signals: + void rollChanged(qreal roll); + void pitchChanged(qreal pitch); + void yawChanged(qreal yaw); + void enabledChanged(bool); + +public slots: + virtual void setRoll(qreal v); + virtual void setPitch(qreal v); + virtual void setYaw(qreal v); + virtual void setEnabled(bool v); + + virtual bool start() = 0; //!< Called to start the sensor services. + virtual void stop(); //!< Called to stop updates from the #CompassClino. + +protected: + qreal m_roll; + qreal m_pitch; + qreal m_yaw; + bool m_enabled; +}; + + +#endif // ABSTRACT_DEVICEORIENTATION_H diff --git a/examples/qt3d/qardboard/dummydeviceorientation.cpp b/examples/qt3d/qardboard/dummydeviceorientation.cpp new file mode 100644 index 000000000..ddf9580e6 --- /dev/null +++ b/examples/qt3d/qardboard/dummydeviceorientation.cpp @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "dummydeviceorientation.h" + +DummyDeviceOrientation::DummyDeviceOrientation(QObject *parent) + : AbstractDeviceOrientation(parent) +{ +} + +bool DummyDeviceOrientation::start() +{ + if (!m_enabled) { + m_enabled = true; + emit enabledChanged(m_enabled); + } + return true; +} + +void DummyDeviceOrientation::stop() +{ + if (m_enabled) { + m_enabled = false; + emit enabledChanged(m_enabled); + } +} diff --git a/examples/qt3d/qardboard/dummydeviceorientation.h b/examples/qt3d/qardboard/dummydeviceorientation.h new file mode 100644 index 000000000..4f18ea4ad --- /dev/null +++ b/examples/qt3d/qardboard/dummydeviceorientation.h @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef DUMMY_DEVICEORIENTATION_H +#define DUMMY_DEVICEORIENTATION_H + +#include + +class DummyDeviceOrientation : public AbstractDeviceOrientation +{ + Q_OBJECT +public: + DummyDeviceOrientation(QObject* parent = 0); + +public slots: + bool start() override; + void stop() override; +}; + + +#endif // DUMMY_DEVICEORIENTATION_H diff --git a/examples/qt3d/qardboard/iosdeviceorientation.h b/examples/qt3d/qardboard/iosdeviceorientation.h new file mode 100644 index 000000000..8f18595dc --- /dev/null +++ b/examples/qt3d/qardboard/iosdeviceorientation.h @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef IOS_DEVICEORIENTATION_H +#define IOS_DEVICEORIENTATION_H + +#include + +class iOSDeviceOrientation : public AbstractDeviceOrientation +{ + Q_OBJECT +public: + iOSDeviceOrientation(QObject* parent = 0); + +public slots: + bool start() override; + void stop() override; +}; + + +#endif // IOS_DEVICEORIENTATION_H diff --git a/examples/qt3d/qardboard/iosdeviceorientation.mm b/examples/qt3d/qardboard/iosdeviceorientation.mm new file mode 100644 index 000000000..c66208136 --- /dev/null +++ b/examples/qt3d/qardboard/iosdeviceorientation.mm @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "iosdeviceorientation.h" +#include "iosdeviceorientation_p.h" + +iOSDeviceOrientation::iOSDeviceOrientation(QObject *parent) + : AbstractDeviceOrientation(parent) +{ + [[iOSDeviceOrientationP instance] setHandler:this]; +} + +bool iOSDeviceOrientation::start() +{ + if (!m_enabled) { + [[iOSDeviceOrientationP instance] start]; + m_enabled = true; + emit enabledChanged(m_enabled); + } + return true; +} + +void iOSDeviceOrientation::stop() +{ + if (m_enabled) { + [[iOSDeviceOrientationP instance] stop]; + m_enabled = false; + emit enabledChanged(m_enabled); + } +} diff --git a/examples/qt3d/qardboard/iosdeviceorientation_p.h b/examples/qt3d/qardboard/iosdeviceorientation_p.h new file mode 100644 index 000000000..ec32a5a91 --- /dev/null +++ b/examples/qt3d/qardboard/iosdeviceorientation_p.h @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#import +#import +#import + + +@interface iOSDeviceOrientationP : NSObject +@property (readonly) BOOL isActive; + ++ (iOSDeviceOrientationP*)instance; +- (void)setHandler:(iOSDeviceOrientation*) handler; +- (void)start; +- (void)stop; +@end diff --git a/examples/qt3d/qardboard/iosdeviceorientation_p.mm b/examples/qt3d/qardboard/iosdeviceorientation_p.mm new file mode 100644 index 000000000..4e7db4820 --- /dev/null +++ b/examples/qt3d/qardboard/iosdeviceorientation_p.mm @@ -0,0 +1,154 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#import +#import + +#include "iosdeviceorientation.h" +#import "iosdeviceorientation_p.h" + +#define RADIANS_TO_DEGREES(radians) ((radians) * (180.0 / M_PI)) +#define DEGREES_TO_RADIANS(angle) ((angle) / 180.0 * M_PI) + + +@interface QIOSMotionManager : NSObject { +} + ++ (CMMotionManager *)sharedManager; +@end + +@interface iOSDeviceOrientationP() +{ + BOOL active; + iOSDeviceOrientation* handler; +} + +@property (strong) CMMotionManager *motionManager; +@end + + + +@implementation iOSDeviceOrientationP + +#define kUpdateFrequency 20.0 + + ++ (iOSDeviceOrientationP*)instance +{ + static iOSDeviceOrientationP* _myInstance = 0; + if (0 == _myInstance) + _myInstance = [[iOSDeviceOrientationP alloc] init]; + return _myInstance; +} + +- (id)init +{ + self = [super init]; + if (self) { + self.motionManager = [QIOSMotionManager sharedManager]; // [[CMMotionManager alloc] init]; + self.motionManager.deviceMotionUpdateInterval = 1. / kUpdateFrequency; + + active = FALSE; + } + return self; +} + +- (void)setHandler:(iOSDeviceOrientation*)h +{ + handler = h; +} + +- (BOOL)isActive +{ + return active; +} + +- (void)start +{ + // Motion updates + [self.motionManager startDeviceMotionUpdatesUsingReferenceFrame:CMAttitudeReferenceFrameXArbitraryCorrectedZVertical + toQueue:[NSOperationQueue currentQueue] + withHandler: ^(CMDeviceMotion *motion, NSError *error) { + //CMAttitude *attitude = motion.attitude; + //NSLog(@"rotation rate = [%f, %f, %f]", attitude.pitch, attitude.roll, attitude.yaw); + if (error) + NSLog(@"%@", [error description]); + else + [self performSelectorOnMainThread:@selector(handleDeviceMotion:) withObject:motion waitUntilDone:YES]; + }]; + active = TRUE; +} + +- (void)stop +{ + [_motionManager stopDeviceMotionUpdates]; + active = FALSE; +} + +- (void)handleDeviceMotion:(CMDeviceMotion*)motion +{ + if (!active) + return; + + if (motion.magneticField.accuracy == CMMagneticFieldCalibrationAccuracyUncalibrated) + return; + + // X: A pitch is a rotation around a lateral axis that passes through the device from side to side. + // Y: A roll is a rotation around a longitudinal axis that passes through the device from its top to bottom. + // Z: A yaw is a rotation around an axis that runs vertically through the device. It is perpendicular to the + // body of the device, with its origin at the center of gravity and directed toward the bottom of the device. + + CMAttitude *attitude = motion.attitude; + handler->setRoll(90 - RADIANS_TO_DEGREES(attitude.roll)); + handler->setPitch(RADIANS_TO_DEGREES(attitude.pitch)); + handler->setYaw(RADIANS_TO_DEGREES(attitude.yaw)); +} + +@end diff --git a/examples/qt3d/qardboard/main.cpp b/examples/qt3d/qardboard/main.cpp new file mode 100644 index 000000000..412f0fc88 --- /dev/null +++ b/examples/qt3d/qardboard/main.cpp @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include +#include + +#ifdef Q_OS_IOS +#include "iosdeviceorientation.h" +#else +#include "dummydeviceorientation.h" +#endif + +int main(int argc, char* argv[]) +{ + QGuiApplication app(argc, argv); + + Qt3DExtras::Quick::Qt3DQuickWindow view; + +#ifdef Q_OS_IOS + qmlRegisterType("Qardboard", 1, 0, "DeviceOrientation"); +#else + qmlRegisterType("Qardboard", 1, 0, "DeviceOrientation"); +#endif + + view.engine()->qmlEngine()->rootContext()->setContextProperty(QStringLiteral("_window"), &view); + view.setSource(QUrl("qrc:/main.qml")); +#ifdef Q_OS_IOS + view.showFullScreen(); +#else + view.resize(800, 400); + view.show(); +#endif + + return app.exec(); +} diff --git a/examples/qt3d/qardboard/main.qml b/examples/qt3d/qardboard/main.qml new file mode 100644 index 000000000..b273c0f57 --- /dev/null +++ b/examples/qt3d/qardboard/main.qml @@ -0,0 +1,205 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import Qt3D.Core 2.0 +import Qt3D.Render 2.0 +import Qt3D.Extras 2.0 +import QtQuick 2.4 as QQ2 + +QardboardRootEntity { + id: root + cameraPosition: cameraController.position + + Entity { + id: cameraController + + function posAtAngle(a) { + return Qt.vector3d(cameraRadius * Math.cos(a), 0.0, cameraRadius * Math.sin(a)) + } + function rotAtAngle(a) { + return a * 180 / Math.PI + 90 + } + + property real circleRotation: 0 + readonly property real cameraRadius: obstaclesRepeater.radius + readonly property vector3d circlePosition: cameraController.posAtAngle(cameraController.circleRotation) + property vector3d position: planeTransform.translation.plus(Qt.vector3d(0, 0, 35)) + + QQ2.NumberAnimation { + target: cameraController + property: "circleRotation" + from: 0; to: Math.PI * 2 + duration: 10000 + loops: QQ2.Animation.Infinite + running: true + } + } + + // AirPlane + Entity { + components: [ + Mesh { + source: "assets/obj/toyplane.obj" + }, + Transform { + id: planeTransform + property real rollAngle: 0.0 + translation: cameraController.posAtAngle(cameraController.circleRotation) + rotation: fromAxesAndAngles(Qt.vector3d(1.0, 0.0, 0.0), planeTransform.rollAngle, + Qt.vector3d(0.0, -1.0, 0.0), cameraController.rotAtAngle(cameraController.circleRotation)) + }, + PhongMaterial { + shininess: 20.0 + diffuse: "#ba1a02" // Inferno Orange + } + ] + + QQ2.SequentialAnimation { + running: true + loops: QQ2.Animation.Infinite + + QQ2.NumberAnimation { + target: planeTransform + property: "rollAngle" + from: -30; to: 45 + duration: 1500 + } + QQ2.NumberAnimation { + target: planeTransform + property: "rollAngle" + from: 45; to: -30 + duration: 3500 + } + } + } + + // Cylinder + Entity { + property CylinderMesh cylinder: CylinderMesh { + radius: 1 + length: 3 + rings: 100 + slices: 20 + } + property Transform transform: Transform { + id: cylinderTransform + property real theta: 0.0 + property real phi: 0.0 + rotation: fromEulerAngles(theta, phi, 0) + } + property Material phong: PhongMaterial {} + + QQ2.ParallelAnimation { + loops: QQ2.Animation.Infinite + running: true + QQ2.SequentialAnimation { + QQ2.NumberAnimation { + target: cylinderTransform + property: "scale" + from: 5; to: 45 + duration: 2000 + easing.type: QQ2.Easing.OutInQuad + } + QQ2.NumberAnimation { + target: cylinderTransform + property: "scale" + from: 45; to: 5 + duration: 2000 + easing.type: QQ2.Easing.InOutQuart + } + } + QQ2.NumberAnimation { + target: cylinderTransform + property: "phi" + from: 0; to: 360 + duration: 4000 + } + QQ2.NumberAnimation { + target: cylinderTransform + property: "theta" + from: 0; to: 720 + duration: 4000 + } + } + + components: [cylinder, transform, phong] + } + + // Torus obsctacles + NodeInstantiator { + id: obstaclesRepeater + model: 4 + readonly property real radius: 130.0; + readonly property real det: 1.0 / model + delegate: Entity { + components: [ + TorusMesh { + radius: 35 + minorRadius: 5 + rings: 100 + slices: 20 + }, + Transform { + id: transform + readonly property real angle: Math.PI * 2.0 * index * obstaclesRepeater.det + translation: Qt.vector3d(obstaclesRepeater.radius * Math.cos(transform.angle), + 0.0, + obstaclesRepeater.radius * Math.sin(transform.angle)) + rotation: fromAxisAndAngle(Qt.vector3d(0.0, 1.0, 0.0), transform.angle * 180 / Math.PI) + }, + PhongMaterial { + diffuse: Qt.rgba(Math.abs(Math.cos(transform.angle)), 204 / 255, 75 / 255, 1) + specular: "white" + shininess: 20.0 + } + ] + } + } +} diff --git a/examples/qt3d/qardboard/qardboard.pro b/examples/qt3d/qardboard/qardboard.pro new file mode 100644 index 000000000..07db75737 --- /dev/null +++ b/examples/qt3d/qardboard/qardboard.pro @@ -0,0 +1,35 @@ +!include( ../examples.pri ) { + error( "Couldn't find the examples.pri file!" ) +} + +SOURCE += main.cpp + +QT += qml quick 3dcore 3drender 3dinput 3dquick 3dextras 3dquickextras + +OTHER_FILES += *.qml + +SOURCES += \ + main.cpp \ + abstractdeviceorientation.cpp \ + dummydeviceorientation.cpp + +HEADERS += \ + abstractdeviceorientation.h \ + dummydeviceorientation.h + +RESOURCES += \ + resources.qrc \ + ../exampleresources/obj.qrc + +ios { + QT += sensors sensors-private + QMAKE_INFO_PLIST = Info.plist + + OBJECTIVE_SOURCES += \ + iosdeviceorientation.mm \ + iosdeviceorientation_p.mm + + HEADERS += \ + iosdeviceorientation.h \ + iosdeviceorientation_p.h +} diff --git a/examples/qt3d/qardboard/resources.qrc b/examples/qt3d/qardboard/resources.qrc new file mode 100644 index 000000000..fae6dc122 --- /dev/null +++ b/examples/qt3d/qardboard/resources.qrc @@ -0,0 +1,10 @@ + + + main.qml + QardboardCamera.qml + QardboardFrameGraph.qml + QardboardRootEntity.qml + QardboardScene3D.qml + PlacedEntity.qml + + diff --git a/examples/qt3d/qt3d.pro b/examples/qt3d/qt3d.pro index 7d0545404..e145ac990 100644 --- a/examples/qt3d/qt3d.pro +++ b/examples/qt3d/qt3d.pro @@ -16,7 +16,8 @@ SUBDIRS += \ instanced-arrays-qml \ lights \ compute-particles \ - 3d-text + 3d-text \ + qardboard qtHaveModule(multimedia): SUBDIRS += audio-visualizer-qml -- cgit v1.2.3 From 5b17f3ef636e3b3f33061e635e1117aa8797f821 Mon Sep 17 00:00:00 2001 From: Kevin Ottens Date: Thu, 16 Feb 2017 16:15:47 +0100 Subject: Fix QML version registration for 5.9 types Put a couple of the types which ended up wrongly at 2.0 with the other ones. Also applies the decision to go from 2.1 straight to 2.9 to realign the minor version with the Qt one. Will make it easier to manage. Change-Id: I7088b6c493296924a1d313c83107d5755e548ede Task-Id: QTBUG-58890 Reviewed-by: Sean Harmer Reviewed-by: Paul Lemire --- .../animation/qt3dquick3danimationplugin.cpp | 29 +++++++++++----------- .../imports/extras/qt3dquick3dextrasplugin.cpp | 16 ++++++------ .../imports/render/qt3dquick3drenderplugin.cpp | 14 +++++------ tests/manual/anim-viewer/main.qml | 4 +-- tests/manual/animation-keyframe-simple/main.qml | 2 +- tests/manual/distancefieldtext/TextScene.qml | 2 +- tests/manual/lod/main.qml | 4 +-- tests/manual/render-qml-to-texture-qml/main.qml | 2 +- tests/manual/video-texture-qml/main.qml | 2 +- 9 files changed, 38 insertions(+), 37 deletions(-) diff --git a/src/quick3d/imports/animation/qt3dquick3danimationplugin.cpp b/src/quick3d/imports/animation/qt3dquick3danimationplugin.cpp index 334bf378f..3db188ce6 100644 --- a/src/quick3d/imports/animation/qt3dquick3danimationplugin.cpp +++ b/src/quick3d/imports/animation/qt3dquick3danimationplugin.cpp @@ -68,23 +68,24 @@ void Qt3DQuick3DAnimationPlugin::registerTypes(const char *uri) Qt3DAnimation::Quick::Quick3DAnimation_initialize(); // @uri Qt3D.Animation - qmlRegisterType(uri, 2, 2, "AnimationClip"); - qmlRegisterType(uri, 2, 2, "ClipAnimator"); - qmlRegisterType(uri, 2, 2, "BlendedClipAnimator"); - qmlRegisterType(uri, 2, 2, "ChannelMapping"); + qmlRegisterType(uri, 2, 9, "AnimationClip"); + qmlRegisterType(uri, 2, 9, "ClipAnimator"); + qmlRegisterType(uri, 2, 9, "BlendedClipAnimator"); + qmlRegisterType(uri, 2, 9, "ChannelMapping"); + qmlRegisterType(uri, 2, 9, "ChannelMapping"); qmlRegisterExtendedType(uri, 2, 2, "ChannelMapper"); + Qt3DAnimation::Animation::Quick::Quick3DChannelMapper>(uri, 2, 9, "ChannelMapper"); qmlRegisterExtendedUncreatableType(uri, 2, 2, "AbstractClipBlendNode", QStringLiteral("QAbstractClipBlendNode is abstract")); - qmlRegisterType(uri, 2, 2, "LerpBlend"); - qmlRegisterType(uri, 2, 2, "AdditiveBlend"); + Qt3DAnimation::Animation::Quick::Quick3DAbstractClipBlendNode>(uri, 2, 9, "AbstractClipBlendNode", QStringLiteral("QAbstractClipBlendNode is abstract")); + qmlRegisterType(uri, 2, 9, "LerpBlend"); + qmlRegisterType(uri, 2, 9, "AdditiveBlend"); - qmlRegisterUncreatableType(uri, 2, 2, "AbstractAnimation", QStringLiteral("AbstractAnimation is abstract")); - qmlRegisterExtendedType(uri, 2, 2, "KeyframeAnimation"); - qmlRegisterExtendedType(uri, 2, 2, "AnimationGroup"); - qmlRegisterExtendedType(uri, 2, 2, "AnimationController"); - qmlRegisterExtendedType(uri, 2, 2, "MorphingAnimation"); - qmlRegisterExtendedType(uri, 2, 2, "MorphTarget"); + qmlRegisterUncreatableType(uri, 2, 9, "AbstractAnimation", QStringLiteral("AbstractAnimation is abstract")); + qmlRegisterExtendedType(uri, 2, 9, "KeyframeAnimation"); + qmlRegisterExtendedType(uri, 2, 9, "AnimationGroup"); + qmlRegisterExtendedType(uri, 2, 9, "AnimationController"); + qmlRegisterExtendedType(uri, 2, 9, "MorphingAnimation"); + qmlRegisterExtendedType(uri, 2, 9, "MorphTarget"); } QT_END_NAMESPACE diff --git a/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp b/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp index 7bf41828b..2dc871a6e 100644 --- a/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp +++ b/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp @@ -85,7 +85,7 @@ void Qt3DQuick3DExtrasPlugin::registerTypes(const char *uri) // Entities qmlRegisterType(uri, 2, 0, "SkyboxEntity"); - qmlRegisterType(uri, 2, 2, "LevelOfDetailLoader"); + qmlRegisterType(uri, 2, 9, "LevelOfDetailLoader"); // Camera Controllers qmlRegisterType(uri, 2, 0, "FirstPersonCameraController"); @@ -102,9 +102,9 @@ void Qt3DQuick3DExtrasPlugin::registerTypes(const char *uri) qmlRegisterType(uri, 2, 0, "PerVertexColorMaterial"); qmlRegisterType(uri, 2, 0, "GoochMaterial"); qmlRegisterType(uri, 2, 0, "TextureMaterial"); - qmlRegisterType(uri, 2, 2, "MetalRoughMaterial"); - qmlRegisterType(uri, 2, 2, "TexturedMetalRoughMaterial"); - qmlRegisterType(uri, 2, 2, "MorphPhongMaterial"); + qmlRegisterType(uri, 2, 9, "MetalRoughMaterial"); + qmlRegisterType(uri, 2, 9, "TexturedMetalRoughMaterial"); + qmlRegisterType(uri, 2, 9, "MorphPhongMaterial"); // Meshes qmlRegisterType(uri, 2, 0, "ConeMesh"); @@ -121,11 +121,11 @@ void Qt3DQuick3DExtrasPlugin::registerTypes(const char *uri) qmlRegisterType(uri, 2, 0, "SphereGeometry"); // 3D Text - qmlRegisterType(uri, 2, 2, "ExtrudedTextGeometry"); - qmlRegisterType(uri, 2, 2, "ExtrudedTextMesh"); + qmlRegisterType(uri, 2, 9, "ExtrudedTextGeometry"); + qmlRegisterType(uri, 2, 9, "ExtrudedTextMesh"); - qmlRegisterType(uri, 2, 2, "DistanceFieldGlyphCache"); - qmlRegisterType(uri, 2, 2, "DistanceFieldText"); + qmlRegisterType(uri, 2, 9, "DistanceFieldGlyphCache"); + qmlRegisterType(uri, 2, 9, "DistanceFieldText"); } diff --git a/src/quick3d/imports/render/qt3dquick3drenderplugin.cpp b/src/quick3d/imports/render/qt3dquick3drenderplugin.cpp index 903e7ae08..1d017487f 100644 --- a/src/quick3d/imports/render/qt3dquick3drenderplugin.cpp +++ b/src/quick3d/imports/render/qt3dquick3drenderplugin.cpp @@ -200,16 +200,16 @@ void Qt3DQuick3DRenderPlugin::registerTypes(const char *uri) qmlRegisterType(uri, 2, 0, "Buffer"); Qt3DRender::Quick::registerExtendedType("QGeometry", "Qt3D.Render/Geometry", uri, 2, 0, "Geometry"); qmlRegisterType(uri, 2, 0, "GeometryRenderer"); - qmlRegisterType(uri, 2, 2, "LevelOfDetail"); - qmlRegisterType(uri, 2, 2, "LevelOfDetailSwitch"); - qmlRegisterType(uri, 2, 2, "BoundingSphere"); + qmlRegisterType(uri, 2, 9, "LevelOfDetail"); + qmlRegisterType(uri, 2, 9, "LevelOfDetailSwitch"); + qmlRegisterType(uri, 2, 9, "BoundingSphere"); // Mesh qmlRegisterType(uri, 2, 0, "Mesh"); // Picking qmlRegisterType(uri, 2, 0, "ObjectPicker"); - qmlRegisterType(uri, 2, 2, "EventForward"); + qmlRegisterType(uri, 2, 9, "EventForward"); qmlRegisterUncreatableType(uri, 2, 0, "PickEvent", QStringLiteral("Events cannot be created")); // Compute Job @@ -239,8 +239,8 @@ void Qt3DQuick3DRenderPlugin::registerTypes(const char *uri) qmlRegisterType(uri, 2, 0, "DispatchCompute"); qmlRegisterType(uri, 2, 1, "RenderCapture"); qmlRegisterUncreatableType(uri, 2, 1, "RenderCaptureReply", QStringLiteral("RenderCaptureReply is only instantiated by RenderCapture")); - qmlRegisterType(uri, 2, 0, "BufferCapture"); - Qt3DRender::Quick::registerExtendedType("QMemoryBarrier", "Qt3D.Render/MemoryBarrier", uri, 2, 0, "MemoryBarrier"); + qmlRegisterType(uri, 2, 9, "BufferCapture"); + Qt3DRender::Quick::registerExtendedType("QMemoryBarrier", "Qt3D.Render/MemoryBarrier", uri, 2, 9, "MemoryBarrier"); // RenderTarget qmlRegisterType(uri, 2, 0, "RenderTargetOutput"); @@ -277,7 +277,7 @@ void Qt3DQuick3DRenderPlugin::registerTypes(const char *uri) qmlRegisterType(uri, 2, 0, "StencilMask"); // Scene2D - Qt3DRender::Quick::registerType("QScene2D", "Qt3D.Render/Scene2D", uri, 2, 2, "Scene2D"); + Qt3DRender::Quick::registerType("QScene2D", "Qt3D.Render/Scene2D", uri, 2, 9, "Scene2D"); } QT_END_NAMESPACE diff --git a/tests/manual/anim-viewer/main.qml b/tests/manual/anim-viewer/main.qml index a31f8182d..15e9cd3f9 100644 --- a/tests/manual/anim-viewer/main.qml +++ b/tests/manual/anim-viewer/main.qml @@ -42,8 +42,8 @@ import QtQuick.Controls.Styles 1.4 import Qt3D.Core 2.0 import Qt3D.Render 2.0 import Qt3D.Input 2.0 -import Qt3D.Extras 2.2 -import Qt3D.Animation 2.2 +import Qt3D.Extras 2.9 +import Qt3D.Animation 2.9 import QtQuick.Scene3D 2.0 diff --git a/tests/manual/animation-keyframe-simple/main.qml b/tests/manual/animation-keyframe-simple/main.qml index 69bccde7d..2c7be6879 100644 --- a/tests/manual/animation-keyframe-simple/main.qml +++ b/tests/manual/animation-keyframe-simple/main.qml @@ -10,7 +10,7 @@ import Qt3D.Core 2.0 import Qt3D.Render 2.0 import Qt3D.Input 2.0 -import Qt3D.Animation 2.2 +import Qt3D.Animation 2.9 import Qt3D.Extras 2.0 DefaultSceneEntity { diff --git a/tests/manual/distancefieldtext/TextScene.qml b/tests/manual/distancefieldtext/TextScene.qml index 75fcf0e20..2d60a1c67 100644 --- a/tests/manual/distancefieldtext/TextScene.qml +++ b/tests/manual/distancefieldtext/TextScene.qml @@ -51,7 +51,7 @@ import Qt3D.Core 2.0 import Qt3D.Render 2.0 import Qt3D.Input 2.0 -import Qt3D.Extras 2.2 +import Qt3D.Extras 2.9 import QtQuick 2.0 as QQ2; Entity { diff --git a/tests/manual/lod/main.qml b/tests/manual/lod/main.qml index 8d9c8722a..d743f2fea 100644 --- a/tests/manual/lod/main.qml +++ b/tests/manual/lod/main.qml @@ -49,9 +49,9 @@ ****************************************************************************/ import Qt3D.Core 2.0 -import Qt3D.Render 2.2 +import Qt3D.Render 2.9 import Qt3D.Input 2.0 -import Qt3D.Extras 2.2 +import Qt3D.Extras 2.9 import QtQuick 2.0 as QQ2 diff --git a/tests/manual/render-qml-to-texture-qml/main.qml b/tests/manual/render-qml-to-texture-qml/main.qml index 32c919af7..3f605a1a3 100644 --- a/tests/manual/render-qml-to-texture-qml/main.qml +++ b/tests/manual/render-qml-to-texture-qml/main.qml @@ -35,7 +35,7 @@ ****************************************************************************/ import Qt3D.Core 2.0 -import Qt3D.Render 2.2 +import Qt3D.Render 2.9 import Qt3D.Input 2.0 import QtQuick 2.0 as QQ2 import QtQuick.Scene3D 2.0 diff --git a/tests/manual/video-texture-qml/main.qml b/tests/manual/video-texture-qml/main.qml index 4e72ab45f..418ec06c4 100644 --- a/tests/manual/video-texture-qml/main.qml +++ b/tests/manual/video-texture-qml/main.qml @@ -35,7 +35,7 @@ ****************************************************************************/ import Qt3D.Core 2.0 -import Qt3D.Render 2.2 +import Qt3D.Render 2.9 import Qt3D.Input 2.0 import QtQuick 2.2 as QQ2 import QtQuick.Window 2.0 as QW2 -- cgit v1.2.3 From cd4aac77040dd5500fd8b9d80f700eb0234390f6 Mon Sep 17 00:00:00 2001 From: Kevin Ottens Date: Thu, 16 Feb 2017 19:58:13 +0100 Subject: Start using REVISION on our properties Adding REVISION 9 on all the new properties from this release. Also registering the extra revisions on the QML side. Change-Id: Ic7eda36bee8ca19508cd73b61cea534f956c6997 Task-Id: QTBUG-58895 Reviewed-by: Sean Harmer --- src/core/nodes/qnode.h | 4 ++-- src/extras/defaults/qforwardrenderer.h | 2 +- src/extras/defaults/qskyboxentity.h | 2 +- src/quick3d/imports/core/qt3dquick3dcoreplugin.cpp | 1 + src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp | 2 ++ src/quick3d/imports/render/qt3dquick3drenderplugin.cpp | 7 +++++++ src/render/framegraph/qviewport.h | 2 +- src/render/frontend/qcamera.h | 2 +- src/render/frontend/qcameralens.h | 2 +- src/render/geometry/qbuffer.h | 2 +- src/render/io/qsceneloader.h | 8 ++++---- src/render/materialsystem/qshaderprogram.h | 4 ++-- src/render/picking/qobjectpicker.h | 2 +- tests/manual/buffercapture-qml/BufferSetterScene.qml | 2 +- tests/manual/buffercapture-qml/ComputeFrameGraph.qml | 2 +- 15 files changed, 27 insertions(+), 17 deletions(-) diff --git a/src/core/nodes/qnode.h b/src/core/nodes/qnode.h index 75ea61cc7..56c92da7f 100644 --- a/src/core/nodes/qnode.h +++ b/src/core/nodes/qnode.h @@ -69,8 +69,8 @@ class QT3DCORESHARED_EXPORT QNode : public QObject Q_OBJECT Q_PROPERTY(Qt3DCore::QNode *parent READ parentNode WRITE setParent NOTIFY parentChanged) Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged) - Q_PROPERTY(PropertyTrackMode propertyTrackMode READ propertyTrackMode WRITE setPropertyTrackMode NOTIFY propertyUpdateModeChanged) - Q_PROPERTY(QStringList trackedProperties READ trackedProperties WRITE setTrackedProperties NOTIFY trackedPropertiesChanged) + Q_PROPERTY(PropertyTrackMode propertyTrackMode READ propertyTrackMode WRITE setPropertyTrackMode NOTIFY propertyUpdateModeChanged REVISION 9) + Q_PROPERTY(QStringList trackedProperties READ trackedProperties WRITE setTrackedProperties NOTIFY trackedPropertiesChanged REVISION 9) public: enum PropertyTrackMode { diff --git a/src/extras/defaults/qforwardrenderer.h b/src/extras/defaults/qforwardrenderer.h index 160236462..a2527a4ec 100644 --- a/src/extras/defaults/qforwardrenderer.h +++ b/src/extras/defaults/qforwardrenderer.h @@ -63,7 +63,7 @@ class QT3DEXTRASSHARED_EXPORT QForwardRenderer : public Qt3DRender::QTechniqueFi Q_PROPERTY(Qt3DCore::QEntity *camera READ camera WRITE setCamera NOTIFY cameraChanged) Q_PROPERTY(QSize externalRenderTargetSize READ externalRenderTargetSize WRITE setExternalRenderTargetSize NOTIFY externalRenderTargetSizeChanged) Q_PROPERTY(bool frustumCulling READ isFrustumCullingEnabled WRITE setFrustumCullingEnabled NOTIFY frustumCullingEnabledChanged) - Q_PROPERTY(float gamma READ gamma WRITE setGamma NOTIFY gammaChanged) + Q_PROPERTY(float gamma READ gamma WRITE setGamma NOTIFY gammaChanged REVISION 9) public: explicit QForwardRenderer(Qt3DCore::QNode *parent = nullptr); ~QForwardRenderer(); diff --git a/src/extras/defaults/qskyboxentity.h b/src/extras/defaults/qskyboxentity.h index cc01ff7bb..2cf6bfa60 100644 --- a/src/extras/defaults/qskyboxentity.h +++ b/src/extras/defaults/qskyboxentity.h @@ -54,7 +54,7 @@ class QT3DEXTRASSHARED_EXPORT QSkyboxEntity : public Qt3DCore::QEntity Q_OBJECT Q_PROPERTY(QString baseName READ baseName WRITE setBaseName NOTIFY baseNameChanged) Q_PROPERTY(QString extension READ extension WRITE setExtension NOTIFY extensionChanged) - Q_PROPERTY(bool gammaCorrect READ isGammaCorrectEnabled WRITE setGammaCorrectEnabled NOTIFY gammaCorrectEnabledChanged) + Q_PROPERTY(bool gammaCorrect READ isGammaCorrectEnabled WRITE setGammaCorrectEnabled NOTIFY gammaCorrectEnabledChanged REVISION 9) public: explicit QSkyboxEntity(Qt3DCore::QNode *parent = nullptr); ~QSkyboxEntity(); diff --git a/src/quick3d/imports/core/qt3dquick3dcoreplugin.cpp b/src/quick3d/imports/core/qt3dquick3dcoreplugin.cpp index b72ee9600..8f470518c 100644 --- a/src/quick3d/imports/core/qt3dquick3dcoreplugin.cpp +++ b/src/quick3d/imports/core/qt3dquick3dcoreplugin.cpp @@ -65,6 +65,7 @@ void Qt3DQuick3DCorePlugin::registerTypes(const char *uri) // Ideally we want to make Node an uncreatable type // We would need qmlRegisterUncreatableExtendedType for that qmlRegisterExtendedUncreatableType(uri, 2, 0, "Node", QStringLiteral("Node is a base class")); + qmlRegisterExtendedUncreatableType(uri, 2, 9, "Node", QStringLiteral("Node is a base class")); } QT_END_NAMESPACE diff --git a/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp b/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp index 2dc871a6e..8aad63178 100644 --- a/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp +++ b/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp @@ -82,9 +82,11 @@ void Qt3DQuick3DExtrasPlugin::registerTypes(const char *uri) { // Framegraphs qmlRegisterType(uri, 2, 0, "ForwardRenderer"); + qmlRegisterRevision(uri, 2, 9); // Entities qmlRegisterType(uri, 2, 0, "SkyboxEntity"); + qmlRegisterRevision(uri, 2, 9); qmlRegisterType(uri, 2, 9, "LevelOfDetailLoader"); // Camera Controllers diff --git a/src/quick3d/imports/render/qt3dquick3drenderplugin.cpp b/src/quick3d/imports/render/qt3dquick3drenderplugin.cpp index 1d017487f..5eae523bd 100644 --- a/src/quick3d/imports/render/qt3dquick3drenderplugin.cpp +++ b/src/quick3d/imports/render/qt3dquick3drenderplugin.cpp @@ -159,6 +159,7 @@ void Qt3DQuick3DRenderPlugin::registerTypes(const char *uri) // @uri Qt3D.Render Qt3DRender::Quick::registerExtendedType("QSceneLoader", "Qt3D.Render/SceneLoader", uri, 2, 0, "SceneLoader"); + qmlRegisterRevision(uri, 2, 9); Qt3DRender::Quick::registerExtendedType("QEffect", "Qt3D.Render/Effect", uri, 2, 0, "Effect"); Qt3DRender::Quick::registerExtendedType("QTechnique", "Qt3D.Render/Technique", uri, 2, 0, "Technique"); qmlRegisterType(uri, 2, 0, "FilterKey"); @@ -168,13 +169,16 @@ void Qt3DQuick3DRenderPlugin::registerTypes(const char *uri) Qt3DRender::Quick::registerExtendedType("QMaterial", "Qt3D.Render/Material", uri, 2, 0, "Material"); Qt3DRender::Quick::registerExtendedType("QRenderPass", "Qt3D.Render/RenderPass", uri, 2, 0, "RenderPass"); qmlRegisterType(uri, 2, 0, "ShaderProgram"); + qmlRegisterRevision(uri, 2, 9); qmlRegisterUncreatableType(uri, 2, 0, "QShaderData", "Quick3D should instantiate Quick3DShaderData only"); qmlRegisterType(uri, 2, 0, "ShaderDataArray"); qmlRegisterType(uri, 2, 0, "ShaderData"); // Camera qmlRegisterType(uri, 2, 0, "Camera"); + qmlRegisterRevision(uri, 2, 9); qmlRegisterType(uri, 2, 0, "CameraLens"); + qmlRegisterRevision(uri, 2, 9); // Textures qmlRegisterType(uri, 2, 0, "WrapMode");//, QStringLiteral("QTextureWrapMode cannot be created from QML")); @@ -197,6 +201,7 @@ void Qt3DQuick3DRenderPlugin::registerTypes(const char *uri) // Geometry qmlRegisterType(uri, 2, 0, "Attribute"); qmlRegisterUncreatableType(uri, 2, 0, "BufferBase", QStringLiteral("Use Quick3DBuffer in QML")); + qmlRegisterUncreatableType(uri, 2, 9, "BufferBase", QStringLiteral("Use Quick3DBuffer in QML")); qmlRegisterType(uri, 2, 0, "Buffer"); Qt3DRender::Quick::registerExtendedType("QGeometry", "Qt3D.Render/Geometry", uri, 2, 0, "Geometry"); qmlRegisterType(uri, 2, 0, "GeometryRenderer"); @@ -209,6 +214,7 @@ void Qt3DQuick3DRenderPlugin::registerTypes(const char *uri) // Picking qmlRegisterType(uri, 2, 0, "ObjectPicker"); + qmlRegisterRevision(uri, 2, 9); qmlRegisterType(uri, 2, 9, "EventForward"); qmlRegisterUncreatableType(uri, 2, 0, "PickEvent", QStringLiteral("Events cannot be created")); @@ -230,6 +236,7 @@ void Qt3DQuick3DRenderPlugin::registerTypes(const char *uri) Qt3DRender::Quick::registerExtendedType("QRenderPassFilter", "Qt3D.Render/RenderPassFilter", uri, 2, 0, "RenderPassFilter"); Qt3DRender::Quick::registerExtendedType("QTechniqueFilter", "Qt3D.Render/TechniqueFilter", uri, 2, 0, "TechniqueFilter"); Qt3DRender::Quick::registerExtendedType("QViewport", "Qt3D.Render/Viewport", uri, 2, 0, "Viewport"); + qmlRegisterRevision(uri, 2, 9); Qt3DRender::Quick::registerExtendedType("QRenderTargetSelector", "Qt3D.Render/RenderTargetSelector", uri, 2, 0, "RenderTargetSelector"); qmlRegisterType(uri, 2, 0, "ClearBuffers"); qmlRegisterType(uri, 2, 0, "FrameGraphNode"); diff --git a/src/render/framegraph/qviewport.h b/src/render/framegraph/qviewport.h index abe423cf4..66a3428c5 100644 --- a/src/render/framegraph/qviewport.h +++ b/src/render/framegraph/qviewport.h @@ -54,7 +54,7 @@ class QT3DRENDERSHARED_EXPORT QViewport : public QFrameGraphNode { Q_OBJECT Q_PROPERTY(QRectF normalizedRect READ normalizedRect WRITE setNormalizedRect NOTIFY normalizedRectChanged) - Q_PROPERTY(float gamma READ gamma WRITE setGamma NOTIFY gammaChanged) + Q_PROPERTY(float gamma READ gamma WRITE setGamma NOTIFY gammaChanged REVISION 9) public: explicit QViewport(Qt3DCore::QNode *parent = nullptr); diff --git a/src/render/frontend/qcamera.h b/src/render/frontend/qcamera.h index 04e54d88c..dd7c63778 100644 --- a/src/render/frontend/qcamera.h +++ b/src/render/frontend/qcamera.h @@ -72,7 +72,7 @@ class QT3DRENDERSHARED_EXPORT QCamera : public Qt3DCore::QEntity Q_PROPERTY(float bottom READ bottom WRITE setBottom NOTIFY bottomChanged) Q_PROPERTY(float top READ top WRITE setTop NOTIFY topChanged) Q_PROPERTY(QMatrix4x4 projectionMatrix READ projectionMatrix WRITE setProjectionMatrix NOTIFY projectionMatrixChanged) - Q_PROPERTY(float exposure READ exposure WRITE setExposure NOTIFY exposureChanged) + Q_PROPERTY(float exposure READ exposure WRITE setExposure NOTIFY exposureChanged REVISION 9) // LookAt Q_PROPERTY(QVector3D position READ position WRITE setPosition NOTIFY positionChanged) Q_PROPERTY(QVector3D upVector READ upVector WRITE setUpVector NOTIFY upVectorChanged) diff --git a/src/render/frontend/qcameralens.h b/src/render/frontend/qcameralens.h index dc7cfa561..fdb0d5868 100644 --- a/src/render/frontend/qcameralens.h +++ b/src/render/frontend/qcameralens.h @@ -66,7 +66,7 @@ class QT3DRENDERSHARED_EXPORT QCameraLens : public Qt3DCore::QComponent Q_PROPERTY(float bottom READ bottom WRITE setBottom NOTIFY bottomChanged) Q_PROPERTY(float top READ top WRITE setTop NOTIFY topChanged) Q_PROPERTY(QMatrix4x4 projectionMatrix READ projectionMatrix WRITE setProjectionMatrix NOTIFY projectionMatrixChanged) - Q_PROPERTY(float exposure READ exposure WRITE setExposure NOTIFY exposureChanged) + Q_PROPERTY(float exposure READ exposure WRITE setExposure NOTIFY exposureChanged REVISION 9) public: explicit QCameraLens(QNode *parent = nullptr); diff --git a/src/render/geometry/qbuffer.h b/src/render/geometry/qbuffer.h index c3ed650f0..3e7f51086 100644 --- a/src/render/geometry/qbuffer.h +++ b/src/render/geometry/qbuffer.h @@ -59,7 +59,7 @@ class QT3DRENDERSHARED_EXPORT QBuffer : public Qt3DCore::QNode Q_PROPERTY(BufferType type READ type WRITE setType NOTIFY typeChanged) Q_PROPERTY(UsageType usage READ usage WRITE setUsage NOTIFY usageChanged) Q_PROPERTY(bool syncData READ isSyncData WRITE setSyncData NOTIFY syncDataChanged) - Q_PROPERTY(AccessType access READ access WRITE setAccess NOTIFY accessChanged) + Q_PROPERTY(AccessType access READ access WRITE setAccess NOTIFY accessChanged REVISION 9) public: enum BufferType diff --git a/src/render/io/qsceneloader.h b/src/render/io/qsceneloader.h index 76f8c4d80..31ec47ac0 100644 --- a/src/render/io/qsceneloader.h +++ b/src/render/io/qsceneloader.h @@ -82,10 +82,10 @@ public: QUrl source() const; Status status() const; - Q_INVOKABLE Qt3DCore::QEntity *entity(const QString &entityName) const; - Q_INVOKABLE QStringList entityNames() const; - Q_INVOKABLE Qt3DCore::QComponent *component(const QString &entityName, - ComponentType componentType) const; + Q_REVISION(9) Q_INVOKABLE Qt3DCore::QEntity *entity(const QString &entityName) const; + Q_REVISION(9) Q_INVOKABLE QStringList entityNames() const; + Q_REVISION(9) Q_INVOKABLE Qt3DCore::QComponent *component(const QString &entityName, + ComponentType componentType) const; public Q_SLOTS: void setSource(const QUrl &arg); diff --git a/src/render/materialsystem/qshaderprogram.h b/src/render/materialsystem/qshaderprogram.h index a5bee7d5f..8c3da1a4a 100644 --- a/src/render/materialsystem/qshaderprogram.h +++ b/src/render/materialsystem/qshaderprogram.h @@ -58,8 +58,8 @@ class QT3DRENDERSHARED_EXPORT QShaderProgram : public Qt3DCore::QNode Q_PROPERTY(QByteArray geometryShaderCode READ geometryShaderCode WRITE setGeometryShaderCode NOTIFY geometryShaderCodeChanged) Q_PROPERTY(QByteArray fragmentShaderCode READ fragmentShaderCode WRITE setFragmentShaderCode NOTIFY fragmentShaderCodeChanged) Q_PROPERTY(QByteArray computeShaderCode READ computeShaderCode WRITE setComputeShaderCode NOTIFY computeShaderCodeChanged) - Q_PROPERTY(QString log READ log NOTIFY logChanged) - Q_PROPERTY(Status status READ status NOTIFY statusChanged) + Q_PROPERTY(QString log READ log NOTIFY logChanged REVISION 9) + Q_PROPERTY(Status status READ status NOTIFY statusChanged REVISION 9) public: explicit QShaderProgram(Qt3DCore::QNode *parent = nullptr); diff --git a/src/render/picking/qobjectpicker.h b/src/render/picking/qobjectpicker.h index b00178851..eb715701f 100644 --- a/src/render/picking/qobjectpicker.h +++ b/src/render/picking/qobjectpicker.h @@ -59,7 +59,7 @@ class QT3DRENDERSHARED_EXPORT QObjectPicker : public Qt3DCore::QComponent Q_PROPERTY(bool dragEnabled READ isDragEnabled WRITE setDragEnabled NOTIFY dragEnabledChanged) Q_PROPERTY(bool pressed READ isPressed NOTIFY pressedChanged) Q_PROPERTY(bool containsMouse READ containsMouse NOTIFY containsMouseChanged) - Q_PROPERTY(Qt3DRender::QEventForward *eventForward READ eventForward WRITE setEventForward NOTIFY eventForwardChanged) + Q_PROPERTY(Qt3DRender::QEventForward *eventForward READ eventForward WRITE setEventForward NOTIFY eventForwardChanged REVISION 9) public: explicit QObjectPicker(QNode *parent = nullptr); diff --git a/tests/manual/buffercapture-qml/BufferSetterScene.qml b/tests/manual/buffercapture-qml/BufferSetterScene.qml index 530b73d43..06eb046a3 100644 --- a/tests/manual/buffercapture-qml/BufferSetterScene.qml +++ b/tests/manual/buffercapture-qml/BufferSetterScene.qml @@ -50,7 +50,7 @@ import QtQuick 2.2 as QQ2 import Qt3D.Core 2.0 -import Qt3D.Render 2.1 +import Qt3D.Render 2.9 import Qt3D.Input 2.0 import Qt3D.Extras 2.0 diff --git a/tests/manual/buffercapture-qml/ComputeFrameGraph.qml b/tests/manual/buffercapture-qml/ComputeFrameGraph.qml index 6c510598b..bc2061e1a 100644 --- a/tests/manual/buffercapture-qml/ComputeFrameGraph.qml +++ b/tests/manual/buffercapture-qml/ComputeFrameGraph.qml @@ -49,7 +49,7 @@ ****************************************************************************/ import Qt3D.Core 2.0 -import Qt3D.Render 2.0 +import Qt3D.Render 2.9 Viewport { RenderSurfaceSelector { -- cgit v1.2.3 From a7942ff7260a213cdb3feb897173847742544f5b Mon Sep 17 00:00:00 2001 From: Kevin Ottens Date: Fri, 17 Feb 2017 13:47:30 +0100 Subject: Clean up QRenderCapture(Reply) API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We don't need the captureId in the public API so deprecate the functions which make it appear and create overloads with no such id when appropriate. Only a pointer to a QRenderCaptureReply is needed to represent a capture request. Also the "isCompleted" parameter is unneeded on the signal since it is always true anyway. If we'd want to do error management it would go via a status flag property or similar. Change-Id: I9571ece3e3f82f46db5b3993ccf035e770c9d55e Task-Id: QTBUG-58877 Reviewed-by: Antti Määttä Reviewed-by: Paul Lemire --- .../imports/render/qt3dquick3drenderplugin.cpp | 1 + src/render/framegraph/qrendercapture.cpp | 36 +++++++++++++++++++++- src/render/framegraph/qrendercapture.h | 11 ++++--- .../render/qrendercapture/tst_qrendercapture.cpp | 9 +++--- tests/manual/rendercapture-cpp/mycapture.h | 26 ++++++---------- tests/manual/rendercapture-qml/CaptureScene.qml | 4 +-- tests/manual/rendercapture-qml/main.qml | 4 +-- 7 files changed, 61 insertions(+), 30 deletions(-) diff --git a/src/quick3d/imports/render/qt3dquick3drenderplugin.cpp b/src/quick3d/imports/render/qt3dquick3drenderplugin.cpp index 5eae523bd..6bc9b213a 100644 --- a/src/quick3d/imports/render/qt3dquick3drenderplugin.cpp +++ b/src/quick3d/imports/render/qt3dquick3drenderplugin.cpp @@ -245,6 +245,7 @@ void Qt3DQuick3DRenderPlugin::registerTypes(const char *uri) qmlRegisterType(uri, 2, 0, "FrustumCulling"); qmlRegisterType(uri, 2, 0, "DispatchCompute"); qmlRegisterType(uri, 2, 1, "RenderCapture"); + qmlRegisterRevision(uri, 2, 9); qmlRegisterUncreatableType(uri, 2, 1, "RenderCaptureReply", QStringLiteral("RenderCaptureReply is only instantiated by RenderCapture")); qmlRegisterType(uri, 2, 9, "BufferCapture"); Qt3DRender::Quick::registerExtendedType("QMemoryBarrier", "Qt3D.Render/MemoryBarrier", uri, 2, 9, "MemoryBarrier"); diff --git a/src/render/framegraph/qrendercapture.cpp b/src/render/framegraph/qrendercapture.cpp index a4a5dabcb..955345cea 100644 --- a/src/render/framegraph/qrendercapture.cpp +++ b/src/render/framegraph/qrendercapture.cpp @@ -115,6 +115,7 @@ namespace Qt3DRender { /*! * \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 @@ -123,6 +124,15 @@ namespace Qt3DRender { * when it is done. The user is reponsible 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. + */ + /*! * \internal */ @@ -212,7 +222,7 @@ QRenderCaptureReply *QRenderCapturePrivate::takeReply(int captureId) { QRenderCaptureReply *reply = nullptr; for (int i = 0; i < m_waitingReplies.size(); ++i) { - if (m_waitingReplies[i]->captureId() == captureId) { + if (m_waitingReplies[i]->d_func()->m_captureId == captureId) { reply = m_waitingReplies[i]; m_waitingReplies.remove(i); break; @@ -239,6 +249,7 @@ QRenderCapture::QRenderCapture(Qt3DCore::QNode *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. @@ -258,6 +269,28 @@ QRenderCaptureReply *QRenderCapture::requestCapture(int 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. + */ +QRenderCaptureReply *QRenderCapture::requestCapture() +{ + Q_D(QRenderCapture); + static int captureId = 1; + QRenderCaptureReply *reply = d->createReply(captureId); + + Qt3DCore::QPropertyUpdatedChangePtr change(new Qt3DCore::QPropertyUpdatedChange(id())); + change->setPropertyName(QByteArrayLiteral("renderCaptureRequest")); + change->setValue(QVariant::fromValue(captureId)); + d->notifyObservers(change); + + captureId++; + + return reply; +} + /*! * \internal */ @@ -271,6 +304,7 @@ void QRenderCapture::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) QRenderCaptureReply *reply = d->takeReply(data.data()->captureId); if (reply) { d->setImage(reply, data.data()->image); + emit reply->completed(); emit reply->completeChanged(true); } } diff --git a/src/render/framegraph/qrendercapture.h b/src/render/framegraph/qrendercapture.h index f3be273f3..698b2d8d4 100644 --- a/src/render/framegraph/qrendercapture.h +++ b/src/render/framegraph/qrendercapture.h @@ -52,18 +52,19 @@ class QT3DRENDERSHARED_EXPORT QRenderCaptureReply : public QObject Q_OBJECT Q_PROPERTY(QImage image READ image CONSTANT) Q_PROPERTY(int captureId READ captureId CONSTANT) - Q_PROPERTY(bool complete READ isComplete NOTIFY completeChanged) + Q_PROPERTY(bool complete READ isComplete NOTIFY completed) public: QImage image() const; - int captureId() const; + Q_DECL_DEPRECATED int captureId() const; bool isComplete() const; Q_INVOKABLE void saveToFile(const QString &fileName) const; Q_SIGNALS: - void completeChanged(bool isComplete); + Q_DECL_DEPRECATED_X("Use completed instead") void completeChanged(bool isComplete); + void completed(); private: Q_DECLARE_PRIVATE(QRenderCaptureReply) @@ -79,7 +80,9 @@ class QT3DRENDERSHARED_EXPORT QRenderCapture : public QFrameGraphNode public: explicit QRenderCapture(Qt3DCore::QNode *parent = nullptr); - Q_INVOKABLE Qt3DRender::QRenderCaptureReply *requestCapture(int captureId); + Q_INVOKABLE Q_DECL_DEPRECATED_X("Use the overload with no parameter") + Qt3DRender::QRenderCaptureReply *requestCapture(int captureId); + Q_REVISION(9) Q_INVOKABLE Qt3DRender::QRenderCaptureReply *requestCapture(); protected: void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) Q_DECL_OVERRIDE; diff --git a/tests/auto/render/qrendercapture/tst_qrendercapture.cpp b/tests/auto/render/qrendercapture/tst_qrendercapture.cpp index ef1e9f53c..e0037f3dd 100644 --- a/tests/auto/render/qrendercapture/tst_qrendercapture.cpp +++ b/tests/auto/render/qrendercapture/tst_qrendercapture.cpp @@ -67,7 +67,7 @@ private Q_SLOTS: arbiter.setArbiterOnNode(renderCapture.data()); // WHEN - QScopedPointer reply(renderCapture->requestCapture(12)); + QScopedPointer reply(renderCapture->requestCapture()); // THEN QCOMPARE(arbiter.events.size(), 1); @@ -75,7 +75,7 @@ private Q_SLOTS: QCOMPARE(change->propertyName(), "renderCaptureRequest"); QCOMPARE(change->subjectId(),renderCapture->id()); QCOMPARE(change->type(), Qt3DCore::PropertyUpdated); - QCOMPARE(change->value().toInt(), 12); + QCOMPARE(change->value().toInt(), 1); arbiter.events.clear(); } @@ -84,12 +84,12 @@ private Q_SLOTS: { // GIVEN QScopedPointer renderCapture(new MyRenderCapture()); - QScopedPointer reply(renderCapture->requestCapture(52)); + QScopedPointer reply(renderCapture->requestCapture()); QImage img = QImage(20, 20, QImage::Format_ARGB32); // WHEN Qt3DRender::RenderCaptureDataPtr data = Qt3DRender::RenderCaptureDataPtr::create(); - data.data()->captureId = 52; + data.data()->captureId = 2; data.data()->image = img; auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(renderCapture->id()); @@ -101,7 +101,6 @@ private Q_SLOTS: // THEN QCOMPARE(reply->isComplete(), true); - QCOMPARE(reply->captureId(), 52); QCOMPARE(reply->image().width(), 20); QCOMPARE(reply->image().height(), 20); QCOMPARE(reply->image().format(), QImage::Format_ARGB32); diff --git a/tests/manual/rendercapture-cpp/mycapture.h b/tests/manual/rendercapture-cpp/mycapture.h index 249561a1e..cfd4afd6c 100644 --- a/tests/manual/rendercapture-cpp/mycapture.h +++ b/tests/manual/rendercapture-cpp/mycapture.h @@ -63,28 +63,23 @@ public: , m_reply(nullptr) , m_imageLabel(imageLabel) , m_continuous(false) - , m_cid(1) { } public slots: - void onCompleted(bool isComplete) + void onCompleted() { - if (isComplete) { - QObject::disconnect(connection); + QObject::disconnect(connection); - m_imageLabel->setPixmap(QPixmap::fromImage(m_reply->image())); + m_imageLabel->setPixmap(QPixmap::fromImage(m_reply->image())); - ++m_cid; + m_reply->saveToFile("capture.bmp"); - m_reply->saveToFile("capture.bmp"); + delete m_reply; + m_reply = nullptr; - delete m_reply; - m_reply = nullptr; - - if (m_continuous) - capture(); - } + if (m_continuous) + capture(); } void setContinuous(bool continuos) @@ -94,8 +89,8 @@ public slots: void capture() { - m_reply = m_capture->requestCapture(m_cid); - connection = QObject::connect(m_reply, &Qt3DRender::QRenderCaptureReply::completeChanged, + m_reply = m_capture->requestCapture(); + connection = QObject::connect(m_reply, &Qt3DRender::QRenderCaptureReply::completed, this, &MyCapture::onCompleted); } @@ -105,7 +100,6 @@ private: QMetaObject::Connection connection; QLabel *m_imageLabel; bool m_continuous; - int m_cid; }; #endif diff --git a/tests/manual/rendercapture-qml/CaptureScene.qml b/tests/manual/rendercapture-qml/CaptureScene.qml index 2329e4730..ea355042a 100644 --- a/tests/manual/rendercapture-qml/CaptureScene.qml +++ b/tests/manual/rendercapture-qml/CaptureScene.qml @@ -57,9 +57,9 @@ import Qt3D.Extras 2.0 Entity { id: sceneRoot - function requestRenderCapture(cid) + function requestRenderCapture() { - return renderCapture.requestCapture(cid) + return renderCapture.requestCapture() } Camera { diff --git a/tests/manual/rendercapture-qml/main.qml b/tests/manual/rendercapture-qml/main.qml index 77e96d739..fdb2e3519 100644 --- a/tests/manual/rendercapture-qml/main.qml +++ b/tests/manual/rendercapture-qml/main.qml @@ -51,7 +51,7 @@ import QtQuick 2.2 import QtQuick.Layouts 1.3 import QtQuick.Controls 1.4 -import Qt3D.Render 2.1 +import Qt3D.Render 2.9 import QtQuick.Scene3D 2.0 Item { @@ -96,7 +96,7 @@ Item { function doRenderCapture() { - reply = scene.requestRenderCapture(cid) + reply = scene.requestRenderCapture() reply.completeChanged.connect(onRenderCaptureComplete) } -- cgit v1.2.3 From a7bc39881783de3db3bc122f20ce11274998a148 Mon Sep 17 00:00:00 2001 From: Kevin Ottens Date: Fri, 17 Feb 2017 16:10:17 +0100 Subject: Introduce QAbstractClipAnimator This becomes the new base class for QClipAnimator. Change-Id: I53d38cae8c3cee73e07084d2d58e317ba19ced7b Task-Id: QTBUG-58899 Reviewed-by: Paul Lemire --- src/animation/frontend/frontend.pri | 3 + src/animation/frontend/qabstractclipanimator.cpp | 130 +++++++++++++++++++++ src/animation/frontend/qabstractclipanimator.h | 90 ++++++++++++++ src/animation/frontend/qabstractclipanimator_p.h | 87 ++++++++++++++ src/animation/frontend/qclipanimator.cpp | 66 +---------- src/animation/frontend/qclipanimator.h | 17 +-- src/animation/frontend/qclipanimator_p.h | 14 +-- .../animation/qt3dquick3danimationplugin.cpp | 2 + 8 files changed, 320 insertions(+), 89 deletions(-) create mode 100644 src/animation/frontend/qabstractclipanimator.cpp create mode 100644 src/animation/frontend/qabstractclipanimator.h create mode 100644 src/animation/frontend/qabstractclipanimator_p.h diff --git a/src/animation/frontend/frontend.pri b/src/animation/frontend/frontend.pri index c6aec043f..d6895510a 100644 --- a/src/animation/frontend/frontend.pri +++ b/src/animation/frontend/frontend.pri @@ -3,6 +3,8 @@ HEADERS += \ $$PWD/qanimationaspect_p.h \ $$PWD/qanimationclip.h \ $$PWD/qanimationclip_p.h \ + $$PWD/qabstractclipanimator.h \ + $$PWD/qabstractclipanimator_p.h \ $$PWD/qabstractclipblendnode.h \ $$PWD/qabstractclipblendnode_p.h \ $$PWD/qclipanimator.h \ @@ -37,6 +39,7 @@ HEADERS += \ SOURCES += \ $$PWD/qanimationaspect.cpp \ $$PWD/qanimationclip.cpp \ + $$PWD/qabstractclipanimator.cpp \ $$PWD/qabstractclipblendnode.cpp \ $$PWD/qclipanimator.cpp \ $$PWD/qblendedclipanimator.cpp \ diff --git a/src/animation/frontend/qabstractclipanimator.cpp b/src/animation/frontend/qabstractclipanimator.cpp new file mode 100644 index 000000000..05f80c8ba --- /dev/null +++ b/src/animation/frontend/qabstractclipanimator.cpp @@ -0,0 +1,130 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qabstractclipanimator.h" +#include "qabstractclipanimator_p.h" +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { + +QAbstractClipAnimatorPrivate::QAbstractClipAnimatorPrivate() + : Qt3DCore::QComponentPrivate() + , m_mapper(nullptr) + , m_running(false) + , m_loops(1) +{ +} + +QAbstractClipAnimator::QAbstractClipAnimator(Qt3DCore::QNode *parent) + : Qt3DCore::QComponent(*new QAbstractClipAnimatorPrivate, parent) +{ +} + +QAbstractClipAnimator::QAbstractClipAnimator(QAbstractClipAnimatorPrivate &dd, Qt3DCore::QNode *parent) + : Qt3DCore::QComponent(dd, parent) +{ +} + +QAbstractClipAnimator::~QAbstractClipAnimator() +{ +} + +bool QAbstractClipAnimator::isRunning() const +{ + Q_D(const QAbstractClipAnimator); + return d->m_running; +} + +QChannelMapper *QAbstractClipAnimator::channelMapper() const +{ + Q_D(const QAbstractClipAnimator); + return d->m_mapper; +} + +int QAbstractClipAnimator::loops() const +{ + Q_D(const QAbstractClipAnimator); + return d->m_loops; +} + +void QAbstractClipAnimator::setRunning(bool running) +{ + Q_D(QAbstractClipAnimator); + if (d->m_running == running) + return; + + d->m_running = running; + emit runningChanged(running); +} + +void QAbstractClipAnimator::setChannelMapper(QChannelMapper *mapping) +{ + Q_D(QAbstractClipAnimator); + if (d->m_mapper == mapping) + return; + + if (d->m_mapper) + d->unregisterDestructionHelper(d->m_mapper); + + if (mapping && !mapping->parent()) + mapping->setParent(this); + d->m_mapper = mapping; + + // Ensures proper bookkeeping + if (d->m_mapper) + d->registerDestructionHelper(d->m_mapper, &QAbstractClipAnimator::setChannelMapper, d->m_mapper); + emit channelMapperChanged(mapping); +} + +void QAbstractClipAnimator::setLoops(int loops) +{ + Q_D(QAbstractClipAnimator); + if (d->m_loops == loops) + return; + + d->m_loops = loops; + emit loopsChanged(loops); +} + +} // namespace Qt3DAnimation + +QT_END_NAMESPACE diff --git a/src/animation/frontend/qabstractclipanimator.h b/src/animation/frontend/qabstractclipanimator.h new file mode 100644 index 000000000..e17740c38 --- /dev/null +++ b/src/animation/frontend/qabstractclipanimator.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3DANIMATION_QABSTRACTCLIPANIMATOR_H +#define QT3DANIMATION_QABSTRACTCLIPANIMATOR_H + +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { + +class QAnimationClip; +class QChannelMapper; +class QAbstractClipAnimatorPrivate; + +class QT3DANIMATIONSHARED_EXPORT QAbstractClipAnimator : public Qt3DCore::QComponent +{ + Q_OBJECT + Q_PROPERTY(bool running READ isRunning WRITE setRunning NOTIFY runningChanged) + Q_PROPERTY(int loops READ loops WRITE setLoops NOTIFY loopsChanged) + Q_PROPERTY(Qt3DAnimation::QChannelMapper *channelMapper READ channelMapper WRITE setChannelMapper NOTIFY channelMapperChanged) + +public: + ~QAbstractClipAnimator(); + + bool isRunning() const; + Qt3DAnimation::QChannelMapper *channelMapper() const; + int loops() const; + +public Q_SLOTS: + void setRunning(bool running); + void setChannelMapper(Qt3DAnimation::QChannelMapper *channelMapper); + void setLoops(int loops); + +Q_SIGNALS: + void runningChanged(bool running); + void channelMapperChanged(Qt3DAnimation::QChannelMapper *channelMapper); + void loopsChanged(int loops); + +protected: + explicit QAbstractClipAnimator(Qt3DCore::QNode *parent = nullptr); + QAbstractClipAnimator(QAbstractClipAnimatorPrivate &dd, Qt3DCore::QNode *parent = nullptr); + +private: + Q_DECLARE_PRIVATE(QAbstractClipAnimator) +}; + +} // namespace Qt3DAnimation + +QT_END_NAMESPACE + +#endif // QT3DANIMATION_QABSTRACTCLIPANIMATOR_H diff --git a/src/animation/frontend/qabstractclipanimator_p.h b/src/animation/frontend/qabstractclipanimator_p.h new file mode 100644 index 000000000..89263af7e --- /dev/null +++ b/src/animation/frontend/qabstractclipanimator_p.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3DANIMATION_QABSTRACTCLIPANIMATOR_P_H +#define QT3DANIMATION_QABSTRACTCLIPANIMATOR_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { + +class QChannelMapper; + +class QAbstractClipAnimatorPrivate : public Qt3DCore::QComponentPrivate +{ +public: + QAbstractClipAnimatorPrivate(); + + Q_DECLARE_PUBLIC(QAbstractClipAnimator) + + Qt3DAnimation::QChannelMapper *m_mapper; + bool m_running; + int m_loops; +}; + +struct QAbstractClipAnimatorData +{ + Qt3DCore::QNodeId mapperId; + bool running; + int loops; +}; + +} // namespace Qt3DAnimation + + +QT_END_NAMESPACE + +#endif // QT3DANIMATION_QABSTRACTCLIPANIMATOR_P_H diff --git a/src/animation/frontend/qclipanimator.cpp b/src/animation/frontend/qclipanimator.cpp index e6c06c989..683d2a8dd 100644 --- a/src/animation/frontend/qclipanimator.cpp +++ b/src/animation/frontend/qclipanimator.cpp @@ -47,21 +47,18 @@ QT_BEGIN_NAMESPACE namespace Qt3DAnimation { QClipAnimatorPrivate::QClipAnimatorPrivate() - : Qt3DCore::QComponentPrivate() + : Qt3DAnimation::QAbstractClipAnimatorPrivate() , m_clip(nullptr) - , m_mapper(nullptr) - , m_running(false) - , m_loops(1) { } QClipAnimator::QClipAnimator(Qt3DCore::QNode *parent) - : Qt3DCore::QComponent(*new QClipAnimatorPrivate, parent) + : Qt3DAnimation::QAbstractClipAnimator(*new QClipAnimatorPrivate, parent) { } QClipAnimator::QClipAnimator(QClipAnimatorPrivate &dd, Qt3DCore::QNode *parent) - : Qt3DCore::QComponent(dd, parent) + : Qt3DAnimation::QAbstractClipAnimator(dd, parent) { } @@ -75,24 +72,6 @@ QAnimationClip *QClipAnimator::clip() const return d->m_clip; } -bool QClipAnimator::isRunning() const -{ - Q_D(const QClipAnimator); - return d->m_running; -} - -QChannelMapper *QClipAnimator::channelMapper() const -{ - Q_D(const QClipAnimator); - return d->m_mapper; -} - -int QClipAnimator::loops() const -{ - Q_D(const QClipAnimator); - return d->m_loops; -} - void QClipAnimator::setClip(QAnimationClip *clip) { Q_D(QClipAnimator); @@ -112,45 +91,6 @@ void QClipAnimator::setClip(QAnimationClip *clip) emit clipChanged(clip); } -void QClipAnimator::setRunning(bool running) -{ - Q_D(QClipAnimator); - if (d->m_running == running) - return; - - d->m_running = running; - emit runningChanged(running); -} - -void QClipAnimator::setChannelMapper(QChannelMapper *mapping) -{ - Q_D(QClipAnimator); - if (d->m_mapper == mapping) - return; - - if (d->m_mapper) - d->unregisterDestructionHelper(d->m_mapper); - - if (mapping && !mapping->parent()) - mapping->setParent(this); - d->m_mapper = mapping; - - // Ensures proper bookkeeping - if (d->m_mapper) - d->registerDestructionHelper(d->m_mapper, &QClipAnimator::setChannelMapper, d->m_mapper); - emit channelMapperChanged(mapping); -} - -void QClipAnimator::setLoops(int loops) -{ - Q_D(QClipAnimator); - if (d->m_loops == loops) - return; - - d->m_loops = loops; - emit loopsChanged(loops); -} - Qt3DCore::QNodeCreatedChangeBasePtr QClipAnimator::createNodeCreationChange() const { auto creationChange = Qt3DCore::QNodeCreatedChangePtr::create(this); diff --git a/src/animation/frontend/qclipanimator.h b/src/animation/frontend/qclipanimator.h index 176d6fc0c..78fe9b6b5 100644 --- a/src/animation/frontend/qclipanimator.h +++ b/src/animation/frontend/qclipanimator.h @@ -41,44 +41,31 @@ #define QT3DANIMATION_QCLIPANIMATOR_H #include -#include +#include QT_BEGIN_NAMESPACE namespace Qt3DAnimation { class QAnimationClip; -class QChannelMapper; class QClipAnimatorPrivate; -class QT3DANIMATIONSHARED_EXPORT QClipAnimator : public Qt3DCore::QComponent +class QT3DANIMATIONSHARED_EXPORT QClipAnimator : public Qt3DAnimation::QAbstractClipAnimator { Q_OBJECT Q_PROPERTY(Qt3DAnimation::QAnimationClip *clip READ clip WRITE setClip NOTIFY clipChanged) - Q_PROPERTY(bool running READ isRunning WRITE setRunning NOTIFY runningChanged) - Q_PROPERTY(int loops READ loops WRITE setLoops NOTIFY loopsChanged) - Q_PROPERTY(Qt3DAnimation::QChannelMapper *channelMapper READ channelMapper WRITE setChannelMapper NOTIFY channelMapperChanged) public: explicit QClipAnimator(Qt3DCore::QNode *parent = nullptr); ~QClipAnimator(); Qt3DAnimation::QAnimationClip *clip() const; - bool isRunning() const; - Qt3DAnimation::QChannelMapper *channelMapper() const; - int loops() const; public Q_SLOTS: void setClip(Qt3DAnimation::QAnimationClip *clip); - void setRunning(bool running); - void setChannelMapper(Qt3DAnimation::QChannelMapper *channelMapper); - void setLoops(int loops); Q_SIGNALS: void clipChanged(Qt3DAnimation::QAnimationClip *clip); - void runningChanged(bool running); - void channelMapperChanged(Qt3DAnimation::QChannelMapper *channelMapper); - void loopsChanged(int loops); protected: QClipAnimator(QClipAnimatorPrivate &dd, Qt3DCore::QNode *parent = nullptr); diff --git a/src/animation/frontend/qclipanimator_p.h b/src/animation/frontend/qclipanimator_p.h index 7bb9c526f..7057ee065 100644 --- a/src/animation/frontend/qclipanimator_p.h +++ b/src/animation/frontend/qclipanimator_p.h @@ -51,16 +51,14 @@ // We mean it. // -#include +#include #include QT_BEGIN_NAMESPACE namespace Qt3DAnimation { -class QChannelMapper; - -class QClipAnimatorPrivate : public Qt3DCore::QComponentPrivate +class QClipAnimatorPrivate : public Qt3DAnimation::QAbstractClipAnimatorPrivate { public: QClipAnimatorPrivate(); @@ -68,17 +66,11 @@ public: Q_DECLARE_PUBLIC(QClipAnimator) QAnimationClip *m_clip; - Qt3DAnimation::QChannelMapper *m_mapper; - bool m_running; - int m_loops; }; -struct QClipAnimatorData +struct QClipAnimatorData : public QAbstractClipAnimatorData { Qt3DCore::QNodeId clipId; - Qt3DCore::QNodeId mapperId; - bool running; - int loops; }; } // namespace Qt3DAnimation diff --git a/src/quick3d/imports/animation/qt3dquick3danimationplugin.cpp b/src/quick3d/imports/animation/qt3dquick3danimationplugin.cpp index 3db188ce6..d47e3c1bc 100644 --- a/src/quick3d/imports/animation/qt3dquick3danimationplugin.cpp +++ b/src/quick3d/imports/animation/qt3dquick3danimationplugin.cpp @@ -38,6 +38,7 @@ ****************************************************************************/ #include "qt3dquick3danimationplugin.h" +#include #include #include #include @@ -69,6 +70,7 @@ void Qt3DQuick3DAnimationPlugin::registerTypes(const char *uri) // @uri Qt3D.Animation qmlRegisterType(uri, 2, 9, "AnimationClip"); + qmlRegisterUncreatableType(uri, 2, 9, "AbstractClipAnimator", QStringLiteral("QAbstractClipAnimator is abstract")); qmlRegisterType(uri, 2, 9, "ClipAnimator"); qmlRegisterType(uri, 2, 9, "BlendedClipAnimator"); qmlRegisterType(uri, 2, 9, "ChannelMapping"); -- cgit v1.2.3 From da43857570a7b0ecb765af7c047e049635f6399b Mon Sep 17 00:00:00 2001 From: Kevin Ottens Date: Fri, 17 Feb 2017 16:27:40 +0100 Subject: Have QBlendedClipAnimator inherit from QAbstractClipAnimator Change-Id: I3141c9fc9f5cc3fbdd2635b45517b684f5ebdec7 Task-Id: QTBUG-58899 Reviewed-by: Paul Lemire --- src/animation/frontend/qblendedclipanimator.cpp | 66 ++----------------------- src/animation/frontend/qblendedclipanimator.h | 17 +------ src/animation/frontend/qblendedclipanimator_p.h | 13 ++--- 3 files changed, 8 insertions(+), 88 deletions(-) diff --git a/src/animation/frontend/qblendedclipanimator.cpp b/src/animation/frontend/qblendedclipanimator.cpp index 9d3bf5ba2..971f4e1e7 100644 --- a/src/animation/frontend/qblendedclipanimator.cpp +++ b/src/animation/frontend/qblendedclipanimator.cpp @@ -46,11 +46,8 @@ QT_BEGIN_NAMESPACE namespace Qt3DAnimation { QBlendedClipAnimatorPrivate::QBlendedClipAnimatorPrivate() - : Qt3DCore::QComponentPrivate() + : Qt3DAnimation::QAbstractClipAnimatorPrivate() , m_blendTreeRoot(nullptr) - , m_mapper(nullptr) - , m_running(false) - , m_loops(1) { } @@ -80,12 +77,12 @@ QBlendedClipAnimatorPrivate::QBlendedClipAnimatorPrivate() \since 5.9 */ QBlendedClipAnimator::QBlendedClipAnimator(Qt3DCore::QNode *parent) - : Qt3DCore::QComponent(*new QBlendedClipAnimatorPrivate, parent) + : Qt3DAnimation::QAbstractClipAnimator(*new QBlendedClipAnimatorPrivate, parent) { } QBlendedClipAnimator::QBlendedClipAnimator(QBlendedClipAnimatorPrivate &dd, Qt3DCore::QNode *parent) - : Qt3DCore::QComponent(dd, parent) + : Qt3DAnimation::QAbstractClipAnimator(dd, parent) { } @@ -99,24 +96,6 @@ QAbstractClipBlendNode *QBlendedClipAnimator::blendTree() const return d->m_blendTreeRoot; } -bool QBlendedClipAnimator::isRunning() const -{ - Q_D(const QBlendedClipAnimator); - return d->m_running; -} - -QChannelMapper *QBlendedClipAnimator::channelMapper() const -{ - Q_D(const QBlendedClipAnimator); - return d->m_mapper; -} - -int QBlendedClipAnimator::loops() const -{ - Q_D(const QBlendedClipAnimator); - return d->m_loops; -} - void QBlendedClipAnimator::setBlendTree(QAbstractClipBlendNode *blendTree) { Q_D(QBlendedClipAnimator); @@ -137,45 +116,6 @@ void QBlendedClipAnimator::setBlendTree(QAbstractClipBlendNode *blendTree) emit blendTreeChanged(blendTree); } -void QBlendedClipAnimator::setRunning(bool running) -{ - Q_D(QBlendedClipAnimator); - if (d->m_running == running) - return; - - d->m_running = running; - emit runningChanged(running); -} - -void QBlendedClipAnimator::setLoops(int loops) -{ - Q_D(QBlendedClipAnimator); - if (d->m_loops == loops) - return; - - d->m_loops = loops; - emit loopsChanged(loops); -} - - -void QBlendedClipAnimator::setChannelMapper(QChannelMapper *mapping) -{ - Q_D(QBlendedClipAnimator); - if (d->m_mapper == mapping) - return; - - if (d->m_mapper) - d->unregisterDestructionHelper(d->m_mapper); - - if (mapping && !mapping->parent()) - mapping->setParent(this); - d->m_mapper = mapping; - - if (d->m_mapper) - d->registerDestructionHelper(d->m_mapper, &QBlendedClipAnimator::setChannelMapper, d->m_mapper); - emit channelMapperChanged(mapping); -} - Qt3DCore::QNodeCreatedChangeBasePtr QBlendedClipAnimator::createNodeCreationChange() const { auto creationChange = Qt3DCore::QNodeCreatedChangePtr::create(this); diff --git a/src/animation/frontend/qblendedclipanimator.h b/src/animation/frontend/qblendedclipanimator.h index be1189f4f..e09e2dbc8 100644 --- a/src/animation/frontend/qblendedclipanimator.h +++ b/src/animation/frontend/qblendedclipanimator.h @@ -41,44 +41,31 @@ #define QT3DANIMATION_QBLENDEDCLIPANIMATOR_H #include -#include +#include QT_BEGIN_NAMESPACE namespace Qt3DAnimation { -class QChannelMapper; class QAbstractClipBlendNode; class QBlendedClipAnimatorPrivate; -class QT3DANIMATIONSHARED_EXPORT QBlendedClipAnimator : public Qt3DCore::QComponent +class QT3DANIMATIONSHARED_EXPORT QBlendedClipAnimator : public Qt3DAnimation::QAbstractClipAnimator { Q_OBJECT Q_PROPERTY(Qt3DAnimation::QAbstractClipBlendNode *blendTree READ blendTree WRITE setBlendTree NOTIFY blendTreeChanged) - Q_PROPERTY(Qt3DAnimation::QChannelMapper *channelMapper READ channelMapper WRITE setChannelMapper NOTIFY channelMapperChanged) - Q_PROPERTY(int loops READ loops WRITE setLoops NOTIFY loopsChanged) - Q_PROPERTY(bool running READ isRunning WRITE setRunning NOTIFY runningChanged) public: explicit QBlendedClipAnimator(Qt3DCore::QNode *parent = nullptr); ~QBlendedClipAnimator(); - bool isRunning() const; - Qt3DAnimation::QChannelMapper *channelMapper() const; QAbstractClipBlendNode *blendTree() const; - int loops() const; public Q_SLOTS: - void setRunning(bool running); - void setChannelMapper(QChannelMapper *channelMapper); void setBlendTree(QAbstractClipBlendNode * blendTree); - void setLoops(int loops); Q_SIGNALS: void blendTreeChanged(QAbstractClipBlendNode * blendTree); - void runningChanged(bool running); - void channelMapperChanged(QChannelMapper *channelMapper); - void loopsChanged(int loops); protected: QBlendedClipAnimator(QBlendedClipAnimatorPrivate &dd, Qt3DCore::QNode *parent = nullptr); diff --git a/src/animation/frontend/qblendedclipanimator_p.h b/src/animation/frontend/qblendedclipanimator_p.h index 47a8bbfd5..e874a528d 100644 --- a/src/animation/frontend/qblendedclipanimator_p.h +++ b/src/animation/frontend/qblendedclipanimator_p.h @@ -51,33 +51,26 @@ // We mean it. // -#include +#include QT_BEGIN_NAMESPACE namespace Qt3DAnimation { class QAbstractClipBlendNode; -class QChannelMapper; -class QBlendedClipAnimatorPrivate : public Qt3DCore::QComponentPrivate +class QBlendedClipAnimatorPrivate : public Qt3DAnimation::QAbstractClipAnimatorPrivate { public: QBlendedClipAnimatorPrivate(); Q_DECLARE_PUBLIC(QBlendedClipAnimator) QAbstractClipBlendNode *m_blendTreeRoot; - QChannelMapper *m_mapper; - bool m_running; - int m_loops; }; -struct QBlendedClipAnimatorData +struct QBlendedClipAnimatorData : public QAbstractClipAnimatorData { Qt3DCore::QNodeId blendTreeRootId; - Qt3DCore::QNodeId mapperId; - bool running; - int loops; }; } // namespace Qt3DAnimation -- cgit v1.2.3 From fdf1ef6f6c44fc8c51e7a226418c336e0478fe01 Mon Sep 17 00:00:00 2001 From: Kevin Ottens Date: Fri, 17 Feb 2017 16:29:08 +0100 Subject: Add Infinite constant to QAbstractClipAnimator Change-Id: I6d9d31d92d14f93fe8a550173cd383a7511d1851 Task-Id: QTBUG-58899 Reviewed-by: Paul Lemire --- src/animation/frontend/qabstractclipanimator.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/animation/frontend/qabstractclipanimator.h b/src/animation/frontend/qabstractclipanimator.h index e17740c38..e106bae74 100644 --- a/src/animation/frontend/qabstractclipanimator.h +++ b/src/animation/frontend/qabstractclipanimator.h @@ -59,6 +59,9 @@ class QT3DANIMATIONSHARED_EXPORT QAbstractClipAnimator : public Qt3DCore::QCompo Q_PROPERTY(Qt3DAnimation::QChannelMapper *channelMapper READ channelMapper WRITE setChannelMapper NOTIFY channelMapperChanged) public: + enum Loops { Infinite = -1 }; + Q_ENUM(Loops) + ~QAbstractClipAnimator(); bool isRunning() const; -- cgit v1.2.3 From 82ff575d3f7b7bc114106dbb23b148837c5e96f1 Mon Sep 17 00:00:00 2001 From: Kevin Ottens Date: Tue, 21 Feb 2017 14:43:15 +0100 Subject: Move environment light uniforms in light.inc.frag Change-Id: I0ce7302b7c1cf8912b925d31d074739208936426 Reviewed-by: Paul Lemire --- src/extras/defaults/qmetalroughmaterial.cpp | 4 ++-- src/extras/defaults/qtexturedmetalroughmaterial.cpp | 4 ++-- src/extras/shaders/gl3/light.inc.frag | 7 +++++++ src/extras/shaders/gl3/metalrough.frag | 10 ++++------ src/extras/shaders/gl3/metalroughuniform.frag | 10 ++++------ 5 files changed, 19 insertions(+), 16 deletions(-) diff --git a/src/extras/defaults/qmetalroughmaterial.cpp b/src/extras/defaults/qmetalroughmaterial.cpp index b988e11ce..3081fa787 100644 --- a/src/extras/defaults/qmetalroughmaterial.cpp +++ b/src/extras/defaults/qmetalroughmaterial.cpp @@ -65,8 +65,8 @@ QMetalRoughMaterialPrivate::QMetalRoughMaterialPrivate() , m_baseColorParameter(new QParameter(QStringLiteral("baseColor"), QColor("grey"))) , m_metalnessParameter(new QParameter(QStringLiteral("metalness"), 0.0f)) , m_roughnessParameter(new QParameter(QStringLiteral("roughness"), 0.0f)) - , m_environmentIrradianceParameter(new QParameter(QStringLiteral("skyIrradiance"), m_environmentIrradianceTexture)) - , m_environmentSpecularParameter(new QParameter(QStringLiteral("skySpecular"), m_environmentSpecularTexture)) + , m_environmentIrradianceParameter(new QParameter(QStringLiteral("envLight.irradiance"), m_environmentIrradianceTexture)) + , m_environmentSpecularParameter(new QParameter(QStringLiteral("envLight.specular"), m_environmentSpecularTexture)) , m_metalRoughEffect(new QEffect()) , m_metalRoughGL3Technique(new QTechnique()) , m_metalRoughGL3RenderPass(new QRenderPass()) diff --git a/src/extras/defaults/qtexturedmetalroughmaterial.cpp b/src/extras/defaults/qtexturedmetalroughmaterial.cpp index ea7c7b9d7..b8faff7ed 100644 --- a/src/extras/defaults/qtexturedmetalroughmaterial.cpp +++ b/src/extras/defaults/qtexturedmetalroughmaterial.cpp @@ -72,8 +72,8 @@ QTexturedMetalRoughMaterialPrivate::QTexturedMetalRoughMaterialPrivate() , m_roughnessParameter(new QParameter(QStringLiteral("roughnessMap"), m_roughnessTexture)) , m_ambientOcclusionParameter(new QParameter(QStringLiteral("ambientOcclusionMap"), m_ambientOcclusionTexture)) , m_normalParameter(new QParameter(QStringLiteral("normalMap"), m_normalTexture)) - , m_environmentIrradianceParameter(new QParameter(QStringLiteral("skyIrradiance"), m_environmentIrradianceTexture)) - , m_environmentSpecularParameter(new QParameter(QStringLiteral("skySpecular"), m_environmentSpecularTexture)) + , m_environmentIrradianceParameter(new QParameter(QStringLiteral("envLight.irradiance"), m_environmentIrradianceTexture)) + , m_environmentSpecularParameter(new QParameter(QStringLiteral("envLight.specular"), m_environmentSpecularTexture)) , m_metalRoughEffect(new QEffect()) , m_metalRoughGL3Technique(new QTechnique()) , m_metalRoughGL3RenderPass(new QRenderPass()) diff --git a/src/extras/shaders/gl3/light.inc.frag b/src/extras/shaders/gl3/light.inc.frag index 3047bdb3c..aaec83840 100644 --- a/src/extras/shaders/gl3/light.inc.frag +++ b/src/extras/shaders/gl3/light.inc.frag @@ -16,6 +16,13 @@ struct Light { uniform Light lights[MAX_LIGHTS]; uniform int lightCount; +// Pre-convolved environment maps +struct EnvironmentLight { + samplerCube irradiance; // For diffuse contribution + samplerCube specular; // For specular contribution +}; +uniform EnvironmentLight envLight; + void adsModelNormalMapped(const in vec3 worldPos, const in vec3 tsNormal, const in vec3 worldEye, diff --git a/src/extras/shaders/gl3/metalrough.frag b/src/extras/shaders/gl3/metalrough.frag index 197d3eec7..dc39108e0 100644 --- a/src/extras/shaders/gl3/metalrough.frag +++ b/src/extras/shaders/gl3/metalrough.frag @@ -61,10 +61,6 @@ out vec4 fragColor; uniform vec3 eyePosition; // World space eye position uniform float time; // Time in seconds -// Pre-convolved environment maps -uniform samplerCube skyIrradiance; // For diffuse contribution -uniform samplerCube skySpecular; // For specular contribution - // PBR Material maps uniform sampler2D baseColorMap; uniform sampler2D metalnessMap; @@ -85,6 +81,8 @@ uniform float exposure = 0.0; // Gamma correction uniform float gamma = 2.2; +#pragma include light.inc.frag + mat3 calcWorldSpaceToTangentSpaceMatrix(const in vec3 wNormal, const in vec4 wTangent) { // Make the tangent truly orthogonal to the normal by using Gram-Schmidt. @@ -176,7 +174,7 @@ vec3 pbrIblModel(const in vec3 wNormal, // Calculate diffuse component vec3 diffuseColor = (1.0 - metalness) * baseColor; - vec3 diffuse = diffuseColor * texture(skyIrradiance, l).rgb; + vec3 diffuse = diffuseColor * texture(envLight.irradiance, l).rgb; // Calculate specular component vec3 dielectricColor = vec3(0.04); @@ -184,7 +182,7 @@ vec3 pbrIblModel(const in vec3 wNormal, vec3 specularFactor = specularModel(F0, lDotH, lDotN, vDotN, n, h); float lod = roughnessToMipLevel(roughness); - vec3 specularSkyColor = textureLod(skySpecular, l, lod).rgb; + vec3 specularSkyColor = textureLod(envLight.specular, l, lod).rgb; vec3 specular = specularSkyColor * specularFactor; // Blend between diffuse and specular to conserve energy diff --git a/src/extras/shaders/gl3/metalroughuniform.frag b/src/extras/shaders/gl3/metalroughuniform.frag index 66201513a..5e776e84b 100644 --- a/src/extras/shaders/gl3/metalroughuniform.frag +++ b/src/extras/shaders/gl3/metalroughuniform.frag @@ -61,10 +61,6 @@ out vec4 fragColor; uniform vec3 eyePosition; // World space eye position uniform float time; // Time in seconds -// Pre-convolved environment maps -uniform samplerCube skyIrradiance; // For diffuse contribution -uniform samplerCube skySpecular; // For specular contribution - // PBR Material maps uniform vec4 baseColor; uniform float metalness; @@ -80,6 +76,8 @@ uniform float exposure = 0.0; // Gamma correction uniform float gamma = 2.2; +#pragma include light.inc.frag + mat3 calcWorldSpaceToTangentSpaceMatrix(const in vec3 wNormal, const in vec4 wTangent) { // Make the tangent truly orthogonal to the normal by using Gram-Schmidt. @@ -170,7 +168,7 @@ vec3 pbrIblModel(const in vec3 wNormal, // Calculate diffuse component vec3 diffuseColor = (1.0 - metalness) * baseColor; - vec3 diffuse = diffuseColor * texture(skyIrradiance, l).rgb; + vec3 diffuse = diffuseColor * texture(envLight.irradiance, l).rgb; // Calculate specular component vec3 dielectricColor = vec3(0.04); @@ -178,7 +176,7 @@ vec3 pbrIblModel(const in vec3 wNormal, vec3 specularFactor = specularModel(F0, lDotH, lDotN, vDotN, n, h); float lod = roughnessToMipLevel(roughness); - vec3 specularSkyColor = textureLod(skySpecular, l, lod).rgb; + vec3 specularSkyColor = textureLod(envLight.specular, l, lod).rgb; vec3 specular = specularSkyColor * specularFactor; // Blend between diffuse and specular to conserve energy -- cgit v1.2.3 From b8d176cf8cdc62b24075743b72b3c8a661d510c0 Mon Sep 17 00:00:00 2001 From: Kevin Ottens Date: Tue, 21 Feb 2017 14:46:03 +0100 Subject: Move metal/rough exposure correction in the main() functions Change-Id: I7d6e0bfd29e53f3bf424636d7031c33ed7267b12 Reviewed-by: Paul Lemire --- src/extras/shaders/gl3/metalrough.frag | 6 +++--- src/extras/shaders/gl3/metalroughuniform.frag | 10 ++++------ 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/extras/shaders/gl3/metalrough.frag b/src/extras/shaders/gl3/metalrough.frag index dc39108e0..5cb1409c2 100644 --- a/src/extras/shaders/gl3/metalrough.frag +++ b/src/extras/shaders/gl3/metalrough.frag @@ -191,9 +191,6 @@ vec3 pbrIblModel(const in vec3 wNormal, // Reduce by ambient occlusion amount iblColor *= ambientOcclusion; - // Apply exposure correction - iblColor *= pow(2.0, exposure); - return iblColor; } @@ -229,6 +226,9 @@ void main() roughness, ambientOcclusion); + // Apply exposure correction + cLinear *= pow(2.0, exposure); + // Apply simple (Reinhard) tonemap transform to get into LDR range [0, 1] vec3 cToneMapped = toneMap(cLinear); diff --git a/src/extras/shaders/gl3/metalroughuniform.frag b/src/extras/shaders/gl3/metalroughuniform.frag index 5e776e84b..a1711c504 100644 --- a/src/extras/shaders/gl3/metalroughuniform.frag +++ b/src/extras/shaders/gl3/metalroughuniform.frag @@ -180,12 +180,7 @@ vec3 pbrIblModel(const in vec3 wNormal, vec3 specular = specularSkyColor * specularFactor; // Blend between diffuse and specular to conserve energy - vec3 iblColor = specular + diffuse * (vec3(1.0) - specularFactor); - - // Apply exposure correction - iblColor *= pow(2.0, exposure); - - return iblColor; + return specular + diffuse * (vec3(1.0) - specularFactor); } vec3 toneMap(const in vec3 c) @@ -207,6 +202,9 @@ void main() metalness, roughness); + // Apply exposure correction + cLinear *= pow(2.0, exposure); + // Apply simple (Reinhard) tonemap transform to get into LDR range [0, 1] vec3 cToneMapped = toneMap(cLinear); -- cgit v1.2.3 From 17826d9e889bbb9f3795e824c5fd2ac299c9e9b3 Mon Sep 17 00:00:00 2001 From: Paul Lemire Date: Thu, 16 Feb 2017 15:20:34 +0000 Subject: QDistanceFieldGlyphCache cleanup -made QDistanceFieldGlyphCache and QTextureAtlas private -remove dptr on QDistanceFieldGlyphCache -use a static hash on glyphCaches based on current scene being used -QTextureAtlas parented by scene root node Task-number: QTBUG-58881 Change-Id: If51d7dfe75e4233b9e7a36473c71fe530247aef7 Reviewed-by: Sean Harmer --- src/core/aspects/qaspectengine.cpp | 2 + src/core/nodes/qnode_p.h | 2 +- src/core/qscene.cpp | 14 +++ src/core/qscene_p.h | 5 + src/extras/text/distancefieldtextrenderer_p_p.h | 1 - src/extras/text/qdistancefieldglyphcache.cpp | 100 ++++++++++++--- src/extras/text/qdistancefieldglyphcache.h | 90 ------------- src/extras/text/qdistancefieldglyphcache_p.h | 87 +++++-------- src/extras/text/qdistancefieldtext.cpp | 82 +++++++----- src/extras/text/qdistancefieldtext.h | 5 - src/extras/text/qdistancefieldtext_p.h | 19 ++- src/extras/text/qtextureatlas.cpp | 2 +- src/extras/text/qtextureatlas.h | 84 ------------- src/extras/text/qtextureatlas_p.h | 82 +++--------- src/extras/text/qtextureatlas_p_p.h | 139 +++++++++++++++++++++ src/extras/text/text.pri | 9 +- .../imports/extras/qt3dquick3dextrasplugin.cpp | 3 - tests/manual/distancefieldtext/TextScene.qml | 5 - 18 files changed, 361 insertions(+), 370 deletions(-) delete mode 100644 src/extras/text/qdistancefieldglyphcache.h delete mode 100644 src/extras/text/qtextureatlas.h create mode 100644 src/extras/text/qtextureatlas_p_p.h diff --git a/src/core/aspects/qaspectengine.cpp b/src/core/aspects/qaspectengine.cpp index 15f975332..c1ec1b4ac 100644 --- a/src/core/aspects/qaspectengine.cpp +++ b/src/core/aspects/qaspectengine.cpp @@ -218,6 +218,8 @@ QAspectEngine::~QAspectEngine() void QAspectEnginePrivate::initNodeTree(QNode *node) { + // Set the root entity on the scene + m_scene->setRootNode(node); QNodeVisitor visitor; visitor.traverse(node, this, &QAspectEnginePrivate::initNode, &QAspectEnginePrivate::initEntity); } diff --git a/src/core/nodes/qnode_p.h b/src/core/nodes/qnode_p.h index 5d6329e62..d4a48aa1e 100644 --- a/src/core/nodes/qnode_p.h +++ b/src/core/nodes/qnode_p.h @@ -74,7 +74,7 @@ public: void init(QNode *parent); - void setScene(QScene *scene); + virtual void setScene(QScene *scene); QScene *scene() const; void setArbiter(QLockableObserverInterface *arbiter) Q_DECL_OVERRIDE; diff --git a/src/core/qscene.cpp b/src/core/qscene.cpp index 972659131..1fcfeaac7 100644 --- a/src/core/qscene.cpp +++ b/src/core/qscene.cpp @@ -55,6 +55,7 @@ public: QScenePrivate(QAspectEngine *engine) : m_engine(engine) , m_arbiter(nullptr) + , m_rootNode(nullptr) { } @@ -67,6 +68,7 @@ public: QLockableObserverInterface *m_arbiter; mutable QReadWriteLock m_lock; mutable QReadWriteLock m_nodePropertyTrackModeLock; + QNode *m_rootNode; }; @@ -171,6 +173,12 @@ QNodeId QScene::nodeIdFromObservable(QObservableInterface *observable) const return d->m_observableToUuid.value(observable); } +QNode *QScene::rootNode() const +{ + Q_D(const QScene); + return d->m_rootNode; +} + void QScene::setArbiter(QLockableObserverInterface *arbiter) { Q_D(QScene); @@ -236,6 +244,12 @@ void QScene::removePropertyTrackDataForNode(QNodeId nodeId) d->m_nodePropertyTrackModeLookupTable.remove(nodeId); } +void QScene::setRootNode(QNode *root) +{ + Q_D(QScene); + d->m_rootNode = root; +} + } // Qt3D QT_END_NAMESPACE diff --git a/src/core/qscene_p.h b/src/core/qscene_p.h index 1a313c249..fdcb23edb 100644 --- a/src/core/qscene_p.h +++ b/src/core/qscene_p.h @@ -83,6 +83,8 @@ public: QVector lookupNodes(const QVector &ids) const; QNodeId nodeIdFromObservable(QObservableInterface *observable) const; + QNode *rootNode() const; + void setArbiter(Qt3DCore::QLockableObserverInterface *arbiter); Qt3DCore::QLockableObserverInterface *arbiter() const; @@ -105,6 +107,9 @@ public: private: Q_DECLARE_PRIVATE(QScene) QScopedPointer d_ptr; + + void setRootNode(QNode *root); + friend class QAspectEnginePrivate; }; } // Qt3D diff --git a/src/extras/text/distancefieldtextrenderer_p_p.h b/src/extras/text/distancefieldtextrenderer_p_p.h index fd2e76167..06c377a35 100644 --- a/src/extras/text/distancefieldtextrenderer_p_p.h +++ b/src/extras/text/distancefieldtextrenderer_p_p.h @@ -52,7 +52,6 @@ // #include -#include #include QT_BEGIN_NAMESPACE diff --git a/src/extras/text/qdistancefieldglyphcache.cpp b/src/extras/text/qdistancefieldglyphcache.cpp index dfe59883c..aacccc7dc 100644 --- a/src/extras/text/qdistancefieldglyphcache.cpp +++ b/src/extras/text/qdistancefieldglyphcache.cpp @@ -41,9 +41,13 @@ #include #include -#include "qdistancefieldglyphcache.h" #include "qdistancefieldglyphcache_p.h" -#include "qtextureatlas.h" +#include "qtextureatlas_p.h" + +#include +#include +#include +#include QT_BEGIN_NAMESPACE @@ -53,6 +57,59 @@ using namespace Qt3DCore; namespace Qt3DExtras { +// ref-count glyphs and keep track of where they are stored +class StoredGlyph { +public: + StoredGlyph() = default; + StoredGlyph(const StoredGlyph &other) = default; + StoredGlyph(const QRawFont &font, quint32 glyph, bool doubleResolution); + + int refCount() const { return m_ref; } + void ref() { ++m_ref; } + int deref() { return m_ref = std::max(m_ref - 1, (quint32) 0); } + + bool addToTextureAtlas(QTextureAtlas *atlas); + void removeFromTextureAtlas(); + + QTextureAtlas *atlas() const { return m_atlas; } + QRectF glyphPathBoundingRect() const { return m_glyphPathBoundingRect; } + QRectF texCoords() const; + +private: + quint32 m_glyph = (quint32) -1; + quint32 m_ref = 0; + QTextureAtlas *m_atlas = nullptr; + QTextureAtlas::TextureId m_atlasEntry = QTextureAtlas::InvalidTexture; + QRectF m_glyphPathBoundingRect; + QImage m_distanceFieldImage; // only used until added to texture atlas +}; + +// A DistanceFieldFont stores all glyphs for a given QRawFont. +// it will use multiple QTextureAtlasess to store the distance +// fields and uses ref-counting for each glyph to ensure that +// unused glyphs are removed from the texture atlasses. +class DistanceFieldFont +{ +public: + DistanceFieldFont(const QRawFont &font, bool doubleRes, Qt3DCore::QNode *parent); + ~DistanceFieldFont(); + + StoredGlyph findGlyph(quint32 glyph) const; + StoredGlyph refGlyph(quint32 glyph); + void derefGlyph(quint32 glyph); + + bool doubleGlyphResolution() const { return m_doubleGlyphResolution; } + +private: + QRawFont m_font; + bool m_doubleGlyphResolution; + Qt3DCore::QNode *m_parentNode; // parent node for the QTextureAtlasses + + QHash m_glyphs; + + QVector m_atlasses; +}; + StoredGlyph::StoredGlyph(const QRawFont &font, quint32 glyph, bool doubleResolution) : m_glyph(glyph) , m_ref(1) @@ -190,7 +247,7 @@ void DistanceFieldFont::derefGlyph(quint32 glyph) // copied from QSGDistanceFieldGlyphCacheManager::fontKey // we use this function to compare QRawFonts, as QRawFont doesn't // implement a stable comparison function -QString QDistanceFieldGlyphCachePrivate::fontKey(const QRawFont &font) +QString QDistanceFieldGlyphCache::fontKey(const QRawFont &font) { QFontEngine *fe = QRawFontPrivate::get(font)->fontEngine; if (!fe->faceId().filename.isEmpty()) { @@ -210,7 +267,7 @@ QString QDistanceFieldGlyphCachePrivate::fontKey(const QRawFont &font) } } -DistanceFieldFont* QDistanceFieldGlyphCachePrivate::getOrCreateDistanceFieldFont(const QRawFont &font) +DistanceFieldFont* QDistanceFieldGlyphCache::getOrCreateDistanceFieldFont(const QRawFont &font) { // return, if font already exists (make sure to only create one DistanceFieldFont for // each unique QRawFont, by building a hash on the QRawFont that ignores the font size) @@ -229,13 +286,13 @@ DistanceFieldFont* QDistanceFieldGlyphCachePrivate::getOrCreateDistanceFieldFont actualFont.setPixelSize(QT_DISTANCEFIELD_BASEFONTSIZE(useDoubleRes) * QT_DISTANCEFIELD_SCALE(useDoubleRes)); // create new font cache - DistanceFieldFont *dff = new DistanceFieldFont(actualFont, useDoubleRes, q_func()); + DistanceFieldFont *dff = new DistanceFieldFont(actualFont, useDoubleRes, m_rootNode); m_fonts.insert(key, dff); return dff; } -QDistanceFieldGlyphCache::QDistanceFieldGlyphCache(QNode *parent) - : QNode(*new QDistanceFieldGlyphCachePrivate(), parent) +QDistanceFieldGlyphCache::QDistanceFieldGlyphCache() + : m_rootNode(nullptr) { } @@ -243,10 +300,19 @@ QDistanceFieldGlyphCache::~QDistanceFieldGlyphCache() { } +void QDistanceFieldGlyphCache::setRootNode(QNode *rootNode) +{ + m_rootNode = rootNode; +} + +QNode *QDistanceFieldGlyphCache::rootNode() const +{ + return m_rootNode; +} + bool QDistanceFieldGlyphCache::doubleGlyphResolution(const QRawFont &font) { - Q_D(QDistanceFieldGlyphCache); - return d->getOrCreateDistanceFieldFont(font)->doubleGlyphResolution(); + return getOrCreateDistanceFieldFont(font)->doubleGlyphResolution(); } namespace { @@ -266,13 +332,11 @@ QDistanceFieldGlyphCache::Glyph refAndGetGlyph(DistanceFieldFont *dff, quint32 g return ret; } -} +} // anonymous QVector QDistanceFieldGlyphCache::refGlyphs(const QGlyphRun &run) { - Q_D(QDistanceFieldGlyphCache); - - DistanceFieldFont *dff = d->getOrCreateDistanceFieldFont(run.rawFont()); + DistanceFieldFont *dff = getOrCreateDistanceFieldFont(run.rawFont()); QVector ret; const QVector glyphs = run.glyphIndexes(); @@ -284,15 +348,12 @@ QVector QDistanceFieldGlyphCache::refGlyphs(con QDistanceFieldGlyphCache::Glyph QDistanceFieldGlyphCache::refGlyph(const QRawFont &font, quint32 glyph) { - Q_D(QDistanceFieldGlyphCache); - return refAndGetGlyph(d->getOrCreateDistanceFieldFont(font), glyph); + return refAndGetGlyph(getOrCreateDistanceFieldFont(font), glyph); } void QDistanceFieldGlyphCache::derefGlyphs(const QGlyphRun &run) { - Q_D(QDistanceFieldGlyphCache); - - DistanceFieldFont *dff = d->getOrCreateDistanceFieldFont(run.rawFont()); + DistanceFieldFont *dff = getOrCreateDistanceFieldFont(run.rawFont()); const QVector glyphs = run.glyphIndexes(); for (quint32 glyph : glyphs) @@ -301,8 +362,7 @@ void QDistanceFieldGlyphCache::derefGlyphs(const QGlyphRun &run) void QDistanceFieldGlyphCache::derefGlyph(const QRawFont &font, quint32 glyph) { - Q_D(QDistanceFieldGlyphCache); - d->getOrCreateDistanceFieldFont(font)->derefGlyph(glyph); + getOrCreateDistanceFieldFont(font)->derefGlyph(glyph); } } // namespace Qt3DExtras diff --git a/src/extras/text/qdistancefieldglyphcache.h b/src/extras/text/qdistancefieldglyphcache.h deleted file mode 100644 index b02625b47..000000000 --- a/src/extras/text/qdistancefieldglyphcache.h +++ /dev/null @@ -1,90 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB). -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt3D module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** 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-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QT3DEXTRAS_QDISTANCEFIELDGLYPHCACHE_H -#define QT3DEXTRAS_QDISTANCEFIELDGLYPHCACHE_H - -#include -#include -#include - -QT_BEGIN_NAMESPACE - -class QRawFont; -class QGlyphRun; - -namespace Qt3DRender { -class QAbstractTexture; -} - -namespace Qt3DExtras { - -class QDistanceFieldGlyphCachePrivate; - -class QT3DEXTRASSHARED_EXPORT QDistanceFieldGlyphCache : public Qt3DCore::QNode -{ - Q_OBJECT - -public: - QDistanceFieldGlyphCache(Qt3DCore::QNode *parent = nullptr); - ~QDistanceFieldGlyphCache(); - - struct Glyph { - Qt3DRender::QAbstractTexture *texture = nullptr; - QRectF glyphPathBoundingRect; // bounding rect of the QPainterPath used to draw the glyph - QRectF texCoords; // texture coordinates within texture - }; - - bool doubleGlyphResolution(const QRawFont &font); - - QVector refGlyphs(const QGlyphRun &run); - Glyph refGlyph(const QRawFont &font, quint32 glyph); - - void derefGlyphs(const QGlyphRun &run); - void derefGlyph(const QRawFont &font, quint32 glyph); - -private: - Q_DECLARE_PRIVATE(QDistanceFieldGlyphCache) -}; - -} // namespace Qt3DExtras - -QT_END_NAMESPACE - -#endif // QT3DEXTRAS_QDISTANCEFIELDGLYPHCACHE_H diff --git a/src/extras/text/qdistancefieldglyphcache_p.h b/src/extras/text/qdistancefieldglyphcache_p.h index 90164cd39..6ca011c76 100644 --- a/src/extras/text/qdistancefieldglyphcache_p.h +++ b/src/extras/text/qdistancefieldglyphcache_p.h @@ -51,82 +51,57 @@ // We mean it. // -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include QT_BEGIN_NAMESPACE -namespace Qt3DExtras { +class QRawFont; +class QGlyphRun; -// ref-count glyphs and keep track of where they are stored -class StoredGlyph { -public: - StoredGlyph() = default; - StoredGlyph(const StoredGlyph &other) = default; - StoredGlyph(const QRawFont &font, quint32 glyph, bool doubleResolution); +namespace Qt3DCore { +class QNode; +} - int refCount() const { return m_ref; } - void ref() { ++m_ref; } - int deref() { return m_ref = std::max(m_ref - 1, (quint32) 0); } +namespace Qt3DRender { +class QAbstractTexture; +} - bool addToTextureAtlas(QTextureAtlas *atlas); - void removeFromTextureAtlas(); +namespace Qt3DExtras { - QTextureAtlas *atlas() const { return m_atlas; } - QRectF glyphPathBoundingRect() const { return m_glyphPathBoundingRect; } - QRectF texCoords() const; +class DistanceFieldFont; +class QDistanceFieldGlyphCachePrivate; -private: - quint32 m_glyph = (quint32) -1; - quint32 m_ref = 0; - QTextureAtlas *m_atlas = nullptr; - QTextureAtlas::TextureId m_atlasEntry = QTextureAtlas::InvalidTexture; - QRectF m_glyphPathBoundingRect; - QImage m_distanceFieldImage; // only used until added to texture atlas -}; - -// A DistanceFieldFont stores all glyphs for a given QRawFont. -// it will use multiple QTextureAtlasess to store the distance -// fields and uses ref-counting for each glyph to ensure that -// unused glyphs are removed from the texture atlasses. -class DistanceFieldFont +class QDistanceFieldGlyphCache { public: - DistanceFieldFont(const QRawFont &font, bool doubleRes, Qt3DCore::QNode *parent); - ~DistanceFieldFont(); - - StoredGlyph findGlyph(quint32 glyph) const; - StoredGlyph refGlyph(quint32 glyph); - void derefGlyph(quint32 glyph); + QDistanceFieldGlyphCache(); + ~QDistanceFieldGlyphCache(); - bool doubleGlyphResolution() const { return m_doubleGlyphResolution; } + void setRootNode(Qt3DCore::QNode *rootNode); + Qt3DCore::QNode *rootNode() const; -private: - QRawFont m_font; - bool m_doubleGlyphResolution; - Qt3DCore::QNode *m_parentNode; // parent node for the QTextureAtlasses + struct Glyph { + Qt3DRender::QAbstractTexture *texture = nullptr; + QRectF glyphPathBoundingRect; // bounding rect of the QPainterPath used to draw the glyph + QRectF texCoords; // texture coordinates within texture + }; - QHash m_glyphs; + bool doubleGlyphResolution(const QRawFont &font); - QVector m_atlasses; -}; + QVector refGlyphs(const QGlyphRun &run); + Glyph refGlyph(const QRawFont &font, quint32 glyph); -class QDistanceFieldGlyphCachePrivate : public Qt3DCore::QNodePrivate -{ -public: - Q_DECLARE_PUBLIC(QDistanceFieldGlyphCache) - - DistanceFieldFont* getOrCreateDistanceFieldFont(const QRawFont &font); + void derefGlyphs(const QGlyphRun &run); + void derefGlyph(const QRawFont &font, quint32 glyph); private: + DistanceFieldFont* getOrCreateDistanceFieldFont(const QRawFont &font); static QString fontKey(const QRawFont &font); QHash m_fonts; + Qt3DCore::QNode *m_rootNode; }; } // namespace Qt3DExtras diff --git a/src/extras/text/qdistancefieldtext.cpp b/src/extras/text/qdistancefieldtext.cpp index fdd40fc5a..88e6e9be5 100644 --- a/src/extras/text/qdistancefieldtext.cpp +++ b/src/extras/text/qdistancefieldtext.cpp @@ -54,6 +54,8 @@ #include #include +#include + QT_BEGIN_NAMESPACE namespace { @@ -67,8 +69,11 @@ inline Q_DECL_CONSTEXPR QRectF scaleRectF(const QRectF &rect, float scale) namespace Qt3DExtras { +QHash QDistanceFieldTextPrivate::m_glyphCacheInstances; + QDistanceFieldTextPrivate::QDistanceFieldTextPrivate() - : m_font(QLatin1String("Times"), 10) + : m_glyphCache(nullptr) + , m_font(QLatin1String("Times"), 10) , m_scaledFont(QLatin1String("Times"), 10) , m_color(QColor(255, 255, 255, 255)) { @@ -78,6 +83,38 @@ QDistanceFieldTextPrivate::~QDistanceFieldTextPrivate() { } +void QDistanceFieldTextPrivate::setScene(Qt3DCore::QScene *scene) +{ + if (scene == m_scene) + return; + + // Unref old glyph cache if it exists + if (m_scene != nullptr) { + m_glyphCache = nullptr; + QDistanceFieldTextPrivate::CacheEntry &entry = QDistanceFieldTextPrivate::m_glyphCacheInstances[m_scene]; + --entry.count; + if (entry.count == 0 && entry.glyphCache != nullptr) { + delete entry.glyphCache; + entry.glyphCache = nullptr; + } + } + + QEntityPrivate::setScene(scene); + + // Ref new glyph cache is scene is valid + if (scene != nullptr) { + QDistanceFieldTextPrivate::CacheEntry &entry = QDistanceFieldTextPrivate::m_glyphCacheInstances[scene]; + if (entry.glyphCache == nullptr) { + entry.glyphCache = new QDistanceFieldGlyphCache(); + entry.glyphCache->setRootNode(scene->rootNode()); + } + m_glyphCache = entry.glyphCache; + ++entry.count; + // Update to populate glyphCache if needed + update(); + } +} + QDistanceFieldText::QDistanceFieldText(QNode *parent) : Qt3DCore::QEntity(*new QDistanceFieldTextPrivate(), parent) { @@ -104,7 +141,8 @@ struct RenderData { void QDistanceFieldTextPrivate::setCurrentGlyphRuns(const QVector &runs) { - Q_ASSERT(m_glyphCache || runs.isEmpty()); + if (runs.isEmpty()) + return; // For each distinct texture, we need a separate DistanceFieldTextRenderer, // for which we need vertex and index data @@ -198,19 +236,20 @@ void QDistanceFieldTextPrivate::setCurrentGlyphRuns(const QVector &ru } // de-ref all glyphs for previous QGlyphRuns - if (m_glyphCache) { - for (int i = 0; i < m_currentGlyphRuns.size(); i++) - m_glyphCache->derefGlyphs(m_currentGlyphRuns[i]); - } + for (int i = 0; i < m_currentGlyphRuns.size(); i++) + m_glyphCache->derefGlyphs(m_currentGlyphRuns[i]); m_currentGlyphRuns = runs; } void QDistanceFieldTextPrivate::update() { + if (m_glyphCache == nullptr) + return; + QVector glyphRuns; // collect all GlyphRuns generated by the QTextLayout - if (m_glyphCache && !m_position.isEmpty() && !m_text.isEmpty() && m_fontScale > 0.f) { + if (!m_position.isEmpty() && !m_text.isEmpty() && m_fontScale > 0.f) { QTextLayout layout(m_text, m_scaledFont); const float lineWidth = m_position.width() / computeActualScale(); float height = 0; @@ -257,7 +296,7 @@ void QDistanceFieldText::setFont(const QFont &font) emit fontChanged(font); - if (!d->m_text.isEmpty() && d->m_glyphCache) + if (!d->m_text.isEmpty()) d->update(); } } @@ -294,8 +333,7 @@ void QDistanceFieldText::setText(const QString &text) d->m_text = text; emit textChanged(text); - if (d->m_glyphCache) - d->update(); + d->update(); } } @@ -312,7 +350,7 @@ void QDistanceFieldText::setPosition(const QRectF &pos) d->m_position = pos; emit positionChanged(pos); - if (!d->m_text.isEmpty() && d->m_glyphCache) + if (!d->m_text.isEmpty()) d->update(); } } @@ -330,28 +368,6 @@ void QDistanceFieldText::setFontScale(float scale) d->m_fontScale = scale; emit fontScaleChanged(scale); - if (!d->m_text.isEmpty() && d->m_glyphCache) - d->update(); - } -} - -QDistanceFieldGlyphCache *QDistanceFieldText::glyphCache() const -{ - Q_D(const QDistanceFieldText); - return d->m_glyphCache; -} - -void QDistanceFieldText::setGlyphCache(QDistanceFieldGlyphCache *glyphCache) -{ - Q_D(QDistanceFieldText); - if (d->m_glyphCache != glyphCache) { - // make sure all glyphs that we still reference in our old glyph cache - // will be de-reffed - d->setCurrentGlyphRuns(QVector()); - - d->m_glyphCache = glyphCache; - emit glyphCacheChanged(glyphCache); - if (!d->m_text.isEmpty()) d->update(); } diff --git a/src/extras/text/qdistancefieldtext.h b/src/extras/text/qdistancefieldtext.h index 2eaafda63..a1bfc9d9e 100644 --- a/src/extras/text/qdistancefieldtext.h +++ b/src/extras/text/qdistancefieldtext.h @@ -61,7 +61,6 @@ class QT3DEXTRASSHARED_EXPORT QDistanceFieldText : public Qt3DCore::QEntity Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged) Q_PROPERTY(QRectF position READ position WRITE setPosition NOTIFY positionChanged) Q_PROPERTY(float fontScale READ fontScale WRITE setFontScale NOTIFY fontScaleChanged) - Q_PROPERTY(Qt3DExtras::QDistanceFieldGlyphCache* glyphCache READ glyphCache WRITE setGlyphCache NOTIFY glyphCacheChanged) public: explicit QDistanceFieldText(Qt3DCore::QNode *parent = nullptr); @@ -82,16 +81,12 @@ public: float fontScale() const; void setFontScale(float scale); - QDistanceFieldGlyphCache *glyphCache() const; - void setGlyphCache(QDistanceFieldGlyphCache *glyphCache); - Q_SIGNALS: void fontChanged(const QFont &font); void colorChanged(const QColor &color); void textChanged(const QString &text); void positionChanged(const QRectF &position); void fontScaleChanged(float scale); - void glyphCacheChanged(QDistanceFieldGlyphCache *glyphCache); private: Q_DECLARE_PRIVATE(QDistanceFieldText) diff --git a/src/extras/text/qdistancefieldtext_p.h b/src/extras/text/qdistancefieldtext_p.h index 578ed7f98..d30f226d6 100644 --- a/src/extras/text/qdistancefieldtext_p.h +++ b/src/extras/text/qdistancefieldtext_p.h @@ -52,12 +52,16 @@ // #include -#include #include +#include #include QT_BEGIN_NAMESPACE +namespace Qt3DCore { +class QScene; +} + namespace Qt3DRender { class QGeometryRenderer; class QGeometry; @@ -79,12 +83,13 @@ public: Q_DECLARE_PUBLIC(QDistanceFieldText) - QDistanceFieldGlyphCache *m_glyphCache = nullptr; - // keep track of the glyphs currently being displayed, // to guarantee proper glyph ref-counting in the // QDistanceFieldGlyphCache QVector m_currentGlyphRuns; + QDistanceFieldGlyphCache *m_glyphCache; + + void setScene(Qt3DCore::QScene *scene) Q_DECL_OVERRIDE; QFont m_font; QFont m_scaledFont; // ignore point or pixel size, set to default value @@ -100,6 +105,14 @@ public: void setCurrentGlyphRuns(const QVector &runs); void update(); + + struct CacheEntry + { + QDistanceFieldGlyphCache *glyphCache = nullptr; + int count = 0; + }; + + static QHash m_glyphCacheInstances; }; } // namespace Qt3DExtras diff --git a/src/extras/text/qtextureatlas.cpp b/src/extras/text/qtextureatlas.cpp index 1a076a3ab..49c6397d6 100644 --- a/src/extras/text/qtextureatlas.cpp +++ b/src/extras/text/qtextureatlas.cpp @@ -37,8 +37,8 @@ ** ****************************************************************************/ -#include "qtextureatlas.h" #include "qtextureatlas_p.h" +#include "qtextureatlas_p_p.h" #include #include #include diff --git a/src/extras/text/qtextureatlas.h b/src/extras/text/qtextureatlas.h deleted file mode 100644 index c70f9dfd3..000000000 --- a/src/extras/text/qtextureatlas.h +++ /dev/null @@ -1,84 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB). -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt3D module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** 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-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QT3DEXTRAS_QTEXTUREATLAS_H -#define QT3DEXTRAS_QTEXTUREATLAS_H - -#include -#include - -QT_BEGIN_NAMESPACE - -namespace Qt3DExtras { - -class QTextureAtlasPrivate; - -class QT3DEXTRASSHARED_EXPORT QTextureAtlas : public Qt3DRender::QAbstractTexture -{ - Q_OBJECT - -public: - typedef int TextureId; - static Q_CONSTEXPR TextureId InvalidTexture = -1; - - QTextureAtlas(Qt3DCore::QNode *parent = nullptr); - ~QTextureAtlas(); - - QOpenGLTexture::PixelFormat pixelFormat() const; - void setPixelFormat(QOpenGLTexture::PixelFormat fmt); - - TextureId addImage(const QImage &image, int padding); - void removeImage(TextureId id); - - int imageCount() const; - - bool hasImage(TextureId id) const; - QRect imagePosition(TextureId id) const; - QRectF imageTexCoords(TextureId id) const; - int imagePadding(TextureId id) const; - -private: - Q_DECLARE_PRIVATE(QTextureAtlas) -}; - -} // namespace Qt3DExtras - -QT_END_NAMESPACE - -#endif // QT3DEXTRAS_QTEXTUREATLAS_H diff --git a/src/extras/text/qtextureatlas_p.h b/src/extras/text/qtextureatlas_p.h index 34386a87a..8dc9e19b3 100644 --- a/src/extras/text/qtextureatlas_p.h +++ b/src/extras/text/qtextureatlas_p.h @@ -51,86 +51,42 @@ // We mean it. // -#include -#include -#include -#include -#include +#include +#include QT_BEGIN_NAMESPACE namespace Qt3DExtras { -// Used to store texture info within atlas -struct AtlasTexture -{ - QRect position; - int padding = 0; -}; +class QTextureAtlasPrivate; -// data shared between QTextureAtlasPrivate and the QTextureGenerators -// we use this extra indirection so we can lazily copy the sub-images -// into the actual texture image in the backend texture loader thread. -class QTextureAtlasData +class QTextureAtlas : public Qt3DRender::QAbstractTexture { -public: - QTextureAtlasData(int w, int h, QImage::Format fmt); - ~QTextureAtlasData(); - - int width() const { return m_image.width(); } - int height() const { return m_image.height(); } + Q_OBJECT - void addImage(const AtlasTexture &texture, const QImage &image); - QByteArray createUpdatedImageData(); - -private: - struct Update { - AtlasTexture textureInfo; - QImage image; - }; - - QMutex m_mutex; - QImage m_image; - QVector m_updates; -}; - -typedef QSharedPointer QTextureAtlasDataPtr; - -class QTextureAtlasPrivate : public Qt3DRender::QAbstractTexturePrivate -{ public: - QTextureAtlasPrivate(); - ~QTextureAtlasPrivate(); + typedef int TextureId; + static Q_CONSTEXPR TextureId InvalidTexture = -1; - Q_DECLARE_PUBLIC(QTextureAtlas) + QTextureAtlas(Qt3DCore::QNode *parent = nullptr); + ~QTextureAtlas(); - QTextureAtlas::TextureId m_currId = 1; // IDs for new sub-textures - int m_currGen = 0; + QOpenGLTexture::PixelFormat pixelFormat() const; + void setPixelFormat(QOpenGLTexture::PixelFormat fmt); - QTextureAtlasDataPtr m_data; - QScopedPointer m_allocator; - QOpenGLTexture::PixelFormat m_pixelFormat; - QHash m_textures; -}; + TextureId addImage(const QImage &image, int padding); + void removeImage(TextureId id); -class QTextureAtlasGenerator : public Qt3DRender::QTextureGenerator -{ -public: - QTextureAtlasGenerator(const QTextureAtlasPrivate *texAtlas); - ~QTextureAtlasGenerator(); - Qt3DRender::QTextureDataPtr operator()() Q_DECL_OVERRIDE; - bool operator==(const QTextureGenerator &other) const Q_DECL_OVERRIDE; + int imageCount() const; - QT3D_FUNCTOR(QTextureAtlasGenerator) + bool hasImage(TextureId id) const; + QRect imagePosition(TextureId id) const; + QRectF imageTexCoords(TextureId id) const; + int imagePadding(TextureId id) const; private: - QTextureAtlasDataPtr m_data; - Qt3DRender::QAbstractTexture::TextureFormat m_format; - QOpenGLTexture::PixelFormat m_pixelFormat; - int m_generation; - Qt3DCore::QNodeId m_atlasId; + Q_DECLARE_PRIVATE(QTextureAtlas) }; -typedef QSharedPointer QTextureAtlasGeneratorPtr; } // namespace Qt3DExtras diff --git a/src/extras/text/qtextureatlas_p_p.h b/src/extras/text/qtextureatlas_p_p.h new file mode 100644 index 000000000..ca18a263a --- /dev/null +++ b/src/extras/text/qtextureatlas_p_p.h @@ -0,0 +1,139 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3DEXTRAS_QTEXTUREATLAS_P_P_H +#define QT3DEXTRAS_QTEXTUREATLAS_P_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DExtras { + +// Used to store texture info within atlas +struct AtlasTexture +{ + QRect position; + int padding = 0; +}; + +// data shared between QTextureAtlasPrivate and the QTextureGenerators +// we use this extra indirection so we can lazily copy the sub-images +// into the actual texture image in the backend texture loader thread. +class QTextureAtlasData +{ +public: + QTextureAtlasData(int w, int h, QImage::Format fmt); + ~QTextureAtlasData(); + + int width() const { return m_image.width(); } + int height() const { return m_image.height(); } + + void addImage(const AtlasTexture &texture, const QImage &image); + QByteArray createUpdatedImageData(); + +private: + struct Update { + AtlasTexture textureInfo; + QImage image; + }; + + QMutex m_mutex; + QImage m_image; + QVector m_updates; +}; + +typedef QSharedPointer QTextureAtlasDataPtr; + +class QTextureAtlasPrivate : public Qt3DRender::QAbstractTexturePrivate +{ +public: + QTextureAtlasPrivate(); + ~QTextureAtlasPrivate(); + + Q_DECLARE_PUBLIC(QTextureAtlas) + + QTextureAtlas::TextureId m_currId = 1; // IDs for new sub-textures + int m_currGen = 0; + + QTextureAtlasDataPtr m_data; + QScopedPointer m_allocator; + QOpenGLTexture::PixelFormat m_pixelFormat; + QHash m_textures; +}; + +class QTextureAtlasGenerator : public Qt3DRender::QTextureGenerator +{ +public: + QTextureAtlasGenerator(const QTextureAtlasPrivate *texAtlas); + ~QTextureAtlasGenerator(); + Qt3DRender::QTextureDataPtr operator()() Q_DECL_OVERRIDE; + bool operator==(const QTextureGenerator &other) const Q_DECL_OVERRIDE; + + QT3D_FUNCTOR(QTextureAtlasGenerator) + +private: + QTextureAtlasDataPtr m_data; + Qt3DRender::QAbstractTexture::TextureFormat m_format; + QOpenGLTexture::PixelFormat m_pixelFormat; + int m_generation; + Qt3DCore::QNodeId m_atlasId; +}; +typedef QSharedPointer QTextureAtlasGeneratorPtr; + +} // namespace Qt3DExtras + +QT_END_NAMESPACE + +#endif // QT3DEXTRAS_QTEXTUREATLAS_P_P_H diff --git a/src/extras/text/text.pri b/src/extras/text/text.pri index 24ab40cc2..583d91de6 100644 --- a/src/extras/text/text.pri +++ b/src/extras/text/text.pri @@ -1,15 +1,14 @@ HEADERS += \ - $$PWD/qtextureatlas.h \ - $$PWD/qtextureatlas_p.h \ - $$PWD/qdistancefieldglyphcache.h \ - $$PWD/qdistancefieldglyphcache_p.h \ $$PWD/qdistancefieldmaterial.h \ $$PWD/qdistancefieldmaterial_p.h \ $$PWD/distancefieldtextrenderer_p.h \ $$PWD/distancefieldtextrenderer_p_p.h \ $$PWD/qdistancefieldtext.h \ $$PWD/qdistancefieldtext_p.h \ - $$PWD/areaallocator_p.h + $$PWD/areaallocator_p.h \ + $$PWD/qdistancefieldglyphcache_p.h \ + $$PWD/qtextureatlas_p_p.h \ + $$PWD/qtextureatlas_p.h SOURCES += \ $$PWD/qtextureatlas.cpp \ diff --git a/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp b/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp index 8aad63178..29a5d9883 100644 --- a/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp +++ b/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp @@ -68,8 +68,6 @@ #include #include #include -#include -#include #include #include #include @@ -126,7 +124,6 @@ void Qt3DQuick3DExtrasPlugin::registerTypes(const char *uri) qmlRegisterType(uri, 2, 9, "ExtrudedTextGeometry"); qmlRegisterType(uri, 2, 9, "ExtrudedTextMesh"); - qmlRegisterType(uri, 2, 9, "DistanceFieldGlyphCache"); qmlRegisterType(uri, 2, 9, "DistanceFieldText"); } diff --git a/tests/manual/distancefieldtext/TextScene.qml b/tests/manual/distancefieldtext/TextScene.qml index 2d60a1c67..54757b400 100644 --- a/tests/manual/distancefieldtext/TextScene.qml +++ b/tests/manual/distancefieldtext/TextScene.qml @@ -91,10 +91,6 @@ Entity { } ] - DistanceFieldGlyphCache { - id: glyphCache - } - function getChars(n) { var s = ""; for (var i = 0; i < n; i++) { @@ -148,7 +144,6 @@ Entity { font.pointSize: 10 text: getChars(strLen) - glyphCache: glyphCache position: Qt.rect(-10, -5, 20, 10) fontScale: 0.1 } -- cgit v1.2.3 From 16b1f88df40da3fad02e772dbaea5703f9564915 Mon Sep 17 00:00:00 2001 From: Paul Lemire Date: Thu, 16 Feb 2017 17:07:28 +0000 Subject: QDistanceFieldText cleanup -renamed QDistanceFieldText to QText2DEntity -renamed QDistanceFieldMaterial to QText2DMaterial -removed fontScale property -replace position property by width/height properties -adjusted manual test accordingly Task-number: QTBUG-58883 Change-Id: Ieb1aae2ef8f397e3a6a636ad651cf83a5565daa0 Reviewed-by: Sean Harmer --- src/extras/text/distancefieldtextrenderer.cpp | 4 +- src/extras/text/distancefieldtextrenderer_p_p.h | 4 +- src/extras/text/qdistancefieldmaterial.cpp | 179 ---------- src/extras/text/qdistancefieldmaterial.h | 72 ---- src/extras/text/qdistancefieldmaterial_p.h | 106 ------ src/extras/text/qdistancefieldtext.cpp | 378 -------------------- src/extras/text/qdistancefieldtext.h | 99 ------ src/extras/text/qdistancefieldtext_p.h | 122 ------- src/extras/text/qtext2dentity.cpp | 381 +++++++++++++++++++++ src/extras/text/qtext2dentity.h | 98 ++++++ src/extras/text/qtext2dentity_p.h | 122 +++++++ src/extras/text/qtext2dmaterial.cpp | 179 ++++++++++ src/extras/text/qtext2dmaterial_p.h | 83 +++++ src/extras/text/qtext2dmaterial_p_p.h | 106 ++++++ src/extras/text/text.pri | 16 +- .../imports/extras/qt3dquick3dextrasplugin.cpp | 4 +- tests/manual/distancefieldtext/TextScene.qml | 10 +- 17 files changed, 988 insertions(+), 975 deletions(-) delete mode 100644 src/extras/text/qdistancefieldmaterial.cpp delete mode 100644 src/extras/text/qdistancefieldmaterial.h delete mode 100644 src/extras/text/qdistancefieldmaterial_p.h delete mode 100644 src/extras/text/qdistancefieldtext.cpp delete mode 100644 src/extras/text/qdistancefieldtext.h delete mode 100644 src/extras/text/qdistancefieldtext_p.h create mode 100644 src/extras/text/qtext2dentity.cpp create mode 100644 src/extras/text/qtext2dentity.h create mode 100644 src/extras/text/qtext2dentity_p.h create mode 100644 src/extras/text/qtext2dmaterial.cpp create mode 100644 src/extras/text/qtext2dmaterial_p.h create mode 100644 src/extras/text/qtext2dmaterial_p_p.h diff --git a/src/extras/text/distancefieldtextrenderer.cpp b/src/extras/text/distancefieldtextrenderer.cpp index 76d9cf50e..9f390e8da 100644 --- a/src/extras/text/distancefieldtextrenderer.cpp +++ b/src/extras/text/distancefieldtextrenderer.cpp @@ -43,7 +43,7 @@ #include #include -#include +#include #include "distancefieldtextrenderer_p.h" #include "distancefieldtextrenderer_p_p.h" @@ -111,7 +111,7 @@ void DistanceFieldTextRendererPrivate::init() m_geometry->addAttribute(m_texCoordAttr); m_geometry->addAttribute(m_indexAttr); - m_material = new QDistanceFieldMaterial(q); + m_material = new QText2DMaterial(q); q->addComponent(m_renderer); q->addComponent(m_material); diff --git a/src/extras/text/distancefieldtextrenderer_p_p.h b/src/extras/text/distancefieldtextrenderer_p_p.h index 06c377a35..af4bc4723 100644 --- a/src/extras/text/distancefieldtextrenderer_p_p.h +++ b/src/extras/text/distancefieldtextrenderer_p_p.h @@ -66,7 +66,7 @@ class QBuffer; namespace Qt3DExtras { -class QDistanceFieldMaterial; +class QText2DMaterial; class DistanceFieldTextRendererPrivate : public Qt3DCore::QEntityPrivate { @@ -85,7 +85,7 @@ public: Qt3DRender::QAttribute *m_indexAttr; Qt3DRender::QBuffer *m_vertexBuffer; Qt3DRender::QBuffer *m_indexBuffer; - QDistanceFieldMaterial *m_material; + QText2DMaterial *m_material; }; } // namespace Qt3DExtras diff --git a/src/extras/text/qdistancefieldmaterial.cpp b/src/extras/text/qdistancefieldmaterial.cpp deleted file mode 100644 index d1c4a493c..000000000 --- a/src/extras/text/qdistancefieldmaterial.cpp +++ /dev/null @@ -1,179 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt3D module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** 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-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qdistancefieldmaterial.h" -#include "qdistancefieldmaterial_p.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE - -namespace Qt3DExtras { - -QDistanceFieldMaterialPrivate::QDistanceFieldMaterialPrivate() - : QMaterialPrivate() - , m_effect(new Qt3DRender::QEffect()) - , m_distanceFieldTexture(nullptr) - , m_textureParameter(new Qt3DRender::QParameter(QStringLiteral("distanceFieldTexture"), QVariant(0))) - , m_textureSizeParameter(new Qt3DRender::QParameter(QStringLiteral("textureSize"), QVariant(256.f))) - , m_colorParameter(new Qt3DRender::QParameter(QStringLiteral("color"), QVariant(QColor(255, 255, 255, 255)))) - , m_gl3Technique(new Qt3DRender::QTechnique()) - , m_gl2Technique(new Qt3DRender::QTechnique()) - , m_es2Technique(new Qt3DRender::QTechnique()) - , m_gl3RenderPass(new Qt3DRender::QRenderPass()) - , m_gl2RenderPass(new Qt3DRender::QRenderPass()) - , m_es2RenderPass(new Qt3DRender::QRenderPass()) - , m_gl3ShaderProgram(new Qt3DRender::QShaderProgram()) - , m_gl2es2ShaderProgram(new Qt3DRender::QShaderProgram()) - , m_blend(new Qt3DRender::QBlendEquation()) - , m_blendArgs(new Qt3DRender::QBlendEquationArguments()) - , m_depthTest(new Qt3DRender::QDepthTest()) -{ -} - -void QDistanceFieldMaterialPrivate::init() -{ - m_gl3ShaderProgram->setVertexShaderCode(Qt3DRender::QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/gl3/distancefieldtext.vert")))); - m_gl3ShaderProgram->setFragmentShaderCode(Qt3DRender::QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/gl3/distancefieldtext.frag")))); - - m_gl2es2ShaderProgram->setVertexShaderCode(Qt3DRender::QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/es2/distancefieldtext.vert")))); - m_gl2es2ShaderProgram->setFragmentShaderCode(Qt3DRender::QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/es2/distancefieldtext.frag")))); - - m_blend->setBlendFunction(Qt3DRender::QBlendEquation::Add); - m_blendArgs->setSourceRgba(Qt3DRender::QBlendEquationArguments::SourceAlpha); - m_blendArgs->setDestinationRgba(Qt3DRender::QBlendEquationArguments::OneMinusSourceAlpha); - m_depthTest->setDepthFunction(Qt3DRender::QDepthTest::LessOrEqual); - - m_gl3RenderPass->setShaderProgram(m_gl3ShaderProgram); - m_gl3RenderPass->addRenderState(m_blend); - m_gl3RenderPass->addRenderState(m_blendArgs); - m_gl3RenderPass->addRenderState(m_depthTest); - - m_gl2RenderPass->setShaderProgram(m_gl2es2ShaderProgram); - m_gl2RenderPass->addRenderState(m_blend); - m_gl2RenderPass->addRenderState(m_blendArgs); - m_gl2RenderPass->addRenderState(m_depthTest); - - m_es2RenderPass->setShaderProgram(m_gl2es2ShaderProgram); - m_es2RenderPass->addRenderState(m_blend); - m_es2RenderPass->addRenderState(m_blendArgs); - m_es2RenderPass->addRenderState(m_depthTest); - - m_gl3Technique->graphicsApiFilter()->setApi(Qt3DRender::QGraphicsApiFilter::OpenGL); - m_gl3Technique->graphicsApiFilter()->setMajorVersion(3); - m_gl3Technique->graphicsApiFilter()->setMinorVersion(1); - m_gl3Technique->graphicsApiFilter()->setProfile(Qt3DRender::QGraphicsApiFilter::CoreProfile); - m_gl3Technique->addRenderPass(m_gl3RenderPass); - - m_gl2Technique->graphicsApiFilter()->setApi(Qt3DRender::QGraphicsApiFilter::OpenGL); - m_gl2Technique->graphicsApiFilter()->setMajorVersion(2); - m_gl2Technique->graphicsApiFilter()->setMinorVersion(0); - m_gl2Technique->graphicsApiFilter()->setProfile(Qt3DRender::QGraphicsApiFilter::NoProfile); - m_gl2Technique->addRenderPass(m_gl2RenderPass); - - m_es2Technique->graphicsApiFilter()->setApi(Qt3DRender::QGraphicsApiFilter::OpenGLES); - m_es2Technique->graphicsApiFilter()->setMajorVersion(2); - m_es2Technique->graphicsApiFilter()->setMinorVersion(0); - m_es2Technique->graphicsApiFilter()->setProfile(Qt3DRender::QGraphicsApiFilter::NoProfile); - m_es2Technique->addRenderPass(m_es2RenderPass); - - Qt3DRender::QFilterKey *filterKey = new Qt3DRender::QFilterKey(q_func()); - filterKey->setName(QStringLiteral("renderingStyle")); - filterKey->setValue(QStringLiteral("forward")); - m_gl3Technique->addFilterKey(filterKey); - m_gl2Technique->addFilterKey(filterKey); - m_es2Technique->addFilterKey(filterKey); - - m_effect->addTechnique(m_gl3Technique); - m_effect->addTechnique(m_gl2Technique); - m_effect->addTechnique(m_es2Technique); - m_effect->addParameter(m_textureParameter); - m_effect->addParameter(m_textureSizeParameter); - m_effect->addParameter(m_colorParameter); - - q_func()->setEffect(m_effect); -} - -QDistanceFieldMaterial::QDistanceFieldMaterial(Qt3DCore::QNode *parent) - : QMaterial(*new QDistanceFieldMaterialPrivate(), parent) -{ - Q_D(QDistanceFieldMaterial); - d->init(); -} - -QDistanceFieldMaterial::~QDistanceFieldMaterial() -{ -} - -void QDistanceFieldMaterial::setColor(const QColor &color) -{ - Q_D(QDistanceFieldMaterial); - d->m_colorParameter->setValue(QVariant::fromValue(color)); -} - -void QDistanceFieldMaterial::setDistanceFieldTexture(Qt3DRender::QAbstractTexture *tex) -{ - Q_D(QDistanceFieldMaterial); - d->m_distanceFieldTexture = tex; - - if (tex) { - d->m_textureParameter->setValue(QVariant::fromValue(tex)); - d->m_textureSizeParameter->setValue(QVariant::fromValue(static_cast(tex->width()))); - } else { - d->m_textureParameter->setValue(0); - d->m_textureSizeParameter->setValue(QVariant::fromValue(1.f)); - } -} - -} // namespace Qt3DExtras - -QT_END_NAMESPACE diff --git a/src/extras/text/qdistancefieldmaterial.h b/src/extras/text/qdistancefieldmaterial.h deleted file mode 100644 index ebecbbcf2..000000000 --- a/src/extras/text/qdistancefieldmaterial.h +++ /dev/null @@ -1,72 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB). -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt3D module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** 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-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QT3DEXTRAS_QDISTANCEFIELDMATERIAL_H -#define QT3DEXTRAS_QDISTANCEFIELDMATERIAL_H - -#include -#include -#include - -QT_BEGIN_NAMESPACE - -namespace Qt3DExtras { - -class QDistanceFieldMaterialPrivate; - -class QDistanceFieldMaterial : public Qt3DRender::QMaterial -{ - Q_OBJECT - -public: - explicit QDistanceFieldMaterial(Qt3DCore::QNode *parent = nullptr); - ~QDistanceFieldMaterial(); - - void setColor(const QColor &color); - void setDistanceFieldTexture(Qt3DRender::QAbstractTexture *tex); - -private: - Q_DECLARE_PRIVATE(QDistanceFieldMaterial) -}; - -} // namespace Qt3DExtras - -QT_END_NAMESPACE - -#endif // QT3DEXTRAS_QDISTANCEFIELDMATERIAL_H diff --git a/src/extras/text/qdistancefieldmaterial_p.h b/src/extras/text/qdistancefieldmaterial_p.h deleted file mode 100644 index 00e3ac93a..000000000 --- a/src/extras/text/qdistancefieldmaterial_p.h +++ /dev/null @@ -1,106 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt3D module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** 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-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QT3DEXTRAS_QDISTANCEFIELDMATERIAL_P_H -#define QT3DEXTRAS_QDISTANCEFIELDMATERIAL_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of other Qt classes. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include - -QT_BEGIN_NAMESPACE - -namespace Qt3DRender { -class QAbstractTexture; -class QEffect; -class QTechnique; -class QParameter; -class QRenderPass; -class QShaderProgram; -class QBlendEquation; -class QBlendEquationArguments; -class QDepthTest; - -} // namespace Qt3DRender - -namespace Qt3DExtras { - -class QDistanceFieldMaterial; - -class QDistanceFieldMaterialPrivate : public Qt3DRender::QMaterialPrivate -{ -public: - QDistanceFieldMaterialPrivate(); - - Qt3DRender::QEffect *m_effect; - Qt3DRender::QAbstractTexture *m_distanceFieldTexture; - Qt3DRender::QParameter *m_textureParameter; - Qt3DRender::QParameter *m_textureSizeParameter; - Qt3DRender::QParameter *m_colorParameter; - Qt3DRender::QTechnique *m_gl3Technique; - Qt3DRender::QTechnique *m_gl2Technique; - Qt3DRender::QTechnique *m_es2Technique; - Qt3DRender::QRenderPass *m_gl3RenderPass; - Qt3DRender::QRenderPass *m_gl2RenderPass; - Qt3DRender::QRenderPass *m_es2RenderPass; - Qt3DRender::QShaderProgram *m_gl3ShaderProgram; - Qt3DRender::QShaderProgram *m_gl2es2ShaderProgram; - Qt3DRender::QBlendEquation *m_blend; - Qt3DRender::QBlendEquationArguments *m_blendArgs; - Qt3DRender::QDepthTest *m_depthTest; - - void init(); - - Q_DECLARE_PUBLIC(QDistanceFieldMaterial) -}; - -} // Qt3DExtras - -QT_END_NAMESPACE - -#endif // QT3DEXTRAS_QDISTANCEFIELDMATERIAL_P_H diff --git a/src/extras/text/qdistancefieldtext.cpp b/src/extras/text/qdistancefieldtext.cpp deleted file mode 100644 index 88e6e9be5..000000000 --- a/src/extras/text/qdistancefieldtext.cpp +++ /dev/null @@ -1,378 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB). -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt3D module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** 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-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qdistancefieldtext.h" -#include "qdistancefieldtext_p.h" -#include "qdistancefieldmaterial.h" - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - -QT_BEGIN_NAMESPACE - -namespace { - -inline Q_DECL_CONSTEXPR QRectF scaleRectF(const QRectF &rect, float scale) -{ - return QRectF(rect.left() * scale, rect.top() * scale, rect.width() * scale, rect.height() * scale); -} - -} // anonymous - -namespace Qt3DExtras { - -QHash QDistanceFieldTextPrivate::m_glyphCacheInstances; - -QDistanceFieldTextPrivate::QDistanceFieldTextPrivate() - : m_glyphCache(nullptr) - , m_font(QLatin1String("Times"), 10) - , m_scaledFont(QLatin1String("Times"), 10) - , m_color(QColor(255, 255, 255, 255)) -{ -} - -QDistanceFieldTextPrivate::~QDistanceFieldTextPrivate() -{ -} - -void QDistanceFieldTextPrivate::setScene(Qt3DCore::QScene *scene) -{ - if (scene == m_scene) - return; - - // Unref old glyph cache if it exists - if (m_scene != nullptr) { - m_glyphCache = nullptr; - QDistanceFieldTextPrivate::CacheEntry &entry = QDistanceFieldTextPrivate::m_glyphCacheInstances[m_scene]; - --entry.count; - if (entry.count == 0 && entry.glyphCache != nullptr) { - delete entry.glyphCache; - entry.glyphCache = nullptr; - } - } - - QEntityPrivate::setScene(scene); - - // Ref new glyph cache is scene is valid - if (scene != nullptr) { - QDistanceFieldTextPrivate::CacheEntry &entry = QDistanceFieldTextPrivate::m_glyphCacheInstances[scene]; - if (entry.glyphCache == nullptr) { - entry.glyphCache = new QDistanceFieldGlyphCache(); - entry.glyphCache->setRootNode(scene->rootNode()); - } - m_glyphCache = entry.glyphCache; - ++entry.count; - // Update to populate glyphCache if needed - update(); - } -} - -QDistanceFieldText::QDistanceFieldText(QNode *parent) - : Qt3DCore::QEntity(*new QDistanceFieldTextPrivate(), parent) -{ -} - -QDistanceFieldText::~QDistanceFieldText() -{ -} - -float QDistanceFieldTextPrivate::computeActualScale() const -{ - // scale font based on fontScale property and given QFont - float scale = m_fontScale; - if (m_font.pointSizeF() > 0) - scale *= m_font.pointSizeF() / m_scaledFont.pointSizeF(); - return scale; -} - -struct RenderData { - int vertexCount = 0; - QVector vertex; - QVector index; -}; - -void QDistanceFieldTextPrivate::setCurrentGlyphRuns(const QVector &runs) -{ - if (runs.isEmpty()) - return; - - // For each distinct texture, we need a separate DistanceFieldTextRenderer, - // for which we need vertex and index data - QHash renderData; - - const float scale = computeActualScale(); - - // process glyph runs - for (const QGlyphRun &run : runs) { - const QVector glyphs = run.glyphIndexes(); - const QVector pos = run.positions(); - - Q_ASSERT(glyphs.size() == pos.size()); - - const bool doubleGlyphResolution = m_glyphCache->doubleGlyphResolution(run.rawFont()); - - // faithfully copied from QSGDistanceFieldGlyphNode::updateGeometry() - const float pixelSize = run.rawFont().pixelSize(); - const float fontScale = pixelSize / QT_DISTANCEFIELD_BASEFONTSIZE(doubleGlyphResolution); - const float margin = QT_DISTANCEFIELD_RADIUS(doubleGlyphResolution) / QT_DISTANCEFIELD_SCALE(doubleGlyphResolution) * fontScale; - - for (int i = 0; i < glyphs.size(); i++) { - const QDistanceFieldGlyphCache::Glyph &dfield = m_glyphCache->refGlyph(run.rawFont(), glyphs[i]); - - if (!dfield.texture) - continue; - - RenderData &data = renderData[dfield.texture]; - - // faithfully copied from QSGDistanceFieldGlyphNode::updateGeometry() - QRectF metrics = scaleRectF(dfield.glyphPathBoundingRect, fontScale); - metrics.adjust(-margin, margin, margin, 3*margin); - - float x1 = m_position.left() + scale * (pos[i].x() + metrics.left()); - float y2 = m_position.bottom() - scale * (pos[i].y() - metrics.top()); - float x2 = x1 + scale * metrics.width(); - float y1 = y2 - scale * metrics.height(); - - // only draw glyphs that are at least partly visible - if (y2 < m_position.top() || x1 > m_position.right()) - continue; - - QRectF texCoords = dfield.texCoords; - - // if a glyph is only partly visible within the given rectangle, - // cut it in half and adjust tex coords - if (y1 < m_position.top()) { - const float insideRatio = (m_position.top() - y2) / (y1 - y2); - y1 = m_position.top(); - texCoords.setHeight(texCoords.height() * insideRatio); - } - - // do the same thing horizontally - if (x2 > m_position.right()) { - const float insideRatio = (m_position.right() - x1) / (x2 - x1); - x2 = m_position.right(); - texCoords.setWidth(texCoords.width() * insideRatio); - } - - data.vertex << x1 << y1 << 0.f << texCoords.left() << texCoords.bottom(); - data.vertex << x1 << y2 << 0.f << texCoords.left() << texCoords.top(); - data.vertex << x2 << y1 << 0.f << texCoords.right() << texCoords.bottom(); - data.vertex << x2 << y2 << 0.f << texCoords.right() << texCoords.top(); - - data.index << data.vertexCount << data.vertexCount+3 << data.vertexCount+1; - data.index << data.vertexCount << data.vertexCount+2 << data.vertexCount+3; - - data.vertexCount += 4; - } - } - - // make sure we have the correct number of DistanceFieldTextRenderers - // TODO: we might keep one renderer at all times, so we won't delete and - // re-allocate one every time the text changes from an empty to a non-empty string - // and vice-versa - while (m_renderers.size() > renderData.size()) - delete m_renderers.takeLast(); - - while (m_renderers.size() < renderData.size()) { - DistanceFieldTextRenderer *renderer = new DistanceFieldTextRenderer(q_func()); - renderer->setColor(m_color); - m_renderers << renderer; - } - - Q_ASSERT(m_renderers.size() == renderData.size()); - - // assign vertex data for all textures to the renderers - int rendererIdx = 0; - for (auto it = renderData.begin(); it != renderData.end(); ++it) { - m_renderers[rendererIdx++]->setGlyphData(it.key(), it.value().vertex, it.value().index); - } - - // de-ref all glyphs for previous QGlyphRuns - for (int i = 0; i < m_currentGlyphRuns.size(); i++) - m_glyphCache->derefGlyphs(m_currentGlyphRuns[i]); - m_currentGlyphRuns = runs; -} - -void QDistanceFieldTextPrivate::update() -{ - if (m_glyphCache == nullptr) - return; - - QVector glyphRuns; - - // collect all GlyphRuns generated by the QTextLayout - if (!m_position.isEmpty() && !m_text.isEmpty() && m_fontScale > 0.f) { - QTextLayout layout(m_text, m_scaledFont); - const float lineWidth = m_position.width() / computeActualScale(); - float height = 0; - layout.beginLayout(); - - while (true) { - QTextLine line = layout.createLine(); - if (!line.isValid()) - break; - - // position current line - line.setLineWidth(lineWidth); - line.setPosition(QPointF(0, height)); - height += line.height(); - - // add glyph runs created by line - const QList runs = line.glyphRuns(); - for (const QGlyphRun &run : runs) - glyphRuns << run; - } - - layout.endLayout(); - } - - setCurrentGlyphRuns(glyphRuns); -} - -QFont QDistanceFieldText::font() const -{ - Q_D(const QDistanceFieldText); - return d->m_font; -} - -void QDistanceFieldText::setFont(const QFont &font) -{ - Q_D(QDistanceFieldText); - if (d->m_font != font) { - // ignore the point size of the font, just make it a default value. - // still we want to make sure that font() returns the same value - // that was passed to setFont(), so we store it nevertheless - d->m_font = font; - d->m_scaledFont = font; - d->m_scaledFont.setPointSize(10); - - emit fontChanged(font); - - if (!d->m_text.isEmpty()) - d->update(); - } -} - -QColor QDistanceFieldText::color() const -{ - Q_D(const QDistanceFieldText); - return d->m_color; -} - -void QDistanceFieldText::setColor(const QColor &color) -{ - Q_D(QDistanceFieldText); - if (d->m_color != color) { - d->m_color = color; - - emit colorChanged(color); - - for (DistanceFieldTextRenderer *renderer : qAsConst(d->m_renderers)) - renderer->setColor(color); - } -} - -QString QDistanceFieldText::text() const -{ - Q_D(const QDistanceFieldText); - return d->m_text; -} - -void QDistanceFieldText::setText(const QString &text) -{ - Q_D(QDistanceFieldText); - if (d->m_text != text) { - d->m_text = text; - emit textChanged(text); - - d->update(); - } -} - -QRectF QDistanceFieldText::position() const -{ - Q_D(const QDistanceFieldText); - return d->m_position; -} - -void QDistanceFieldText::setPosition(const QRectF &pos) -{ - Q_D(QDistanceFieldText); - if (d->m_position != pos) { - d->m_position = pos; - emit positionChanged(pos); - - if (!d->m_text.isEmpty()) - d->update(); - } -} - -float QDistanceFieldText::fontScale() const -{ - Q_D(const QDistanceFieldText); - return d->m_fontScale; -} - -void QDistanceFieldText::setFontScale(float scale) -{ - Q_D(QDistanceFieldText); - if (d->m_fontScale != scale) { - d->m_fontScale = scale; - emit fontScaleChanged(scale); - - if (!d->m_text.isEmpty()) - d->update(); - } -} - -} // namespace Qt3DExtras - -QT_END_NAMESPACE diff --git a/src/extras/text/qdistancefieldtext.h b/src/extras/text/qdistancefieldtext.h deleted file mode 100644 index a1bfc9d9e..000000000 --- a/src/extras/text/qdistancefieldtext.h +++ /dev/null @@ -1,99 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB). -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt3D module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** 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-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QT3DEXTRAS_QDISTANCEFIELDTEXT_H -#define QT3DEXTRAS_QDISTANCEFIELDTEXT_H - -#include -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE - -namespace Qt3DExtras { - -class QDistanceFieldGlyphCache; -class QDistanceFieldTextPrivate; - -class QT3DEXTRASSHARED_EXPORT QDistanceFieldText : public Qt3DCore::QEntity -{ - Q_OBJECT - Q_PROPERTY(QFont font READ font WRITE setFont NOTIFY fontChanged) - Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged) - Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged) - Q_PROPERTY(QRectF position READ position WRITE setPosition NOTIFY positionChanged) - Q_PROPERTY(float fontScale READ fontScale WRITE setFontScale NOTIFY fontScaleChanged) - -public: - explicit QDistanceFieldText(Qt3DCore::QNode *parent = nullptr); - ~QDistanceFieldText(); - - QFont font() const; - void setFont(const QFont &font); - - QColor color() const; - void setColor(const QColor &color); - - QString text() const; - void setText(const QString &text); - - QRectF position() const; - void setPosition(const QRectF &position); - - float fontScale() const; - void setFontScale(float scale); - -Q_SIGNALS: - void fontChanged(const QFont &font); - void colorChanged(const QColor &color); - void textChanged(const QString &text); - void positionChanged(const QRectF &position); - void fontScaleChanged(float scale); - -private: - Q_DECLARE_PRIVATE(QDistanceFieldText) -}; - -} // namespace Qt3DExtras - -QT_END_NAMESPACE - -#endif // QT3DEXTRAS_QDISTANCEFIELDTEXT_H diff --git a/src/extras/text/qdistancefieldtext_p.h b/src/extras/text/qdistancefieldtext_p.h deleted file mode 100644 index d30f226d6..000000000 --- a/src/extras/text/qdistancefieldtext_p.h +++ /dev/null @@ -1,122 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB). -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt3D module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** 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-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QT3DEXTRAS_QDISTANCEFIELDTEXT_P_H -#define QT3DEXTRAS_QDISTANCEFIELDTEXT_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of other Qt classes. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE - -namespace Qt3DCore { -class QScene; -} - -namespace Qt3DRender { -class QGeometryRenderer; -class QGeometry; -class QMaterial; -class QAttribute; -class QBuffer; -} - -namespace Qt3DExtras { - -class QDistanceFieldMaterial; -class QDistanceFieldText; - -class QDistanceFieldTextPrivate : public Qt3DCore::QEntityPrivate -{ -public: - QDistanceFieldTextPrivate(); - ~QDistanceFieldTextPrivate(); - - Q_DECLARE_PUBLIC(QDistanceFieldText) - - // keep track of the glyphs currently being displayed, - // to guarantee proper glyph ref-counting in the - // QDistanceFieldGlyphCache - QVector m_currentGlyphRuns; - QDistanceFieldGlyphCache *m_glyphCache; - - void setScene(Qt3DCore::QScene *scene) Q_DECL_OVERRIDE; - - QFont m_font; - QFont m_scaledFont; // ignore point or pixel size, set to default value - - QColor m_color; - QRectF m_position; - QString m_text; - float m_fontScale = 1.0f; - - QVector m_renderers; - - float computeActualScale() const; - - void setCurrentGlyphRuns(const QVector &runs); - void update(); - - struct CacheEntry - { - QDistanceFieldGlyphCache *glyphCache = nullptr; - int count = 0; - }; - - static QHash m_glyphCacheInstances; -}; - -} // namespace Qt3DExtras - -QT_END_NAMESPACE - -#endif // QT3DEXTRAS_QDISTANCEFIELDTEXT_P_H diff --git a/src/extras/text/qtext2dentity.cpp b/src/extras/text/qtext2dentity.cpp new file mode 100644 index 000000000..dbd4368bc --- /dev/null +++ b/src/extras/text/qtext2dentity.cpp @@ -0,0 +1,381 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtext2dentity.h" +#include "qtext2dentity_p.h" +#include "qtext2dmaterial_p.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +namespace { + +inline Q_DECL_CONSTEXPR QRectF scaleRectF(const QRectF &rect, float scale) +{ + return QRectF(rect.left() * scale, rect.top() * scale, rect.width() * scale, rect.height() * scale); +} + +} // anonymous + +namespace Qt3DExtras { + +QHash QText2DEntityPrivate::m_glyphCacheInstances; + +QText2DEntityPrivate::QText2DEntityPrivate() + : m_glyphCache(nullptr) + , m_font(QLatin1String("Times"), 10) + , m_scaledFont(QLatin1String("Times"), 10) + , m_color(QColor(255, 255, 255, 255)) + , m_width(0.0f) + , m_height(0.0f) +{ +} + +QText2DEntityPrivate::~QText2DEntityPrivate() +{ +} + +void QText2DEntityPrivate::setScene(Qt3DCore::QScene *scene) +{ + if (scene == m_scene) + return; + + // Unref old glyph cache if it exists + if (m_scene != nullptr) { + m_glyphCache = nullptr; + QText2DEntityPrivate::CacheEntry &entry = QText2DEntityPrivate::m_glyphCacheInstances[m_scene]; + --entry.count; + if (entry.count == 0 && entry.glyphCache != nullptr) { + delete entry.glyphCache; + entry.glyphCache = nullptr; + } + } + + QEntityPrivate::setScene(scene); + + // Ref new glyph cache is scene is valid + if (scene != nullptr) { + QText2DEntityPrivate::CacheEntry &entry = QText2DEntityPrivate::m_glyphCacheInstances[scene]; + if (entry.glyphCache == nullptr) { + entry.glyphCache = new QDistanceFieldGlyphCache(); + entry.glyphCache->setRootNode(scene->rootNode()); + } + m_glyphCache = entry.glyphCache; + ++entry.count; + // Update to populate glyphCache if needed + update(); + } +} + +QText2DEntity::QText2DEntity(QNode *parent) + : Qt3DCore::QEntity(*new QText2DEntityPrivate(), parent) +{ +} + +QText2DEntity::~QText2DEntity() +{ +} + +float QText2DEntityPrivate::computeActualScale() const +{ + // scale font based on fontScale property and given QFont + float scale = 1.0f; + if (m_font.pointSizeF() > 0) + scale *= m_font.pointSizeF() / m_scaledFont.pointSizeF(); + return scale; +} + +struct RenderData { + int vertexCount = 0; + QVector vertex; + QVector index; +}; + +void QText2DEntityPrivate::setCurrentGlyphRuns(const QVector &runs) +{ + if (runs.isEmpty()) + return; + + // For each distinct texture, we need a separate DistanceFieldTextRenderer, + // for which we need vertex and index data + QHash renderData; + + const float scale = computeActualScale(); + + // process glyph runs + for (const QGlyphRun &run : runs) { + const QVector glyphs = run.glyphIndexes(); + const QVector pos = run.positions(); + + Q_ASSERT(glyphs.size() == pos.size()); + + const bool doubleGlyphResolution = m_glyphCache->doubleGlyphResolution(run.rawFont()); + + // faithfully copied from QSGDistanceFieldGlyphNode::updateGeometry() + const float pixelSize = run.rawFont().pixelSize(); + const float fontScale = pixelSize / QT_DISTANCEFIELD_BASEFONTSIZE(doubleGlyphResolution); + const float margin = QT_DISTANCEFIELD_RADIUS(doubleGlyphResolution) / QT_DISTANCEFIELD_SCALE(doubleGlyphResolution) * fontScale; + + for (int i = 0; i < glyphs.size(); i++) { + const QDistanceFieldGlyphCache::Glyph &dfield = m_glyphCache->refGlyph(run.rawFont(), glyphs[i]); + + if (!dfield.texture) + continue; + + RenderData &data = renderData[dfield.texture]; + + // faithfully copied from QSGDistanceFieldGlyphNode::updateGeometry() + QRectF metrics = scaleRectF(dfield.glyphPathBoundingRect, fontScale); + metrics.adjust(-margin, margin, margin, 3*margin); + + const float top = 0.0f; + const float left = 0.0f; + const float right = m_width; + const float bottom = m_height; + + float x1 = left + scale * (pos[i].x() + metrics.left()); + float y2 = bottom - scale * (pos[i].y() - metrics.top()); + float x2 = x1 + scale * metrics.width(); + float y1 = y2 - scale * metrics.height(); + + // only draw glyphs that are at least partly visible + if (y2 < top || x1 > right) + continue; + + QRectF texCoords = dfield.texCoords; + + // if a glyph is only partly visible within the given rectangle, + // cut it in half and adjust tex coords + if (y1 < top) { + const float insideRatio = (top - y2) / (y1 - y2); + y1 = top; + texCoords.setHeight(texCoords.height() * insideRatio); + } + + // do the same thing horizontally + if (x2 > right) { + const float insideRatio = (right - x1) / (x2 - x1); + x2 = right; + texCoords.setWidth(texCoords.width() * insideRatio); + } + + data.vertex << x1 << y1 << 0.f << texCoords.left() << texCoords.bottom(); + data.vertex << x1 << y2 << 0.f << texCoords.left() << texCoords.top(); + data.vertex << x2 << y1 << 0.f << texCoords.right() << texCoords.bottom(); + data.vertex << x2 << y2 << 0.f << texCoords.right() << texCoords.top(); + + data.index << data.vertexCount << data.vertexCount+3 << data.vertexCount+1; + data.index << data.vertexCount << data.vertexCount+2 << data.vertexCount+3; + + data.vertexCount += 4; + } + } + + // make sure we have the correct number of DistanceFieldTextRenderers + // TODO: we might keep one renderer at all times, so we won't delete and + // re-allocate one every time the text changes from an empty to a non-empty string + // and vice-versa + while (m_renderers.size() > renderData.size()) + delete m_renderers.takeLast(); + + while (m_renderers.size() < renderData.size()) { + DistanceFieldTextRenderer *renderer = new DistanceFieldTextRenderer(q_func()); + renderer->setColor(m_color); + m_renderers << renderer; + } + + Q_ASSERT(m_renderers.size() == renderData.size()); + + // assign vertex data for all textures to the renderers + int rendererIdx = 0; + for (auto it = renderData.begin(); it != renderData.end(); ++it) { + m_renderers[rendererIdx++]->setGlyphData(it.key(), it.value().vertex, it.value().index); + } + + // de-ref all glyphs for previous QGlyphRuns + for (int i = 0; i < m_currentGlyphRuns.size(); i++) + m_glyphCache->derefGlyphs(m_currentGlyphRuns[i]); + m_currentGlyphRuns = runs; +} + +void QText2DEntityPrivate::update() +{ + if (m_glyphCache == nullptr) + return; + + QVector glyphRuns; + + // collect all GlyphRuns generated by the QTextLayout + if ((m_width > 0.0f || m_height > 0.0f) && !m_text.isEmpty()) { + QTextLayout layout(m_text, m_scaledFont); + const float lineWidth = m_width / computeActualScale(); + float height = 0; + layout.beginLayout(); + + while (true) { + QTextLine line = layout.createLine(); + if (!line.isValid()) + break; + + // position current line + line.setLineWidth(lineWidth); + line.setPosition(QPointF(0, height)); + height += line.height(); + + // add glyph runs created by line + const QList runs = line.glyphRuns(); + for (const QGlyphRun &run : runs) + glyphRuns << run; + } + + layout.endLayout(); + } + + setCurrentGlyphRuns(glyphRuns); +} + +QFont QText2DEntity::font() const +{ + Q_D(const QText2DEntity); + return d->m_font; +} + +void QText2DEntity::setFont(const QFont &font) +{ + Q_D(QText2DEntity); + if (d->m_font != font) { + // ignore the point size of the font, just make it a default value. + // still we want to make sure that font() returns the same value + // that was passed to setFont(), so we store it nevertheless + d->m_font = font; + d->m_scaledFont = font; + d->m_scaledFont.setPointSize(10); + + emit fontChanged(font); + + if (!d->m_text.isEmpty()) + d->update(); + } +} + +QColor QText2DEntity::color() const +{ + Q_D(const QText2DEntity); + return d->m_color; +} + +void QText2DEntity::setColor(const QColor &color) +{ + Q_D(QText2DEntity); + if (d->m_color != color) { + d->m_color = color; + + emit colorChanged(color); + + for (DistanceFieldTextRenderer *renderer : qAsConst(d->m_renderers)) + renderer->setColor(color); + } +} + +QString QText2DEntity::text() const +{ + Q_D(const QText2DEntity); + return d->m_text; +} + +void QText2DEntity::setText(const QString &text) +{ + Q_D(QText2DEntity); + if (d->m_text != text) { + d->m_text = text; + emit textChanged(text); + + d->update(); + } +} + +float QText2DEntity::width() const +{ + Q_D(const QText2DEntity); + return d->m_width; +} + +float QText2DEntity::height() const +{ + Q_D(const QText2DEntity); + return d->m_height; +} + +void QText2DEntity::setWidth(float width) +{ + Q_D(QText2DEntity); + if (width != d->m_width) { + d->m_width = width; + emit widthChanged(width); + d->update(); + } +} + +void QText2DEntity::setHeight(float height) +{ + Q_D(QText2DEntity); + if (height != d->m_height) { + d->m_height = height; + emit heightChanged(height); + d->update(); + } +} + +} // namespace Qt3DExtras + +QT_END_NAMESPACE diff --git a/src/extras/text/qtext2dentity.h b/src/extras/text/qtext2dentity.h new file mode 100644 index 000000000..39be91a0f --- /dev/null +++ b/src/extras/text/qtext2dentity.h @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3DEXTRAS_QTEXT2DENTITY_H +#define QT3DEXTRAS_QTEXT2DENTITY_H + +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DExtras { + +class QText2DEntityPrivate; + +class QT3DEXTRASSHARED_EXPORT QText2DEntity : public Qt3DCore::QEntity +{ + Q_OBJECT + Q_PROPERTY(QFont font READ font WRITE setFont NOTIFY fontChanged) + Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged) + Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged) + Q_PROPERTY(float width READ width WRITE setWidth NOTIFY widthChanged) + Q_PROPERTY(float height READ height WRITE setHeight NOTIFY heightChanged) + +public: + explicit QText2DEntity(Qt3DCore::QNode *parent = nullptr); + ~QText2DEntity(); + + QFont font() const; + void setFont(const QFont &font); + + QColor color() const; + void setColor(const QColor &color); + + QString text() const; + void setText(const QString &text); + + float width() const; + float height() const; + + void setWidth(float width); + void setHeight(float height); + +Q_SIGNALS: + void fontChanged(const QFont &font); + void colorChanged(const QColor &color); + void textChanged(const QString &text); + void widthChanged(float width); + void heightChanged(float height); + +private: + Q_DECLARE_PRIVATE(QText2DEntity) +}; + +} // namespace Qt3DExtras + +QT_END_NAMESPACE + +#endif // QT3DEXTRAS_QTEXT2DENTITY_H diff --git a/src/extras/text/qtext2dentity_p.h b/src/extras/text/qtext2dentity_p.h new file mode 100644 index 000000000..863431091 --- /dev/null +++ b/src/extras/text/qtext2dentity_p.h @@ -0,0 +1,122 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3DEXTRAS_QTEXT2DENTITY_P_H +#define QT3DEXTRAS_QTEXT2DENTITY_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DCore { +class QScene; +} + +namespace Qt3DRender { +class QGeometryRenderer; +class QGeometry; +class QMaterial; +class QAttribute; +class QBuffer; +} + +namespace Qt3DExtras { + +class QText2DMaterial; +class QText2DEntity; + +class QText2DEntityPrivate : public Qt3DCore::QEntityPrivate +{ +public: + QText2DEntityPrivate(); + ~QText2DEntityPrivate(); + + Q_DECLARE_PUBLIC(QText2DEntity) + + // keep track of the glyphs currently being displayed, + // to guarantee proper glyph ref-counting in the + // QDistanceFieldGlyphCache + QVector m_currentGlyphRuns; + QDistanceFieldGlyphCache *m_glyphCache; + + void setScene(Qt3DCore::QScene *scene) Q_DECL_OVERRIDE; + + QFont m_font; + QFont m_scaledFont; // ignore point or pixel size, set to default value + + QColor m_color; + QString m_text; + float m_width; + float m_height; + + QVector m_renderers; + + float computeActualScale() const; + + void setCurrentGlyphRuns(const QVector &runs); + void update(); + + struct CacheEntry + { + QDistanceFieldGlyphCache *glyphCache = nullptr; + int count = 0; + }; + + static QHash m_glyphCacheInstances; +}; + +} // namespace Qt3DExtras + +QT_END_NAMESPACE + +#endif // QT3DEXTRAS_QTEXT2DENTITY_P_H diff --git a/src/extras/text/qtext2dmaterial.cpp b/src/extras/text/qtext2dmaterial.cpp new file mode 100644 index 000000000..d8bf312c4 --- /dev/null +++ b/src/extras/text/qtext2dmaterial.cpp @@ -0,0 +1,179 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtext2dmaterial_p.h" +#include "qtext2dmaterial_p_p.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DExtras { + +QText2DMaterialPrivate::QText2DMaterialPrivate() + : QMaterialPrivate() + , m_effect(new Qt3DRender::QEffect()) + , m_distanceFieldTexture(nullptr) + , m_textureParameter(new Qt3DRender::QParameter(QStringLiteral("distanceFieldTexture"), QVariant(0))) + , m_textureSizeParameter(new Qt3DRender::QParameter(QStringLiteral("textureSize"), QVariant(256.f))) + , m_colorParameter(new Qt3DRender::QParameter(QStringLiteral("color"), QVariant(QColor(255, 255, 255, 255)))) + , m_gl3Technique(new Qt3DRender::QTechnique()) + , m_gl2Technique(new Qt3DRender::QTechnique()) + , m_es2Technique(new Qt3DRender::QTechnique()) + , m_gl3RenderPass(new Qt3DRender::QRenderPass()) + , m_gl2RenderPass(new Qt3DRender::QRenderPass()) + , m_es2RenderPass(new Qt3DRender::QRenderPass()) + , m_gl3ShaderProgram(new Qt3DRender::QShaderProgram()) + , m_gl2es2ShaderProgram(new Qt3DRender::QShaderProgram()) + , m_blend(new Qt3DRender::QBlendEquation()) + , m_blendArgs(new Qt3DRender::QBlendEquationArguments()) + , m_depthTest(new Qt3DRender::QDepthTest()) +{ +} + +void QText2DMaterialPrivate::init() +{ + m_gl3ShaderProgram->setVertexShaderCode(Qt3DRender::QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/gl3/distancefieldtext.vert")))); + m_gl3ShaderProgram->setFragmentShaderCode(Qt3DRender::QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/gl3/distancefieldtext.frag")))); + + m_gl2es2ShaderProgram->setVertexShaderCode(Qt3DRender::QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/es2/distancefieldtext.vert")))); + m_gl2es2ShaderProgram->setFragmentShaderCode(Qt3DRender::QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/es2/distancefieldtext.frag")))); + + m_blend->setBlendFunction(Qt3DRender::QBlendEquation::Add); + m_blendArgs->setSourceRgba(Qt3DRender::QBlendEquationArguments::SourceAlpha); + m_blendArgs->setDestinationRgba(Qt3DRender::QBlendEquationArguments::OneMinusSourceAlpha); + m_depthTest->setDepthFunction(Qt3DRender::QDepthTest::LessOrEqual); + + m_gl3RenderPass->setShaderProgram(m_gl3ShaderProgram); + m_gl3RenderPass->addRenderState(m_blend); + m_gl3RenderPass->addRenderState(m_blendArgs); + m_gl3RenderPass->addRenderState(m_depthTest); + + m_gl2RenderPass->setShaderProgram(m_gl2es2ShaderProgram); + m_gl2RenderPass->addRenderState(m_blend); + m_gl2RenderPass->addRenderState(m_blendArgs); + m_gl2RenderPass->addRenderState(m_depthTest); + + m_es2RenderPass->setShaderProgram(m_gl2es2ShaderProgram); + m_es2RenderPass->addRenderState(m_blend); + m_es2RenderPass->addRenderState(m_blendArgs); + m_es2RenderPass->addRenderState(m_depthTest); + + m_gl3Technique->graphicsApiFilter()->setApi(Qt3DRender::QGraphicsApiFilter::OpenGL); + m_gl3Technique->graphicsApiFilter()->setMajorVersion(3); + m_gl3Technique->graphicsApiFilter()->setMinorVersion(1); + m_gl3Technique->graphicsApiFilter()->setProfile(Qt3DRender::QGraphicsApiFilter::CoreProfile); + m_gl3Technique->addRenderPass(m_gl3RenderPass); + + m_gl2Technique->graphicsApiFilter()->setApi(Qt3DRender::QGraphicsApiFilter::OpenGL); + m_gl2Technique->graphicsApiFilter()->setMajorVersion(2); + m_gl2Technique->graphicsApiFilter()->setMinorVersion(0); + m_gl2Technique->graphicsApiFilter()->setProfile(Qt3DRender::QGraphicsApiFilter::NoProfile); + m_gl2Technique->addRenderPass(m_gl2RenderPass); + + m_es2Technique->graphicsApiFilter()->setApi(Qt3DRender::QGraphicsApiFilter::OpenGLES); + m_es2Technique->graphicsApiFilter()->setMajorVersion(2); + m_es2Technique->graphicsApiFilter()->setMinorVersion(0); + m_es2Technique->graphicsApiFilter()->setProfile(Qt3DRender::QGraphicsApiFilter::NoProfile); + m_es2Technique->addRenderPass(m_es2RenderPass); + + Qt3DRender::QFilterKey *filterKey = new Qt3DRender::QFilterKey(q_func()); + filterKey->setName(QStringLiteral("renderingStyle")); + filterKey->setValue(QStringLiteral("forward")); + m_gl3Technique->addFilterKey(filterKey); + m_gl2Technique->addFilterKey(filterKey); + m_es2Technique->addFilterKey(filterKey); + + m_effect->addTechnique(m_gl3Technique); + m_effect->addTechnique(m_gl2Technique); + m_effect->addTechnique(m_es2Technique); + m_effect->addParameter(m_textureParameter); + m_effect->addParameter(m_textureSizeParameter); + m_effect->addParameter(m_colorParameter); + + q_func()->setEffect(m_effect); +} + +QText2DMaterial::QText2DMaterial(Qt3DCore::QNode *parent) + : QMaterial(*new QText2DMaterialPrivate(), parent) +{ + Q_D(QText2DMaterial); + d->init(); +} + +QText2DMaterial::~QText2DMaterial() +{ +} + +void QText2DMaterial::setColor(const QColor &color) +{ + Q_D(QText2DMaterial); + d->m_colorParameter->setValue(QVariant::fromValue(color)); +} + +void QText2DMaterial::setDistanceFieldTexture(Qt3DRender::QAbstractTexture *tex) +{ + Q_D(QText2DMaterial); + d->m_distanceFieldTexture = tex; + + if (tex) { + d->m_textureParameter->setValue(QVariant::fromValue(tex)); + d->m_textureSizeParameter->setValue(QVariant::fromValue(static_cast(tex->width()))); + } else { + d->m_textureParameter->setValue(0); + d->m_textureSizeParameter->setValue(QVariant::fromValue(1.f)); + } +} + +} // namespace Qt3DExtras + +QT_END_NAMESPACE diff --git a/src/extras/text/qtext2dmaterial_p.h b/src/extras/text/qtext2dmaterial_p.h new file mode 100644 index 000000000..cf967b02b --- /dev/null +++ b/src/extras/text/qtext2dmaterial_p.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3DEXTRAS_QTEXT2DMATERIAL_P_H +#define QT3DEXTRAS_QTEXT2DMATERIAL_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DExtras { + +class QText2DMaterialPrivate; + +class QText2DMaterial : public Qt3DRender::QMaterial +{ + Q_OBJECT + +public: + explicit QText2DMaterial(Qt3DCore::QNode *parent = nullptr); + ~QText2DMaterial(); + + void setColor(const QColor &color); + void setDistanceFieldTexture(Qt3DRender::QAbstractTexture *tex); + +private: + Q_DECLARE_PRIVATE(QText2DMaterial) +}; + +} // namespace Qt3DExtras + +QT_END_NAMESPACE + +#endif // QT3DEXTRAS_QTEXT2DMATERIAL_P_H diff --git a/src/extras/text/qtext2dmaterial_p_p.h b/src/extras/text/qtext2dmaterial_p_p.h new file mode 100644 index 000000000..90f0a71f1 --- /dev/null +++ b/src/extras/text/qtext2dmaterial_p_p.h @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3DEXTRAS_QTEXT2DMATERIAL_P_P_H +#define QT3DEXTRAS_QTEXT2DMATERIAL_P_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { +class QAbstractTexture; +class QEffect; +class QTechnique; +class QParameter; +class QRenderPass; +class QShaderProgram; +class QBlendEquation; +class QBlendEquationArguments; +class QDepthTest; + +} // namespace Qt3DRender + +namespace Qt3DExtras { + +class QText2DMaterial; + +class QText2DMaterialPrivate : public Qt3DRender::QMaterialPrivate +{ +public: + QText2DMaterialPrivate(); + + Qt3DRender::QEffect *m_effect; + Qt3DRender::QAbstractTexture *m_distanceFieldTexture; + Qt3DRender::QParameter *m_textureParameter; + Qt3DRender::QParameter *m_textureSizeParameter; + Qt3DRender::QParameter *m_colorParameter; + Qt3DRender::QTechnique *m_gl3Technique; + Qt3DRender::QTechnique *m_gl2Technique; + Qt3DRender::QTechnique *m_es2Technique; + Qt3DRender::QRenderPass *m_gl3RenderPass; + Qt3DRender::QRenderPass *m_gl2RenderPass; + Qt3DRender::QRenderPass *m_es2RenderPass; + Qt3DRender::QShaderProgram *m_gl3ShaderProgram; + Qt3DRender::QShaderProgram *m_gl2es2ShaderProgram; + Qt3DRender::QBlendEquation *m_blend; + Qt3DRender::QBlendEquationArguments *m_blendArgs; + Qt3DRender::QDepthTest *m_depthTest; + + void init(); + + Q_DECLARE_PUBLIC(QText2DMaterial) +}; + +} // Qt3DExtras + +QT_END_NAMESPACE + +#endif // QT3DEXTRAS_QTEXT2DMATERIAL_P_P_H diff --git a/src/extras/text/text.pri b/src/extras/text/text.pri index 583d91de6..1d2cb793c 100644 --- a/src/extras/text/text.pri +++ b/src/extras/text/text.pri @@ -1,21 +1,21 @@ HEADERS += \ - $$PWD/qdistancefieldmaterial.h \ - $$PWD/qdistancefieldmaterial_p.h \ $$PWD/distancefieldtextrenderer_p.h \ $$PWD/distancefieldtextrenderer_p_p.h \ - $$PWD/qdistancefieldtext.h \ - $$PWD/qdistancefieldtext_p.h \ $$PWD/areaallocator_p.h \ $$PWD/qdistancefieldglyphcache_p.h \ $$PWD/qtextureatlas_p_p.h \ - $$PWD/qtextureatlas_p.h + $$PWD/qtextureatlas_p.h \ + $$PWD/qtext2dentity_p.h \ + $$PWD/qtext2dentity.h \ + $$PWD/qtext2dmaterial_p_p.h \ + $$PWD/qtext2dmaterial_p.h SOURCES += \ $$PWD/qtextureatlas.cpp \ $$PWD/qdistancefieldglyphcache.cpp \ - $$PWD/qdistancefieldmaterial.cpp \ - $$PWD/qdistancefieldtext.cpp \ $$PWD/distancefieldtextrenderer.cpp \ - $$PWD/areaallocator.cpp + $$PWD/areaallocator.cpp \ + $$PWD/qtext2dentity.cpp \ + $$PWD/qtext2dmaterial.cpp INCLUDEPATH += $$PWD diff --git a/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp b/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp index 29a5d9883..95924182d 100644 --- a/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp +++ b/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp @@ -68,7 +68,7 @@ #include #include #include -#include +#include #include #include @@ -124,7 +124,7 @@ void Qt3DQuick3DExtrasPlugin::registerTypes(const char *uri) qmlRegisterType(uri, 2, 9, "ExtrudedTextGeometry"); qmlRegisterType(uri, 2, 9, "ExtrudedTextMesh"); - qmlRegisterType(uri, 2, 9, "DistanceFieldText"); + qmlRegisterType(uri, 2, 9, "Text2DEntity"); } diff --git a/tests/manual/distancefieldtext/TextScene.qml b/tests/manual/distancefieldtext/TextScene.qml index 54757b400..5e94a9aaf 100644 --- a/tests/manual/distancefieldtext/TextScene.qml +++ b/tests/manual/distancefieldtext/TextScene.qml @@ -113,6 +113,7 @@ Entity { components: [ Transform { id: rot + translation: Qt.vector3d(-5, -5, 0) } ] @@ -139,13 +140,12 @@ Entity { } } - DistanceFieldText { + Text2DEntity { id: text - - font.pointSize: 10 + font.pointSize: 1 text: getChars(strLen) - position: Qt.rect(-10, -5, 20, 10) - fontScale: 0.1 + width: 20 + height: 10 } } } -- cgit v1.2.3 From 42af57acc976cf3142623ac2b13dabbfcf9e643a Mon Sep 17 00:00:00 2001 From: Paul Lemire Date: Wed, 15 Feb 2017 14:27:13 +0000 Subject: QNode PropertyTrackMode cleanup Task-number: QTBUG-58897 Change-Id: Ie92c26e7b34ea7730461786f484ff50b003f747a Reviewed-by: Sean Harmer --- src/core/nodes/qnode.cpp | 72 ++++---- src/core/nodes/qnode.h | 27 +-- src/core/nodes/qnode_p.h | 4 +- src/core/qpostman.cpp | 16 +- src/core/qscene_p.h | 4 +- src/quick3d/imports/core/qt3dquick3dcoreplugin.cpp | 3 +- src/quick3d/quick3d/items/items.pri | 6 +- src/quick3d/quick3d/items/quick3dnodev9.cpp | 203 +++++++++++++++++++++ src/quick3d/quick3d/items/quick3dnodev9_p.h | 109 +++++++++++ tests/auto/core/nodes/tst_nodes.cpp | 48 +++-- tests/auto/core/qpostman/tst_qpostman.cpp | 18 +- tests/auto/core/qscene/tst_qscene.cpp | 77 ++++---- tests/auto/quick3d/3dcore/3dcore.qml | 2 + tests/auto/quick3d/quick3d.pro | 3 +- tests/auto/quick3d/quick3dnode/quick3dnode.pro | 13 ++ tests/auto/quick3d/quick3dnode/quick3dnode.qrc | 5 + tests/auto/quick3d/quick3dnode/quick3dnodev9.qml | 36 ++++ tests/auto/quick3d/quick3dnode/tst_quick3dnode.cpp | 55 ++++++ .../test_scene_model_to_eye.qml | 6 +- .../test_scene_model_to_world.qml | 6 +- .../tst_updateshaderdatatransformjob.cpp | 4 +- 21 files changed, 574 insertions(+), 143 deletions(-) create mode 100644 src/quick3d/quick3d/items/quick3dnodev9.cpp create mode 100644 src/quick3d/quick3d/items/quick3dnodev9_p.h create mode 100644 tests/auto/quick3d/quick3dnode/quick3dnode.pro create mode 100644 tests/auto/quick3d/quick3dnode/quick3dnode.qrc create mode 100644 tests/auto/quick3d/quick3dnode/quick3dnodev9.qml create mode 100644 tests/auto/quick3d/quick3dnode/tst_quick3dnode.cpp diff --git a/src/core/nodes/qnode.cpp b/src/core/nodes/qnode.cpp index c3c28b85d..6219790e6 100644 --- a/src/core/nodes/qnode.cpp +++ b/src/core/nodes/qnode.cpp @@ -73,7 +73,7 @@ QNodePrivate::QNodePrivate() , m_blockNotifications(false) , m_hasBackendNode(false) , m_enabled(true) - , m_propertyTrackMode(QNode::DefaultTrackMode) + , m_defaultPropertyTrackMode(QNode::TrackFinalValues) , m_propertyChangesSetup(false) , m_signals(this) { @@ -608,9 +608,9 @@ void QNodePrivate::updatePropertyTrackMode() { if (m_scene != nullptr) { QScene::NodePropertyTrackData trackData; - trackData.updateMode = m_propertyTrackMode; - trackData.namedProperties = m_trackedProperties; - m_scene->setPropertyTrackDataForNode(m_id,trackData); + trackData.defaultTrackMode = m_defaultPropertyTrackMode; + trackData.trackedPropertiesOverrides = m_trackedPropertiesOverrides; + m_scene->setPropertyTrackDataForNode(m_id, trackData); } } @@ -803,30 +803,16 @@ void QNode::setEnabled(bool isEnabled) emit enabledChanged(isEnabled); } -void QNode::setPropertyTrackMode(QNode::PropertyTrackMode mode) +void QNode::setDefaultPropertyTrackingMode(QNode::PropertyTrackingMode mode) { Q_D(QNode); - if (d->m_propertyTrackMode == mode) + if (d->m_defaultPropertyTrackMode == mode) return; - d->m_propertyTrackMode = mode; + d->m_defaultPropertyTrackMode = mode; // The backend doesn't care about such notification const bool blocked = blockNotifications(true); - emit propertyUpdateModeChanged(mode); - blockNotifications(blocked); - d->updatePropertyTrackMode(); -} - -void QNode::setTrackedProperties(const QStringList &trackedProperties) -{ - Q_D(QNode); - if (d->m_trackedProperties == trackedProperties) - return; - - d->m_trackedProperties = trackedProperties; - // The backend doesn't care about such notification - const bool blocked = blockNotifications(true); - emit trackedPropertiesChanged(trackedProperties); + emit defaultPropertyTrackingModeChanged(mode); blockNotifications(blocked); d->updatePropertyTrackMode(); } @@ -848,29 +834,45 @@ bool QNode::isEnabled() const } /*! - \property Qt3DCore::QNode::propertyTrackMode + \property Qt3DCore::QNode::defaultPropertyTrackingMode - Holds the property track mode which determines whether a QNode should - be listening for property updates + Holds the default property tracking mode which determines whether a QNode should + be listening for property updates. This only applies to properties which + haven't been overridden by a call to setPropertyTracking. - By default it is set to QNode::DontTrackProperties + By default it is set to QNode::TrackFinalValues */ -QNode::PropertyTrackMode QNode::propertyTrackMode() const +QNode::PropertyTrackingMode QNode::defaultPropertyTrackingMode() const { Q_D(const QNode); - return d->m_propertyTrackMode; + return d->m_defaultPropertyTrackMode; } -/*! - \property Qt3DCore::QNode::trackedProperties +void QNode::setPropertyTracking(const QString &propertyName, QNode::PropertyTrackingMode trackMode) +{ + Q_D(QNode); + d->m_trackedPropertiesOverrides.insert(propertyName, trackMode); + d->updatePropertyTrackMode(); +} - Holds the names of the properties to be tracked when propertyTrackMode is - set to TrackNamedProperties. -*/ -QStringList QNode::trackedProperties() const +QNode::PropertyTrackingMode QNode::propertyTracking(const QString &propertyName) const { Q_D(const QNode); - return d->m_trackedProperties; + return d->m_trackedPropertiesOverrides.value(propertyName, d->m_defaultPropertyTrackMode); +} + +void QNode::clearPropertyTracking(const QString &propertyName) +{ + Q_D(QNode); + d->m_trackedPropertiesOverrides.remove(propertyName); + d->updatePropertyTrackMode(); +} + +void QNode::clearPropertyTrackings() +{ + Q_D(QNode); + d->m_trackedPropertiesOverrides.clear(); + d->updatePropertyTrackMode(); } QNodeCreatedChangeBasePtr QNode::createNodeCreationChange() const diff --git a/src/core/nodes/qnode.h b/src/core/nodes/qnode.h index 56c92da7f..818d6a722 100644 --- a/src/core/nodes/qnode.h +++ b/src/core/nodes/qnode.h @@ -69,16 +69,15 @@ class QT3DCORESHARED_EXPORT QNode : public QObject Q_OBJECT Q_PROPERTY(Qt3DCore::QNode *parent READ parentNode WRITE setParent NOTIFY parentChanged) Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged) - Q_PROPERTY(PropertyTrackMode propertyTrackMode READ propertyTrackMode WRITE setPropertyTrackMode NOTIFY propertyUpdateModeChanged REVISION 9) - Q_PROPERTY(QStringList trackedProperties READ trackedProperties WRITE setTrackedProperties NOTIFY trackedPropertiesChanged REVISION 9) + Q_PROPERTY(PropertyTrackingMode defaultPropertyTrackingMode READ defaultPropertyTrackingMode WRITE setDefaultPropertyTrackingMode NOTIFY defaultPropertyTrackingModeChanged REVISION 9) public: - enum PropertyTrackMode { - DefaultTrackMode, - TrackNamedPropertiesMode, - TrackAllPropertiesMode + enum PropertyTrackingMode { + TrackFinalValues, + DontTrackValues, + TrackAllValues }; - Q_ENUM(PropertyTrackMode) + Q_ENUM(PropertyTrackingMode) explicit QNode(QNode *parent = nullptr); virtual ~QNode(); @@ -92,20 +91,22 @@ public: QNodeVector childNodes() const; bool isEnabled() const; - PropertyTrackMode propertyTrackMode() const; - QStringList trackedProperties() const; + PropertyTrackingMode defaultPropertyTrackingMode() const; + + void setPropertyTracking(const QString &propertyName, PropertyTrackingMode trackMode); + PropertyTrackingMode propertyTracking(const QString &propertyName) const; + void clearPropertyTracking(const QString &propertyName); + void clearPropertyTrackings(); public Q_SLOTS: void setParent(QNode *parent); void setEnabled(bool isEnabled); - void setPropertyTrackMode(PropertyTrackMode mode); - void setTrackedProperties(const QStringList &trackedProperties); + void setDefaultPropertyTrackingMode(PropertyTrackingMode mode); Q_SIGNALS: void parentChanged(QObject *parent); void enabledChanged(bool enabled); - void propertyUpdateModeChanged(PropertyTrackMode mode); - void trackedPropertiesChanged(const QStringList &trackedProperties); + void defaultPropertyTrackingModeChanged(PropertyTrackingMode mode); void nodeDestroyed(); protected: diff --git a/src/core/nodes/qnode_p.h b/src/core/nodes/qnode_p.h index d4a48aa1e..bfac1cbe1 100644 --- a/src/core/nodes/qnode_p.h +++ b/src/core/nodes/qnode_p.h @@ -98,8 +98,8 @@ public: bool m_blockNotifications; bool m_hasBackendNode; bool m_enabled; - QNode::PropertyTrackMode m_propertyTrackMode; - QStringList m_trackedProperties; + QNode::PropertyTrackingMode m_defaultPropertyTrackMode; + QHash m_trackedPropertiesOverrides; static QNodePrivate *get(QNode *q); static void nodePtrDeleter(QNode *q); diff --git a/src/core/qpostman.cpp b/src/core/qpostman.cpp index 206399070..db7a9500e 100644 --- a/src/core/qpostman.cpp +++ b/src/core/qpostman.cpp @@ -117,15 +117,19 @@ bool QPostman::shouldNotifyFrontend(const QSceneChangePtr &e) const QPropertyUpdatedChangePtr propertyChange = qSharedPointerDynamicCast(e); if (Q_LIKELY(d->m_scene != nullptr) && !propertyChange.isNull()) { const QScene::NodePropertyTrackData propertyTrackData - = d->m_scene->lookupNodePropertyTrackData(e->subjectId()); - switch (propertyTrackData.updateMode) { - case QNode::TrackAllPropertiesMode: + = d->m_scene->lookupNodePropertyTrackData(e->subjectId()); + + const QNode::PropertyTrackingMode trackMode = propertyTrackData.trackedPropertiesOverrides.value(QLatin1String(propertyChange->propertyName()), + propertyTrackData.defaultTrackMode); + + switch (trackMode) { + case QNode::TrackAllValues: return true; - case QNode::TrackNamedPropertiesMode: - return propertyTrackData.namedProperties.contains(QLatin1String(propertyChange->propertyName())); + case QNode::DontTrackValues: + return false; - case QNode::DefaultTrackMode: { + case QNode::TrackFinalValues: { const bool isIntermediate = QPropertyUpdatedChangeBasePrivate::get(propertyChange.data())->m_isIntermediate; return !isIntermediate; diff --git a/src/core/qscene_p.h b/src/core/qscene_p.h index fdcb23edb..d200abf42 100644 --- a/src/core/qscene_p.h +++ b/src/core/qscene_p.h @@ -97,8 +97,8 @@ public: // Node -> Property Update Data struct NodePropertyTrackData { - QNode::PropertyTrackMode updateMode = QNode::DefaultTrackMode; - QStringList namedProperties; + QNode::PropertyTrackingMode defaultTrackMode = QNode::TrackFinalValues; + QHash trackedPropertiesOverrides; }; NodePropertyTrackData lookupNodePropertyTrackData(QNodeId id) const; void setPropertyTrackDataForNode(QNodeId id, const NodePropertyTrackData &data); diff --git a/src/quick3d/imports/core/qt3dquick3dcoreplugin.cpp b/src/quick3d/imports/core/qt3dquick3dcoreplugin.cpp index 8f470518c..51509f4ab 100644 --- a/src/quick3d/imports/core/qt3dquick3dcoreplugin.cpp +++ b/src/quick3d/imports/core/qt3dquick3dcoreplugin.cpp @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -65,7 +66,7 @@ void Qt3DQuick3DCorePlugin::registerTypes(const char *uri) // Ideally we want to make Node an uncreatable type // We would need qmlRegisterUncreatableExtendedType for that qmlRegisterExtendedUncreatableType(uri, 2, 0, "Node", QStringLiteral("Node is a base class")); - qmlRegisterExtendedUncreatableType(uri, 2, 9, "Node", QStringLiteral("Node is a base class")); + qmlRegisterExtendedUncreatableType(uri, 2, 9, "Node", QStringLiteral("Node is a base class")); } QT_END_NAMESPACE diff --git a/src/quick3d/quick3d/items/items.pri b/src/quick3d/quick3d/items/items.pri index 4c5e93fb2..4749c83cf 100644 --- a/src/quick3d/quick3d/items/items.pri +++ b/src/quick3d/quick3d/items/items.pri @@ -3,12 +3,14 @@ HEADERS += \ $$PWD/quick3dentity_p.h \ $$PWD/quick3dentityloader_p_p.h \ $$PWD/quick3dentityloader_p.h \ - $$PWD/quick3dnode_p.h + $$PWD/quick3dnode_p.h \ + $$PWD/quick3dnodev9_p.h SOURCES += \ $$PWD/quick3dnode.cpp \ $$PWD/quick3dentity.cpp \ $$PWD/quick3dentityloader.cpp \ - $$PWD/quick3dnodeinstantiator.cpp + $$PWD/quick3dnodeinstantiator.cpp \ + $$PWD/quick3dnodev9.cpp INCLUDEPATH += $$PWD diff --git a/src/quick3d/quick3d/items/quick3dnodev9.cpp b/src/quick3d/quick3d/items/quick3dnodev9.cpp new file mode 100644 index 000000000..d1a9011b5 --- /dev/null +++ b/src/quick3d/quick3d/items/quick3dnodev9.cpp @@ -0,0 +1,203 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "quick3dnodev9_p.h" +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DCore { +namespace Quick { + +Quick3DNodeV9::Quick3DNodeV9(QObject *parent) + : QObject(parent) +{ +} + +/*! + \qmlproperty QJSValue Qt3DCore::Node::propertyTrackingOverrides + \default {} + + Assuming a Qt3DCore::Node needs to override the PropertyTrackingMode on two + properties (enabled and displacement), the value should be set as shown + below. + + \badcode + propertyTrackingOverrides: { + "enabled": Entity.DontTrackValues, + "displacement": Entity.TrackFinalValues + } + \endcode + + \since 2.9 +*/ + +QJSValue Quick3DNodeV9::propertyTrackingOverrides() const +{ + return m_propertyTrackingOverrides; +} + +void Quick3DNodeV9::setPropertyTrackingOverrides(const QJSValue &value) +{ + m_propertyTrackingOverrides = value; + + QNode *parentNode = this->parentNode(); + parentNode->clearPropertyTrackings(); + + if (value.isObject()) { + QJSValueIterator it(value); + while (it.hasNext()) { + it.next(); + parentNode->setPropertyTracking(it.name(), static_cast(it.value().toInt())); + } + } + emit propertyTrackingOverridesChanged(value); +} + +/*! + \qmlproperty list Qt3DCore::Node::data + \default +*/ + +QQmlListProperty Quick3DNodeV9::data() +{ + return QQmlListProperty(this, 0, + Quick3DNodeV9::appendData, + Quick3DNodeV9::dataCount, + Quick3DNodeV9::dataAt, + Quick3DNodeV9::clearData); +} + +/*! + \qmlproperty list Qt3DCore::Node::childNodes + \readonly +*/ + +QQmlListProperty Quick3DNodeV9::childNodes() +{ + return QQmlListProperty(this, 0, + Quick3DNodeV9::appendChild, + Quick3DNodeV9::childCount, + Quick3DNodeV9::childAt, + Quick3DNodeV9::clearChildren); +} + +void Quick3DNodeV9::appendData(QQmlListProperty *list, QObject *obj) +{ + if (!obj) + return; + + Quick3DNodeV9 *self = static_cast(list->object); + self->childAppended(0, obj); +} + +QObject *Quick3DNodeV9::dataAt(QQmlListProperty *list, int index) +{ + Quick3DNodeV9 *self = static_cast(list->object); + return self->parentNode()->children().at(index); +} + +int Quick3DNodeV9::dataCount(QQmlListProperty *list) +{ + Quick3DNodeV9 *self = static_cast(list->object); + return self->parentNode()->children().count(); +} + +void Quick3DNodeV9::clearData(QQmlListProperty *list) +{ + Quick3DNodeV9 *self = static_cast(list->object); + for (QObject *const child : self->parentNode()->children()) + self->childRemoved(0, child); +} + +void Quick3DNodeV9::appendChild(QQmlListProperty *list, Qt3DCore::QNode *obj) +{ + if (!obj) + return; + + Quick3DNodeV9 *self = static_cast(list->object); + Q_ASSERT(!self->parentNode()->children().contains(obj)); + + self->childAppended(0, obj); +} + +Qt3DCore::QNode *Quick3DNodeV9::childAt(QQmlListProperty *list, int index) +{ + Quick3DNodeV9 *self = static_cast(list->object); + return qobject_cast(self->parentNode()->children().at(index)); +} + +int Quick3DNodeV9::childCount(QQmlListProperty *list) +{ + Quick3DNodeV9 *self = static_cast(list->object); + return self->parentNode()->children().count(); +} + +void Quick3DNodeV9::clearChildren(QQmlListProperty *list) +{ + Quick3DNodeV9 *self = static_cast(list->object); + for (QObject *const child : self->parentNode()->children()) + self->childRemoved(0, child); +} + +void Quick3DNodeV9::childAppended(int, QObject *obj) +{ + QNode *parentNode = this->parentNode(); + if (obj->parent() == parentNode) + obj->setParent(0); + // Set after otherwise addChild might not work + if (QNode *n = qobject_cast(obj)) + n->setParent(parentNode); + else + obj->setParent(parentNode); +} + +void Quick3DNodeV9::childRemoved(int, QObject *obj) +{ + if (QNode *n = qobject_cast(obj)) + n->setParent(Q_NODE_NULLPTR); + else + obj->setParent(nullptr); +} + + +} // namespace Quick +} // namespace Qt3DCore + +QT_END_NAMESPACE diff --git a/src/quick3d/quick3d/items/quick3dnodev9_p.h b/src/quick3d/quick3d/items/quick3dnodev9_p.h new file mode 100644 index 000000000..d969c4b64 --- /dev/null +++ b/src/quick3d/quick3d/items/quick3dnodev9_p.h @@ -0,0 +1,109 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3D_QUICK_QUICK3DNODEV9_P_H +#define QT3D_QUICK_QUICK3DNODEV9_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DCore { +namespace Quick { + +class QT3DQUICKSHARED_PRIVATE_EXPORT Quick3DNodeV9 : public QObject +{ + Q_OBJECT + Q_PROPERTY(QJSValue propertyTrackingOverrides READ propertyTrackingOverrides WRITE setPropertyTrackingOverrides NOTIFY propertyTrackingOverridesChanged) + Q_PROPERTY(QQmlListProperty data READ data) + Q_PROPERTY(QQmlListProperty childNodes READ childNodes) + Q_CLASSINFO("DefaultProperty", "data") + +public: + explicit Quick3DNodeV9(QObject *parent = nullptr); + + QJSValue propertyTrackingOverrides() const; + QQmlListProperty data(); + QQmlListProperty childNodes(); + + inline QNode *parentNode() const { return qobject_cast(parent()); } + +Q_SIGNALS: + void propertyTrackingOverridesChanged(const QJSValue &value); + +private Q_SLOTS: + void setPropertyTrackingOverrides(const QJSValue &value); + void childAppended(int idx, QObject *child); + void childRemoved(int idx, QObject *child); + +private: + static void appendData(QQmlListProperty *list, QObject *obj); + static QObject *dataAt(QQmlListProperty *list, int index); + static int dataCount(QQmlListProperty *list); + static void clearData(QQmlListProperty *list); + + static void appendChild(QQmlListProperty *list, Qt3DCore::QNode *obj); + static QNode *childAt(QQmlListProperty *list, int index); + static int childCount(QQmlListProperty *list); + static void clearChildren(QQmlListProperty *list); + + QJSValue m_propertyTrackingOverrides; +}; + +} // namespace Quick +} // namespace Qt3DCore + +QT_END_NAMESPACE + + +#endif // QT3D_QUICK_QUICK3DNODEV9_P_H diff --git a/tests/auto/core/nodes/tst_nodes.cpp b/tests/auto/core/nodes/tst_nodes.cpp index 90e0084e8..89d396931 100644 --- a/tests/auto/core/nodes/tst_nodes.cpp +++ b/tests/auto/core/nodes/tst_nodes.cpp @@ -250,7 +250,7 @@ public: void tst_Nodes::initTestCase() { - qRegisterMetaType("PropertyTrackMode"); + qRegisterMetaType("PropertyTrackingMode"); } void tst_Nodes::defaultNodeConstruction() @@ -969,8 +969,7 @@ void tst_Nodes::checkDefaultConstruction() // THEN QCOMPARE(node.parentNode(), nullptr); QCOMPARE(node.isEnabled(), true); - QCOMPARE(node.propertyTrackMode(), Qt3DCore::QNode::DefaultTrackMode); - QCOMPARE(node.trackedProperties(), QStringList()); + QCOMPARE(node.defaultPropertyTrackingMode(), Qt3DCore::QNode::TrackFinalValues); } void tst_Nodes::checkPropertyChanges() @@ -1019,41 +1018,37 @@ void tst_Nodes::checkPropertyChanges() } { // WHEN - QSignalSpy spy(&node, SIGNAL(propertyUpdateModeChanged(PropertyTrackMode))); - const Qt3DCore::QNode::PropertyTrackMode newValue = Qt3DCore::QNode::TrackAllPropertiesMode; - node.setPropertyTrackMode(newValue); + QSignalSpy spy(&node, SIGNAL(defaultPropertyTrackingModeChanged(PropertyTrackingMode))); + const Qt3DCore::QNode::PropertyTrackingMode newValue = Qt3DCore::QNode::TrackAllValues; + node.setDefaultPropertyTrackingMode(newValue); // THEN QVERIFY(spy.isValid()); - QCOMPARE(node.propertyTrackMode(), newValue); + QCOMPARE(node.defaultPropertyTrackingMode(), newValue); QCOMPARE(spy.count(), 1); // WHEN spy.clear(); - node.setPropertyTrackMode(newValue); + node.setDefaultPropertyTrackingMode(newValue); // THEN - QCOMPARE(node.propertyTrackMode(), newValue); + QCOMPARE(node.defaultPropertyTrackingMode(), newValue); QCOMPARE(spy.count(), 0); } { // WHEN - QSignalSpy spy(&node, SIGNAL(trackedPropertiesChanged(const QStringList &))); - const QStringList newValue = QStringList() << QStringLiteral("C1") << QStringLiteral("C2") << QStringLiteral("C3"); - node.setTrackedProperties(newValue); + const QString enabledPropertyName = QStringLiteral("enabled"); + node.setDefaultPropertyTrackingMode(Qt3DCore::QNode::DontTrackValues); + node.setPropertyTracking(enabledPropertyName, Qt3DCore::QNode::TrackAllValues); // THEN - QVERIFY(spy.isValid()); - QCOMPARE(node.trackedProperties(), newValue); - QCOMPARE(spy.count(), 1); + QCOMPARE(node.propertyTracking(enabledPropertyName), Qt3DCore::QNode::TrackAllValues); // WHEN - spy.clear(); - node.setTrackedProperties(newValue); + node.clearPropertyTracking(enabledPropertyName); // THEN - QCOMPARE(node.trackedProperties(), newValue); - QCOMPARE(spy.count(), 0); + QCOMPARE(node.propertyTracking(enabledPropertyName), Qt3DCore::QNode::DontTrackValues); } } @@ -1065,9 +1060,9 @@ void tst_Nodes::checkCreationData() node.setParent(&root); node.setEnabled(true); - node.setPropertyTrackMode(Qt3DCore::QNode::TrackNamedPropertiesMode); - const QStringList trackedPropertyNames = QStringList() << QStringLiteral("327"); - node.setTrackedProperties(trackedPropertyNames); + const QString enabledPropertyName = QStringLiteral("enabled"); + node.setDefaultPropertyTrackingMode(Qt3DCore::QNode::DontTrackValues); + node.setPropertyTracking(enabledPropertyName, Qt3DCore::QNode::TrackAllValues); // WHEN QVector creationChanges; @@ -1152,7 +1147,7 @@ void tst_Nodes::checkPropertyTrackModeUpdate() { // WHEN - node.setPropertyTrackMode(Qt3DCore::QNode::TrackAllPropertiesMode); + node.setDefaultPropertyTrackingMode(Qt3DCore::QNode::TrackAllValues); QCoreApplication::processEvents(); // THEN -> this properties is non notifying @@ -1161,7 +1156,7 @@ void tst_Nodes::checkPropertyTrackModeUpdate() { // WHEN - node.setPropertyTrackMode(Qt3DCore::QNode::TrackAllPropertiesMode); + node.setDefaultPropertyTrackingMode(Qt3DCore::QNode::TrackAllValues); QCoreApplication::processEvents(); // THEN @@ -1176,11 +1171,10 @@ void tst_Nodes::checkTrackedPropertyNamesUpdate() TestArbiter arbiter; Qt3DCore::QNode node; arbiter.setArbiterOnNode(&node); - const QStringList newValue = QStringList() << QStringLiteral("883") << QStringLiteral("454"); { // WHEN - node.setTrackedProperties(newValue); + node.setPropertyTracking(QStringLiteral("883"), Qt3DCore::QNode::TrackAllValues); QCoreApplication::processEvents(); // THEN -> this properties is non notifying @@ -1189,7 +1183,7 @@ void tst_Nodes::checkTrackedPropertyNamesUpdate() { // WHEN - node.setTrackedProperties(newValue); + node.setPropertyTracking(QStringLiteral("883"), Qt3DCore::QNode::DontTrackValues); QCoreApplication::processEvents(); // THEN diff --git a/tests/auto/core/qpostman/tst_qpostman.cpp b/tests/auto/core/qpostman/tst_qpostman.cpp index 1dabf143f..612db6257 100644 --- a/tests/auto/core/qpostman/tst_qpostman.cpp +++ b/tests/auto/core/qpostman/tst_qpostman.cpp @@ -174,7 +174,7 @@ private Q_SLOTS: { // WHEN - receiverNode->setPropertyTrackMode(QNode::TrackAllPropertiesMode); + receiverNode->setDefaultPropertyTrackingMode(QNode::TrackAllValues); auto updateChange = QPropertyUpdatedChangePtr::create(receiverNode->id()); updateChange->setValue(1584); @@ -189,8 +189,8 @@ private Q_SLOTS: { // GIVEN - receiverNode->setPropertyTrackMode(QNode::TrackNamedPropertiesMode); - receiverNode->setTrackedProperties(QStringList() << QStringLiteral("vette")); + receiverNode->setDefaultPropertyTrackingMode(QNode::DontTrackValues); + receiverNode->setPropertyTracking(QStringLiteral("vette"), Qt3DCore::QNode::TrackAllValues); { // WHEN @@ -220,8 +220,8 @@ private Q_SLOTS: { // GIVEN - receiverNode->setTrackedProperties(QStringList() << QStringLiteral("vette")); - receiverNode->setPropertyTrackMode(QNode::TrackAllPropertiesMode); + receiverNode->setPropertyTracking(QStringLiteral("vette"), Qt3DCore::QNode::TrackAllValues); + receiverNode->setDefaultPropertyTrackingMode(QNode::TrackAllValues); { // WHEN @@ -246,8 +246,8 @@ private Q_SLOTS: { // GIVEN - receiverNode->setTrackedProperties(QStringList()); - receiverNode->setPropertyTrackMode(QNode::DefaultTrackMode); + receiverNode->clearPropertyTrackings(); + receiverNode->setDefaultPropertyTrackingMode(QNode::TrackFinalValues); { // WHEN @@ -279,8 +279,8 @@ private Q_SLOTS: { // GIVEN - receiverNode->setTrackedProperties(QStringList()); - receiverNode->setPropertyTrackMode(QNode::DefaultTrackMode); + receiverNode->clearPropertyTrackings(); + receiverNode->setDefaultPropertyTrackingMode(QNode::TrackFinalValues); { // WHEN diff --git a/tests/auto/core/qscene/tst_qscene.cpp b/tests/auto/core/qscene/tst_qscene.cpp index 485143041..f4b04362d 100644 --- a/tests/auto/core/qscene/tst_qscene.cpp +++ b/tests/auto/core/qscene/tst_qscene.cpp @@ -487,36 +487,37 @@ void tst_QScene::setPropertyTrackData() // GIVEN Qt3DCore::QNodeId fakeNodeId = Qt3DCore::QNodeId::createId(); QScopedPointer scene(new Qt3DCore::QScene); - const QStringList propertyNamesList = QStringList() << QStringLiteral("1340"); + QHash overridenTrackedProperties; + overridenTrackedProperties.insert(QStringLiteral("1340"), Qt3DCore::QNode::TrackAllValues); // WHEN { Qt3DCore::QScene::NodePropertyTrackData trackData; - trackData.namedProperties = propertyNamesList; - trackData.updateMode = Qt3DCore::QNode::TrackNamedPropertiesMode; + trackData.trackedPropertiesOverrides = overridenTrackedProperties; + trackData.defaultTrackMode = Qt3DCore::QNode::DontTrackValues; scene->setPropertyTrackDataForNode(fakeNodeId, trackData); } // THEN { Qt3DCore::QScene::NodePropertyTrackData trackData = scene->lookupNodePropertyTrackData(fakeNodeId); - QCOMPARE(trackData.namedProperties, propertyNamesList); - QCOMPARE(trackData.updateMode, Qt3DCore::QNode::TrackNamedPropertiesMode); + QCOMPARE(trackData.trackedPropertiesOverrides, overridenTrackedProperties); + QCOMPARE(trackData.defaultTrackMode, Qt3DCore::QNode::DontTrackValues); } // WHEN { Qt3DCore::QScene::NodePropertyTrackData trackData; - trackData.namedProperties = propertyNamesList; - trackData.updateMode = Qt3DCore::QNode::DefaultTrackMode; + trackData.trackedPropertiesOverrides.clear(); + trackData.defaultTrackMode = Qt3DCore::QNode::TrackFinalValues; scene->setPropertyTrackDataForNode(fakeNodeId, trackData); } // THEN { Qt3DCore::QScene::NodePropertyTrackData trackData = scene->lookupNodePropertyTrackData(fakeNodeId); - QCOMPARE(trackData.namedProperties, propertyNamesList); - QCOMPARE(trackData.updateMode, Qt3DCore::QNode::DefaultTrackMode); + QCOMPARE(trackData.trackedPropertiesOverrides.size(), 0); + QCOMPARE(trackData.defaultTrackMode, Qt3DCore::QNode::TrackFinalValues); } } @@ -525,21 +526,20 @@ void tst_QScene::lookupNodePropertyTrackData() // GIVEN QScopedPointer scene(new Qt3DCore::QScene); Qt3DCore::QNodeId fakeNodeId = Qt3DCore::QNodeId::createId(); - const QStringList propertyNamesList = QStringList() << QStringLiteral("383"); // THEN -> default value for non existent id Qt3DCore::QScene::NodePropertyTrackData trackData = scene->lookupNodePropertyTrackData(fakeNodeId); - QCOMPARE(trackData.namedProperties, QStringList()); - QCOMPARE(trackData.updateMode, Qt3DCore::QNode::DefaultTrackMode); + QCOMPARE(trackData.trackedPropertiesOverrides.size(), 0); + QCOMPARE(trackData.defaultTrackMode, Qt3DCore::QNode::TrackFinalValues); // WHEN - trackData.namedProperties = propertyNamesList; - trackData.updateMode = Qt3DCore::QNode::TrackNamedPropertiesMode; + trackData.trackedPropertiesOverrides.insert(QStringLiteral("383"), Qt3DCore::QNode::TrackAllValues); + trackData.defaultTrackMode = Qt3DCore::QNode::DontTrackValues; scene->setPropertyTrackDataForNode(fakeNodeId, trackData); trackData = scene->lookupNodePropertyTrackData(fakeNodeId); - QCOMPARE(trackData.namedProperties, propertyNamesList); - QCOMPARE(trackData.updateMode, Qt3DCore::QNode::TrackNamedPropertiesMode); + QCOMPARE(trackData.trackedPropertiesOverrides.size(), 1); + QCOMPARE(trackData.defaultTrackMode, Qt3DCore::QNode::DontTrackValues); } void tst_QScene::removePropertyTrackData() @@ -550,15 +550,15 @@ void tst_QScene::removePropertyTrackData() // WHEN Qt3DCore::QScene::NodePropertyTrackData trackData; - trackData.namedProperties = QStringList() << QStringLiteral("1584"); - trackData.updateMode = Qt3DCore::QNode::TrackNamedPropertiesMode; + trackData.trackedPropertiesOverrides.insert(QStringLiteral("1584"), Qt3DCore::QNode::TrackAllValues); + trackData.defaultTrackMode = Qt3DCore::QNode::DontTrackValues; scene->setPropertyTrackDataForNode(fakeNodeId, trackData); scene->removePropertyTrackDataForNode(fakeNodeId); // THEN -> default value for non existent id trackData = scene->lookupNodePropertyTrackData(fakeNodeId); - QCOMPARE(trackData.namedProperties, QStringList()); - QCOMPARE(trackData.updateMode, Qt3DCore::QNode::DefaultTrackMode); + QCOMPARE(trackData.trackedPropertiesOverrides.size(), 0); + QCOMPARE(trackData.defaultTrackMode, Qt3DCore::QNode::TrackFinalValues); } void tst_QScene::nodeSetAndUnsetPropertyTrackData() @@ -569,9 +569,8 @@ void tst_QScene::nodeSetAndUnsetPropertyTrackData() Qt3DCore::QNodePrivate::get(&parentNode)->setScene(scene.data()); Qt3DCore::QNode *childNode = new Qt3DCore::QNode(); - const QStringList propertyNamesList = QStringList() << QStringLiteral("883"); - childNode->setTrackedProperties(propertyNamesList); - childNode->setPropertyTrackMode(Qt3DCore::QNode::TrackNamedPropertiesMode); + childNode->setPropertyTracking(QStringLiteral("883"), Qt3DCore::QNode::TrackAllValues); + childNode->setDefaultPropertyTrackingMode(Qt3DCore::QNode::DontTrackValues); // WHEN childNode->setParent(&parentNode); @@ -580,8 +579,9 @@ void tst_QScene::nodeSetAndUnsetPropertyTrackData() // THEN QCOMPARE(Qt3DCore::QNodePrivate::get(childNode)->m_scene, scene.data()); Qt3DCore::QScene::NodePropertyTrackData trackData = scene->lookupNodePropertyTrackData(childNode->id()); - QCOMPARE(trackData.updateMode, Qt3DCore::QNode::TrackNamedPropertiesMode); - QCOMPARE(trackData.namedProperties, propertyNamesList); + QCOMPARE(trackData.defaultTrackMode, Qt3DCore::QNode::DontTrackValues); + QCOMPARE(trackData.trackedPropertiesOverrides.size(), 1); + QCOMPARE(trackData.trackedPropertiesOverrides[QStringLiteral("883")], Qt3DCore::QNode::TrackAllValues); // WHEN const Qt3DCore::QNodeId childNodeId = childNode->id(); @@ -590,8 +590,8 @@ void tst_QScene::nodeSetAndUnsetPropertyTrackData() // THEN -> default value for non existent id trackData = scene->lookupNodePropertyTrackData(childNodeId); - QCOMPARE(trackData.namedProperties, QStringList()); - QCOMPARE(trackData.updateMode, Qt3DCore::QNode::DefaultTrackMode); + QCOMPARE(trackData.trackedPropertiesOverrides.size(), 0); + QCOMPARE(trackData.defaultTrackMode, Qt3DCore::QNode::TrackFinalValues); } void tst_QScene::nodeUpdatePropertyTrackData() @@ -602,9 +602,9 @@ void tst_QScene::nodeUpdatePropertyTrackData() Qt3DCore::QNodePrivate::get(&parentNode)->setScene(scene.data()); Qt3DCore::QNode *childNode = new Qt3DCore::QNode(); - const QStringList propertyNamesList = QStringList() << QStringLiteral("883"); - childNode->setTrackedProperties(propertyNamesList); - childNode->setPropertyTrackMode(Qt3DCore::QNode::TrackNamedPropertiesMode); + const QString propertyName = QStringLiteral("883"); + childNode->setPropertyTracking(propertyName, Qt3DCore::QNode::TrackFinalValues); + childNode->setDefaultPropertyTrackingMode(Qt3DCore::QNode::DontTrackValues); // WHEN childNode->setParent(&parentNode); @@ -613,23 +613,26 @@ void tst_QScene::nodeUpdatePropertyTrackData() // THEN QCOMPARE(Qt3DCore::QNodePrivate::get(childNode)->m_scene, scene.data()); Qt3DCore::QScene::NodePropertyTrackData trackData = scene->lookupNodePropertyTrackData(childNode->id()); - QCOMPARE(trackData.updateMode, Qt3DCore::QNode::TrackNamedPropertiesMode); - QCOMPARE(trackData.namedProperties, propertyNamesList); + QCOMPARE(trackData.defaultTrackMode, Qt3DCore::QNode::DontTrackValues); + QCOMPARE(trackData.trackedPropertiesOverrides.size(), 1); + QCOMPARE(trackData.trackedPropertiesOverrides[propertyName], Qt3DCore::QNode::TrackFinalValues); // WHEN - childNode->setPropertyTrackMode(Qt3DCore::QNode::TrackAllPropertiesMode); + childNode->setDefaultPropertyTrackingMode(Qt3DCore::QNode::TrackAllValues); // THEN trackData = scene->lookupNodePropertyTrackData(childNode->id()); - QCOMPARE(trackData.updateMode, Qt3DCore::QNode::TrackAllPropertiesMode); + QCOMPARE(trackData.defaultTrackMode, Qt3DCore::QNode::TrackAllValues); // WHEN - const QStringList propertyNamesList2 = QStringList() << QStringLiteral("Viper"); - childNode->setTrackedProperties(propertyNamesList2); + const QString propertyName2 = QStringLiteral("Viper"); + childNode->setPropertyTracking(propertyName2, Qt3DCore::QNode::DontTrackValues); // THEN trackData = scene->lookupNodePropertyTrackData(childNode->id()); - QCOMPARE(trackData.namedProperties, propertyNamesList2); + QCOMPARE(trackData.trackedPropertiesOverrides.size(), 2); + QCOMPARE(trackData.trackedPropertiesOverrides[propertyName], Qt3DCore::QNode::TrackFinalValues); + QCOMPARE(trackData.trackedPropertiesOverrides[propertyName2], Qt3DCore::QNode::DontTrackValues); } QTEST_MAIN(tst_QScene) diff --git a/tests/auto/quick3d/3dcore/3dcore.qml b/tests/auto/quick3d/3dcore/3dcore.qml index 1d9d885ff..df9dd429b 100644 --- a/tests/auto/quick3d/3dcore/3dcore.qml +++ b/tests/auto/quick3d/3dcore/3dcore.qml @@ -28,6 +28,7 @@ import Qt3D.Core 2.0 as QQ3Core20 +import Qt3D.Core 2.9 as QQ3Core29 import QtQuick 2.0 Item { @@ -40,4 +41,5 @@ Item { QQ3Core20.Transform {} //Qt3DCore::QTransform QQ3Core20.QuaternionAnimation {} //Qt3DCore::Quick::QQuaternionAnimation + QQ3Core29.Entity {} //Qt3DCore::QEntity, Qt3DCore::Quick::Quick3DEntity } diff --git a/tests/auto/quick3d/quick3d.pro b/tests/auto/quick3d/quick3d.pro index 8abe04550..dd67a3ef4 100644 --- a/tests/auto/quick3d/quick3d.pro +++ b/tests/auto/quick3d/quick3d.pro @@ -7,5 +7,6 @@ qtConfig(private_tests) { 3drender \ 3dinput \ 3dcore \ - quick3dbuffer + quick3dbuffer \ + quick3dnode } diff --git a/tests/auto/quick3d/quick3dnode/quick3dnode.pro b/tests/auto/quick3d/quick3dnode/quick3dnode.pro new file mode 100644 index 000000000..5b3038c42 --- /dev/null +++ b/tests/auto/quick3d/quick3dnode/quick3dnode.pro @@ -0,0 +1,13 @@ +TEMPLATE = app + +TARGET = tst_quick3dnode + +QT += 3dcore 3dcore-private 3drender 3drender-private 3dquick 3dquick-private 3dquickrender-private testlib + +CONFIG += testcase + +include(../../render/qmlscenereader/qmlscenereader.pri) + +SOURCES += tst_quick3dnode.cpp + +RESOURCES += quick3dnode.qrc diff --git a/tests/auto/quick3d/quick3dnode/quick3dnode.qrc b/tests/auto/quick3d/quick3dnode/quick3dnode.qrc new file mode 100644 index 000000000..afdbbbb66 --- /dev/null +++ b/tests/auto/quick3d/quick3dnode/quick3dnode.qrc @@ -0,0 +1,5 @@ + + + quick3dnodev9.qml + + diff --git a/tests/auto/quick3d/quick3dnode/quick3dnodev9.qml b/tests/auto/quick3d/quick3dnode/quick3dnodev9.qml new file mode 100644 index 000000000..5429faf4e --- /dev/null +++ b/tests/auto/quick3d/quick3dnode/quick3dnodev9.qml @@ -0,0 +1,36 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Paul Lemire +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $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$ +** +****************************************************************************/ + +import Qt3D.Core 2.9 + +Entity { + propertyTrackingOverrides: { + "enabled": Entity.DontTrackValues, + "displacement": Entity.TrackFinalValues + } +} diff --git a/tests/auto/quick3d/quick3dnode/tst_quick3dnode.cpp b/tests/auto/quick3d/quick3dnode/tst_quick3dnode.cpp new file mode 100644 index 000000000..38bf46a7a --- /dev/null +++ b/tests/auto/quick3d/quick3dnode/tst_quick3dnode.cpp @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $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 +#include +#include +#include + +class tst_Quick3DNode : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + + void checkPropertyTrackingOverrides_V9() + { + // GIVEN + QmlSceneReader sceneReader(QUrl("qrc:/quick3dnodev9.qml")); + + // THEN + QVERIFY(sceneReader.root() != nullptr); + Qt3DCore::QNode *node = static_cast(sceneReader.root()); + QCOMPARE(node->propertyTracking(QLatin1String("enabled")), Qt3DCore::QNode::DontTrackValues); + QCOMPARE(node->propertyTracking(QLatin1String("displacement")), Qt3DCore::QNode::TrackFinalValues); + } +}; + +QTEST_MAIN(tst_Quick3DNode) + +#include "tst_quick3dnode.moc" diff --git a/tests/auto/render/updateshaderdatatransformjob/test_scene_model_to_eye.qml b/tests/auto/render/updateshaderdatatransformjob/test_scene_model_to_eye.qml index 20585b5de..3b21b08ba 100644 --- a/tests/auto/render/updateshaderdatatransformjob/test_scene_model_to_eye.qml +++ b/tests/auto/render/updateshaderdatatransformjob/test_scene_model_to_eye.qml @@ -48,9 +48,9 @@ ** ****************************************************************************/ -import Qt3D.Core 2.0 -import Qt3D.Render 2.0 -import Qt3D.Extras 2.0 +import Qt3D.Core 2.9 +import Qt3D.Render 2.9 +import Qt3D.Extras 2.9 import QtQuick.Window 2.0 Entity { diff --git a/tests/auto/render/updateshaderdatatransformjob/test_scene_model_to_world.qml b/tests/auto/render/updateshaderdatatransformjob/test_scene_model_to_world.qml index d3e766021..59ccdd27f 100644 --- a/tests/auto/render/updateshaderdatatransformjob/test_scene_model_to_world.qml +++ b/tests/auto/render/updateshaderdatatransformjob/test_scene_model_to_world.qml @@ -48,9 +48,9 @@ ** ****************************************************************************/ -import Qt3D.Core 2.0 -import Qt3D.Render 2.0 -import Qt3D.Extras 2.0 +import Qt3D.Core 2.9 +import Qt3D.Render 2.9 +import Qt3D.Extras 2.9 import QtQuick.Window 2.0 Entity { diff --git a/tests/auto/render/updateshaderdatatransformjob/tst_updateshaderdatatransformjob.cpp b/tests/auto/render/updateshaderdatatransformjob/tst_updateshaderdatatransformjob.cpp index 9b53d1f65..c076aa21e 100644 --- a/tests/auto/render/updateshaderdatatransformjob/tst_updateshaderdatatransformjob.cpp +++ b/tests/auto/render/updateshaderdatatransformjob/tst_updateshaderdatatransformjob.cpp @@ -165,7 +165,7 @@ private Q_SLOTS: Qt3DRender::Render::ShaderData *backendShaderData = collection.backendShaderData.first(); // THEN - QCOMPARE(backendShaderData->properties().size(), 2); + QCOMPARE(backendShaderData->properties().size(), 3); QVERIFY(backendShaderData->properties().contains(QLatin1String("eyePosition"))); QVERIFY(backendShaderData->properties().contains(QLatin1String("eyePositionTransformed"))); @@ -205,7 +205,7 @@ private Q_SLOTS: Qt3DRender::Render::ShaderData *backendShaderData = collection.backendShaderData.first(); // THEN - QCOMPARE(backendShaderData->properties().size(), 2); + QCOMPARE(backendShaderData->properties().size(), 3); QVERIFY(backendShaderData->properties().contains(QLatin1String("position"))); QVERIFY(backendShaderData->properties().contains(QLatin1String("positionTransformed"))); -- cgit v1.2.3 From ddc878f2fc978a3b740b7ccf9258c824c6ba959a Mon Sep 17 00:00:00 2001 From: Paul Lemire Date: Thu, 16 Feb 2017 18:43:53 +0000 Subject: QBoundingSphere cleanup Is now a Q_GADGET value type Added QBoundingSphere creator functions on QLevelOfDetails and Quick3DLevelOfDetailsLoader Note: cannot be a nested type on QLevelOfDetails as moc doesn't support it Task-number: QTBUG-58892 Change-Id: Ic7b6d68c6e1119c1f61a858f49379efc1e9c2104 Reviewed-by: Sean Harmer --- .../imports/render/qt3dquick3drenderplugin.cpp | 4 +- .../items/quick3dlevelofdetailloader.cpp | 11 +- .../items/quick3dlevelofdetailloader_p.h | 10 +- src/render/backend/levelofdetail.cpp | 25 ++-- src/render/backend/levelofdetail_p.h | 8 +- src/render/frontend/qboundingsphere.cpp | 148 ------------------- src/render/frontend/qboundingsphere.h | 82 ----------- src/render/frontend/qboundingsphere_p.h | 76 ---------- src/render/frontend/qlevelofdetail.cpp | 46 ++---- src/render/frontend/qlevelofdetail.h | 16 ++- src/render/frontend/qlevelofdetail_p.h | 6 +- .../frontend/qlevelofdetailboundingsphere.cpp | 159 +++++++++++++++++++++ src/render/frontend/qlevelofdetailboundingsphere.h | 81 +++++++++++ src/render/frontend/render-frontend.pri | 9 +- src/render/jobs/updatelevelofdetailjob.cpp | 4 +- .../render/levelofdetail/tst_levelofdetail.cpp | 11 +- tests/manual/lod/main.qml | 7 +- 17 files changed, 310 insertions(+), 393 deletions(-) delete mode 100644 src/render/frontend/qboundingsphere.cpp delete mode 100644 src/render/frontend/qboundingsphere.h delete mode 100644 src/render/frontend/qboundingsphere_p.h create mode 100644 src/render/frontend/qlevelofdetailboundingsphere.cpp create mode 100644 src/render/frontend/qlevelofdetailboundingsphere.h diff --git a/src/quick3d/imports/render/qt3dquick3drenderplugin.cpp b/src/quick3d/imports/render/qt3dquick3drenderplugin.cpp index 6bc9b213a..51214c8df 100644 --- a/src/quick3d/imports/render/qt3dquick3drenderplugin.cpp +++ b/src/quick3d/imports/render/qt3dquick3drenderplugin.cpp @@ -57,7 +57,7 @@ #include #include #include -#include +#include #include #include #include @@ -207,7 +207,7 @@ void Qt3DQuick3DRenderPlugin::registerTypes(const char *uri) qmlRegisterType(uri, 2, 0, "GeometryRenderer"); qmlRegisterType(uri, 2, 9, "LevelOfDetail"); qmlRegisterType(uri, 2, 9, "LevelOfDetailSwitch"); - qmlRegisterType(uri, 2, 9, "BoundingSphere"); + qRegisterMetaType("LevelOfDetailBoundingSphere"); // Mesh qmlRegisterType(uri, 2, 0, "Mesh"); diff --git a/src/quick3d/quick3dextras/items/quick3dlevelofdetailloader.cpp b/src/quick3d/quick3dextras/items/quick3dlevelofdetailloader.cpp index f3d3f4323..087342063 100644 --- a/src/quick3d/quick3dextras/items/quick3dlevelofdetailloader.cpp +++ b/src/quick3d/quick3dextras/items/quick3dlevelofdetailloader.cpp @@ -38,7 +38,7 @@ ****************************************************************************/ #include "quick3dlevelofdetailloader_p_p.h" -#include +#include #include #include @@ -156,13 +156,18 @@ void Quick3DLevelOfDetailLoader::setThresholds(const QVector &thresholds) d->m_lod->setThresholds(thresholds); } -Qt3DRender::QBoundingSphere *Quick3DLevelOfDetailLoader::volumeOverride() const +Qt3DRender::QLevelOfDetailBoundingSphere Quick3DLevelOfDetailLoader::createBoundingSphere(const QVector3D ¢er, float radius) +{ + return Qt3DRender::QLevelOfDetailBoundingSphere(center, radius); +} + +Qt3DRender::QLevelOfDetailBoundingSphere Quick3DLevelOfDetailLoader::volumeOverride() const { Q_D(const Quick3DLevelOfDetailLoader); return d->m_lod->volumeOverride(); } -void Quick3DLevelOfDetailLoader::setVolumeOverride(Qt3DRender::QBoundingSphere *volumeOverride) +void Quick3DLevelOfDetailLoader::setVolumeOverride(const Qt3DRender::QLevelOfDetailBoundingSphere &volumeOverride) { Q_D(Quick3DLevelOfDetailLoader); d->m_lod->setVolumeOverride(volumeOverride); diff --git a/src/quick3d/quick3dextras/items/quick3dlevelofdetailloader_p.h b/src/quick3d/quick3dextras/items/quick3dlevelofdetailloader_p.h index 1ef359fe7..445e7bca6 100644 --- a/src/quick3d/quick3dextras/items/quick3dlevelofdetailloader_p.h +++ b/src/quick3d/quick3dextras/items/quick3dlevelofdetailloader_p.h @@ -72,7 +72,7 @@ class QT3DQUICKEXTRASSHARED_PRIVATE_EXPORT Quick3DLevelOfDetailLoader : public Q Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged) Q_PROPERTY(Qt3DRender::QLevelOfDetail::ThresholdType thresholdType READ thresholdType WRITE setThresholdType NOTIFY thresholdTypeChanged) Q_PROPERTY(QVector thresholds READ thresholds WRITE setThresholds NOTIFY thresholdsChanged) - Q_PROPERTY(Qt3DRender::QBoundingSphere *volumeOverride READ volumeOverride WRITE setVolumeOverride NOTIFY volumeOverrideChanged) + Q_PROPERTY(Qt3DRender::QLevelOfDetailBoundingSphere volumeOverride READ volumeOverride WRITE setVolumeOverride NOTIFY volumeOverrideChanged) Q_PROPERTY(QObject *entity READ entity NOTIFY entityChanged) Q_PROPERTY(QUrl source READ source NOTIFY sourceChanged) @@ -90,13 +90,15 @@ public: void setThresholdType(Qt3DRender::QLevelOfDetail::ThresholdType thresholdType); QVector thresholds() const; void setThresholds(const QVector &thresholds); - Qt3DRender::QBoundingSphere *volumeOverride() const; - void setVolumeOverride(Qt3DRender::QBoundingSphere *volumeOverride); + Qt3DRender::QLevelOfDetailBoundingSphere volumeOverride() const; + void setVolumeOverride(const Qt3DRender::QLevelOfDetailBoundingSphere &volumeOverride); + + Q_INVOKABLE Qt3DRender::QLevelOfDetailBoundingSphere createBoundingSphere(const QVector3D ¢er, float radius); QObject *entity() const; QUrl source() const; -signals: +Q_SIGNALS: void sourcesChanged(); void cameraChanged(); void currentIndexChanged(); diff --git a/src/render/backend/levelofdetail.cpp b/src/render/backend/levelofdetail.cpp index 9ff0ef532..d7806fc4d 100644 --- a/src/render/backend/levelofdetail.cpp +++ b/src/render/backend/levelofdetail.cpp @@ -39,7 +39,6 @@ #include "levelofdetail_p.h" #include -#include #include #include #include @@ -56,7 +55,7 @@ LevelOfDetail::LevelOfDetail() : BackendNode(BackendNode::ReadWrite) , m_currentIndex(0) , m_thresholdType(QLevelOfDetail::DistanceToCamera) - , m_radius(1.f) + , m_volumeOverride() { } @@ -73,8 +72,7 @@ void LevelOfDetail::initializeFromPeer(const QNodeCreatedChangeBasePtr &change) m_currentIndex = data.currentIndex; m_thresholdType = data.thresholdType; m_thresholds = data.thresholds; - m_radius = data.radius; - m_center = data.center; + m_volumeOverride = data.volumeOverride; } void LevelOfDetail::cleanup() @@ -86,23 +84,16 @@ void LevelOfDetail::sceneChangeEvent(const QSceneChangePtr &e) { if (e->type() == PropertyUpdated) { const QPropertyUpdatedChangePtr &propertyChange = qSharedPointerCast(e); - if (propertyChange->propertyName() == QByteArrayLiteral("currentIndex")) { + if (propertyChange->propertyName() == QByteArrayLiteral("currentIndex")) m_currentIndex = propertyChange->value().value(); - } else if (propertyChange->propertyName() == QByteArrayLiteral("camera")) { + else if (propertyChange->propertyName() == QByteArrayLiteral("camera")) m_camera = propertyChange->value().value(); - } else if (propertyChange->propertyName() == QByteArrayLiteral("thresholdType")) { + else if (propertyChange->propertyName() == QByteArrayLiteral("thresholdType")) m_thresholdType = propertyChange->value().value(); - } else if (propertyChange->propertyName() == QByteArrayLiteral("thresholds")) { + else if (propertyChange->propertyName() == QByteArrayLiteral("thresholds")) m_thresholds = propertyChange->value().value>(); - } else if (propertyChange->propertyName() == QByteArrayLiteral("center")) { - m_center = propertyChange->value().value(); - } else if (propertyChange->propertyName() == QByteArrayLiteral("radius")) { - m_radius = propertyChange->value().value(); - } else if (propertyChange->propertyName() == QByteArrayLiteral("volumeOverride")) { - auto volumeOverride = propertyChange->value().value(); - m_center = volumeOverride ? volumeOverride->center() : QVector3D(); - m_radius = volumeOverride ? volumeOverride->radius() : -1.f; - } + else if (propertyChange->propertyName() == QByteArrayLiteral("volumeOverride")) + m_volumeOverride = propertyChange->value().value(); } markDirty(AbstractRenderer::GeometryDirty); diff --git a/src/render/backend/levelofdetail_p.h b/src/render/backend/levelofdetail_p.h index 83809a631..05f5686bb 100644 --- a/src/render/backend/levelofdetail_p.h +++ b/src/render/backend/levelofdetail_p.h @@ -79,8 +79,9 @@ public: int currentIndex() const { return m_currentIndex; } QLevelOfDetail::ThresholdType thresholdType() const { return m_thresholdType; } QVector thresholds() const { return m_thresholds; } - float radius() const { return m_radius; } - QVector3D center() const { return m_center; } + float radius() const { return m_volumeOverride.radius(); } + QVector3D center() const { return m_volumeOverride.center(); } + bool hasBoundingVolumeOverride() const { return !m_volumeOverride.isEmpty(); } void setCurrentIndex(int currentIndex); @@ -90,8 +91,7 @@ private: int m_currentIndex; QLevelOfDetail::ThresholdType m_thresholdType; QVector m_thresholds; - float m_radius; - QVector3D m_center; + QLevelOfDetailBoundingSphere m_volumeOverride; }; } // namespace Render diff --git a/src/render/frontend/qboundingsphere.cpp b/src/render/frontend/qboundingsphere.cpp deleted file mode 100644 index 4d8b1aba8..000000000 --- a/src/render/frontend/qboundingsphere.cpp +++ /dev/null @@ -1,148 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt3D module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** 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-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qboundingsphere.h" -#include "qboundingsphere_p.h" - -QT_BEGIN_NAMESPACE - -namespace Qt3DRender { - -QBoundingSpherePrivate::QBoundingSpherePrivate() - : QObjectPrivate() - , m_radius(1.f) -{ - -} - -/*! - \class Qt3DRender::QBoundingSphere - \inmodule Qt3DRender - \since 5.9 - \brief The QBoundingSphere class provides a simple spherical volume, defined by it's center and radius. -*/ - -/*! - \qmltype LevelOfDetail - \instantiates Qt3DRender::QLevelOfDetail - \inherits Component3D - \inqmlmodule Qt3D.Render - \brief The BoundingSphere class provides a simple spherical volume, defined by it's center and radius. -*/ - -/*! - * \qmlproperty QVector3D BoundingSphere::center - * - * Specifies the center of the bounding sphere - */ - -/*! - * \property QBoundingSphere::center - * - * Specifies the center of the bounding sphere - */ - -/*! - * \qmlproperty qreal BoundingSphere::radius - * - * Specifies the radius of the bounding sphere - */ - -/*! - * \property QBoundingSphere::radius - * - * Specifies the radius of the bounding sphere - */ - -/*! \fn Qt3DRender::QBoundingSphere::QBoundingSphere(QObject *parent) - Constructs a new QBoundingSphere with the specified \a parent. - */ -QBoundingSphere::QBoundingSphere(QObject *parent) - : QObject(*new QBoundingSpherePrivate, parent) -{ - -} - -QBoundingSphere::QBoundingSphere(const QVector3D ¢er, float radius, QObject *parent) - : QBoundingSphere(parent) -{ - Q_D(QBoundingSphere); - d->m_center = center; - d->m_radius = radius; -} - -QVector3D QBoundingSphere::center() const -{ - Q_D(const QBoundingSphere); - return d->m_center; -} - -float QBoundingSphere::radius() const -{ - Q_D(const QBoundingSphere); - return d->m_radius; -} - -/*! - * Sets the radius of the bounding sphere. - */ -void QBoundingSphere::setRadius(float radius) -{ - Q_D(QBoundingSphere); - if (d->m_radius != radius) { - d->m_radius = radius; - emit radiusChanged(radius); - } -} - -/*! - * Sets the center of the bounding sphere. - */ -void QBoundingSphere::setCenter(const QVector3D ¢er) -{ - Q_D(QBoundingSphere); - if (d->m_center != center) { - d->m_center = center; - emit centerChanged(center); - } -} - -} // namespace Qt3DRender - -QT_END_NAMESPACE diff --git a/src/render/frontend/qboundingsphere.h b/src/render/frontend/qboundingsphere.h deleted file mode 100644 index e7f9b7784..000000000 --- a/src/render/frontend/qboundingsphere.h +++ /dev/null @@ -1,82 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt3D module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** 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-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QT3DRENDER_QBOUNDINGSPHERE_H -#define QT3DRENDER_QBOUNDINGSPHERE_H - -#include -#include - -#include - -QT_BEGIN_NAMESPACE - -namespace Qt3DRender { - -class QBoundingSpherePrivate; - -class QT3DRENDERSHARED_EXPORT QBoundingSphere : public QObject -{ - Q_OBJECT - Q_PROPERTY(QVector3D center READ center WRITE setCenter NOTIFY centerChanged) - Q_PROPERTY(float radius READ radius WRITE setRadius NOTIFY radiusChanged) -public: - explicit QBoundingSphere(QObject *parent = nullptr); - QBoundingSphere(const QVector3D ¢er, float radius, QObject *parent = nullptr); - - QVector3D center() const; - float radius() const; - -public Q_SLOTS: - void setRadius(float radius); - void setCenter(const QVector3D ¢er); - -Q_SIGNALS: - void radiusChanged(float radius); - void centerChanged(const QVector3D ¢er); - -private: - Q_DECLARE_PRIVATE(QBoundingSphere) -}; - -} // namespace Qt3DRender - -QT_END_NAMESPACE - -#endif // QT3DRENDER_QBOUNDINGSPHERE_H diff --git a/src/render/frontend/qboundingsphere_p.h b/src/render/frontend/qboundingsphere_p.h deleted file mode 100644 index 171e4440f..000000000 --- a/src/render/frontend/qboundingsphere_p.h +++ /dev/null @@ -1,76 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt3D module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** 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-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QT3DRENDER_QBOUNDINGSPHERE_P_H -#define QT3DRENDER_QBOUNDINGSPHERE_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of other Qt classes. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include -#include - -QT_BEGIN_NAMESPACE - -namespace Qt3DRender { - -class QT3DRENDERSHARED_EXPORT QBoundingSpherePrivate : public QObjectPrivate -{ -public: - QBoundingSpherePrivate(); - - Q_DECLARE_PUBLIC(QBoundingSphere) - - QVector3D m_center; - float m_radius; -}; - -} // namespace Qt3DRender - -QT_END_NAMESPACE - -#endif // QT3DRENDER_QBOUNDINGSPHERE_P_H diff --git a/src/render/frontend/qlevelofdetail.cpp b/src/render/frontend/qlevelofdetail.cpp index 0d70803ca..b62bf2277 100644 --- a/src/render/frontend/qlevelofdetail.cpp +++ b/src/render/frontend/qlevelofdetail.cpp @@ -37,7 +37,6 @@ ** ****************************************************************************/ -#include "qboundingsphere.h" #include "qlevelofdetail.h" #include "qlevelofdetail_p.h" #include "qcamera.h" @@ -52,22 +51,9 @@ QLevelOfDetailPrivate::QLevelOfDetailPrivate() , m_camera(nullptr) , m_currentIndex(0) , m_thresholdType(QLevelOfDetail::DistanceToCamera) - , m_volumeOverride(nullptr) + , m_volumeOverride() { Q_Q(QLevelOfDetail); - m_volumeOverride = new QBoundingSphere(q); - QObject::connect(m_volumeOverride, SIGNAL(radiusChanged(float)), q, SLOT(_q_radiusChanged(float))); - QObject::connect(m_volumeOverride, SIGNAL(centerChanged(const QVector3D &)), q, SLOT(_q_centerChanged(const QVector3D&))); -} - -void QLevelOfDetailPrivate::_q_radiusChanged(float radius) -{ - notifyPropertyChange("radius", radius); -} - -void QLevelOfDetailPrivate::_q_centerChanged(const QVector3D ¢er) -{ - notifyPropertyChange("center", center); } /*! @@ -207,9 +193,9 @@ void QLevelOfDetailPrivate::_q_centerChanged(const QVector3D ¢er) * Specifies what is used as a proxy for the entity when computing distance * or size. * - * \value BoundingSphere use the bounding sphere specified by the center + * \value LevelOfDetailBoundingSphere use the bounding sphere specified by the center * and radius properties. - * \value ChildrenBoundingSphere use the bounding sphere of the entity the + * \value Children LevelOfDetailBoundingSphere use the bounding sphere of the entity the * component is attached to. */ @@ -220,9 +206,9 @@ void QLevelOfDetailPrivate::_q_centerChanged(const QVector3D ¢er) * or size. * * \list - * \li BoundingSphere use the bounding sphere specified by the center + * \li LevelOfDetailBoundingSphere use the bounding sphere specified by the center * and radius properties. - * \li ChildrenBoundingSphere use the bounding sphere of the entity the + * \li Children LevelOfDetailBoundingSphere use the bounding sphere of the entity the * component is attached to. * \endlist * \sa Qt3DRender::QLevelOfDetail::SizeProxyMode @@ -306,7 +292,7 @@ void QLevelOfDetailPrivate::_q_centerChanged(const QVector3D ¢er) * If this value to null, the bounding volume of the entity is used. Care must be * taken that this bounding volume never becomes invalid. * - * \sa BoundingSphere + * \sa LevelOfDetailBoundingSphere */ /*! @@ -319,7 +305,7 @@ void QLevelOfDetailPrivate::_q_centerChanged(const QVector3D ¢er) * If this value to nullptr, the bounding volume of the entity is used. Care must be * taken that this bounding volume never becomes invalid. * - * \sa QBoundingSphere + * \sa LevelOfDetailBoundingSphere */ @@ -354,8 +340,7 @@ Qt3DCore::QNodeCreatedChangeBasePtr QLevelOfDetail::createNodeCreationChange() c data.currentIndex = d->m_currentIndex; data.thresholdType = d->m_thresholdType; data.thresholds = d->m_thresholds; - data.radius = d->m_volumeOverride ? d->m_volumeOverride->radius() : -1.f; - data.center = d->m_volumeOverride ? d->m_volumeOverride->center() : QVector3D(); + data.volumeOverride = d->m_volumeOverride; return creationChange; } @@ -441,6 +426,11 @@ QVector QLevelOfDetail::thresholds() const return d->m_thresholds; } +QLevelOfDetailBoundingSphere QLevelOfDetail::createBoundingSphere(const QVector3D ¢er, float radius) +{ + return QLevelOfDetailBoundingSphere(center, radius); +} + /*! * Sets the range values. * \sa Qt3DRender::QLevelOfDetail::thresholdType @@ -454,23 +444,17 @@ void QLevelOfDetail::setThresholds(QVector thresholds) } } -QBoundingSphere *QLevelOfDetail::volumeOverride() const +QLevelOfDetailBoundingSphere QLevelOfDetail::volumeOverride() const { Q_D(const QLevelOfDetail); return d->m_volumeOverride; } -void QLevelOfDetail::setVolumeOverride(QBoundingSphere *volumeOverride) +void QLevelOfDetail::setVolumeOverride(const QLevelOfDetailBoundingSphere &volumeOverride) { Q_D(QLevelOfDetail); if (d->m_volumeOverride != volumeOverride) { - if (d->m_volumeOverride) - disconnect(d->m_volumeOverride); d->m_volumeOverride = volumeOverride; - if (d->m_volumeOverride) { - connect(d->m_volumeOverride, SIGNAL(radiusChanged(float)), this, SLOT(_q_radiusChanged(float))); - connect(d->m_volumeOverride, SIGNAL(centerChanged(const QVector3D &)), this, SLOT(_q_centerChanged(const QVector3D&))); - } emit volumeOverrideChanged(volumeOverride); } } diff --git a/src/render/frontend/qlevelofdetail.h b/src/render/frontend/qlevelofdetail.h index f3325aea0..c0d56c9cd 100644 --- a/src/render/frontend/qlevelofdetail.h +++ b/src/render/frontend/qlevelofdetail.h @@ -42,6 +42,7 @@ #include #include +#include #include @@ -50,7 +51,6 @@ QT_BEGIN_NAMESPACE namespace Qt3DRender { class QCamera; -class QBoundingSphere; class QLevelOfDetailPrivate; class QT3DRENDERSHARED_EXPORT QLevelOfDetail : public Qt3DCore::QComponent @@ -60,7 +60,7 @@ class QT3DRENDERSHARED_EXPORT QLevelOfDetail : public Qt3DCore::QComponent Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged) Q_PROPERTY(ThresholdType thresholdType READ thresholdType WRITE setThresholdType NOTIFY thresholdTypeChanged) Q_PROPERTY(QVector thresholds READ thresholds WRITE setThresholds NOTIFY thresholdsChanged) - Q_PROPERTY(Qt3DRender::QBoundingSphere *volumeOverride READ volumeOverride WRITE setVolumeOverride NOTIFY volumeOverrideChanged) + Q_PROPERTY(Qt3DRender::QLevelOfDetailBoundingSphere volumeOverride READ volumeOverride WRITE setVolumeOverride NOTIFY volumeOverrideChanged) public: enum ThresholdType { @@ -76,21 +76,23 @@ public: int currentIndex() const; ThresholdType thresholdType() const; QVector thresholds() const; - QBoundingSphere *volumeOverride() const; + QLevelOfDetailBoundingSphere volumeOverride() const; + + Q_INVOKABLE QLevelOfDetailBoundingSphere createBoundingSphere(const QVector3D ¢er, float radius); public Q_SLOTS: void setCamera(QCamera *camera); void setCurrentIndex(int currentIndex); void setThresholdType(ThresholdType thresholdType); void setThresholds(QVector thresholds); - void setVolumeOverride(QBoundingSphere *volumeOverride); + void setVolumeOverride(const QLevelOfDetailBoundingSphere &volumeOverride); Q_SIGNALS: void cameraChanged(QCamera *camera); void currentIndexChanged(int currentIndex); void thresholdTypeChanged(ThresholdType thresholdType); void thresholdsChanged(QVector thresholds); - void volumeOverrideChanged(QBoundingSphere *volumeOverride); + void volumeOverrideChanged(const QLevelOfDetailBoundingSphere &volumeOverride); protected: explicit QLevelOfDetail(QLevelOfDetailPrivate &dd, Qt3DCore::QNode *parent = nullptr); @@ -99,12 +101,12 @@ protected: private: Q_DECLARE_PRIVATE(QLevelOfDetail) - Q_PRIVATE_SLOT(d_func(), void _q_radiusChanged(float)) - Q_PRIVATE_SLOT(d_func(), void _q_centerChanged(const QVector3D&)) }; } // namespace Qt3DRender QT_END_NAMESPACE +Q_DECLARE_METATYPE(Qt3DRender::QLevelOfDetailBoundingSphere) + #endif // QT3DRENDER_QLEVELOFDETAIL_H diff --git a/src/render/frontend/qlevelofdetail_p.h b/src/render/frontend/qlevelofdetail_p.h index ab25e9ad3..1d7a05a71 100644 --- a/src/render/frontend/qlevelofdetail_p.h +++ b/src/render/frontend/qlevelofdetail_p.h @@ -53,6 +53,7 @@ #include #include +#include #include @@ -74,7 +75,7 @@ public: int m_currentIndex; QLevelOfDetail::ThresholdType m_thresholdType; QVector m_thresholds; - QPointer m_volumeOverride; + QLevelOfDetailBoundingSphere m_volumeOverride; }; struct QLevelOfDetailData @@ -83,8 +84,7 @@ struct QLevelOfDetailData int currentIndex; QLevelOfDetail::ThresholdType thresholdType; QVector thresholds; - float radius; - QVector3D center; + QLevelOfDetailBoundingSphere volumeOverride; }; } // namespace Qt3DRender diff --git a/src/render/frontend/qlevelofdetailboundingsphere.cpp b/src/render/frontend/qlevelofdetailboundingsphere.cpp new file mode 100644 index 000000000..eae92a0d7 --- /dev/null +++ b/src/render/frontend/qlevelofdetailboundingsphere.cpp @@ -0,0 +1,159 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qlevelofdetailboundingsphere.h" +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +class QLevelOfDetailBoundingSpherePrivate: public QSharedData +{ +public: + QLevelOfDetailBoundingSpherePrivate() + : QSharedData() + , m_radius(0.0f) + {} + + QLevelOfDetailBoundingSpherePrivate(const QVector3D ¢er, float radius) + : QSharedData() + , m_center(center) + , m_radius(radius) + {} + + ~QLevelOfDetailBoundingSpherePrivate() + {} + + QVector3D m_center; + float m_radius; +}; + +/*! + \class Qt3DRender::QLevelOfDetailBoundingSphere + \inmodule Qt3DRender + \since 5.9 + \brief The QLevelOfDetailBoundingSphere class provides a simple spherical volume, defined by it's center and radius. +*/ + +/*! + \qmltype LevelOfDetail + \instantiates Qt3DRender::QLevelOfDetailBoundingSphere + \inherits Component3D + \inqmlmodule Qt3D.Render + \brief The LevelOfDetailBoundingSphere class provides a simple spherical volume, defined by it's center and radius. +*/ + +/*! + * \qmlproperty QVector3D LevelOfDetailBoundingSphere::center + * + * Specifies the center of the bounding sphere + */ + +/*! + * \property QLevelOfDetailBoundingSphere::center + * + * Specifies the center of the bounding sphere + */ + +/*! + * \qmlproperty qreal LevelOfDetailBoundingSphere::radius + * + * Specifies the radius of the bounding sphere + */ + +/*! + * \property QLevelOfDetailBoundingSphere::radius + * + * Specifies the radius of the bounding sphere + */ + +/*! \fn Qt3DRender::QLevelOfDetailBoundingSphere::QLevelOfDetailBoundingSphere(const QVector3D ¢er = QVector3D(), float radius = -1.0f) + Constructs a new QLevelOfDetailBoundingSphere with the specified \a center and \a radius. + */ + + +QLevelOfDetailBoundingSphere::QLevelOfDetailBoundingSphere(const QVector3D ¢er, float radius) + : d_ptr(new QLevelOfDetailBoundingSpherePrivate(center, radius)) +{ +} + +QLevelOfDetailBoundingSphere::QLevelOfDetailBoundingSphere(const QLevelOfDetailBoundingSphere &other) + : d_ptr(other.d_ptr) +{ +} + +QLevelOfDetailBoundingSphere::~QLevelOfDetailBoundingSphere() +{ +} + +QLevelOfDetailBoundingSphere &QLevelOfDetailBoundingSphere::operator =(const QLevelOfDetailBoundingSphere &other) +{ + d_ptr = other.d_ptr; + return *this; +} + +QVector3D QLevelOfDetailBoundingSphere::center() const +{ + return d_ptr->m_center; +} + +float QLevelOfDetailBoundingSphere::radius() const +{ + return d_ptr->m_radius; +} + +bool QLevelOfDetailBoundingSphere::isEmpty() const +{ + return d_ptr->m_radius <= 0.0f; +} + +bool QLevelOfDetailBoundingSphere::operator ==(const QLevelOfDetailBoundingSphere &other) const +{ + return d_ptr->m_center == other.center() && other.d_ptr->m_radius == other.radius(); +} + +bool QLevelOfDetailBoundingSphere::operator !=(const QLevelOfDetailBoundingSphere &other) const +{ + return !(*this == other); +} + +} // namespace Qt3DRender + +QT_END_NAMESPACE diff --git a/src/render/frontend/qlevelofdetailboundingsphere.h b/src/render/frontend/qlevelofdetailboundingsphere.h new file mode 100644 index 000000000..659b6c6cc --- /dev/null +++ b/src/render/frontend/qlevelofdetailboundingsphere.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3DRENDER_QLEVELOFDETAILBOUNDINGSPHERE_H +#define QT3DRENDER_QLEVELOFDETAILBOUNDINGSPHERE_H + +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +class QLevelOfDetailBoundingSpherePrivate; + +class QT3DRENDERSHARED_EXPORT QLevelOfDetailBoundingSphere +{ + Q_GADGET + Q_PROPERTY(QVector3D center READ center CONSTANT) + Q_PROPERTY(float radius READ radius CONSTANT) +public: + explicit QLevelOfDetailBoundingSphere(const QVector3D ¢er = QVector3D(), float radius = 1.0f); + QLevelOfDetailBoundingSphere(const QLevelOfDetailBoundingSphere &other); + ~QLevelOfDetailBoundingSphere(); + + QLevelOfDetailBoundingSphere &operator =(const QLevelOfDetailBoundingSphere &other); + + QVector3D center() const; + float radius() const; + + bool isEmpty() const; + bool operator ==(const QLevelOfDetailBoundingSphere &other) const; + bool operator !=(const QLevelOfDetailBoundingSphere &other) const; + +private: + QSharedDataPointer d_ptr; +}; + +} // namespace Qt3DRender + +QT_END_NAMESPACE + +#endif // QT3DRENDER_QLEVELOFDETAILBOUNDINGSPHERE_H diff --git a/src/render/frontend/render-frontend.pri b/src/render/frontend/render-frontend.pri index 7a27ba095..75666a270 100644 --- a/src/render/frontend/render-frontend.pri +++ b/src/render/frontend/render-frontend.pri @@ -2,8 +2,6 @@ INCLUDEPATH += $$PWD HEADERS += \ $$PWD/qabstractfunctor.h \ - $$PWD/qboundingsphere.h \ - $$PWD/qboundingsphere_p.h \ $$PWD/qrenderaspect.h \ $$PWD/qrenderaspect_p.h \ $$PWD/qitemmodelbuffer_p.h \ @@ -29,11 +27,11 @@ HEADERS += \ $$PWD/qcomputecommand.h \ $$PWD/qrenderplugin_p.h \ $$PWD/qrenderpluginfactory_p.h \ - $$PWD/qrenderpluginfactoryif_p.h + $$PWD/qrenderpluginfactoryif_p.h \ + $$PWD/qlevelofdetailboundingsphere.h SOURCES += \ $$PWD/qabstractfunctor.cpp \ - $$PWD/qboundingsphere.cpp \ $$PWD/qrenderaspect.cpp \ $$PWD/qitemmodelbuffer.cpp \ $$PWD/sphere.cpp \ @@ -48,5 +46,6 @@ SOURCES += \ $$PWD/qrendertargetoutput.cpp \ $$PWD/qcomputecommand.cpp \ $$PWD/qrenderpluginfactory.cpp \ - $$PWD/qrenderpluginfactoryif.cpp + $$PWD/qrenderpluginfactoryif.cpp \ + $$PWD/qlevelofdetailboundingsphere.cpp diff --git a/src/render/jobs/updatelevelofdetailjob.cpp b/src/render/jobs/updatelevelofdetailjob.cpp index 940d26850..36b83263a 100644 --- a/src/render/jobs/updatelevelofdetailjob.cpp +++ b/src/render/jobs/updatelevelofdetailjob.cpp @@ -162,7 +162,7 @@ void UpdateLevelOfDetailJob::updateEntityLodByDistance(Entity *entity, LevelOfDe const QVector thresholds = lod->thresholds(); QVector3D center = lod->center(); - if (lod->radius() > 0.f || entity->worldBoundingVolume() == nullptr) { + if (lod->hasBoundingVolumeOverride() || entity->worldBoundingVolume() == nullptr) { center = *entity->worldTransform() * center; } else { center = entity->worldBoundingVolume()->center(); @@ -198,7 +198,7 @@ void UpdateLevelOfDetailJob::updateEntityLodByScreenArea(Entity *entity, LevelOf const QVector thresholds = lod->thresholds(); Sphere bv(lod->center(), lod->radius()); - if (lod->radius() <= 0.f && entity->worldBoundingVolume() != nullptr) { + if (!lod->hasBoundingVolumeOverride() && entity->worldBoundingVolume() != nullptr) { bv = *(entity->worldBoundingVolume()); } else { bv.transform(*entity->worldTransform()); diff --git a/tests/auto/render/levelofdetail/tst_levelofdetail.cpp b/tests/auto/render/levelofdetail/tst_levelofdetail.cpp index ab0e8c4b8..1446811a8 100644 --- a/tests/auto/render/levelofdetail/tst_levelofdetail.cpp +++ b/tests/auto/render/levelofdetail/tst_levelofdetail.cpp @@ -29,7 +29,7 @@ #include #include #include -#include +#include #include #include #include @@ -57,8 +57,8 @@ private Q_SLOTS: QCOMPARE(renderLod.currentIndex(), lod.currentIndex()); QCOMPARE(renderLod.thresholdType(), lod.thresholdType()); QCOMPARE(renderLod.thresholds(), lod.thresholds()); - QCOMPARE(renderLod.center(), lod.volumeOverride()->center()); - QCOMPARE(renderLod.radius(), lod.volumeOverride()->radius()); + QCOMPARE(renderLod.center(), lod.volumeOverride().center()); + QCOMPARE(renderLod.radius(), lod.volumeOverride().radius()); } void checkInitialAndCleanedUpState() @@ -129,8 +129,9 @@ private Q_SLOTS: { // WHEN Qt3DCore::QPropertyUpdatedChangePtr updateChange(new Qt3DCore::QPropertyUpdatedChange(Qt3DCore::QNodeId())); - updateChange->setValue(QVector3D(1., 2., 3.)); - updateChange->setPropertyName("center"); + Qt3DRender::QLevelOfDetailBoundingSphere sphere(QVector3D(1.0f, 2.0f, 3.0f), 1.0f); + updateChange->setValue(QVariant::fromValue(sphere)); + updateChange->setPropertyName("volumeOverride"); renderLod.sceneChangeEvent(updateChange); // THEN diff --git a/tests/manual/lod/main.qml b/tests/manual/lod/main.qml index d743f2fea..0c03ff257 100644 --- a/tests/manual/lod/main.qml +++ b/tests/manual/lod/main.qml @@ -127,9 +127,7 @@ Entity { camera: camera thresholds: [1000, 600, 300, 180] thresholdType: LevelOfDetail.ProjectedScreenPixelSize - volumeOverride: BoundingSphere { - radius: 2. - } + volumeOverride: lod.createBoundingSphere(Qt.vector3d(0, 0, 0), 2.0) } ] } @@ -143,6 +141,7 @@ Entity { ] LevelOfDetailLoader { + id: lodLoader components: [ Transform { scale: .5 translation: Qt.vector3d(-8, 0, 0) @@ -151,7 +150,7 @@ Entity { camera: camera thresholds: [20, 35, 50, 65] thresholdType: LevelOfDetail.DistanceToCamera - volumeOverride: null + volumeOverride: lodLoader.createBoundingSphere(Qt.vector3d(0, 0, 0), -1) sources: ["qrc:/SphereEntity.qml", "qrc:/CylinderEntity.qml", "qrc:/ConeEntity.qml", "qrc:/CuboidEntity.qml"] } } -- cgit v1.2.3 From 94259717f42105fe85fbf2aa449cabcdca5d347b Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Thu, 23 Feb 2017 16:20:21 +0100 Subject: Use qDegreesToRadians to make cler what's happening Adding half a degree is so much clearer than adding pi/360 as a number. Task-number: QTBUG-58083 Change-Id: Iffa9db2d3de929c47aea2e4930ad9f9dcb0ece9a Reviewed-by: Sean Harmer --- tests/manual/custom-mesh-update-data-cpp/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/manual/custom-mesh-update-data-cpp/main.cpp b/tests/manual/custom-mesh-update-data-cpp/main.cpp index c7f5742dc..80ee2088d 100644 --- a/tests/manual/custom-mesh-update-data-cpp/main.cpp +++ b/tests/manual/custom-mesh-update-data-cpp/main.cpp @@ -277,7 +277,7 @@ int main(int argc, char* argv[]) void TimerObject::timeout() { - angle += float(M_PI / 360.0); + angle += qDegreesToRadians(0.5f); QByteArray updateData; updateData.resize(3*sizeof(float)); -- cgit v1.2.3 From 929d0108dc61f7a76e14477d4451a9a3fb3ed75a Mon Sep 17 00:00:00 2001 From: Sergio Martins Date: Sun, 12 Feb 2017 23:52:16 +0000 Subject: Fix container detachments when using range loop Fixes -Wclazy-range-loop warnings. Change-Id: I6348b259a444203afe3490ea41c149c9b6740164 Reviewed-by: Kevin Ottens --- src/render/backend/openglvertexarrayobject.cpp | 4 ++-- src/render/framegraph/rendercapture.cpp | 2 +- src/render/frontend/qlevelofdetailswitch.cpp | 6 ++++-- src/render/frontend/qrenderaspect.cpp | 4 ++-- src/render/io/qsceneloader.cpp | 6 ++++-- src/render/jobs/pickboundingvolumejob.cpp | 6 ++++-- src/render/jobs/sendbuffercapturejob.cpp | 2 +- src/render/materialsystem/shader.cpp | 2 +- src/render/picking/posteventstofrontend.cpp | 3 +-- src/render/picking/qeventforward.cpp | 4 ++-- 10 files changed, 22 insertions(+), 17 deletions(-) diff --git a/src/render/backend/openglvertexarrayobject.cpp b/src/render/backend/openglvertexarrayobject.cpp index b88ddfb7b..eefc208d5 100644 --- a/src/render/backend/openglvertexarrayobject.cpp +++ b/src/render/backend/openglvertexarrayobject.cpp @@ -68,7 +68,7 @@ void OpenGLVertexArrayObject::bind() m_ctx->m_currentVAO = this; // We need to specify array and vertex attributes - for (const GraphicsContext::VAOVertexAttribute &attr : m_vertexAttributes) + for (const GraphicsContext::VAOVertexAttribute &attr : qAsConst(m_vertexAttributes)) m_ctx->enableAttribute(attr); if (!m_indexAttribute.isNull()) m_ctx->bindGLBuffer(m_ctx->m_renderer->nodeManagers()->glBufferManager()->data(m_indexAttribute), @@ -85,7 +85,7 @@ void OpenGLVertexArrayObject::release() m_vao->release(); } else { if (m_ctx->m_currentVAO == this) { - for (const GraphicsContext::VAOVertexAttribute &attr : m_vertexAttributes) + for (const GraphicsContext::VAOVertexAttribute &attr : qAsConst(m_vertexAttributes)) m_ctx->disableAttribute(attr); m_ctx->m_currentVAO = nullptr; } diff --git a/src/render/framegraph/rendercapture.cpp b/src/render/framegraph/rendercapture.cpp index 6b6c48375..1d3117c0d 100644 --- a/src/render/framegraph/rendercapture.cpp +++ b/src/render/framegraph/rendercapture.cpp @@ -92,7 +92,7 @@ void RenderCapture::sendRenderCaptures() { QMutexLocker lock(&m_mutex); - for (const RenderCaptureDataPtr data : m_renderCaptureData) { + for (const RenderCaptureDataPtr data : qAsConst(m_renderCaptureData)) { auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId()); e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll); e->setPropertyName("renderCaptureData"); diff --git a/src/render/frontend/qlevelofdetailswitch.cpp b/src/render/frontend/qlevelofdetailswitch.cpp index 9a63343ed..a6d2b1530 100644 --- a/src/render/frontend/qlevelofdetailswitch.cpp +++ b/src/render/frontend/qlevelofdetailswitch.cpp @@ -107,8 +107,10 @@ void QLevelOfDetailSwitch::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &cha emit currentIndexChanged(ndx); int entityIndex = 0; - for (Qt3DCore::QEntity *entity : entities()) { - for (Qt3DCore::QNode *childNode : entity->childNodes()) { + const auto entities = this->entities(); + for (Qt3DCore::QEntity *entity : entities) { + const auto childNodes = entity->childNodes(); + for (Qt3DCore::QNode *childNode : childNodes) { Qt3DCore::QEntity *childEntity = qobject_cast(childNode); if (childEntity) { childEntity->setEnabled(entityIndex == ndx); diff --git a/src/render/frontend/qrenderaspect.cpp b/src/render/frontend/qrenderaspect.cpp index eff502f4e..81e8ff463 100644 --- a/src/render/frontend/qrenderaspect.cpp +++ b/src/render/frontend/qrenderaspect.cpp @@ -254,7 +254,7 @@ void QRenderAspectPrivate::registerBackendTypes() q->registerBackendType(QSharedPointer >::create(m_renderer)); // Plugins - for (Render::QRenderPlugin *plugin : m_renderPlugins) + for (Render::QRenderPlugin *plugin : qAsConst(m_renderPlugins)) plugin->registerBackendTypes(q, m_renderer); } @@ -318,7 +318,7 @@ void QRenderAspectPrivate::unregisterBackendTypes() unregisterBackendType(); // Plugins - for (Render::QRenderPlugin *plugin : m_renderPlugins) + for (Render::QRenderPlugin *plugin : qAsConst(m_renderPlugins)) plugin->unregisterBackendTypes(q); } diff --git a/src/render/io/qsceneloader.cpp b/src/render/io/qsceneloader.cpp index 5070bb9e5..c9506d9fa 100644 --- a/src/render/io/qsceneloader.cpp +++ b/src/render/io/qsceneloader.cpp @@ -198,7 +198,8 @@ void QSceneLoaderPrivate::populateEntityMap(QEntity *parentEntity) { // Topmost parent entity is not considered part of the scene as that is typically // an unnamed entity inserted by importer. - for (auto childNode : parentEntity->childNodes()) { + const QNodeVector childNodes = parentEntity->childNodes(); + for (auto childNode : childNodes) { auto childEntity = qobject_cast(childNode); if (childEntity) { m_entityMap.insert(childEntity->objectName(), childEntity); @@ -349,7 +350,8 @@ QComponent *QSceneLoader::component(const QString &entityName, QSceneLoader::ComponentType componentType) const { QEntity *e = entity(entityName); - for (auto component : e->components()) { + const QComponentVector components = e->components(); + for (auto component : components) { switch (componentType) { case GeometryRendererComponent: if (qobject_cast(component)) diff --git a/src/render/jobs/pickboundingvolumejob.cpp b/src/render/jobs/pickboundingvolumejob.cpp index 7285bcfb7..ecb16f985 100644 --- a/src/render/jobs/pickboundingvolumejob.cpp +++ b/src/render/jobs/pickboundingvolumejob.cpp @@ -167,7 +167,8 @@ bool PickBoundingVolumeJob::runHelper() m_oneEnabledAtLeast = false; m_oneHoverAtLeast = false; - for (auto handle : m_manager->objectPickerManager()->activeHandles()) { + const auto activeHandles = m_manager->objectPickerManager()->activeHandles(); + for (auto handle : activeHandles) { auto picker = m_manager->objectPickerManager()->data(handle); m_oneEnabledAtLeast |= picker->isEnabled(); m_oneHoverAtLeast |= picker->isHoverEnabled(); @@ -229,7 +230,8 @@ bool PickBoundingVolumeJob::runHelper() // Forward keyboard events if (keyEvents.size() > 0) { - for (Entity *e : entitiesGatherer.entities()) { + const QVector entities = entitiesGatherer.entities(); + for (Entity *e : entities) { ObjectPicker *picker = e->renderComponent(); if (picker != nullptr) { if (picker->isEventForwardingEnabled()) { diff --git a/src/render/jobs/sendbuffercapturejob.cpp b/src/render/jobs/sendbuffercapturejob.cpp index 3785d8238..7829931f7 100644 --- a/src/render/jobs/sendbuffercapturejob.cpp +++ b/src/render/jobs/sendbuffercapturejob.cpp @@ -75,7 +75,7 @@ void SendBufferCaptureJob::addRequest(QPair request) void SendBufferCaptureJob::run() { QMutexLocker locker(&m_mutex); - for (QPair pendingCapture : m_pendingSendBufferCaptures) { + for (const QPair &pendingCapture : qAsConst(m_pendingSendBufferCaptures)) { pendingCapture.first->updateDataFromGPUToCPU(pendingCapture.second); } diff --git a/src/render/materialsystem/shader.cpp b/src/render/materialsystem/shader.cpp index 69d22297a..e534a1ffc 100644 --- a/src/render/materialsystem/shader.cpp +++ b/src/render/materialsystem/shader.cpp @@ -272,7 +272,7 @@ void Shader::prepareUniforms(ShaderParameterPack &pack) const auto end = values.cend(); while (it != end) { // Find if there's a uniform with the same name id - for (const ShaderUniform &uniform : m_uniforms) { + for (const ShaderUniform &uniform : qAsConst(m_uniforms)) { if (uniform.m_nameId == it.key()) { pack.setSubmissionUniform(uniform); break; diff --git a/src/render/picking/posteventstofrontend.cpp b/src/render/picking/posteventstofrontend.cpp index 51f986902..d75f5d6a7 100644 --- a/src/render/picking/posteventstofrontend.cpp +++ b/src/render/picking/posteventstofrontend.cpp @@ -60,8 +60,7 @@ PostEventsToFrontend::PostEventsToFrontend(const QVector &events) PostEventsToFrontend::~PostEventsToFrontend() { - for (QEvent *e : m_events) - delete e; + qDeleteAll(m_events); } QVector &PostEventsToFrontend::events() diff --git a/src/render/picking/qeventforward.cpp b/src/render/picking/qeventforward.cpp index cb5f9cfbb..4121e61b8 100644 --- a/src/render/picking/qeventforward.cpp +++ b/src/render/picking/qeventforward.cpp @@ -273,8 +273,8 @@ void QEventForward::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) = qSharedPointerCast(change); if (e->type() == Qt3DCore::PropertyUpdated && d->m_target != nullptr) { if (e->propertyName() == QByteArrayLiteral("events")) { - PostEventsToFrontendPtr postedEvents = e->value().value(); - for (QEvent *event : postedEvents->events()) + const QVector postedEvents = e->value().value()->events(); + for (QEvent *event : postedEvents) QCoreApplication::sendEvent(d->m_target, event); } } -- cgit v1.2.3 From 92a2759a8cf7a77958a788216f1bee762789ca59 Mon Sep 17 00:00:00 2001 From: Kevin Ottens Date: Wed, 22 Feb 2017 12:19:40 +0100 Subject: Integrate the light uniforms in the metal/rough materials Change-Id: I0179c797421eabb5fd2a5cffbb400a2926800566 Reviewed-by: Sean Harmer --- src/extras/shaders/gl3/metalrough.frag | 135 +++++++++++++++++++++++--- src/extras/shaders/gl3/metalroughuniform.frag | 126 +++++++++++++++++++++--- 2 files changed, 236 insertions(+), 25 deletions(-) diff --git a/src/extras/shaders/gl3/metalrough.frag b/src/extras/shaders/gl3/metalrough.frag index 5cb1409c2..4712e7cd8 100644 --- a/src/extras/shaders/gl3/metalrough.frag +++ b/src/extras/shaders/gl3/metalrough.frag @@ -111,6 +111,26 @@ float roughnessToMipLevel(float roughness) return (mipLevels - 1.0 - mipOffset) * (1.0 - (1.0 - roughness) / maxT); } +// Helper function to map from linear roughness value to non-linear alpha (shininess) +float roughnessToAlpha(const in float roughness) +{ + // Constants to control how to convert from roughness [0,1] to + // shininess (alpha) [minAlpha, maxAlpha] using a power law with + // a power of 1 / rho. + const float minAlpha = 1.0; + const float maxAlpha = 1024.0; + const float rho = 3.0; + + return minAlpha + (maxAlpha - minAlpha) * (1.0 - pow(roughness, 1.0 / rho)); +} + +float normalDistribution(const in vec3 n, const in vec3 h, const in float roughness) +{ + // Blinn-Phong approximation + float alpha = roughnessToAlpha(roughness); + return (alpha + 2.0) / (2.0 * 3.14159) * pow(max(dot(n, h), 0.0), alpha); +} + vec3 fresnelFactor(const in vec3 color, const in float cosineFactor) { // Calculate the Fresnel effect value @@ -130,28 +150,104 @@ float geometricModel(const in float lDotN, } vec3 specularModel(const in vec3 F0, - const in float lDotH, - const in float lDotN, + const in float sDotH, + const in float sDotN, const in float vDotN, const in vec3 n, const in vec3 h) { - // Clamp lDotN and vDotN to small positive value to prevent the + // Clamp sDotN and vDotN to small positive value to prevent the // denominator in the reflection equation going to infinity. Balance this // by using the clamped values in the geometric factor function to // avoid ugly seams in the specular lighting. - float sDotNPrime = max(lDotN, 0.001); + float sDotNPrime = max(sDotN, 0.001); float vDotNPrime = max(vDotN, 0.001); - vec3 F = fresnelFactor(F0, lDotH); + vec3 F = fresnelFactor(F0, sDotH); float G = geometricModel(sDotNPrime, vDotNPrime, h); - // TODO: Verify which parts of the BRDF Lys is preconvolving and multiply - // by the remaining factors here. vec3 cSpec = F * G / (4.0 * sDotNPrime * vDotNPrime); return clamp(cSpec, vec3(0.0), vec3(1.0)); } +vec3 pbrModel(const in int lightIndex, + const in vec3 wPosition, + const in vec3 wNormal, + const in vec3 wView, + const in vec3 baseColor, + const in float metalness, + const in float roughness, + const in float ambientOcclusion) +{ + // Calculate some useful quantities + vec3 n = wNormal; + vec3 s = vec3(0.0); + vec3 v = wView; + vec3 h = vec3(0.0); + + float vDotN = dot(v, n); + float sDotN = 0.0; + float sDotH = 0.0; + float att = 1.0; + + if (lights[lightIndex].type != TYPE_DIRECTIONAL) { + // Point and Spot lights + vec3 sUnnormalized = vec3(lights[lightIndex].position) - wPosition; + s = normalize(sUnnormalized); + + // Calculate the attenuation factor + sDotN = dot(s, n); + if (sDotN > 0.0) { + if (lights[lightIndex].constantAttenuation != 0.0 + || lights[lightIndex].linearAttenuation != 0.0 + || lights[lightIndex].quadraticAttenuation != 0.0) { + float dist = length(sUnnormalized); + att = 1.0 / (lights[lightIndex].constantAttenuation + + lights[lightIndex].linearAttenuation * dist + + lights[lightIndex].quadraticAttenuation * dist * dist); + } + + // The light direction is in world space already + if (lights[lightIndex].type == TYPE_SPOT) { + // Check if fragment is inside or outside of the spot light cone + if (degrees(acos(dot(-s, lights[lightIndex].direction))) > lights[lightIndex].cutOffAngle) + sDotN = 0.0; + } + } + } else { + // Directional lights + // The light direction is in world space already + s = normalize(-lights[lightIndex].direction); + sDotN = dot(s, n); + } + + h = normalize(s + v); + sDotH = dot(s, h); + + // Calculate diffuse component + vec3 diffuseColor = (1.0 - metalness) * baseColor; + vec3 diffuse = diffuseColor * max(sDotN, 0.0) / 3.14159; + + // Calculate specular component + vec3 dielectricColor = vec3(0.04); + vec3 F0 = mix(dielectricColor, baseColor, metalness); + vec3 specularFactor = vec3(0.0); + if (sDotN > 0.0) { + specularFactor = specularModel(F0, sDotH, sDotN, vDotN, n, h); + specularFactor *= normalDistribution(n, h, roughness); + } + vec3 specularColor = lights[lightIndex].color; + vec3 specular = specularColor * specularFactor; + + // Blend between diffuse and specular to conserver energy + vec3 color = lights[lightIndex].intensity * (specular + diffuse * (vec3(1.0) - specular)); + + // Reduce by ambient occlusion amount + color *= ambientOcclusion; + + return color; +} + vec3 pbrIblModel(const in vec3 wNormal, const in vec3 wView, const in vec3 baseColor, @@ -206,6 +302,8 @@ vec3 gammaCorrect(const in vec3 color) void main() { + vec3 cLinear = vec3(0.0); + // Calculate the perturbed texture coordinates from parallax occlusion mapping mat3 worldToTangentMatrix = calcWorldSpaceToTangentSpaceMatrix(worldNormal, worldTangent); vec3 wView = normalize(eyePosition - worldPosition); @@ -219,12 +317,23 @@ void main() vec3 tNormal = 2.0 * texture(normalMap, texCoord).rgb - vec3(1.0); vec3 wNormal = normalize(transpose(worldToTangentMatrix) * tNormal); - vec3 cLinear = pbrIblModel(wNormal, - wView, - baseColor, - metalness, - roughness, - ambientOcclusion); + cLinear += pbrIblModel(wNormal, + wView, + baseColor, + metalness, + roughness, + ambientOcclusion); + + for (int i = 0; i < lightCount; ++i) { + cLinear += pbrModel(i, + worldPosition, + wNormal, + wView, + baseColor.rgb, + metalness, + roughness, + ambientOcclusion); + } // Apply exposure correction cLinear *= pow(2.0, exposure); diff --git a/src/extras/shaders/gl3/metalroughuniform.frag b/src/extras/shaders/gl3/metalroughuniform.frag index a1711c504..8be76e9c2 100644 --- a/src/extras/shaders/gl3/metalroughuniform.frag +++ b/src/extras/shaders/gl3/metalroughuniform.frag @@ -106,6 +106,26 @@ float roughnessToMipLevel(float roughness) return (mipLevels - 1.0 - mipOffset) * (1.0 - (1.0 - roughness) / maxT); } +// Helper function to map from linear roughness value to non-linear alpha (shininess) +float roughnessToAlpha(const in float roughness) +{ + // Constants to control how to convert from roughness [0,1] to + // shininess (alpha) [minAlpha, maxAlpha] using a power law with + // a power of 1 / rho. + const float minAlpha = 1.0; + const float maxAlpha = 1024.0; + const float rho = 3.0; + + return minAlpha + (maxAlpha - minAlpha) * (1.0 - pow(roughness, 1.0 / rho)); +} + +float normalDistribution(const in vec3 n, const in vec3 h, const in float roughness) +{ + // Blinn-Phong approximation + float alpha = roughnessToAlpha(roughness); + return (alpha + 2.0) / (2.0 * 3.14159) * pow(max(dot(n, h), 0.0), alpha); +} + vec3 fresnelFactor(const in vec3 color, const in float cosineFactor) { // Calculate the Fresnel effect value @@ -125,28 +145,98 @@ float geometricModel(const in float lDotN, } vec3 specularModel(const in vec3 F0, - const in float lDotH, - const in float lDotN, + const in float sDotH, + const in float sDotN, const in float vDotN, const in vec3 n, const in vec3 h) { - // Clamp lDotN and vDotN to small positive value to prevent the + // Clamp sDotN and vDotN to small positive value to prevent the // denominator in the reflection equation going to infinity. Balance this // by using the clamped values in the geometric factor function to // avoid ugly seams in the specular lighting. - float sDotNPrime = max(lDotN, 0.001); + float sDotNPrime = max(sDotN, 0.001); float vDotNPrime = max(vDotN, 0.001); - vec3 F = fresnelFactor(F0, lDotH); + vec3 F = fresnelFactor(F0, sDotH); float G = geometricModel(sDotNPrime, vDotNPrime, h); - // TODO: Verify which parts of the BRDF Lys is preconvolving and multiply - // by the remaining factors here. vec3 cSpec = F * G / (4.0 * sDotNPrime * vDotNPrime); return clamp(cSpec, vec3(0.0), vec3(1.0)); } +vec3 pbrModel(const in int lightIndex, + const in vec3 wPosition, + const in vec3 wNormal, + const in vec3 wView, + const in vec3 baseColor, + const in float metalness, + const in float roughness) +{ + // Calculate some useful quantities + vec3 n = wNormal; + vec3 s = vec3(0.0); + vec3 v = wView; + vec3 h = vec3(0.0); + + float vDotN = dot(v, n); + float sDotN = 0.0; + float sDotH = 0.0; + float att = 1.0; + + if (lights[lightIndex].type != TYPE_DIRECTIONAL) { + // Point and Spot lights + vec3 sUnnormalized = vec3(lights[lightIndex].position) - wPosition; + s = normalize(sUnnormalized); + + // Calculate the attenuation factor + sDotN = dot(s, n); + if (sDotN > 0.0) { + if (lights[lightIndex].constantAttenuation != 0.0 + || lights[lightIndex].linearAttenuation != 0.0 + || lights[lightIndex].quadraticAttenuation != 0.0) { + float dist = length(sUnnormalized); + att = 1.0 / (lights[lightIndex].constantAttenuation + + lights[lightIndex].linearAttenuation * dist + + lights[lightIndex].quadraticAttenuation * dist * dist); + } + + // The light direction is in world space already + if (lights[lightIndex].type == TYPE_SPOT) { + // Check if fragment is inside or outside of the spot light cone + if (degrees(acos(dot(-s, lights[lightIndex].direction))) > lights[lightIndex].cutOffAngle) + sDotN = 0.0; + } + } + } else { + // Directional lights + // The light direction is in world space already + s = normalize(-lights[lightIndex].direction); + sDotN = dot(s, n); + } + + h = normalize(s + v); + sDotH = dot(s, h); + + // Calculate diffuse component + vec3 diffuseColor = (1.0 - metalness) * baseColor * lights[lightIndex].color; + vec3 diffuse = diffuseColor * max(sDotN, 0.0) / 3.14159; + + // Calculate specular component + vec3 dielectricColor = vec3(0.04); + vec3 F0 = mix(dielectricColor, baseColor, metalness); + vec3 specularFactor = vec3(0.0); + if (sDotN > 0.0) { + specularFactor = specularModel(F0, sDotH, sDotN, vDotN, n, h); + specularFactor *= normalDistribution(n, h, roughness); + } + vec3 specularColor = lights[lightIndex].color; + vec3 specular = specularColor * specularFactor; + + // Blend between diffuse and specular to conserver energy + return att * lights[lightIndex].intensity * (specular + diffuse * (vec3(1.0) - specular)); +} + vec3 pbrIblModel(const in vec3 wNormal, const in vec3 wView, const in vec3 baseColor, @@ -195,12 +285,24 @@ vec3 gammaCorrect(const in vec3 color) void main() { + vec3 cLinear = vec3(0.0); + vec3 worldView = normalize(eyePosition - worldPosition); - vec3 cLinear = pbrIblModel(worldNormal, - worldView, - baseColor.rgb, - metalness, - roughness); + cLinear += pbrIblModel(worldNormal, + worldView, + baseColor.rgb, + metalness, + roughness); + + for (int i = 0; i < lightCount; ++i) { + cLinear += pbrModel(i, + worldPosition, + worldNormal, + worldView, + baseColor.rgb, + metalness, + roughness); + } // Apply exposure correction cLinear *= pow(2.0, exposure); -- cgit v1.2.3 From 12111fd494d927bb75a8a41e3771ff6983119274 Mon Sep 17 00:00:00 2001 From: Kevin Ottens Date: Thu, 23 Feb 2017 13:53:23 +0100 Subject: QShaderData: fix texture support in properties There was only code dealing with sub-shader data but nothing allowing to check if a property was a texture, this is now properly handled. Change-Id: I48984727eff975e9f3e2c21c5185b336efc963fd Reviewed-by: Sean Harmer --- .../quick3drender/items/quick3dshaderdata.cpp | 8 +- src/render/backend/renderview.cpp | 2 + src/render/jobs/renderviewjobutils.cpp | 19 ++- src/render/jobs/renderviewjobutils_p.h | 2 + src/render/materialsystem/qshaderdata_p.h | 6 +- .../render/renderviewutils/tst_renderviewutils.cpp | 156 ++++++++++++++++++++- 6 files changed, 179 insertions(+), 14 deletions(-) diff --git a/src/quick3d/quick3drender/items/quick3dshaderdata.cpp b/src/quick3d/quick3drender/items/quick3dshaderdata.cpp index dbf351695..1287f1603 100644 --- a/src/quick3d/quick3drender/items/quick3dshaderdata.cpp +++ b/src/quick3d/quick3drender/items/quick3dshaderdata.cpp @@ -84,11 +84,9 @@ public: } } return innerValues; - } else if (v.userType() == quick3DShaderDataTypeId) { - Qt3DCore::QNodeId id; - QShaderData *shaderData = v.value(); - if (shaderData) - id = shaderData->id(); + } else if (v.canConvert()) { + const auto node = v.value(); + const auto id = Qt3DCore::qIdForNode(node); return QVariant::fromValue(id); } return v; diff --git a/src/render/backend/renderview.cpp b/src/render/backend/renderview.cpp index c7d2c7864..bd184594f 100644 --- a/src/render/backend/renderview.cpp +++ b/src/render/backend/renderview.cpp @@ -361,6 +361,7 @@ QVector RenderView::buildDrawRenderCommands(const QVectorshaderDataManager = m_manager->shaderDataManager(); + builder->textureManager = m_manager->textureManager(); m_localData.setLocalData(builder); QVector commands; @@ -479,6 +480,7 @@ QVector RenderView::buildComputeRenderCommands(const QVectorshaderDataManager = m_manager->shaderDataManager(); + builder->textureManager = m_manager->textureManager(); m_localData.setLocalData(builder); // If the RenderView contains only a ComputeDispatch then it cares about diff --git a/src/render/jobs/renderviewjobutils.cpp b/src/render/jobs/renderviewjobutils.cpp index f75ea3f0c..500fcc56a 100644 --- a/src/render/jobs/renderviewjobutils.cpp +++ b/src/render/jobs/renderviewjobutils.cpp @@ -416,6 +416,7 @@ const int qNodeIdTypeId = qMetaTypeId(); UniformBlockValueBuilder::UniformBlockValueBuilder() : updatedPropertiesOnly(false) , shaderDataManager(nullptr) + , textureManager(nullptr) { } @@ -432,11 +433,16 @@ void UniformBlockValueBuilder::buildActiveUniformNameValueMapHelper(ShaderData * if (list.at(0).userType() == qNodeIdTypeId) { // Array of struct qmlPropertyName[i].structMember for (int i = 0; i < list.size(); ++i) { if (list.at(i).userType() == qNodeIdTypeId) { - ShaderData *subShaderData = shaderDataManager->lookupResource(list.at(i).value()); - if (subShaderData) + const auto nodeId = value.value(); + ShaderData *subShaderData = shaderDataManager->lookupResource(nodeId); + if (subShaderData) { buildActiveUniformNameValueMapStructHelper(subShaderData, blockName + QLatin1Char('.') + qmlPropertyName + blockArray.arg(i), QLatin1String("")); + } else if (textureManager->contains(nodeId)) { + const auto varId = StringToInt::lookupId(blockName + QLatin1Char('.') + qmlPropertyName + blockArray.arg(i)); + activeUniformNamesToValue.insert(varId, value); + } } } } else { // Array of scalar/vec qmlPropertyName[0] @@ -447,11 +453,16 @@ void UniformBlockValueBuilder::buildActiveUniformNameValueMapHelper(ShaderData * } } } else if (value.userType() == qNodeIdTypeId) { // Struct qmlPropertyName.structMember - ShaderData *rSubShaderData = shaderDataManager->lookupResource(value.value()); - if (rSubShaderData) + const auto nodeId = value.value(); + ShaderData *rSubShaderData = shaderDataManager->lookupResource(nodeId); + if (rSubShaderData) { buildActiveUniformNameValueMapStructHelper(rSubShaderData, blockName, qmlPropertyName); + } else if (textureManager->contains(nodeId)) { + const auto varId = StringToInt::lookupId(blockName + QLatin1Char('.') + qmlPropertyName); + activeUniformNamesToValue.insert(varId, value); + } } else { // Scalar / Vec QString varName = blockName + QLatin1Char('.') + qmlPropertyName; if (uniforms.contains(varName)) { diff --git a/src/render/jobs/renderviewjobutils_p.h b/src/render/jobs/renderviewjobutils_p.h index bc042a582..c1d37b28a 100644 --- a/src/render/jobs/renderviewjobutils_p.h +++ b/src/render/jobs/renderviewjobutils_p.h @@ -83,6 +83,7 @@ class NodeManagers; class ShaderDataManager; struct ShaderUniform; class ShaderData; +class TextureManager; class RenderStateManager; class RenderStateCollection; @@ -169,6 +170,7 @@ struct Q_AUTOTEST_EXPORT UniformBlockValueBuilder QHash uniforms; UniformBlockValueBuilderHash activeUniformNamesToValue; ShaderDataManager *shaderDataManager; + TextureManager *textureManager; QMatrix4x4 viewMatrix; }; diff --git a/src/render/materialsystem/qshaderdata_p.h b/src/render/materialsystem/qshaderdata_p.h index bfa139890..53e3caefd 100644 --- a/src/render/materialsystem/qshaderdata_p.h +++ b/src/render/materialsystem/qshaderdata_p.h @@ -70,10 +70,10 @@ class QShaderDataPropertyReader: public PropertyReaderInterface { QVariant readProperty(const QVariant &v) Q_DECL_OVERRIDE { - QShaderData *shaderData = nullptr; + const auto node = v.value(); - if (v.userType() == qShaderDataTypeId && (shaderData = v.value()) != nullptr) { - return QVariant::fromValue(shaderData->id()); + if (node) { + return QVariant::fromValue(node->id()); } else if (v.userType() == qVectorShaderDataTypeId) { QVariantList vlist; const auto data_ = v.value >(); diff --git a/tests/auto/render/renderviewutils/tst_renderviewutils.cpp b/tests/auto/render/renderviewutils/tst_renderviewutils.cpp index e4681a257..c38b2795e 100644 --- a/tests/auto/render/renderviewutils/tst_renderviewutils.cpp +++ b/tests/auto/render/renderviewutils/tst_renderviewutils.cpp @@ -43,6 +43,8 @@ class tst_RenderViewUtils : public Qt3DCore::QBackendNodeTester private Q_SLOTS: void topLevelScalarValueNoUniforms(); void topLevelScalarValue(); + void topLevelTextureValueNoUniforms(); + void topLevelTextureValue(); void topLevelArrayValue(); void topLevelStructValue_data(); void topLevelStructValue(); @@ -66,6 +68,15 @@ private: // Init the backend element simulateInitialization(frontend, backend); } + + void initBackendTexture(Qt3DRender::QAbstractTexture *frontend, + Qt3DRender::Render::TextureManager *manager) + { + // Create backend element for frontend one + Qt3DRender::Render::Texture *backend = manager->getOrCreateResource(frontend->id()); + // Init the backend element + simulateInitialization(frontend, backend); + } }; class ScalarShaderData : public Qt3DRender::QShaderData @@ -109,6 +120,47 @@ private: float m_scalar; }; +class TextureShaderData : public Qt3DRender::QShaderData +{ + Q_OBJECT + Q_PROPERTY(Qt3DRender::QAbstractTexture* texture READ texture WRITE setTexture NOTIFY textureChanged) + +public: + TextureShaderData() + : Qt3DRender::QShaderData() + , m_texture(nullptr) + { + } + + void setTexture(Qt3DRender::QAbstractTexture *texture) + { + if (texture != m_texture) { + m_texture = texture; + emit textureChanged(); + } + } + + Qt3DRender::QAbstractTexture *texture() const + { + return m_texture; + } + + QHash buildUniformMap(const QString &blockName) + { + QHash uniforms; + + uniforms.insert(blockName + QStringLiteral(".texture"), Qt3DRender::Render::ShaderUniform()); + + return uniforms; + } + +Q_SIGNALS: + void textureChanged(); + +private: + Qt3DRender::QAbstractTexture *m_texture; +}; + class ArrayShaderData : public Qt3DRender::QShaderData { @@ -294,6 +346,7 @@ void tst_RenderViewUtils::topLevelScalarValueNoUniforms() // GIVEN QScopedPointer shaderData(new ScalarShaderData()); QScopedPointer manager(new Qt3DRender::Render::ShaderDataManager()); + QScopedPointer textureManager(new Qt3DRender::Render::TextureManager()); // WHEN shaderData->setScalar(883.0f); @@ -306,6 +359,7 @@ void tst_RenderViewUtils::topLevelScalarValueNoUniforms() // WHEB Qt3DRender::Render::UniformBlockValueBuilder blockBuilder; blockBuilder.shaderDataManager = manager.data(); + blockBuilder.textureManager = textureManager.data(); blockBuilder.updatedPropertiesOnly = false; // build name-value map blockBuilder.buildActiveUniformNameValueMapStructHelper(backendShaderData, QStringLiteral("")); @@ -320,6 +374,7 @@ void tst_RenderViewUtils::topLevelScalarValue() // GIVEN QScopedPointer shaderData(new ScalarShaderData()); QScopedPointer manager(new Qt3DRender::Render::ShaderDataManager()); + QScopedPointer textureManager(new Qt3DRender::Render::TextureManager()); // WHEN shaderData->setScalar(883.0f); @@ -332,6 +387,7 @@ void tst_RenderViewUtils::topLevelScalarValue() // WHEN Qt3DRender::Render::UniformBlockValueBuilder blockBuilder; blockBuilder.shaderDataManager = manager.data(); + blockBuilder.textureManager = textureManager.data(); blockBuilder.updatedPropertiesOnly = false; blockBuilder.uniforms = shaderData->buildUniformMap(QStringLiteral("MyBlock")); // build name-value map @@ -353,11 +409,83 @@ void tst_RenderViewUtils::topLevelScalarValue() } } +void tst_RenderViewUtils::topLevelTextureValueNoUniforms() +{ + // GIVEN + QScopedPointer shaderData(new TextureShaderData); + QScopedPointer manager(new Qt3DRender::Render::ShaderDataManager); + QScopedPointer texture(new Qt3DRender::QTexture2D); + QScopedPointer textureManager(new Qt3DRender::Render::TextureManager()); + + // WHEN + shaderData->setTexture(texture.data()); + initBackendShaderData(shaderData.data(), manager.data()); + + // THEN + Qt3DRender::Render::ShaderData *backendShaderData = manager->lookupResource(shaderData->id()); + QVERIFY(backendShaderData != nullptr); + + // WHEB + Qt3DRender::Render::UniformBlockValueBuilder blockBuilder; + blockBuilder.shaderDataManager = manager.data(); + blockBuilder.textureManager = textureManager.data(); + blockBuilder.updatedPropertiesOnly = false; + // build name-value map + blockBuilder.buildActiveUniformNameValueMapStructHelper(backendShaderData, QStringLiteral("")); + + // THEN + // activeUniformNamesToValue should be empty as blockBuilder.uniforms is + QVERIFY(blockBuilder.activeUniformNamesToValue.isEmpty()); +} + +void tst_RenderViewUtils::topLevelTextureValue() +{ + // GIVEN + QScopedPointer shaderData(new TextureShaderData); + QScopedPointer manager(new Qt3DRender::Render::ShaderDataManager); + QScopedPointer texture(new Qt3DRender::QTexture2D); + QScopedPointer textureManager(new Qt3DRender::Render::TextureManager()); + + // WHEN + initBackendTexture(texture.data(), textureManager.data()); + shaderData->setTexture(texture.data()); + initBackendShaderData(shaderData.data(), manager.data()); + + // THEN + Qt3DRender::Render::ShaderData *backendShaderData = manager->lookupResource(shaderData->id()); + QVERIFY(backendShaderData != nullptr); + + // WHEN + Qt3DRender::Render::UniformBlockValueBuilder blockBuilder; + blockBuilder.shaderDataManager = manager.data(); + blockBuilder.textureManager = textureManager.data(); + blockBuilder.updatedPropertiesOnly = false; + blockBuilder.uniforms = shaderData->buildUniformMap(QStringLiteral("MyBlock")); + // build name-value map + blockBuilder.buildActiveUniformNameValueMapStructHelper(backendShaderData, QStringLiteral("MyBlock")); + + // THEN + QVERIFY(blockBuilder.uniforms.count() == 1); + QCOMPARE(blockBuilder.activeUniformNamesToValue.count(), 1); + + // WHEN + Qt3DRender::Render::UniformBlockValueBuilderHash::const_iterator it = blockBuilder.activeUniformNamesToValue.begin(); + const Qt3DRender::Render::UniformBlockValueBuilderHash::const_iterator end = blockBuilder.activeUniformNamesToValue.end(); + + while (it != end) { + // THEN + QVERIFY(blockBuilder.uniforms.contains(Qt3DRender::Render::StringToInt::lookupString(it.key()))); + QCOMPARE(it.value(), QVariant::fromValue(shaderData->texture()->id())); + ++it; + } +} + void tst_RenderViewUtils::topLevelArrayValue() { // GIVEN QScopedPointer shaderData(new ArrayShaderData()); QScopedPointer manager(new Qt3DRender::Render::ShaderDataManager()); + QScopedPointer textureManager(new Qt3DRender::Render::TextureManager()); // WHEN QVariantList arrayValues = QVariantList() << 454 << 350 << 383 << 427 << 552; @@ -371,6 +499,7 @@ void tst_RenderViewUtils::topLevelArrayValue() // WHEN Qt3DRender::Render::UniformBlockValueBuilder blockBuilder; blockBuilder.shaderDataManager = manager.data(); + blockBuilder.textureManager = textureManager.data(); blockBuilder.updatedPropertiesOnly = false; blockBuilder.uniforms = shaderData->buildUniformMap(QStringLiteral("MyBlock")); // build name-value map @@ -430,6 +559,7 @@ void tst_RenderViewUtils::topLevelStructValue() QFETCH(StructShaderData *, shaderData); QFETCH(QString, blockName); QScopedPointer manager(new Qt3DRender::Render::ShaderDataManager()); + QScopedPointer textureManager(new Qt3DRender::Render::TextureManager()); // WHEN initBackendShaderData(shaderData, manager.data()); @@ -441,6 +571,7 @@ void tst_RenderViewUtils::topLevelStructValue() // WHEN Qt3DRender::Render::UniformBlockValueBuilder blockBuilder; blockBuilder.shaderDataManager = manager.data(); + blockBuilder.textureManager = textureManager.data(); blockBuilder.updatedPropertiesOnly = false; blockBuilder.uniforms = shaderData->buildUniformMap(blockName); const QHash expectedValues = shaderData->buildUniformMapValues(blockName); @@ -468,10 +599,14 @@ void tst_RenderViewUtils::topLevelDynamicProperties() // GIVEN QScopedPointer shaderData(new Qt3DRender::QShaderData()); QScopedPointer manager(new Qt3DRender::Render::ShaderDataManager()); + QScopedPointer texture(new Qt3DRender::QTexture2D); + QScopedPointer textureManager(new Qt3DRender::Render::TextureManager()); // WHEN + initBackendTexture(texture.data(), textureManager.data()); shaderData->setProperty("scalar", 883.0f); shaderData->setProperty("array", QVariantList() << 454 << 350 << 383 << 427 << 552); + shaderData->setProperty("texture", QVariant::fromValue(texture.data())); initBackendShaderData(shaderData.data(), manager.data()); // THEN @@ -481,20 +616,24 @@ void tst_RenderViewUtils::topLevelDynamicProperties() // WHEN Qt3DRender::Render::UniformBlockValueBuilder blockBuilder; blockBuilder.shaderDataManager = manager.data(); + blockBuilder.textureManager = textureManager.data(); blockBuilder.updatedPropertiesOnly = false; blockBuilder.uniforms.insert(QStringLiteral("MyBlock.scalar"), Qt3DRender::Render::ShaderUniform()); blockBuilder.uniforms.insert(QStringLiteral("MyBlock.array[0]"), Qt3DRender::Render::ShaderUniform()); + blockBuilder.uniforms.insert(QStringLiteral("MyBlock.texture"), Qt3DRender::Render::ShaderUniform()); // build name-value map blockBuilder.buildActiveUniformNameValueMapStructHelper(backendShaderData, QStringLiteral("MyBlock")); // THEN - QVERIFY(blockBuilder.uniforms.count() == 2); - QCOMPARE(blockBuilder.activeUniformNamesToValue.count(), 2); + QVERIFY(blockBuilder.uniforms.count() == 3); + QCOMPARE(blockBuilder.activeUniformNamesToValue.count(), 3); QCOMPARE(blockBuilder.activeUniformNamesToValue.value(Qt3DRender::Render::StringToInt::lookupId("MyBlock.scalar")), shaderData->property("scalar")); QCOMPARE(blockBuilder.activeUniformNamesToValue.value(Qt3DRender::Render::StringToInt::lookupId("MyBlock.array[0]")), shaderData->property("array")); + QCOMPARE(blockBuilder.activeUniformNamesToValue.value(Qt3DRender::Render::StringToInt::lookupId("MyBlock.texture")), + QVariant::fromValue(texture->id())); } void tst_RenderViewUtils::transformedProperties() @@ -558,6 +697,19 @@ void tst_RenderViewUtils::shouldNotifyDynamicPropertyChanges() QCOMPARE(change->type(), Qt3DCore::PropertyUpdated); QCOMPARE(change->propertyName(), QByteArrayLiteral("scalar")); QCOMPARE(change->value().toFloat(), 883.0f); + + arbiter.events.clear(); + + // WHEN + QScopedPointer texture(new Qt3DRender::QTexture2D); + shaderData->setProperty("texture", QVariant::fromValue(texture.data())); + + // THEN + QCOMPARE(arbiter.events.size(), 1); + change = arbiter.events.first().dynamicCast(); + QCOMPARE(change->type(), Qt3DCore::PropertyUpdated); + QCOMPARE(change->propertyName(), QByteArrayLiteral("texture")); + QCOMPARE(change->value(), QVariant::fromValue(texture->id())); } QTEST_MAIN(tst_RenderViewUtils) -- cgit v1.2.3 From 67eec4f57a47271685e805c1ff74c80b2570c6ab Mon Sep 17 00:00:00 2001 From: Kevin Ottens Date: Thu, 23 Feb 2017 15:13:28 +0100 Subject: Add QEnvironmentLight into Qt3DRender This is a better API to set the environment lighting than what we currently have on the metal/rough materials. Still needs to be integrated in the renderer and to adjust the materials to make use of it. Change-Id: Ie1e46a0fa67916460147200c9cbbfbab8b037cee Reviewed-by: Sean Harmer --- src/render/backend/handle_types_p.h | 2 + src/render/backend/managers_p.h | 12 + src/render/backend/nodemanagers.cpp | 8 + src/render/backend/nodemanagers_p.h | 7 + src/render/lights/environmentlight.cpp | 66 +++++ src/render/lights/environmentlight_p.h | 81 ++++++ src/render/lights/lights.pri | 5 + src/render/lights/qenvironmentlight.cpp | 189 +++++++++++++ src/render/lights/qenvironmentlight.h | 86 ++++++ src/render/lights/qenvironmentlight_p.h | 85 ++++++ .../render/qenvironmentlight/qenvironmentlight.pro | 11 + .../qenvironmentlight/tst_qenvironmentlight.cpp | 301 +++++++++++++++++++++ tests/auto/render/render.pro | 1 + 13 files changed, 854 insertions(+) create mode 100644 src/render/lights/environmentlight.cpp create mode 100644 src/render/lights/environmentlight_p.h create mode 100644 src/render/lights/qenvironmentlight.cpp create mode 100644 src/render/lights/qenvironmentlight.h create mode 100644 src/render/lights/qenvironmentlight_p.h create mode 100644 tests/auto/render/qenvironmentlight/qenvironmentlight.pro create mode 100644 tests/auto/render/qenvironmentlight/tst_qenvironmentlight.cpp diff --git a/src/render/backend/handle_types_p.h b/src/render/backend/handle_types_p.h index c8c73b749..352519e75 100644 --- a/src/render/backend/handle_types_p.h +++ b/src/render/backend/handle_types_p.h @@ -90,6 +90,7 @@ class ObjectPicker; class BoundingVolumeDebug; class OpenGLVertexArrayObject; class Light; +class EnvironmentLight; class ComputeCommand; class GLBuffer; class RenderStateNode; @@ -122,6 +123,7 @@ typedef Qt3DCore::QHandle HGeometryRenderer; typedef Qt3DCore::QHandle HObjectPicker; typedef Qt3DCore::QHandle HBoundingVolumeDebug; typedef Qt3DCore::QHandle HLight; +typedef Qt3DCore::QHandle HEnvironmentLight; typedef Qt3DCore::QHandle HComputeCommand; typedef Qt3DCore::QHandle HGLBuffer; typedef Qt3DCore::QHandle HRenderState; diff --git a/src/render/backend/managers_p.h b/src/render/backend/managers_p.h index a75c27b25..db65967de 100644 --- a/src/render/backend/managers_p.h +++ b/src/render/backend/managers_p.h @@ -77,6 +77,7 @@ #include #include #include +#include #include #include @@ -391,6 +392,17 @@ public: LightManager() {} }; +class EnvironmentLightManager : public Qt3DCore::QResourceManager< + EnvironmentLight, + Qt3DCore::QNodeId, + 16, + Qt3DCore::ArrayAllocatingPolicy, + Qt3DCore::NonLockingPolicy> +{ +public: + EnvironmentLightManager() {} +}; + class ComputeCommandManager : public Qt3DCore::QResourceManager< ComputeCommand, Qt3DCore::QNodeId, diff --git a/src/render/backend/nodemanagers.cpp b/src/render/backend/nodemanagers.cpp index f6a3441c2..5540d1c44 100644 --- a/src/render/backend/nodemanagers.cpp +++ b/src/render/backend/nodemanagers.cpp @@ -89,6 +89,7 @@ NodeManagers::NodeManagers() , m_objectPickerManager(new ObjectPickerManager()) // , m_boundingVolumeDebugManager(new BoundingVolumeDebugManager()) , m_lightManager(new LightManager()) + , m_environmentLightManager(new EnvironmentLightManager()) , m_computeJobManager(new ComputeCommandManager()) , m_renderStateManager(new RenderStateManager()) , m_eventForwardManager(new EventForwardManager()) @@ -129,6 +130,7 @@ NodeManagers::~NodeManagers() delete m_objectPickerManager; // delete m_boundingVolumeDebugManager; delete m_lightManager; + delete m_environmentLightManager; delete m_computeJobManager; delete m_renderStateManager; delete m_renderNodesManager; @@ -320,6 +322,12 @@ LightManager *NodeManagers::manager() const Q_DECL_NOTHROW return m_lightManager; } +template<> +EnvironmentLightManager *NodeManagers::manager() const Q_DECL_NOTHROW +{ + return m_environmentLightManager; +} + template<> ComputeCommandManager *NodeManagers::manager() const Q_DECL_NOTHROW { diff --git a/src/render/backend/nodemanagers_p.h b/src/render/backend/nodemanagers_p.h index 993e6f5cc..deae132c9 100644 --- a/src/render/backend/nodemanagers_p.h +++ b/src/render/backend/nodemanagers_p.h @@ -96,6 +96,7 @@ class TextureImageDataManager; class LayerManager; class LevelOfDetailManager; class LightManager; +class EnvironmentLightManager; class ComputeCommandManager; class RenderStateManager; class EventForwardManager; @@ -129,6 +130,7 @@ class ObjectPicker; class EventForward; //class BoundingVolumeDebug; class Light; +class EnvironmentLight; class ComputeCommand; class RenderStateNode; class OpenGLVertexArrayObject; @@ -207,6 +209,7 @@ public: inline ObjectPickerManager *objectPickerManager() const Q_DECL_NOEXCEPT { return m_objectPickerManager; } // inline BoundingVolumeDebugManager *boundingVolumeDebugManager() const Q_DECL_NOEXCEPT { return m_boundingVolumeDebugManager; } inline LightManager *lightManager() const Q_DECL_NOEXCEPT { return m_lightManager; } + inline EnvironmentLightManager *environmentLightManager() const Q_DECL_NOEXCEPT { return m_environmentLightManager; } inline ComputeCommandManager *computeJobManager() const Q_DECL_NOEXCEPT { return m_computeJobManager; } inline RenderStateManager *renderStateManager() const Q_DECL_NOEXCEPT { return m_renderStateManager; } inline EventForwardManager *eventForwardManager() const Q_DECL_NOEXCEPT { return m_eventForwardManager; } @@ -246,6 +249,7 @@ private: ObjectPickerManager *m_objectPickerManager; // BoundingVolumeDebugManager *m_boundingVolumeDebugManager; LightManager *m_lightManager; + EnvironmentLightManager *m_environmentLightManager; ComputeCommandManager *m_computeJobManager; RenderStateManager *m_renderStateManager; EventForwardManager *m_eventForwardManager; @@ -348,6 +352,9 @@ QT3DRENDERSHARED_PRIVATE_EXPORT EventForwardManager *NodeManagers::manager LightManager *NodeManagers::manager() const Q_DECL_NOEXCEPT; +template<> +EnvironmentLightManager *NodeManagers::manager() const Q_DECL_NOEXCEPT; + template<> QT3DRENDERSHARED_PRIVATE_EXPORT ComputeCommandManager *NodeManagers::manager() const Q_DECL_NOEXCEPT; diff --git a/src/render/lights/environmentlight.cpp b/src/render/lights/environmentlight.cpp new file mode 100644 index 000000000..d4245fb6e --- /dev/null +++ b/src/render/lights/environmentlight.cpp @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "environmentlight_p.h" +#include "qenvironmentlight.h" +#include "qenvironmentlight_p.h" + +QT_BEGIN_NAMESPACE + +using namespace Qt3DCore; + +namespace Qt3DRender { +namespace Render { + +QNodeId EnvironmentLight::shaderData() const +{ + return m_shaderDataId; +} + +void EnvironmentLight::initializeFromPeer(const QNodeCreatedChangeBasePtr &change) +{ + const auto typedChange = qSharedPointerCast>(change); + const auto &data = typedChange->data; + m_shaderDataId = data.shaderDataId; +} + +} // namespace Render +} // namespace Qt3DRender + +QT_END_NAMESPACE diff --git a/src/render/lights/environmentlight_p.h b/src/render/lights/environmentlight_p.h new file mode 100644 index 000000000..2ebe72b12 --- /dev/null +++ b/src/render/lights/environmentlight_p.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3DRENDER_RENDER_ENVIRONMENTLIGHT_P_H +#define QT3DRENDER_RENDER_ENVIRONMENTLIGHT_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +namespace Render { + +class Q_AUTOTEST_EXPORT EnvironmentLight : public BackendNode +{ +public: + Qt3DCore::QNodeId shaderData() const; + +private: + void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL; + + Qt3DCore::QNodeId m_shaderDataId; +}; + +} // namespace Render + +} // namespace Qt3DRender + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(Qt3DRender::Render::EnvironmentLight*) // LCOV_EXCL_LINE + +#endif // QT3DRENDER_RENDER_ENVIRONMENTLIGHT_P_H diff --git a/src/render/lights/lights.pri b/src/render/lights/lights.pri index 408253d74..dbaa4352f 100644 --- a/src/render/lights/lights.pri +++ b/src/render/lights/lights.pri @@ -5,17 +5,22 @@ HEADERS += \ $$PWD/qabstractlight_p.h \ $$PWD/qdirectionallight.h \ $$PWD/qdirectionallight_p.h \ + $$PWD/qenvironmentlight.h \ + $$PWD/qenvironmentlight_p.h \ $$PWD/qpointlight.h \ $$PWD/qpointlight_p.h \ $$PWD/qspotlight.h \ $$PWD/qspotlight_p.h \ + $$PWD/environmentlight_p.h \ $$PWD/light_p.h \ $$PWD/lightsource_p.h SOURCES += \ $$PWD/qabstractlight.cpp \ $$PWD/qdirectionallight.cpp \ + $$PWD/qenvironmentlight.cpp \ $$PWD/qpointlight.cpp \ $$PWD/qspotlight.cpp \ + $$PWD/environmentlight.cpp \ $$PWD/light.cpp \ $$PWD/lightsource.cpp diff --git a/src/render/lights/qenvironmentlight.cpp b/src/render/lights/qenvironmentlight.cpp new file mode 100644 index 000000000..a094af7b2 --- /dev/null +++ b/src/render/lights/qenvironmentlight.cpp @@ -0,0 +1,189 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qenvironmentlight.h" +#include "qenvironmentlight_p.h" +#include "qabstracttexture.h" + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender +{ + +/*! + * \qmltype EnvironmentLight + * \inqmlmodule Qt3D.Render + * \instantiates Qt3DRender::QEnvironmentLight + * \brief Encapsulate an environment light object in a Qt 3D scene. + * \since 5.9 + */ + +QEnvironmentLightPrivate::QEnvironmentLightPrivate() + : m_shaderData(new QShaderData) + , m_irradiance(nullptr) + , m_specular(nullptr) +{ +} + +QEnvironmentLightPrivate::~QEnvironmentLightPrivate() +{ +} + +Qt3DCore::QNodeCreatedChangeBasePtr QEnvironmentLight::createNodeCreationChange() const +{ + auto creationChange = Qt3DCore::QNodeCreatedChangePtr::create(this); + auto &data = creationChange->data; + Q_D(const QEnvironmentLight); + data.shaderDataId = qIdForNode(d->m_shaderData); + return creationChange; +} + +/*! + \class Qt3DRender::QEnvironmentLight + \inmodule Qt3DRender + \brief Encapsulate an environment light object in a Qt 3D scene. + \since 5.9 +*/ + +QEnvironmentLight::QEnvironmentLight(Qt3DCore::QNode *parent) + : QComponent(*new QEnvironmentLightPrivate, parent) +{ + Q_D(QEnvironmentLight); + d->m_shaderData->setParent(this); +} + +/*! \internal */ +QEnvironmentLight::QEnvironmentLight(QEnvironmentLightPrivate &dd, QNode *parent) + : QComponent(dd, parent) +{ + Q_D(QEnvironmentLight); + d->m_shaderData->setParent(this); +} + +QEnvironmentLight::~QEnvironmentLight() +{ +} + +/*! + \qmlproperty Texture EnvironmentLight::irradiance + + Holds the current environment irradiance map texture. + + By default, the environment irradiance texture is null. +*/ + +/*! + \property QEnvironmentLight::irradiance + + Holds the current environment irradiance map texture. + + By default, the environment irradiance texture is null. +*/ +QAbstractTexture *QEnvironmentLight::irradiance() const +{ + Q_D(const QEnvironmentLight); + return d->m_irradiance; +} + +/*! + \qmlproperty Texture EnvironmentLight::specular + + Holds the current environment specular map texture. + + By default, the environment specular texture is null. +*/ + +/*! + \property QEnvironmentLight::specular + + Holds the current environment specular map texture. + + By default, the environment specular texture is null. +*/ +QAbstractTexture *QEnvironmentLight::specular() const +{ + Q_D(const QEnvironmentLight); + return d->m_specular; +} + +void QEnvironmentLight::setIrradiance(QAbstractTexture *i) +{ + Q_D(QEnvironmentLight); + if (irradiance() == i) + return; + + if (irradiance()) + d->unregisterDestructionHelper(irradiance()); + + if (i && !i->parent()) + i->setParent(this); + + d->m_irradiance = i; + d->m_shaderData->setProperty("irradiance", QVariant::fromValue(i)); + + if (i) + d->registerDestructionHelper(i, &QEnvironmentLight::setIrradiance, i); + + emit irradianceChanged(i); +} + +void QEnvironmentLight::setSpecular(QAbstractTexture *s) +{ + Q_D(QEnvironmentLight); + if (specular() == s) + return; + + if (irradiance()) + d->unregisterDestructionHelper(specular()); + + if (s && !s->parent()) + s->setParent(this); + + d->m_specular = s; + d->m_shaderData->setProperty("specular", QVariant::fromValue(s)); + + if (s) + d->registerDestructionHelper(s, &QEnvironmentLight::setSpecular, s); + + emit specularChanged(s); +} + +} // namespace Qt3DRender + +QT_END_NAMESPACE diff --git a/src/render/lights/qenvironmentlight.h b/src/render/lights/qenvironmentlight.h new file mode 100644 index 000000000..0a5087c42 --- /dev/null +++ b/src/render/lights/qenvironmentlight.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3DRENDER_QENVIRONMENTLIGHT_H +#define QT3DRENDER_QENVIRONMENTLIGHT_H + +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +class QAbstractTexture; +class QEnvironmentLightPrivate; + +class QT3DRENDERSHARED_EXPORT QEnvironmentLight : public Qt3DCore::QComponent +{ + Q_OBJECT + Q_PROPERTY(Qt3DRender::QAbstractTexture *irradiance READ irradiance WRITE setIrradiance NOTIFY irradianceChanged) + Q_PROPERTY(Qt3DRender::QAbstractTexture *specular READ specular WRITE setSpecular NOTIFY specularChanged) + +public: + explicit QEnvironmentLight(Qt3DCore::QNode *parent = nullptr); + ~QEnvironmentLight(); + + Qt3DRender::QAbstractTexture *irradiance() const; + Qt3DRender::QAbstractTexture *specular() const; + +public Q_SLOTS: + void setIrradiance(Qt3DRender::QAbstractTexture *irradiance); + void setSpecular(Qt3DRender::QAbstractTexture *specular); + +protected: + explicit QEnvironmentLight(QEnvironmentLightPrivate &dd, Qt3DCore::QNode *parent = nullptr); + +Q_SIGNALS: + void irradianceChanged(Qt3DRender::QAbstractTexture *environmentIrradiance); + void specularChanged(Qt3DRender::QAbstractTexture *environmentSpecular); + +private: + Q_DECLARE_PRIVATE(QEnvironmentLight) + Qt3DCore::QNodeCreatedChangeBasePtr createNodeCreationChange() const Q_DECL_OVERRIDE; +}; + +} // namespace Qt3DRender + +QT_END_NAMESPACE + +#endif // QT3DRENDER_QENVIRONMENTLIGHT_H diff --git a/src/render/lights/qenvironmentlight_p.h b/src/render/lights/qenvironmentlight_p.h new file mode 100644 index 000000000..e98da5f59 --- /dev/null +++ b/src/render/lights/qenvironmentlight_p.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3DRENDER_QENVIRONMENTLIGHT_P_H +#define QT3DRENDER_QENVIRONMENTLIGHT_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +class QAbstractTexture; +class QEnvironmentLight; + +class Q_AUTOTEST_EXPORT QEnvironmentLightPrivate : public Qt3DCore::QComponentPrivate +{ +public: + explicit QEnvironmentLightPrivate(); + ~QEnvironmentLightPrivate(); + + Q_DECLARE_PUBLIC(QEnvironmentLight) + QShaderData *m_shaderData; + QAbstractTexture *m_irradiance; + QAbstractTexture *m_specular; +}; + +struct QEnvironmentLightData +{ + Qt3DCore::QNodeId shaderDataId; +}; + +} + +QT_END_NAMESPACE + +#endif // QT3DRENDER_QENVIRONMENTLIGHT_P_H diff --git a/tests/auto/render/qenvironmentlight/qenvironmentlight.pro b/tests/auto/render/qenvironmentlight/qenvironmentlight.pro new file mode 100644 index 000000000..8a66f65ba --- /dev/null +++ b/tests/auto/render/qenvironmentlight/qenvironmentlight.pro @@ -0,0 +1,11 @@ +TEMPLATE = app + +TARGET = tst_environmentlight + +QT += core-private 3dcore 3dcore-private 3drender 3drender-private testlib + +CONFIG += testcase + +SOURCES += tst_qenvironmentlight.cpp + +include(../../core/common/common.pri) diff --git a/tests/auto/render/qenvironmentlight/tst_qenvironmentlight.cpp b/tests/auto/render/qenvironmentlight/tst_qenvironmentlight.cpp new file mode 100644 index 000000000..76b3603c9 --- /dev/null +++ b/tests/auto/render/qenvironmentlight/tst_qenvironmentlight.cpp @@ -0,0 +1,301 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $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 +#include + +#include +#include +#include +#include + +#include +#include +#include "testpostmanarbiter.h" + +class tst_QEnvironmentLight: public QObject +{ + Q_OBJECT +private Q_SLOTS: + void checkDefaultConstruction() + { + // GIVEN + Qt3DRender::QEnvironmentLight light; + + // THEN + QVERIFY(light.findChild()); + QCOMPARE(light.irradiance(), nullptr); + QCOMPARE(light.specular(), nullptr); + } + + void shouldTakeOwnershipOfParentlessTextures() + { + // GIVEN + Qt3DRender::QEnvironmentLight light; + auto irradiance = new Qt3DRender::QTexture2D; + auto specular = new Qt3DRender::QTexture2D; + + // WHEN + light.setIrradiance(irradiance); + light.setSpecular(specular); + + // THEN + QCOMPARE(irradiance->parent(), &light); + QCOMPARE(specular->parent(), &light); + } + + void shouldNotChangeOwnershipOfParentedTextures() + { + // GIVEN + Qt3DCore::QNode node; + Qt3DRender::QEnvironmentLight light; + auto irradiance = new Qt3DRender::QTexture2D(&node); + auto specular = new Qt3DRender::QTexture2D(&node); + + // WHEN + light.setIrradiance(irradiance); + light.setSpecular(specular); + + // WHEN + delete irradiance; + delete specular; + + // THEN + } + + void checkPropertyChanges() + { + // GIVEN + Qt3DRender::QEnvironmentLight light; + auto shaderData = light.findChild(); + + { + auto texture = new Qt3DRender::QTexture2D(&light); + QSignalSpy spy(&light, &Qt3DRender::QEnvironmentLight::irradianceChanged); + + // WHEN + light.setIrradiance(texture); + + // THEN + QCOMPARE(light.irradiance(), texture); + QCOMPARE(shaderData->property("irradiance").value(), texture); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.takeFirst().first().value(), texture); + + // WHEN + light.setIrradiance(texture); + + // THEN + QCOMPARE(light.irradiance(), texture); + QCOMPARE(shaderData->property("irradiance").value(), texture); + QCOMPARE(spy.count(), 0); + + // WHEN + light.setIrradiance(nullptr); + + // THEN + QCOMPARE(light.irradiance(), nullptr); + QCOMPARE(shaderData->property("irradiance").value(), nullptr); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.takeFirst().first().value(), nullptr); + } + { + auto texture = new Qt3DRender::QTexture2D(&light); + QSignalSpy spy(&light, &Qt3DRender::QEnvironmentLight::irradianceChanged); + + // WHEN + light.setIrradiance(texture); + + // THEN + QCOMPARE(light.irradiance(), texture); + QCOMPARE(shaderData->property("irradiance").value(), texture); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.takeFirst().first().value(), texture); + + // WHEN + delete texture; + + // THEN + QCOMPARE(light.irradiance(), nullptr); + QCOMPARE(shaderData->property("irradiance").value(), nullptr); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.takeFirst().first().value(), nullptr); + } + { + auto texture = new Qt3DRender::QTexture2D; + QSignalSpy spy(&light, &Qt3DRender::QEnvironmentLight::irradianceChanged); + + // WHEN + light.setIrradiance(texture); + + // THEN + QCOMPARE(light.irradiance(), texture); + QCOMPARE(shaderData->property("irradiance").value(), texture); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.takeFirst().first().value(), texture); + + // WHEN + delete texture; + + // THEN + QCOMPARE(light.irradiance(), nullptr); + QCOMPARE(shaderData->property("irradiance").value(), nullptr); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.takeFirst().first().value(), nullptr); + } + { + auto texture = new Qt3DRender::QTexture2D(&light); + QSignalSpy spy(&light, &Qt3DRender::QEnvironmentLight::specularChanged); + + // WHEN + light.setSpecular(texture); + + // THEN + QCOMPARE(light.specular(), texture); + QCOMPARE(shaderData->property("specular").value(), texture); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.takeFirst().first().value(), texture); + + // WHEN + light.setSpecular(texture); + + // THEN + QCOMPARE(light.specular(), texture); + QCOMPARE(shaderData->property("specular").value(), texture); + QCOMPARE(spy.count(), 0); + + // WHEN + light.setSpecular(nullptr); + + // THEN + QCOMPARE(light.specular(), nullptr); + QCOMPARE(shaderData->property("specular").value(), nullptr); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.takeFirst().first().value(), nullptr); + } + { + auto texture = new Qt3DRender::QTexture2D(&light); + QSignalSpy spy(&light, &Qt3DRender::QEnvironmentLight::specularChanged); + + // WHEN + light.setSpecular(texture); + + // THEN + QCOMPARE(light.specular(), texture); + QCOMPARE(shaderData->property("specular").value(), texture); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.takeFirst().first().value(), texture); + + // WHEN + delete texture; + + // THEN + QCOMPARE(light.specular(), nullptr); + QCOMPARE(shaderData->property("specular").value(), nullptr); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.takeFirst().first().value(), nullptr); + } + { + auto texture = new Qt3DRender::QTexture2D; + QSignalSpy spy(&light, &Qt3DRender::QEnvironmentLight::specularChanged); + + // WHEN + light.setSpecular(texture); + + // THEN + QCOMPARE(light.specular(), texture); + QCOMPARE(shaderData->property("specular").value(), texture); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.takeFirst().first().value(), texture); + + // WHEN + delete texture; + + // THEN + QCOMPARE(light.specular(), nullptr); + QCOMPARE(shaderData->property("specular").value(), nullptr); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.takeFirst().first().value(), nullptr); + } + } + + void checkCreationData() + { + // GIVEN + Qt3DRender::QEnvironmentLight light; + auto shaderData = light.findChild(); + + // WHEN + QVector creationChanges; + + { + Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&light); + creationChanges = creationChangeGenerator.creationChanges(); + } + + // THEN + { + QCOMPARE(creationChanges.size(), 2); // EnvironmentLight + ShaderData + + const auto creationChangeData = qSharedPointerCast>(creationChanges.first()); + const Qt3DRender::QEnvironmentLightData cloneData = creationChangeData->data; + + QCOMPARE(cloneData.shaderDataId, shaderData->id()); + QCOMPARE(light.id(), creationChangeData->subjectId()); + QCOMPARE(light.isEnabled(), true); + QCOMPARE(light.isEnabled(), creationChangeData->isNodeEnabled()); + QCOMPARE(light.metaObject(), creationChangeData->metaObject()); + } + + // WHEN + light.setEnabled(false); + + { + Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&light); + creationChanges = creationChangeGenerator.creationChanges(); + } + + // THEN + { + QCOMPARE(creationChanges.size(), 2); // EnvironmentLight + ShaderData + + const auto creationChangeData = qSharedPointerCast>(creationChanges.first()); + const Qt3DRender::QEnvironmentLightData cloneData = creationChangeData->data; + + QCOMPARE(cloneData.shaderDataId, shaderData->id()); + QCOMPARE(light.id(), creationChangeData->subjectId()); + QCOMPARE(light.isEnabled(), false); + QCOMPARE(light.isEnabled(), creationChangeData->isNodeEnabled()); + QCOMPARE(light.metaObject(), creationChangeData->metaObject()); + } + } +}; + +QTEST_MAIN(tst_QEnvironmentLight) + +#include "tst_qenvironmentlight.moc" diff --git a/tests/auto/render/render.pro b/tests/auto/render/render.pro index 052b19dd3..fc98cf7da 100644 --- a/tests/auto/render/render.pro +++ b/tests/auto/render/render.pro @@ -31,6 +31,7 @@ qtConfig(private_tests) { qframegraphnode \ qlayerfilter \ qabstractlight \ + qenvironmentlight \ qray3d \ qrenderpassfilter \ qrendertargetselector \ -- cgit v1.2.3 From 4b1c9059d5e8f49acda36ad5467646eac5477a54 Mon Sep 17 00:00:00 2001 From: Kevin Ottens Date: Thu, 23 Feb 2017 16:06:02 +0100 Subject: Register QEnvironmentLight Change-Id: Id21a30ced06944ac627def707cb13d9212bace4a Reviewed-by: Sean Harmer --- src/render/frontend/qrenderaspect.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/render/frontend/qrenderaspect.cpp b/src/render/frontend/qrenderaspect.cpp index 81e8ff463..a1a65989f 100644 --- a/src/render/frontend/qrenderaspect.cpp +++ b/src/render/frontend/qrenderaspect.cpp @@ -75,6 +75,7 @@ #include #include #include +#include #include #include #include @@ -121,6 +122,7 @@ #include #include #include +#include #include #include #include @@ -223,6 +225,7 @@ void QRenderAspectPrivate::registerBackendTypes() q->registerBackendType(QSharedPointer >::create(m_renderer)); q->registerBackendType(QSharedPointer >::create(m_renderer)); q->registerBackendType(QSharedPointer::create(m_renderer, m_nodeManagers)); + q->registerBackendType(QSharedPointer >::create(m_renderer)); q->registerBackendType(QSharedPointer >::create(m_renderer)); q->registerBackendType(QSharedPointer >::create(m_renderer)); q->registerBackendType(QSharedPointer >::create(m_renderer)); @@ -288,6 +291,7 @@ void QRenderAspectPrivate::unregisterBackendTypes() unregisterBackendType(); unregisterBackendType(); unregisterBackendType(); + unregisterBackendType(); unregisterBackendType(); unregisterBackendType(); unregisterBackendType(); -- cgit v1.2.3 From 179045694287689d1d746a156874e95b76cd9efb Mon Sep 17 00:00:00 2001 From: Kevin Ottens Date: Thu, 23 Feb 2017 16:06:29 +0100 Subject: Expose QEnvironmentLight to QML Change-Id: I7925df5d4bec59c353e4a07bbbc57f5e0c4ff5ff Reviewed-by: Sean Harmer --- src/quick3d/imports/render/qt3dquick3drenderplugin.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/quick3d/imports/render/qt3dquick3drenderplugin.cpp b/src/quick3d/imports/render/qt3dquick3drenderplugin.cpp index 51214c8df..f162e3d2b 100644 --- a/src/quick3d/imports/render/qt3dquick3drenderplugin.cpp +++ b/src/quick3d/imports/render/qt3dquick3drenderplugin.cpp @@ -61,6 +61,7 @@ #include #include #include +#include #include #include #include @@ -229,6 +230,7 @@ void Qt3DQuick3DRenderPlugin::registerTypes(const char *uri) qmlRegisterUncreatableType(uri, 2, 0, "Light", QStringLiteral("Light is an abstract base class")); qmlRegisterType(uri, 2, 0, "PointLight"); qmlRegisterType(uri, 2, 0, "DirectionalLight"); + qmlRegisterType(uri, 2, 9, "EnvironmentLight"); qmlRegisterType(uri, 2, 0, "SpotLight"); // FrameGraph -- cgit v1.2.3 From c10fa3bf20f5ac000a0ba67f2ec8e101af040d6f Mon Sep 17 00:00:00 2001 From: Kevin Ottens Date: Thu, 23 Feb 2017 16:07:18 +0100 Subject: Integrate EnvironmentLight with Entity This will be needed to gather the environment lights in the scene. Change-Id: Icabcfb378c4938448bd241460b0f3fa3811c0287 Reviewed-by: Sean Harmer --- src/render/backend/entity.cpp | 32 ++++++++++++++++++++++++++++++++ src/render/backend/entity_p.h | 10 ++++++++++ tests/auto/render/entity/tst_entity.cpp | 12 +++++++++++- 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/src/render/backend/entity.cpp b/src/render/backend/entity.cpp index 42233c85a..898c1e36e 100644 --- a/src/render/backend/entity.cpp +++ b/src/render/backend/entity.cpp @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include @@ -118,6 +119,7 @@ void Entity::cleanup() m_levelOfDetailComponents.clear(); m_shaderDataComponents.clear(); m_lightComponents.clear(); + m_environmentLightComponents.clear(); m_localBoundingVolume.reset(); m_worldBoundingVolume.reset(); m_worldBoundingVolumeWithChildren.reset(); @@ -174,6 +176,7 @@ void Entity::initializeFromPeer(const QNodeCreatedChangeBasePtr &change) m_levelOfDetailComponents.clear(); m_shaderDataComponents.clear(); m_lightComponents.clear(); + m_environmentLightComponents.clear(); m_localBoundingVolume.reset(new Sphere(peerId())); m_worldBoundingVolume.reset(new Sphere(peerId())); m_worldBoundingVolumeWithChildren.reset(new Sphere(peerId())); @@ -293,6 +296,8 @@ void Entity::addComponent(Qt3DCore::QComponent *component) m_materialComponent = component->id(); } else if (qobject_cast(component) != nullptr) { m_lightComponents.append(component->id()); + } else if (qobject_cast(component) != nullptr) { + m_environmentLightComponents.append(component->id()); } else if (qobject_cast(component) != nullptr) { m_shaderDataComponents.append(component->id()); } else if (qobject_cast(component) != nullptr) { @@ -326,6 +331,8 @@ void Entity::addComponent(Qt3DCore::QNodeIdTypePair idAndType) m_materialComponent = id; } else if (type->inherits(&QAbstractLight::staticMetaObject)) { // QAbstractLight subclasses QShaderData m_lightComponents.append(id); + } else if (type->inherits(&QEnvironmentLight::staticMetaObject)) { + m_environmentLightComponents.append(id); } else if (type->inherits(&QShaderData::staticMetaObject)) { m_shaderDataComponents.append(id); } else if (type->inherits(&QGeometryRenderer::staticMetaObject)) { @@ -363,6 +370,8 @@ void Entity::removeComponent(Qt3DCore::QNodeId nodeId) // m_boundingVolumeDebugComponent = QNodeId(); } else if (m_lightComponents.contains(nodeId)) { m_lightComponents.removeAll(nodeId); + } else if (m_environmentLightComponents.contains(nodeId)) { + m_environmentLightComponents.removeAll(nodeId); } else if (m_computeComponent == nodeId) { m_computeComponent = QNodeId(); } @@ -456,6 +465,16 @@ QVector Entity::componentsHandle() const return lightHandles; } +template<> +QVector Entity::componentsHandle() const +{ + QVector lightHandles; + lightHandles.reserve(m_environmentLightComponents.size()); + for (QNodeId id : m_environmentLightComponents) + lightHandles.append(m_nodeManagers->environmentLightManager()->lookupHandle(id)); + return lightHandles; +} + template<> HComputeCommand Entity::componentHandle() const { @@ -534,6 +553,16 @@ QVector Entity::renderComponents() const return lights; } +template<> +QVector Entity::renderComponents() const +{ + QVector lights; + lights.reserve(m_environmentLightComponents.size()); + for (QNodeId id : m_environmentLightComponents) + lights.append(m_nodeManagers->environmentLightManager()->lookupResource(id)); + return lights; +} + //template<> //BoundingVolumeDebug *Entity::renderComponent() const //{ @@ -581,6 +610,9 @@ QNodeId Entity::componentUuid() const { return m_computeComponen template<> QVector Entity::componentsUuid() const { return m_lightComponents; } +template<> +QVector Entity::componentsUuid() const { return m_environmentLightComponents; } + RenderEntityFunctor::RenderEntityFunctor(AbstractRenderer *renderer, NodeManagers *manager) : m_nodeManagers(manager) , m_renderer(renderer) diff --git a/src/render/backend/entity_p.h b/src/render/backend/entity_p.h index c86019444..9f010509a 100644 --- a/src/render/backend/entity_p.h +++ b/src/render/backend/entity_p.h @@ -190,6 +190,7 @@ private: QVector m_levelOfDetailComponents; QVector m_shaderDataComponents; QVector m_lightComponents; + QVector m_environmentLightComponents; Qt3DCore::QNodeId m_geometryRendererComponent; Qt3DCore::QNodeId m_objectPickerComponent; Qt3DCore::QNodeId m_boundingVolumeDebugComponent; @@ -232,6 +233,9 @@ QVector Entity::componentsHandle() const; template<> QVector Entity::componentsHandle() const; +template<> +QVector Entity::componentsHandle() const; + template<> Q_AUTOTEST_EXPORT HComputeCommand Entity::componentHandle() const; @@ -266,6 +270,9 @@ QVector Entity::renderComponents() const; template<> QVector Entity::renderComponents() const; +template<> +QVector Entity::renderComponents() const; + template<> Q_AUTOTEST_EXPORT ComputeCommand *Entity::renderComponent() const; @@ -303,6 +310,9 @@ Q_AUTOTEST_EXPORT Qt3DCore::QNodeId Entity::componentUuid() cons template<> Q_AUTOTEST_EXPORT QVector Entity::componentsUuid() const; +template<> +Q_AUTOTEST_EXPORT QVector Entity::componentsUuid() const; + class RenderEntityFunctor : public Qt3DCore::QBackendNodeMapper { public: diff --git a/tests/auto/render/entity/tst_entity.cpp b/tests/auto/render/entity/tst_entity.cpp index 0bd3a6054..d1a222c92 100644 --- a/tests/auto/render/entity/tst_entity.cpp +++ b/tests/auto/render/entity/tst_entity.cpp @@ -38,6 +38,7 @@ #include #include +#include #include #include #include @@ -64,6 +65,7 @@ QNodeId computeJobUuid(Entity *entity) { return entity->componentUuid layersUuid(Entity *entity) { return entity->componentsUuid(); } QVector shadersUuid(Entity *entity) { return entity->componentsUuid(); } +QVector environmentLightsUuid(Entity *entity) { return entity->componentsUuid(); } class tst_RenderEntity : public QObject { @@ -86,7 +88,8 @@ private slots: << new QObjectPicker << new QLayer << new QShaderData - << new QComputeCommand; + << new QComputeCommand + << new QEnvironmentLight; QTest::newRow("all components") << components; } @@ -112,6 +115,7 @@ private slots: QVERIFY(entity.componentUuid().isNull()); QVERIFY(entity.componentsUuid().isEmpty()); QVERIFY(entity.componentsUuid().isEmpty()); + QVERIFY(entity.componentsUuid().isEmpty()); QVERIFY(!entity.isBoundingVolumeDirty()); QVERIFY(entity.childrenHandles().isEmpty()); @@ -139,6 +143,7 @@ private slots: QVERIFY(!entity.componentUuid().isNull()); QVERIFY(!entity.componentsUuid().isEmpty()); QVERIFY(!entity.componentsUuid().isEmpty()); + QVERIFY(!entity.componentsUuid().isEmpty()); QVERIFY(entity.isBoundingVolumeDirty()); QVERIFY(!entity.childrenHandles().isEmpty()); QVERIFY(renderer.dirtyBits() != 0); @@ -157,6 +162,7 @@ private slots: QVERIFY(entity.componentUuid().isNull()); QVERIFY(entity.componentsUuid().isEmpty()); QVERIFY(entity.componentsUuid().isEmpty()); + QVERIFY(entity.componentsUuid().isEmpty()); QVERIFY(!entity.isBoundingVolumeDirty()); QVERIFY(entity.childrenHandles().isEmpty()); containsAll = entity.containsComponentsOfType(); @@ -236,6 +242,10 @@ private slots: components.clear(); components << new QShaderData << new QShaderData << new QShaderData; QTest::newRow("shader data") << components << reinterpret_cast(shadersUuid); + + components.clear(); + components << new QEnvironmentLight << new QEnvironmentLight << new QEnvironmentLight; + QTest::newRow("environmentLights") << components << reinterpret_cast(environmentLightsUuid); } void shouldHandleComponentsEvents() -- cgit v1.2.3 From e40572b9bcbf85c0c978c6234ecfd33354748525 Mon Sep 17 00:00:00 2001 From: Kevin Ottens Date: Thu, 23 Feb 2017 16:10:41 +0100 Subject: The LightGatherer job also collects the EnvironmentLight Change-Id: Idf8a6d03bce309c27ef1ae0c47549f02a21c3eba Reviewed-by: Sean Harmer --- src/render/jobs/lightgatherer.cpp | 9 +++++++++ src/render/jobs/lightgatherer_p.h | 8 ++++++++ 2 files changed, 17 insertions(+) diff --git a/src/render/jobs/lightgatherer.cpp b/src/render/jobs/lightgatherer.cpp index 39023bc35..e62544f15 100644 --- a/src/render/jobs/lightgatherer.cpp +++ b/src/render/jobs/lightgatherer.cpp @@ -51,6 +51,7 @@ namespace Render { LightGatherer::LightGatherer() : Qt3DCore::QAspectJob() , m_manager(nullptr) + , m_environmentLight(nullptr) { SET_JOB_RUN_STAT_TYPE(this, JobTypes::LightGathering, 0); } @@ -58,13 +59,21 @@ LightGatherer::LightGatherer() void LightGatherer::run() { const QVector handles = m_manager->activeHandles(); + int envLightCount = 0; for (const HEntity handle : handles) { Entity *node = m_manager->data(handle); const QVector lights = node->renderComponents(); if (!lights.isEmpty()) m_lights.push_back(LightSource(node, lights)); + const QVector envLights = node->renderComponents(); + envLightCount += envLights.size(); + if (!envLights.isEmpty() && !m_environmentLight) + m_environmentLight = envLights.first(); } + + if (envLightCount > 1) + qWarning() << "More than one environment light found, extra instances are ignored"; } } // Render diff --git a/src/render/jobs/lightgatherer_p.h b/src/render/jobs/lightgatherer_p.h index e2954fd07..4eaeb8f19 100644 --- a/src/render/jobs/lightgatherer_p.h +++ b/src/render/jobs/lightgatherer_p.h @@ -61,6 +61,7 @@ namespace Qt3DRender { namespace Render { class EntityManager; +class EnvironmentLight; class Q_AUTOTEST_EXPORT LightGatherer : public Qt3DCore::QAspectJob { @@ -69,12 +70,19 @@ public: inline void setManager(EntityManager *manager) Q_DECL_NOTHROW { m_manager = manager; } inline QVector &lights() { return m_lights; } + inline EnvironmentLight *takeEnvironmentLight() + { + auto envLight = m_environmentLight; + m_environmentLight = nullptr; + return envLight; + } void run() Q_DECL_FINAL; private: EntityManager *m_manager; QVector m_lights; + EnvironmentLight *m_environmentLight; }; typedef QSharedPointer LightGathererPtr; -- cgit v1.2.3 From 98baac15388b536b5108cccc0cf3311c4d9d048c Mon Sep 17 00:00:00 2001 From: Kevin Ottens Date: Thu, 23 Feb 2017 16:12:34 +0100 Subject: RenderView: bind the found EnvironmentLight If an EnvironmentLight is found, we bind its textures via the ShaderData and also give a non null value to envLightCount, otherwise it gets a 0. This new counter will be used in the shaders. Change-Id: I4a5b61ddcf44d78cde3d500eea3654b6681296e8 Reviewed-by: Sean Harmer --- src/render/backend/renderview.cpp | 24 +++++++++++++++++++++--- src/render/backend/renderview_p.h | 4 +++- src/render/backend/renderviewbuilder.cpp | 1 + 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/src/render/backend/renderview.cpp b/src/render/backend/renderview.cpp index bd184594f..5c17d9a24 100644 --- a/src/render/backend/renderview.cpp +++ b/src/render/backend/renderview.cpp @@ -220,6 +220,7 @@ RenderView::RenderView() , m_compute(false) , m_frustumCulling(false) , m_memoryBarrier(QMemoryBarrier::None) + , m_environmentLight(nullptr) { m_workGroups[0] = 1; m_workGroups[1] = 1; @@ -414,7 +415,12 @@ QVector RenderView::buildDrawRenderCommands(const QVectorworldTransform()), lightSources.mid(0, std::max(lightSources.size(), MAX_LIGHTS))); + setShaderAndUniforms(command, + pass, + globalParameters, + *(node->worldTransform()), + lightSources.mid(0, std::max(lightSources.size(), MAX_LIGHTS)), + m_environmentLight); // Store all necessary information for actual drawing if command is valid command->m_isValid = !command->m_attributes.empty(); @@ -514,7 +520,8 @@ QVector RenderView::buildComputeRenderCommands(const QVectorworldTransform()), - QVector()); + QVector(), + nullptr); commands.append(command); } } @@ -702,7 +709,7 @@ void RenderView::buildSortingKey(RenderCommand *command) const } void RenderView::setShaderAndUniforms(RenderCommand *command, RenderPass *rPass, ParameterInfoList ¶meters, const QMatrix4x4 &worldTransform, - const QVector &activeLightSources) const + const QVector &activeLightSources, EnvironmentLight *environmentLight) const { // The VAO Handle is set directly in the renderer thread so as to avoid having to use a mutex here // Set shader, technique, and effect by basically doing : @@ -830,6 +837,17 @@ void RenderView::setShaderAndUniforms(RenderCommand *command, RenderPass *rPass, setUniformValue(command->m_parameterPack, LIGHT_COLOR_NAMES[0], QVector3D(1.0f, 1.0f, 1.0f)); setUniformValue(command->m_parameterPack, LIGHT_INTENSITY_NAMES[0], 0.5f); } + + // Environment Light + int envLightCount = 0; + if (environmentLight && environmentLight->isEnabled()) { + ShaderData *shaderData = m_manager->shaderDataManager()->lookupResource(environmentLight->shaderData()); + if (shaderData) { + setDefaultUniformBlockShaderDataValue(command->m_parameterPack, shader, shaderData, QStringLiteral("envLight")); + envLightCount = 1; + } + } + setUniformValue(command->m_parameterPack, StringToInt::lookupId(QStringLiteral("envLightCount")), envLightCount); } // Set frag outputs in the shaders if hash not empty if (!fragOutputs.isEmpty()) diff --git a/src/render/backend/renderview_p.h b/src/render/backend/renderview_p.h index 5c0f5971a..440d51638 100644 --- a/src/render/backend/renderview_p.h +++ b/src/render/backend/renderview_p.h @@ -215,6 +215,7 @@ public: QSurface *surface() const { return m_surface; } void setLightSources(const QVector &lightSources) Q_DECL_NOTHROW { m_lightSources = lightSources; } + void setEnvironmentLight(EnvironmentLight *environmentLight) Q_DECL_NOTHROW { m_environmentLight = environmentLight; } void updateMatrices(); @@ -253,7 +254,7 @@ public: private: void setShaderAndUniforms(RenderCommand *command, RenderPass *pass, ParameterInfoList ¶meters, const QMatrix4x4 &worldTransform, - const QVector &activeLightSources) const; + const QVector &activeLightSources, EnvironmentLight *environmentLight) const; mutable QThreadStorage m_localData; @@ -289,6 +290,7 @@ private: // the render thread is submitting these commands. QVector m_commands; mutable QVector m_lightSources; + EnvironmentLight *m_environmentLight; QHash> m_parameters; diff --git a/src/render/backend/renderviewbuilder.cpp b/src/render/backend/renderviewbuilder.cpp index 55d8ba462..f1355d27e 100644 --- a/src/render/backend/renderviewbuilder.cpp +++ b/src/render/backend/renderviewbuilder.cpp @@ -190,6 +190,7 @@ public: if (!rv->noDraw()) { // Set the light sources rv->setLightSources(std::move(m_lightGathererJob->lights())); + rv->setEnvironmentLight(m_lightGathererJob->takeEnvironmentLight()); // We sort the vector so that the removal can then be performed linearly -- cgit v1.2.3 From 271ff077ed2235eee149f23f157d8e17d058af4b Mon Sep 17 00:00:00 2001 From: Kevin Ottens Date: Thu, 23 Feb 2017 16:14:21 +0100 Subject: MetalRough: Don't call pbrIblModel if we have no env light Change-Id: I4a09a4a8768c6d5db640b5482ea41601961006fe Reviewed-by: Sean Harmer --- src/extras/shaders/gl3/light.inc.frag | 1 + src/extras/shaders/gl3/metalrough.frag | 14 ++++++++------ src/extras/shaders/gl3/metalroughuniform.frag | 12 +++++++----- 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/extras/shaders/gl3/light.inc.frag b/src/extras/shaders/gl3/light.inc.frag index aaec83840..ce5c581cf 100644 --- a/src/extras/shaders/gl3/light.inc.frag +++ b/src/extras/shaders/gl3/light.inc.frag @@ -22,6 +22,7 @@ struct EnvironmentLight { samplerCube specular; // For specular contribution }; uniform EnvironmentLight envLight; +uniform int envLightCount = 0; void adsModelNormalMapped(const in vec3 worldPos, const in vec3 tsNormal, diff --git a/src/extras/shaders/gl3/metalrough.frag b/src/extras/shaders/gl3/metalrough.frag index 4712e7cd8..225541775 100644 --- a/src/extras/shaders/gl3/metalrough.frag +++ b/src/extras/shaders/gl3/metalrough.frag @@ -317,12 +317,14 @@ void main() vec3 tNormal = 2.0 * texture(normalMap, texCoord).rgb - vec3(1.0); vec3 wNormal = normalize(transpose(worldToTangentMatrix) * tNormal); - cLinear += pbrIblModel(wNormal, - wView, - baseColor, - metalness, - roughness, - ambientOcclusion); + for (int i = 0; i < envLightCount; ++i) { + cLinear += pbrIblModel(wNormal, + wView, + baseColor, + metalness, + roughness, + ambientOcclusion); + } for (int i = 0; i < lightCount; ++i) { cLinear += pbrModel(i, diff --git a/src/extras/shaders/gl3/metalroughuniform.frag b/src/extras/shaders/gl3/metalroughuniform.frag index 8be76e9c2..a851c957c 100644 --- a/src/extras/shaders/gl3/metalroughuniform.frag +++ b/src/extras/shaders/gl3/metalroughuniform.frag @@ -288,11 +288,13 @@ void main() vec3 cLinear = vec3(0.0); vec3 worldView = normalize(eyePosition - worldPosition); - cLinear += pbrIblModel(worldNormal, - worldView, - baseColor.rgb, - metalness, - roughness); + for (int i = 0; i < envLightCount; ++i) { + cLinear += pbrIblModel(worldNormal, + worldView, + baseColor.rgb, + metalness, + roughness); + } for (int i = 0; i < lightCount; ++i) { cLinear += pbrModel(i, -- cgit v1.2.3 From 2a485273c1da1f56412bfd19795ac5a29331b770 Mon Sep 17 00:00:00 2001 From: Kevin Ottens Date: Thu, 23 Feb 2017 16:27:24 +0100 Subject: Remove env light API from metal/rough materials Now that EnvironmentLight is available in Qt3DRender this is no longer necessary. We have a much better way to set the environment lighting now. Change-Id: I492d1383aaf4e60b434c7ab94f3696e499545f9f Reviewed-by: Sean Harmer --- src/extras/defaults/qmetalroughmaterial.cpp | 75 ++-------------------- src/extras/defaults/qmetalroughmaterial.h | 8 --- src/extras/defaults/qmetalroughmaterial_p.h | 2 - .../defaults/qtexturedmetalroughmaterial.cpp | 74 ++------------------- src/extras/defaults/qtexturedmetalroughmaterial.h | 8 --- .../defaults/qtexturedmetalroughmaterial_p.h | 2 - 6 files changed, 14 insertions(+), 155 deletions(-) diff --git a/src/extras/defaults/qmetalroughmaterial.cpp b/src/extras/defaults/qmetalroughmaterial.cpp index 3081fa787..ea213ab82 100644 --- a/src/extras/defaults/qmetalroughmaterial.cpp +++ b/src/extras/defaults/qmetalroughmaterial.cpp @@ -94,10 +94,6 @@ void QMetalRoughMaterialPrivate::init() this, &QMetalRoughMaterialPrivate::handleMetallicChanged); connect(m_roughnessParameter, &Qt3DRender::QParameter::valueChanged, this, &QMetalRoughMaterialPrivate::handleRoughnessChanged); - connect(m_environmentIrradianceParameter, &Qt3DRender::QParameter::valueChanged, - this, &QMetalRoughMaterialPrivate::handleEnvironmentIrradianceChanged); - connect(m_environmentSpecularParameter, &Qt3DRender::QParameter::valueChanged, - this, &QMetalRoughMaterialPrivate::handleEnvironmentSpecularChanged); m_metalRoughGL3Shader->setVertexShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/gl3/metalrough.vert")))); m_metalRoughGL3Shader->setFragmentShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/gl3/metalroughuniform.frag")))); @@ -120,6 +116,13 @@ void QMetalRoughMaterialPrivate::init() m_metalRoughEffect->addParameter(m_baseColorParameter); m_metalRoughEffect->addParameter(m_metalnessParameter); m_metalRoughEffect->addParameter(m_roughnessParameter); + + // Note that even though those parameters are not exposed in the API, + // they need to be kept around for now due to a bug in some drivers/GPUs + // (at least Intel) which cause issues with unbound textures even if you + // don't try to sample from them. + // Can probably go away once we generate the shaders and deal in this + // case in a better way. m_metalRoughEffect->addParameter(m_environmentIrradianceParameter); m_metalRoughEffect->addParameter(m_environmentSpecularParameter); @@ -143,18 +146,6 @@ void QMetalRoughMaterialPrivate::handleRoughnessChanged(const QVariant &var) emit q->roughnessChanged(var.toFloat()); } -void QMetalRoughMaterialPrivate::handleEnvironmentIrradianceChanged(const QVariant &var) -{ - Q_Q(QMetalRoughMaterial); - emit q->environmentIrradianceChanged(var.value()); -} - -void QMetalRoughMaterialPrivate::handleEnvironmentSpecularChanged(const QVariant &var) -{ - Q_Q(QMetalRoughMaterial); - emit q->environmentSpecularChanged(var.value()); -} - /*! \class Qt3DExtras::QMetalRoughMaterial \brief The QMetalRoughMaterial provides a default implementation of PBR @@ -226,46 +217,6 @@ float QMetalRoughMaterial::roughness() const return d->m_roughnessParameter->value().toFloat(); } -/*! - \property QMetalRoughMaterial::environmentIrradiance - - Holds the current environment irradiance map texture. - - By default, the environment irradiance texture has the following properties: - - \list - \li Linear minification and magnification filters - \li Linear mipmap with mipmapping enabled - \li Repeat wrap mode - \li Maximum anisotropy of 16.0 - \endlist -*/ -QAbstractTexture *QMetalRoughMaterial::environmentIrradiance() const -{ - Q_D(const QMetalRoughMaterial); - return d->m_environmentIrradianceParameter->value().value(); -} - -/*! - \property QMetalRoughMaterial::environmentSpecular - - Holds the current environment specular map texture. - - By default, the environment specular texture has the following properties: - - \list - \li Linear minification and magnification filters - \li Linear mipmap with mipmapping enabled - \li Repeat wrap mode - \li Maximum anisotropy of 16.0 - \endlist -*/ -QAbstractTexture *QMetalRoughMaterial::environmentSpecular() const -{ - Q_D(const QMetalRoughMaterial); - return d->m_environmentSpecularParameter->value().value(); -} - void QMetalRoughMaterial::setBaseColor(const QColor &baseColor) { Q_D(QMetalRoughMaterial); @@ -284,18 +235,6 @@ void QMetalRoughMaterial::setRoughness(float roughness) d->m_roughnessParameter->setValue(QVariant::fromValue(roughness)); } -void QMetalRoughMaterial::setEnvironmentIrradiance(QAbstractTexture *environmentIrradiance) -{ - Q_D(QMetalRoughMaterial); - d->m_environmentIrradianceParameter->setValue(QVariant::fromValue(environmentIrradiance)); -} - -void QMetalRoughMaterial::setEnvironmentSpecular(QAbstractTexture *environmentSpecular) -{ - Q_D(QMetalRoughMaterial); - d->m_environmentSpecularParameter->setValue(QVariant::fromValue(environmentSpecular)); -} - } // namespace Qt3DExtras QT_END_NAMESPACE diff --git a/src/extras/defaults/qmetalroughmaterial.h b/src/extras/defaults/qmetalroughmaterial.h index e13d6c1e9..a7de7b80c 100644 --- a/src/extras/defaults/qmetalroughmaterial.h +++ b/src/extras/defaults/qmetalroughmaterial.h @@ -60,8 +60,6 @@ class QT3DEXTRASSHARED_EXPORT QMetalRoughMaterial : public Qt3DRender::QMaterial Q_PROPERTY(QColor baseColor READ baseColor WRITE setBaseColor NOTIFY baseColorChanged) Q_PROPERTY(float metalness READ metalness WRITE setMetalness NOTIFY metalnessChanged) Q_PROPERTY(float roughness READ roughness WRITE setRoughness NOTIFY roughnessChanged) - Q_PROPERTY(Qt3DRender::QAbstractTexture *environmentIrradiance READ environmentIrradiance WRITE setEnvironmentIrradiance NOTIFY environmentIrradianceChanged) - Q_PROPERTY(Qt3DRender::QAbstractTexture *environmentSpecular READ environmentSpecular WRITE setEnvironmentSpecular NOTIFY environmentSpecularChanged) public: explicit QMetalRoughMaterial(Qt3DCore::QNode *parent = nullptr); @@ -70,22 +68,16 @@ public: QColor baseColor() const; float metalness() const; float roughness() const; - Qt3DRender::QAbstractTexture *environmentIrradiance() const; - Qt3DRender::QAbstractTexture *environmentSpecular() const; public Q_SLOTS: void setBaseColor(const QColor &baseColor); void setMetalness(float metalness); void setRoughness(float roughness); - void setEnvironmentIrradiance(Qt3DRender::QAbstractTexture *environmentIrradiance); - void setEnvironmentSpecular(Qt3DRender::QAbstractTexture *environmentSpecular); Q_SIGNALS: void baseColorChanged(const QColor &baseColor); void metalnessChanged(float metalness); void roughnessChanged(float roughness); - void environmentIrradianceChanged(Qt3DRender::QAbstractTexture *environmentIrradiance); - void environmentSpecularChanged(Qt3DRender::QAbstractTexture *environmentSpecular); protected: QMetalRoughMaterial(QMetalRoughMaterialPrivate &dd, Qt3DCore::QNode *parent = nullptr); diff --git a/src/extras/defaults/qmetalroughmaterial_p.h b/src/extras/defaults/qmetalroughmaterial_p.h index b406df996..3090b9757 100644 --- a/src/extras/defaults/qmetalroughmaterial_p.h +++ b/src/extras/defaults/qmetalroughmaterial_p.h @@ -81,8 +81,6 @@ public: void handleBaseColorChanged(const QVariant &var); void handleMetallicChanged(const QVariant &var); void handleRoughnessChanged(const QVariant &var); - void handleEnvironmentIrradianceChanged(const QVariant &var); - void handleEnvironmentSpecularChanged(const QVariant &var); Qt3DRender::QAbstractTexture *m_environmentIrradianceTexture; Qt3DRender::QAbstractTexture *m_environmentSpecularTexture; diff --git a/src/extras/defaults/qtexturedmetalroughmaterial.cpp b/src/extras/defaults/qtexturedmetalroughmaterial.cpp index b8faff7ed..e09517866 100644 --- a/src/extras/defaults/qtexturedmetalroughmaterial.cpp +++ b/src/extras/defaults/qtexturedmetalroughmaterial.cpp @@ -135,10 +135,6 @@ void QTexturedMetalRoughMaterialPrivate::init() this, &QTexturedMetalRoughMaterialPrivate::handleAmbientOcclusionChanged); connect(m_normalParameter, &Qt3DRender::QParameter::valueChanged, this, &QTexturedMetalRoughMaterialPrivate::handleNormalChanged); - connect(m_environmentIrradianceParameter, &Qt3DRender::QParameter::valueChanged, - this, &QTexturedMetalRoughMaterialPrivate::handleEnvironmentIrradianceChanged); - connect(m_environmentSpecularParameter, &Qt3DRender::QParameter::valueChanged, - this, &QTexturedMetalRoughMaterialPrivate::handleEnvironmentSpecularChanged); m_metalRoughGL3Shader->setVertexShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/gl3/metalrough.vert")))); m_metalRoughGL3Shader->setFragmentShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/gl3/metalrough.frag")))); @@ -163,6 +159,13 @@ void QTexturedMetalRoughMaterialPrivate::init() m_metalRoughEffect->addParameter(m_roughnessParameter); m_metalRoughEffect->addParameter(m_ambientOcclusionParameter); m_metalRoughEffect->addParameter(m_normalParameter); + + // Note that even though those parameters are not exposed in the API, + // they need to be kept around for now due to a bug in some drivers/GPUs + // (at least Intel) which cause issues with unbound textures even if you + // don't try to sample from them. + // Can probably go away once we generate the shaders and deal in this + // case in a better way. m_metalRoughEffect->addParameter(m_environmentIrradianceParameter); m_metalRoughEffect->addParameter(m_environmentSpecularParameter); @@ -197,18 +200,6 @@ void QTexturedMetalRoughMaterialPrivate::handleNormalChanged(const QVariant &var emit q->normalChanged(var.value()); } -void QTexturedMetalRoughMaterialPrivate::handleEnvironmentIrradianceChanged(const QVariant &var) -{ - Q_Q(QTexturedMetalRoughMaterial); - emit q->environmentIrradianceChanged(var.value()); -} - -void QTexturedMetalRoughMaterialPrivate::handleEnvironmentSpecularChanged(const QVariant &var) -{ - Q_Q(QTexturedMetalRoughMaterial); - emit q->environmentSpecularChanged(var.value()); -} - /*! \class Qt3DExtras::QTexturedMetalRoughMaterial \brief The QTexturedMetalRoughMaterial provides a default implementation of PBR @@ -346,45 +337,6 @@ QAbstractTexture *QTexturedMetalRoughMaterial::normal() const return d->m_normalParameter->value().value(); } -/*! - \property QTexturedMetalRoughMaterial::environmentIrradiance - - Holds the current environment irradiance map texture. - - By default, the environment irradiance texture has the following properties: - - \list - \li Linear minification and magnification filters - \li Linear mipmap with mipmapping enabled - \li Repeat wrap mode - \li Maximum anisotropy of 16.0 - \endlist -*/ -QAbstractTexture *QTexturedMetalRoughMaterial::environmentIrradiance() const -{ - Q_D(const QTexturedMetalRoughMaterial); - return d->m_environmentIrradianceParameter->value().value(); -} - -/*! - \property QTexturedMetalRoughMaterial::environmentSpecular - - Holds the current environment specular map texture. - - By default, the environment specular texture has the following properties: - - \list - \li Linear minification and magnification filters - \li Linear mipmap with mipmapping enabled - \li Repeat wrap mode - \li Maximum anisotropy of 16.0 - \endlist -*/ -QAbstractTexture *QTexturedMetalRoughMaterial::environmentSpecular() const -{ - Q_D(const QTexturedMetalRoughMaterial); - return d->m_environmentSpecularParameter->value().value(); -} void QTexturedMetalRoughMaterial::setBaseColor(QAbstractTexture *baseColor) { @@ -416,18 +368,6 @@ void QTexturedMetalRoughMaterial::setNormal(QAbstractTexture *normal) d->m_normalParameter->setValue(QVariant::fromValue(normal)); } -void QTexturedMetalRoughMaterial::setEnvironmentIrradiance(QAbstractTexture *environmentIrradiance) -{ - Q_D(QTexturedMetalRoughMaterial); - d->m_environmentIrradianceParameter->setValue(QVariant::fromValue(environmentIrradiance)); -} - -void QTexturedMetalRoughMaterial::setEnvironmentSpecular(QAbstractTexture *environmentSpecular) -{ - Q_D(QTexturedMetalRoughMaterial); - d->m_environmentSpecularParameter->setValue(QVariant::fromValue(environmentSpecular)); -} - } // namespace Qt3DExtras QT_END_NAMESPACE diff --git a/src/extras/defaults/qtexturedmetalroughmaterial.h b/src/extras/defaults/qtexturedmetalroughmaterial.h index c5c3fce33..27c33ad6d 100644 --- a/src/extras/defaults/qtexturedmetalroughmaterial.h +++ b/src/extras/defaults/qtexturedmetalroughmaterial.h @@ -57,8 +57,6 @@ class QT3DEXTRASSHARED_EXPORT QTexturedMetalRoughMaterial : public Qt3DRender::Q Q_PROPERTY(Qt3DRender::QAbstractTexture *roughness READ roughness WRITE setRoughness NOTIFY roughnessChanged) Q_PROPERTY(Qt3DRender::QAbstractTexture *ambientOcclusion READ ambientOcclusion WRITE setAmbientOcclusion NOTIFY ambientOcclusionChanged) Q_PROPERTY(Qt3DRender::QAbstractTexture *normal READ normal WRITE setNormal NOTIFY normalChanged) - Q_PROPERTY(Qt3DRender::QAbstractTexture *environmentIrradiance READ environmentIrradiance WRITE setEnvironmentIrradiance NOTIFY environmentIrradianceChanged) - Q_PROPERTY(Qt3DRender::QAbstractTexture *environmentSpecular READ environmentSpecular WRITE setEnvironmentSpecular NOTIFY environmentSpecularChanged) public: explicit QTexturedMetalRoughMaterial(Qt3DCore::QNode *parent = nullptr); @@ -69,8 +67,6 @@ public: Qt3DRender::QAbstractTexture *roughness() const; Qt3DRender::QAbstractTexture *ambientOcclusion() const; Qt3DRender::QAbstractTexture *normal() const; - Qt3DRender::QAbstractTexture *environmentIrradiance() const; - Qt3DRender::QAbstractTexture *environmentSpecular() const; public Q_SLOTS: void setBaseColor(Qt3DRender::QAbstractTexture *baseColor); @@ -78,8 +74,6 @@ public Q_SLOTS: void setRoughness(Qt3DRender::QAbstractTexture *roughness); void setAmbientOcclusion(Qt3DRender::QAbstractTexture *ambientOcclusion); void setNormal(Qt3DRender::QAbstractTexture *normal); - void setEnvironmentIrradiance(Qt3DRender::QAbstractTexture *environmentIrradiance); - void setEnvironmentSpecular(Qt3DRender::QAbstractTexture *environmentSpecular); Q_SIGNALS: void baseColorChanged(Qt3DRender::QAbstractTexture *baseColor); @@ -87,8 +81,6 @@ Q_SIGNALS: void roughnessChanged(Qt3DRender::QAbstractTexture *roughness); void ambientOcclusionChanged(Qt3DRender::QAbstractTexture *ambientOcclusion); void normalChanged(Qt3DRender::QAbstractTexture *normal); - void environmentIrradianceChanged(Qt3DRender::QAbstractTexture *environmentIrradiance); - void environmentSpecularChanged(Qt3DRender::QAbstractTexture *environmentSpecular); protected: QTexturedMetalRoughMaterial(QTexturedMetalRoughMaterialPrivate &dd, Qt3DCore::QNode *parent = nullptr); diff --git a/src/extras/defaults/qtexturedmetalroughmaterial_p.h b/src/extras/defaults/qtexturedmetalroughmaterial_p.h index 084824304..8972726e5 100644 --- a/src/extras/defaults/qtexturedmetalroughmaterial_p.h +++ b/src/extras/defaults/qtexturedmetalroughmaterial_p.h @@ -83,8 +83,6 @@ public: void handleRoughnessChanged(const QVariant &var); void handleAmbientOcclusionChanged(const QVariant &var); void handleNormalChanged(const QVariant &var); - void handleEnvironmentIrradianceChanged(const QVariant &var); - void handleEnvironmentSpecularChanged(const QVariant &var); Qt3DRender::QAbstractTexture *m_baseColorTexture; Qt3DRender::QAbstractTexture *m_metalnessTexture; -- cgit v1.2.3 From 7a3648ef4e884429dbe4bb60ab5a0a838bc5abfc Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Thu, 16 Feb 2017 17:38:52 +0000 Subject: Introduce QAbstractAnimationClip and rename QAnimationClip Introduced an abstract base class for types of animation clip. Also renamed QAnimationClip to QAnimationClipLoader since it loads data from files. Also renamed corresponding backend type and fixed up unit tests accordingly. Task-number: QTBUG-58898 Change-Id: I01a96e108cbbcd12e01913693e96610598965018 Reviewed-by: Kevin Ottens --- src/animation/backend/animationclip.cpp | 218 --------------------- src/animation/backend/animationclip_p.h | 122 ------------ src/animation/backend/animationcliploader.cpp | 218 +++++++++++++++++++++ src/animation/backend/animationcliploader_p.h | 122 ++++++++++++ src/animation/backend/animationutils.cpp | 6 +- src/animation/backend/animationutils_p.h | 8 +- src/animation/backend/backend.pri | 8 +- src/animation/backend/buildblendtreesjob.cpp | 4 +- src/animation/backend/clipanimator.cpp | 2 +- src/animation/backend/clipblendnode.cpp | 6 +- .../backend/evaluateblendclipanimatorjob.cpp | 4 +- src/animation/backend/evaluateclipanimatorjob.cpp | 2 +- .../backend/findrunningclipanimatorsjob.cpp | 2 +- src/animation/backend/handle_types_p.h | 4 +- src/animation/backend/handler.cpp | 4 +- src/animation/backend/handler_p.h | 8 +- src/animation/backend/loadanimationclipjob.cpp | 6 +- src/animation/backend/managers_p.h | 10 +- src/animation/frontend/frontend.pri | 13 +- src/animation/frontend/qabstractanimationclip.cpp | 91 +++++++++ src/animation/frontend/qabstractanimationclip.h | 75 +++++++ src/animation/frontend/qabstractanimationclip_p.h | 76 +++++++ src/animation/frontend/qabstractclipanimator.cpp | 1 - src/animation/frontend/qabstractclipanimator_p.h | 1 - src/animation/frontend/qabstractclipblendnode.cpp | 8 +- src/animation/frontend/qabstractclipblendnode.h | 8 +- src/animation/frontend/qabstractclipblendnode_p.h | 4 +- src/animation/frontend/qadditiveblend.cpp | 1 - src/animation/frontend/qanimationaspect.cpp | 10 +- src/animation/frontend/qanimationclip.cpp | 120 ------------ src/animation/frontend/qanimationclip.h | 83 -------- src/animation/frontend/qanimationclip_p.h | 84 -------- src/animation/frontend/qanimationcliploader.cpp | 92 +++++++++ src/animation/frontend/qanimationcliploader.h | 79 ++++++++ src/animation/frontend/qanimationcliploader_p.h | 78 ++++++++ src/animation/frontend/qclipanimator.cpp | 6 +- src/animation/frontend/qclipanimator.h | 11 +- src/animation/frontend/qclipanimator_p.h | 5 +- .../frontend/qclipblendnodecreatedchange.cpp | 2 +- src/animation/frontend/qlerpblend.cpp | 1 - .../animation/qt3dquick3danimationplugin.cpp | 6 +- .../items/quick3dabstractclipblendnode.cpp | 24 +-- .../items/quick3dabstractclipblendnode_p.h | 14 +- .../animation/additiveblend/tst_additiveblend.cpp | 4 +- tests/auto/animation/animation.pro | 4 +- .../auto/animation/animationclip/animationclip.pro | 12 -- .../animation/animationclip/tst_animationclip.cpp | 155 --------------- .../animationcliploader/animationcliploader.pro | 12 ++ .../tst_animationcliploader.cpp | 155 +++++++++++++++ .../tst_blendedclipanimator.cpp | 2 +- .../animation/clipanimator/tst_clipanimator.cpp | 8 +- .../animation/clipblendnode/tst_clipblendnode.cpp | 6 +- tests/auto/animation/lerpblend/tst_lerpblend.cpp | 4 +- .../tst_qabstractclipblendnode.cpp | 8 +- .../qadditiveblend/tst_qadditiveblend.cpp | 6 +- .../animation/qanimationclip/qanimationclip.pro | 12 -- .../qanimationclip/tst_qanimationclip.cpp | 166 ---------------- .../qanimationcliploader/qanimationcliploader.pro | 12 ++ .../tst_qanimationcliploader.cpp | 166 ++++++++++++++++ .../tst_qblendedclipanimator.cpp | 2 - .../animation/qclipanimator/tst_qclipanimator.cpp | 16 +- tests/auto/animation/qlerpblend/tst_qlerpblend.cpp | 6 +- 62 files changed, 1304 insertions(+), 1099 deletions(-) delete mode 100644 src/animation/backend/animationclip.cpp delete mode 100644 src/animation/backend/animationclip_p.h create mode 100644 src/animation/backend/animationcliploader.cpp create mode 100644 src/animation/backend/animationcliploader_p.h create mode 100644 src/animation/frontend/qabstractanimationclip.cpp create mode 100644 src/animation/frontend/qabstractanimationclip.h create mode 100644 src/animation/frontend/qabstractanimationclip_p.h delete mode 100644 src/animation/frontend/qanimationclip.cpp delete mode 100644 src/animation/frontend/qanimationclip.h delete mode 100644 src/animation/frontend/qanimationclip_p.h create mode 100644 src/animation/frontend/qanimationcliploader.cpp create mode 100644 src/animation/frontend/qanimationcliploader.h create mode 100644 src/animation/frontend/qanimationcliploader_p.h delete mode 100644 tests/auto/animation/animationclip/animationclip.pro delete mode 100644 tests/auto/animation/animationclip/tst_animationclip.cpp create mode 100644 tests/auto/animation/animationcliploader/animationcliploader.pro create mode 100644 tests/auto/animation/animationcliploader/tst_animationcliploader.cpp delete mode 100644 tests/auto/animation/qanimationclip/qanimationclip.pro delete mode 100644 tests/auto/animation/qanimationclip/tst_qanimationclip.cpp create mode 100644 tests/auto/animation/qanimationcliploader/qanimationcliploader.pro create mode 100644 tests/auto/animation/qanimationcliploader/tst_qanimationcliploader.cpp diff --git a/src/animation/backend/animationclip.cpp b/src/animation/backend/animationclip.cpp deleted file mode 100644 index 7b96f66e9..000000000 --- a/src/animation/backend/animationclip.cpp +++ /dev/null @@ -1,218 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). -** Contact: http://www.qt-project.org/legal -** -** 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 "animationclip_p.h" -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE - -namespace Qt3DAnimation { -namespace Animation { - -AnimationClip::AnimationClip() - : BackendNode(ReadWrite) - , m_source() - , m_name() - , m_objectName() - , m_channelGroups() - , m_duration(0.0f) -{ -} - -void AnimationClip::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) -{ - const auto typedChange = qSharedPointerCast>(change); - const auto &data = typedChange->data; - m_source = data.source; - if (!m_source.isEmpty()) - setDirty(Handler::AnimationClipDirty); -} - -void AnimationClip::cleanup() -{ - setEnabled(false); - m_handler = nullptr; - m_source.clear(); - m_channelGroups.clear(); - m_duration = 0.0f; - - clearData(); -} - -void AnimationClip::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) -{ - switch (e->type()) { - case Qt3DCore::PropertyUpdated: { - const auto change = qSharedPointerCast(e); - if (change->propertyName() == QByteArrayLiteral("source")) { - m_source = change->value().toUrl(); - setDirty(Handler::AnimationClipDirty); - } - break; - } - - default: - break; - } - QBackendNode::sceneChangeEvent(e); -} - -/*! - \internal - Called by LoadAnimationClipJob on the threadpool - */ -void AnimationClip::loadAnimation() -{ - qCDebug(Jobs) << Q_FUNC_INFO << m_source; - clearData(); - - // TODO: Handle remote files - QString filePath = Qt3DRender::QUrlHelper::urlToLocalFileOrQrc(m_source); - QFile file(filePath); - if (!file.open(QIODevice::ReadOnly)) { - qWarning() << "Could not find animation clip:" << filePath; - return; - } - - QByteArray animationData = file.readAll(); - QJsonDocument document = QJsonDocument::fromJson(animationData); - QJsonObject rootObject = document.object(); - - // TODO: Allow loading of a named animation from a file containing many - QJsonArray animationsArray = rootObject[QLatin1String("animations")].toArray(); - qCDebug(Jobs) << "Found" << animationsArray.size() << "animations:"; - for (int i = 0; i < animationsArray.size(); ++i) { - QJsonObject animation = animationsArray.at(i).toObject(); - qCDebug(Jobs) << "\tName:" << animation[QLatin1String("action")].toString() - << "Object:" << animation[QLatin1String("object")].toString(); - } - - // For now just load the first animation - QJsonObject animation = animationsArray.at(0).toObject(); - m_name = animation[QLatin1String("action")].toString(); - m_objectName = animation[QLatin1String("object")].toString(); - QJsonArray groupsArray = animation[QLatin1String("groups")].toArray(); - const int groupCount = groupsArray.size(); - m_channelGroups.resize(groupCount); - for (int i = 0; i < groupCount; ++i) { - const QJsonObject group = groupsArray.at(i).toObject(); - m_channelGroups[i].read(group); - } - - const float t = findDuration(); - setDuration(t); - - m_channelCount = findChannelCount(); - - qCDebug(Jobs) << "Loaded animation data:" << *this; -} - -void AnimationClip::setDuration(float duration) -{ - if (qFuzzyCompare(duration, m_duration)) - return; - - m_duration = duration; - - // Send a change to the frontend - auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId()); - e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll); - e->setPropertyName("duration"); - e->setValue(m_duration); - notifyObservers(e); -} - -/*! - \internal - - Given the index of a channel group, \a channelGroupIndex, calculates - the base index of the first channel in this group. For example, if - there are two channel groups each with 3 channels and you request - the channelBaseIndex(1), the return value will be 3. Indices 0-2 are - for the first group, so the first channel of the second group occurs - at index 3. - */ -int AnimationClip::channelBaseIndex(int channelGroupIndex) const -{ - int index = 0; - for (int i = 0; i < channelGroupIndex; ++i) - index += m_channelGroups[i].channels.size(); - return index; -} - -void AnimationClip::clearData() -{ - m_name.clear(); - m_objectName.clear(); - m_channelGroups.clear(); -} - -float AnimationClip::findDuration() -{ - // Iterate over the contained fcurves and find the longest one - double tMax = 0.0; - for (const ChannelGroup &channelGroup : qAsConst(m_channelGroups)) { - for (const Channel &channel : qAsConst(channelGroup.channels)) { - const float t = channel.fcurve.endTime(); - if (t > tMax) - tMax = t; - } - } - return tMax; -} - -int AnimationClip::findChannelCount() -{ - int channelCount = 0; - for (const ChannelGroup &channelGroup : qAsConst(m_channelGroups)) - channelCount += channelGroup.channels.size(); - return channelCount; -} - -} // namespace Animation -} // namespace Qt3DAnimation - -QT_END_NAMESPACE diff --git a/src/animation/backend/animationclip_p.h b/src/animation/backend/animationclip_p.h deleted file mode 100644 index cfd8558c7..000000000 --- a/src/animation/backend/animationclip_p.h +++ /dev/null @@ -1,122 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). -** Contact: http://www.qt-project.org/legal -** -** 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$ -** -****************************************************************************/ - -#ifndef QT3DANIMATION_ANIMATION_ANIMATIONCLIP_P_H -#define QT3DANIMATION_ANIMATION_ANIMATIONCLIP_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of other Qt classes. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include -#include -#include - -QT_BEGIN_NAMESPACE - -namespace Qt3DAnimation { -namespace Animation { - -class Handler; - -class Q_AUTOTEST_EXPORT AnimationClip : public BackendNode -{ -public: - AnimationClip(); - - void cleanup(); - void setSource(const QUrl &source) { m_source = source; } - QUrl source() const { return m_source; } - void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_OVERRIDE; - - QString name() const { return m_name; } - QString objectName() const { return m_objectName; } - const QVector &channelGroups() const { return m_channelGroups; } - - // Called from jobs - void loadAnimation(); - void setDuration(float duration); - float duration() const { return m_duration; } - int channelCount() const { return m_channelCount; } - int channelBaseIndex(int channelGroupIndex) const; - -private: - void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL; - void clearData(); - float findDuration(); - int findChannelCount(); - - QUrl m_source; - - QString m_name; - QString m_objectName; - QVector m_channelGroups; - float m_duration; - int m_channelCount; -}; - -#ifndef QT_NO_DEBUG_STREAM -inline QDebug operator<<(QDebug dbg, const AnimationClip &animationClip) -{ - QDebugStateSaver saver(dbg); - dbg << "QNodeId =" << animationClip.peerId() << endl - << "Name =" << animationClip.name() << endl - << "Object Name =" << animationClip.objectName() << endl - << "Channel Groups:" << endl; - - const QVector channelGroups = animationClip.channelGroups(); - for (const auto channelGroup : channelGroups) { - dbg << channelGroup; - } - - return dbg; -} -#endif - -} // namespace Animation -} // namespace Qt3DAnimation - - -QT_END_NAMESPACE - -#endif // QT3DANIMATION_ANIMATION_ANIMATIONCLIP_P_H diff --git a/src/animation/backend/animationcliploader.cpp b/src/animation/backend/animationcliploader.cpp new file mode 100644 index 000000000..96323885c --- /dev/null +++ b/src/animation/backend/animationcliploader.cpp @@ -0,0 +1,218 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** 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 "animationcliploader_p.h" +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { +namespace Animation { + +AnimationClipLoader::AnimationClipLoader() + : BackendNode(ReadWrite) + , m_source() + , m_name() + , m_objectName() + , m_channelGroups() + , m_duration(0.0f) +{ +} + +void AnimationClipLoader::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) +{ + const auto typedChange = qSharedPointerCast>(change); + const auto &data = typedChange->data; + m_source = data.source; + if (!m_source.isEmpty()) + setDirty(Handler::AnimationClipDirty); +} + +void AnimationClipLoader::cleanup() +{ + setEnabled(false); + m_handler = nullptr; + m_source.clear(); + m_channelGroups.clear(); + m_duration = 0.0f; + + clearData(); +} + +void AnimationClipLoader::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) +{ + switch (e->type()) { + case Qt3DCore::PropertyUpdated: { + const auto change = qSharedPointerCast(e); + if (change->propertyName() == QByteArrayLiteral("source")) { + m_source = change->value().toUrl(); + setDirty(Handler::AnimationClipDirty); + } + break; + } + + default: + break; + } + QBackendNode::sceneChangeEvent(e); +} + +/*! + \internal + Called by LoadAnimationClipJob on the threadpool + */ +void AnimationClipLoader::loadAnimation() +{ + qCDebug(Jobs) << Q_FUNC_INFO << m_source; + clearData(); + + // TODO: Handle remote files + QString filePath = Qt3DRender::QUrlHelper::urlToLocalFileOrQrc(m_source); + QFile file(filePath); + if (!file.open(QIODevice::ReadOnly)) { + qWarning() << "Could not find animation clip:" << filePath; + return; + } + + QByteArray animationData = file.readAll(); + QJsonDocument document = QJsonDocument::fromJson(animationData); + QJsonObject rootObject = document.object(); + + // TODO: Allow loading of a named animation from a file containing many + QJsonArray animationsArray = rootObject[QLatin1String("animations")].toArray(); + qCDebug(Jobs) << "Found" << animationsArray.size() << "animations:"; + for (int i = 0; i < animationsArray.size(); ++i) { + QJsonObject animation = animationsArray.at(i).toObject(); + qCDebug(Jobs) << "\tName:" << animation[QLatin1String("action")].toString() + << "Object:" << animation[QLatin1String("object")].toString(); + } + + // For now just load the first animation + QJsonObject animation = animationsArray.at(0).toObject(); + m_name = animation[QLatin1String("action")].toString(); + m_objectName = animation[QLatin1String("object")].toString(); + QJsonArray groupsArray = animation[QLatin1String("groups")].toArray(); + const int groupCount = groupsArray.size(); + m_channelGroups.resize(groupCount); + for (int i = 0; i < groupCount; ++i) { + const QJsonObject group = groupsArray.at(i).toObject(); + m_channelGroups[i].read(group); + } + + const float t = findDuration(); + setDuration(t); + + m_channelCount = findChannelCount(); + + qCDebug(Jobs) << "Loaded animation data:" << *this; +} + +void AnimationClipLoader::setDuration(float duration) +{ + if (qFuzzyCompare(duration, m_duration)) + return; + + m_duration = duration; + + // Send a change to the frontend + auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId()); + e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll); + e->setPropertyName("duration"); + e->setValue(m_duration); + notifyObservers(e); +} + +/*! + \internal + + Given the index of a channel group, \a channelGroupIndex, calculates + the base index of the first channel in this group. For example, if + there are two channel groups each with 3 channels and you request + the channelBaseIndex(1), the return value will be 3. Indices 0-2 are + for the first group, so the first channel of the second group occurs + at index 3. + */ +int AnimationClipLoader::channelBaseIndex(int channelGroupIndex) const +{ + int index = 0; + for (int i = 0; i < channelGroupIndex; ++i) + index += m_channelGroups[i].channels.size(); + return index; +} + +void AnimationClipLoader::clearData() +{ + m_name.clear(); + m_objectName.clear(); + m_channelGroups.clear(); +} + +float AnimationClipLoader::findDuration() +{ + // Iterate over the contained fcurves and find the longest one + double tMax = 0.0; + for (const ChannelGroup &channelGroup : qAsConst(m_channelGroups)) { + for (const Channel &channel : qAsConst(channelGroup.channels)) { + const float t = channel.fcurve.endTime(); + if (t > tMax) + tMax = t; + } + } + return tMax; +} + +int AnimationClipLoader::findChannelCount() +{ + int channelCount = 0; + for (const ChannelGroup &channelGroup : qAsConst(m_channelGroups)) + channelCount += channelGroup.channels.size(); + return channelCount; +} + +} // namespace Animation +} // namespace Qt3DAnimation + +QT_END_NAMESPACE diff --git a/src/animation/backend/animationcliploader_p.h b/src/animation/backend/animationcliploader_p.h new file mode 100644 index 000000000..28dcb5994 --- /dev/null +++ b/src/animation/backend/animationcliploader_p.h @@ -0,0 +1,122 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** 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$ +** +****************************************************************************/ + +#ifndef QT3DANIMATION_ANIMATION_ANIMATIONCLIP_P_H +#define QT3DANIMATION_ANIMATION_ANIMATIONCLIP_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { +namespace Animation { + +class Handler; + +class Q_AUTOTEST_EXPORT AnimationClipLoader : public BackendNode +{ +public: + AnimationClipLoader(); + + void cleanup(); + void setSource(const QUrl &source) { m_source = source; } + QUrl source() const { return m_source; } + void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_OVERRIDE; + + QString name() const { return m_name; } + QString objectName() const { return m_objectName; } + const QVector &channelGroups() const { return m_channelGroups; } + + // Called from jobs + void loadAnimation(); + void setDuration(float duration); + float duration() const { return m_duration; } + int channelCount() const { return m_channelCount; } + int channelBaseIndex(int channelGroupIndex) const; + +private: + void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL; + void clearData(); + float findDuration(); + int findChannelCount(); + + QUrl m_source; + + QString m_name; + QString m_objectName; + QVector m_channelGroups; + float m_duration; + int m_channelCount; +}; + +#ifndef QT_NO_DEBUG_STREAM +inline QDebug operator<<(QDebug dbg, const AnimationClipLoader &animationClip) +{ + QDebugStateSaver saver(dbg); + dbg << "QNodeId =" << animationClip.peerId() << endl + << "Name =" << animationClip.name() << endl + << "Object Name =" << animationClip.objectName() << endl + << "Channel Groups:" << endl; + + const QVector channelGroups = animationClip.channelGroups(); + for (const auto channelGroup : channelGroups) { + dbg << channelGroup; + } + + return dbg; +} +#endif + +} // namespace Animation +} // namespace Qt3DAnimation + + +QT_END_NAMESPACE + +#endif // QT3DANIMATION_ANIMATION_ANIMATIONCLIP_P_H diff --git a/src/animation/backend/animationutils.cpp b/src/animation/backend/animationutils.cpp index c81893013..db2d6eadb 100644 --- a/src/animation/backend/animationutils.cpp +++ b/src/animation/backend/animationutils.cpp @@ -51,7 +51,7 @@ QT_BEGIN_NAMESPACE namespace Qt3DAnimation { namespace Animation { -AnimationUtils::ClipPreEvaluationData AnimationUtils::evaluationDataForClip(AnimationClip *clip, +AnimationUtils::ClipPreEvaluationData AnimationUtils::evaluationDataForClip(AnimationClipLoader *clip, const AnimationUtils::AnimatorEvaluationData &animatorData) { // global time values expected in seconds @@ -165,7 +165,7 @@ QVector AnimationUtils::channelsToIndicesHelper(const ChannelGroup &channel return indices; } -QVector AnimationUtils::evaluateClipAtLocalTime(AnimationClip *clip, float localTime) +QVector AnimationUtils::evaluateClipAtLocalTime(AnimationClipLoader *clip, float localTime) { QVector channelResults; Q_ASSERT(clip); @@ -263,7 +263,7 @@ QVector AnimationUtils::preparePropertyChanges(Qt3DCo return changes; } -QVector AnimationUtils::buildPropertyMappings(Handler *handler, const AnimationClip *clip, const ChannelMapper *mapper) +QVector AnimationUtils::buildPropertyMappings(Handler *handler, const AnimationClipLoader *clip, const ChannelMapper *mapper) { QVector mappingDataVec; ChannelMappingManager *mappingManager = handler->channelMappingManager(); diff --git a/src/animation/backend/animationutils_p.h b/src/animation/backend/animationutils_p.h index b662ec445..6f541998e 100644 --- a/src/animation/backend/animationutils_p.h +++ b/src/animation/backend/animationutils_p.h @@ -59,7 +59,7 @@ namespace Animation { struct ChannelGroup; class Handler; -class AnimationClip; +class AnimationClipLoader; class ChannelMapper; class Q_AUTOTEST_EXPORT AnimationUtils @@ -113,7 +113,7 @@ public: return data; } - static ClipPreEvaluationData evaluationDataForClip(AnimationClip *clip, const AnimatorEvaluationData &animatorData); + static ClipPreEvaluationData evaluationDataForClip(AnimationClipLoader *clip, const AnimatorEvaluationData &animatorData); static QVector channelsToIndices(const ChannelGroup &channelGroup, int dataType, @@ -122,14 +122,14 @@ public: int dataType, int offset, const QStringList &suffixes); - static QVector evaluateClipAtLocalTime(AnimationClip *clip, + static QVector evaluateClipAtLocalTime(AnimationClipLoader *clip, float localTime); static QVector preparePropertyChanges(Qt3DCore::QNodeId peerId, const QVector &mappingData, const QVector &channelResults, bool finalFrame); static QVector buildPropertyMappings(Handler *handler, - const AnimationClip *clip, + const AnimationClipLoader *clip, const ChannelMapper *mapper); private: diff --git a/src/animation/backend/backend.pri b/src/animation/backend/backend.pri index 7eb8913c8..eab1f035b 100644 --- a/src/animation/backend/backend.pri +++ b/src/animation/backend/backend.pri @@ -2,7 +2,6 @@ INCLUDEPATH += $$PWD HEADERS += \ - $$PWD/animationclip_p.h \ $$PWD/handle_types_p.h \ $$PWD/handler_p.h \ $$PWD/nodefunctor_p.h \ @@ -25,10 +24,10 @@ HEADERS += \ $$PWD/animationutils_p.h \ $$PWD/buildblendtreesjob_p.h \ $$PWD/evaluateblendclipanimatorjob_p.h \ - $$PWD/additiveblend_p.h + $$PWD/additiveblend_p.h \ + $$PWD/animationcliploader_p.h SOURCES += \ - $$PWD/animationclip.cpp \ $$PWD/handler.cpp \ $$PWD/fcurve.cpp \ $$PWD/bezierevaluator.cpp \ @@ -48,4 +47,5 @@ SOURCES += \ $$PWD/animationutils.cpp \ $$PWD/buildblendtreesjob.cpp \ $$PWD/evaluateblendclipanimatorjob.cpp \ - $$PWD/additiveblend.cpp + $$PWD/additiveblend.cpp \ + $$PWD/animationcliploader.cpp diff --git a/src/animation/backend/buildblendtreesjob.cpp b/src/animation/backend/buildblendtreesjob.cpp index e86aa4978..f57bf5201 100644 --- a/src/animation/backend/buildblendtreesjob.cpp +++ b/src/animation/backend/buildblendtreesjob.cpp @@ -136,8 +136,8 @@ QVector buildBlendMappingDataForNode(const void buildEntryForBlendClipNode(Handler *handler, const ChannelMapper *mapper, BlendedClipAnimator::BlendNodeData &nodeData) { // Retrieve Animation clips - const AnimationClip *clip1 = handler->animationClipManager()->lookupResource(nodeData.left); - const AnimationClip *clip2 = handler->animationClipManager()->lookupResource(nodeData.right); + const AnimationClipLoader *clip1 = handler->animationClipLoaderManager()->lookupResource(nodeData.left); + const AnimationClipLoader *clip2 = handler->animationClipLoaderManager()->lookupResource(nodeData.right); Q_ASSERT(clip1 && clip2); diff --git a/src/animation/backend/clipanimator.cpp b/src/animation/backend/clipanimator.cpp index ff3cb1b12..72f818d88 100644 --- a/src/animation/backend/clipanimator.cpp +++ b/src/animation/backend/clipanimator.cpp @@ -37,7 +37,7 @@ #include "clipanimator_p.h" #include #include -#include +#include #include #include #include diff --git a/src/animation/backend/clipblendnode.cpp b/src/animation/backend/clipblendnode.cpp index a763f7f48..10220d9c9 100644 --- a/src/animation/backend/clipblendnode.cpp +++ b/src/animation/backend/clipblendnode.cpp @@ -36,7 +36,7 @@ #include "clipblendnode_p.h" #include -#include +#include #include #include @@ -80,7 +80,7 @@ void ClipBlendNode::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Qt3DCore::QPropertyNodeAddedChangePtr change = qSharedPointerCast(e); if (change->metaObject()->inherits(&QAbstractClipBlendNode::staticMetaObject)) addChildId(change->addedNodeId()); - else if (change->metaObject()->inherits(&QAnimationClip::staticMetaObject)) + else if (change->metaObject()->inherits(&QAbstractAnimationClip::staticMetaObject)) m_clipIds.push_back(change->addedNodeId()); break; } @@ -89,7 +89,7 @@ void ClipBlendNode::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Qt3DCore::QPropertyNodeRemovedChangePtr change = qSharedPointerCast(e); if (change->metaObject()->inherits(&QAbstractClipBlendNode::staticMetaObject)) removeChildId(change->removedNodeId()); - else if (change->metaObject()->inherits(&QAnimationClip::staticMetaObject)) + else if (change->metaObject()->inherits(&QAbstractAnimationClip::staticMetaObject)) m_clipIds.removeOne(change->removedNodeId()); break; } diff --git a/src/animation/backend/evaluateblendclipanimatorjob.cpp b/src/animation/backend/evaluateblendclipanimatorjob.cpp index 440943ce4..51dcd6c14 100644 --- a/src/animation/backend/evaluateblendclipanimatorjob.cpp +++ b/src/animation/backend/evaluateblendclipanimatorjob.cpp @@ -113,8 +113,8 @@ QVector fromBlendingMappingData(const QVectoranimationClipManager()->lookupResource(nodeData.left); - AnimationClip *clip2 = m_handler->animationClipManager()->lookupResource(nodeData.right); + AnimationClipLoader *clip1 = m_handler->animationClipLoaderManager()->lookupResource(nodeData.left); + AnimationClipLoader *clip2 = m_handler->animationClipLoaderManager()->lookupResource(nodeData.right); Q_ASSERT(clip1 && clip2); // Prepare for evaluation (convert global time to local time ....) diff --git a/src/animation/backend/evaluateclipanimatorjob.cpp b/src/animation/backend/evaluateclipanimatorjob.cpp index f4f919d25..a2e481371 100644 --- a/src/animation/backend/evaluateclipanimatorjob.cpp +++ b/src/animation/backend/evaluateclipanimatorjob.cpp @@ -63,7 +63,7 @@ void EvaluateClipAnimatorJob::run() Q_ASSERT(clipAnimator); // Evaluate the fcurves - AnimationClip *clip = m_handler->animationClipManager()->lookupResource(clipAnimator->clipId()); + AnimationClipLoader *clip = m_handler->animationClipLoaderManager()->lookupResource(clipAnimator->clipId()); Q_ASSERT(clip); // Prepare for evaluation (convert global time to local time ....) const AnimationUtils::AnimatorEvaluationData animatorEvaluationData = AnimationUtils::animatorEvaluationDataForAnimator(clipAnimator, globalTime); diff --git a/src/animation/backend/findrunningclipanimatorsjob.cpp b/src/animation/backend/findrunningclipanimatorsjob.cpp index fcffab8cc..bdc12e2a2 100644 --- a/src/animation/backend/findrunningclipanimatorsjob.cpp +++ b/src/animation/backend/findrunningclipanimatorsjob.cpp @@ -73,7 +73,7 @@ void FindRunningClipAnimatorsJob::run() // TODO: Should be possible to parallelise this with the fcurve evaluation as // sending the property change events doesn't happen until after evaluation if (canRun) { - const AnimationClip *clip = m_handler->animationClipManager()->lookupResource(clipAnimator->clipId()); + const AnimationClipLoader *clip = m_handler->animationClipLoaderManager()->lookupResource(clipAnimator->clipId()); const ChannelMapper *mapper = m_handler->channelMapperManager()->lookupResource(clipAnimator->mapperId()); Q_ASSERT(clip && mapper); const QVector mappingData = AnimationUtils::buildPropertyMappings(m_handler, clip, mapper); diff --git a/src/animation/backend/handle_types_p.h b/src/animation/backend/handle_types_p.h index f6f77eb20..f5093783b 100644 --- a/src/animation/backend/handle_types_p.h +++ b/src/animation/backend/handle_types_p.h @@ -58,13 +58,13 @@ QT_BEGIN_NAMESPACE namespace Qt3DAnimation { namespace Animation { -class AnimationClip; +class AnimationClipLoader; class ClipAnimator; class BlendedClipAnimator; class ChannelMapping; class ChannelMapper; -typedef Qt3DCore::QHandle HAnimationClip; +typedef Qt3DCore::QHandle HAnimationClip; typedef Qt3DCore::QHandle HClipAnimator; typedef Qt3DCore::QHandle HBlendedClipAnimator; typedef Qt3DCore::QHandle HChannelMapping; diff --git a/src/animation/backend/handler.cpp b/src/animation/backend/handler.cpp index 87146aa63..04c46b40a 100644 --- a/src/animation/backend/handler.cpp +++ b/src/animation/backend/handler.cpp @@ -51,7 +51,7 @@ namespace Qt3DAnimation { namespace Animation { Handler::Handler() - : m_animationClipManager(new AnimationClipManager) + : m_animationClipLoaderManager(new AnimationClipLoaderManager) , m_clipAnimatorManager(new ClipAnimatorManager) , m_blendedClipAnimatorManager(new BlendedClipAnimatorManager) , m_channelMappingManager(new ChannelMappingManager) @@ -75,7 +75,7 @@ void Handler::setDirty(DirtyFlag flag, Qt3DCore::QNodeId nodeId) { switch (flag) { case AnimationClipDirty: { - const auto handle = m_animationClipManager->lookupHandle(nodeId); + const auto handle = m_animationClipLoaderManager->lookupHandle(nodeId); m_dirtyAnimationClips.push_back(handle); break; } diff --git a/src/animation/backend/handler_p.h b/src/animation/backend/handler_p.h index 91640c477..dcabf6088 100644 --- a/src/animation/backend/handler_p.h +++ b/src/animation/backend/handler_p.h @@ -63,8 +63,8 @@ class tst_Handler; namespace Qt3DAnimation { namespace Animation { -class AnimationClip; -class AnimationClipManager; +class AnimationClipLoader; +class AnimationClipLoaderManager; class ClipAnimator; class ClipAnimatorManager; class BlendedClipAnimator; @@ -107,7 +107,7 @@ public: void setBlendedClipAnimatorRunning(const HBlendedClipAnimator &handle, bool running); QVector runningBlenndedClipAnimators() const { return m_runningBlendedClipAnimators; } - AnimationClipManager *animationClipManager() const Q_DECL_NOTHROW { return m_animationClipManager.data(); } + AnimationClipLoaderManager *animationClipLoaderManager() const Q_DECL_NOTHROW { return m_animationClipLoaderManager.data(); } ClipAnimatorManager *clipAnimatorManager() const Q_DECL_NOTHROW { return m_clipAnimatorManager.data(); } BlendedClipAnimatorManager *blendedClipAnimatorManager() const Q_DECL_NOTHROW { return m_blendedClipAnimatorManager.data(); } ChannelMappingManager *channelMappingManager() const Q_DECL_NOTHROW { return m_channelMappingManager.data(); } @@ -117,7 +117,7 @@ public: QVector jobsToExecute(qint64 time); private: - QScopedPointer m_animationClipManager; + QScopedPointer m_animationClipLoaderManager; QScopedPointer m_clipAnimatorManager; QScopedPointer m_blendedClipAnimatorManager; QScopedPointer m_channelMappingManager; diff --git a/src/animation/backend/loadanimationclipjob.cpp b/src/animation/backend/loadanimationclipjob.cpp index 39809f9eb..152b60a58 100644 --- a/src/animation/backend/loadanimationclipjob.cpp +++ b/src/animation/backend/loadanimationclipjob.cpp @@ -36,7 +36,7 @@ #include "loadanimationclipjob_p.h" -#include +#include #include #include #include @@ -69,9 +69,9 @@ void LoadAnimationClipJob::clearDirtyAnimationClips() void LoadAnimationClipJob::run() { Q_ASSERT(m_handler); - AnimationClipManager *animationClipManager = m_handler->animationClipManager(); + AnimationClipLoaderManager *animationClipManager = m_handler->animationClipLoaderManager(); for (const auto animationClipHandle : qAsConst(m_animationClipHandles)) { - AnimationClip *animationClip = animationClipManager->data(animationClipHandle); + AnimationClipLoader *animationClip = animationClipManager->data(animationClipHandle); animationClip->loadAnimation(); } diff --git a/src/animation/backend/managers_p.h b/src/animation/backend/managers_p.h index 3b811121a..1680dc7bf 100644 --- a/src/animation/backend/managers_p.h +++ b/src/animation/backend/managers_p.h @@ -53,7 +53,7 @@ #include #include -#include +#include #include #include #include @@ -67,14 +67,14 @@ namespace Animation { class ClipBlendNode; -class AnimationClipManager : public Qt3DCore::QResourceManager< - AnimationClip, +class AnimationClipLoaderManager : public Qt3DCore::QResourceManager< + AnimationClipLoader, Qt3DCore::QNodeId, 16, Qt3DCore::ArrayAllocatingPolicy> { public: - AnimationClipManager() {} + AnimationClipLoaderManager() {} }; class ClipAnimatorManager : public Qt3DCore::QResourceManager< @@ -135,7 +135,7 @@ private: } // namespace Animation } // namespace Qt3DAnimation -Q_DECLARE_RESOURCE_INFO(Qt3DAnimation::Animation::AnimationClip, Q_REQUIRES_CLEANUP) +Q_DECLARE_RESOURCE_INFO(Qt3DAnimation::Animation::AnimationClipLoader, Q_REQUIRES_CLEANUP) Q_DECLARE_RESOURCE_INFO(Qt3DAnimation::Animation::ClipAnimator, Q_REQUIRES_CLEANUP) Q_DECLARE_RESOURCE_INFO(Qt3DAnimation::Animation::BlendedClipAnimator, Q_REQUIRES_CLEANUP) Q_DECLARE_RESOURCE_INFO(Qt3DAnimation::Animation::ChannelMapping, Q_REQUIRES_CLEANUP) diff --git a/src/animation/frontend/frontend.pri b/src/animation/frontend/frontend.pri index d6895510a..d31193a04 100644 --- a/src/animation/frontend/frontend.pri +++ b/src/animation/frontend/frontend.pri @@ -1,10 +1,10 @@ HEADERS += \ $$PWD/qanimationaspect.h \ $$PWD/qanimationaspect_p.h \ - $$PWD/qanimationclip.h \ - $$PWD/qanimationclip_p.h \ $$PWD/qabstractclipanimator.h \ $$PWD/qabstractclipanimator_p.h \ + $$PWD/qabstractanimationclip.h \ + $$PWD/qabstractanimationclip_p.h \ $$PWD/qabstractclipblendnode.h \ $$PWD/qabstractclipblendnode_p.h \ $$PWD/qclipanimator.h \ @@ -34,12 +34,14 @@ HEADERS += \ $$PWD/qmorphtarget.h \ $$PWD/qmorphtarget_p.h \ $$PWD/qvertexblendanimation.h \ - $$PWD/qvertexblendanimation_p.h + $$PWD/qvertexblendanimation_p.h \ + $$PWD/qanimationcliploader.h \ + $$PWD/qanimationcliploader_p.h SOURCES += \ $$PWD/qanimationaspect.cpp \ - $$PWD/qanimationclip.cpp \ $$PWD/qabstractclipanimator.cpp \ + $$PWD/qabstractanimationclip.cpp \ $$PWD/qabstractclipblendnode.cpp \ $$PWD/qclipanimator.cpp \ $$PWD/qblendedclipanimator.cpp \ @@ -54,6 +56,7 @@ SOURCES += \ $$PWD/qmorphinganimation.cpp \ $$PWD/qabstractanimation.cpp \ $$PWD/qmorphtarget.cpp \ - $$PWD/qvertexblendanimation.cpp + $$PWD/qvertexblendanimation.cpp \ + $$PWD/qanimationcliploader.cpp INCLUDEPATH += $$PWD diff --git a/src/animation/frontend/qabstractanimationclip.cpp b/src/animation/frontend/qabstractanimationclip.cpp new file mode 100644 index 000000000..5fdf7ae68 --- /dev/null +++ b/src/animation/frontend/qabstractanimationclip.cpp @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** 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 "qabstractanimationclip.h" +#include "qabstractanimationclip_p.h" +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { + +QAbstractAnimationClipPrivate::QAbstractAnimationClipPrivate() + : Qt3DCore::QNodePrivate() + , m_duration(0.0f) +{ +} + +void QAbstractAnimationClipPrivate::setDuration(float duration) +{ + if (qFuzzyCompare(duration, m_duration)) + return; + + Q_Q(QAbstractAnimationClip); + bool wasBlocked = q->blockNotifications(true); + m_duration = duration; + emit q->durationChanged(duration); + q->blockNotifications(wasBlocked); +} + +QAbstractAnimationClip::QAbstractAnimationClip(QAbstractAnimationClipPrivate &dd, + Qt3DCore::QNode *parent) + : Qt3DCore::QNode(dd, parent) +{ +} + +QAbstractAnimationClip::~QAbstractAnimationClip() +{ +} + +float QAbstractAnimationClip::duration() const +{ + Q_D(const QAbstractAnimationClip); + return d->m_duration; +} + +void QAbstractAnimationClip::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) +{ + Q_D(QAbstractAnimationClip); + if (change->type() == Qt3DCore::PropertyUpdated) { + Qt3DCore::QPropertyUpdatedChangePtr e = qSharedPointerCast(change); + if (e->propertyName() == QByteArrayLiteral("duration")) + d->setDuration(e->value().toFloat()); + } +} + +} // namespace Qt3DAnimation + +QT_END_NAMESPACE diff --git a/src/animation/frontend/qabstractanimationclip.h b/src/animation/frontend/qabstractanimationclip.h new file mode 100644 index 000000000..377725fa1 --- /dev/null +++ b/src/animation/frontend/qabstractanimationclip.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** 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$ +** +****************************************************************************/ + +#ifndef QT3DANIMATION_QABSTRACTANIMATIONCLIP_H +#define QT3DANIMATION_QABSTRACTANIMATIONCLIP_H + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { + +class QAbstractAnimationClipPrivate; + +class QT3DANIMATIONSHARED_EXPORT QAbstractAnimationClip : public Qt3DCore::QNode +{ + Q_OBJECT + Q_PROPERTY(float duration READ duration NOTIFY durationChanged) + +public: + ~QAbstractAnimationClip(); + + float duration() const; + +Q_SIGNALS: + void durationChanged(float duration); + +protected: + QAbstractAnimationClip(QAbstractAnimationClipPrivate &dd, Qt3DCore::QNode *parent = nullptr); + void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) Q_DECL_OVERRIDE; + +private: + Q_DECLARE_PRIVATE(QAbstractAnimationClip) +}; + +} // namespace Qt3DAnimation + +QT_END_NAMESPACE + +#endif // QT3DANIMATION_QABSTRACTANIMATIONCLIP_H diff --git a/src/animation/frontend/qabstractanimationclip_p.h b/src/animation/frontend/qabstractanimationclip_p.h new file mode 100644 index 000000000..8b74bee94 --- /dev/null +++ b/src/animation/frontend/qabstractanimationclip_p.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** 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$ +** +****************************************************************************/ + +#ifndef QT3DANIMATION_QABSTRACTANIMATIONCLIP_P_H +#define QT3DANIMATION_QABSTRACTANIMATIONCLIP_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include "qabstractanimationclip.h" + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { + +class QAbstractAnimationClipPrivate : public Qt3DCore::QNodePrivate +{ +public: + QAbstractAnimationClipPrivate(); + + Q_DECLARE_PUBLIC(QAbstractAnimationClip) + + void setDuration(float duration); + + // Set from the backend + float m_duration; +}; + +} // namespace Qt3DAnimation + + +QT_END_NAMESPACE + +#endif // QT3DANIMATION_QABSTRACTANIMATIONCLIP_P_H diff --git a/src/animation/frontend/qabstractclipanimator.cpp b/src/animation/frontend/qabstractclipanimator.cpp index 05f80c8ba..439737601 100644 --- a/src/animation/frontend/qabstractclipanimator.cpp +++ b/src/animation/frontend/qabstractclipanimator.cpp @@ -39,7 +39,6 @@ #include "qabstractclipanimator.h" #include "qabstractclipanimator_p.h" -#include #include QT_BEGIN_NAMESPACE diff --git a/src/animation/frontend/qabstractclipanimator_p.h b/src/animation/frontend/qabstractclipanimator_p.h index 89263af7e..58553c8c1 100644 --- a/src/animation/frontend/qabstractclipanimator_p.h +++ b/src/animation/frontend/qabstractclipanimator_p.h @@ -52,7 +52,6 @@ // #include -#include QT_BEGIN_NAMESPACE diff --git a/src/animation/frontend/qabstractclipblendnode.cpp b/src/animation/frontend/qabstractclipblendnode.cpp index 4154b4223..10e3b9ef5 100644 --- a/src/animation/frontend/qabstractclipblendnode.cpp +++ b/src/animation/frontend/qabstractclipblendnode.cpp @@ -38,7 +38,7 @@ #include "qabstractclipblendnode_p.h" #include #include -#include +#include QT_BEGIN_NAMESPACE @@ -63,7 +63,7 @@ QAbstractClipBlendNode::~QAbstractClipBlendNode() { } -void QAbstractClipBlendNode::addClip(QAnimationClip *clip) +void QAbstractClipBlendNode::addClip(QAbstractAnimationClip *clip) { Q_D(QAbstractClipBlendNode); if (!d->m_clips.contains(clip)) { @@ -87,7 +87,7 @@ void QAbstractClipBlendNode::addClip(QAnimationClip *clip) } } -void QAbstractClipBlendNode::removeClip(QAnimationClip *clip) +void QAbstractClipBlendNode::removeClip(QAbstractAnimationClip *clip) { Q_D(QAbstractClipBlendNode); if (d->m_changeArbiter != nullptr) { @@ -100,7 +100,7 @@ void QAbstractClipBlendNode::removeClip(QAnimationClip *clip) d->unregisterDestructionHelper(clip); } -QVector QAbstractClipBlendNode::clips() const +QVector QAbstractClipBlendNode::clips() const { Q_D(const QAbstractClipBlendNode); return d->m_clips; diff --git a/src/animation/frontend/qabstractclipblendnode.h b/src/animation/frontend/qabstractclipblendnode.h index 35714026c..d51190351 100644 --- a/src/animation/frontend/qabstractclipblendnode.h +++ b/src/animation/frontend/qabstractclipblendnode.h @@ -44,7 +44,7 @@ QT_BEGIN_NAMESPACE namespace Qt3DAnimation { -class QAnimationClip; +class QAbstractAnimationClip; class QAbstractClipBlendNodePrivate; class QT3DANIMATIONSHARED_EXPORT QAbstractClipBlendNode : public Qt3DCore::QNode @@ -53,10 +53,10 @@ class QT3DANIMATIONSHARED_EXPORT QAbstractClipBlendNode : public Qt3DCore::QNode public: ~QAbstractClipBlendNode(); - QVector clips() const; + QVector clips() const; QAbstractClipBlendNode *parentClipBlendNode() const; - void addClip(QAnimationClip *clip); - void removeClip(QAnimationClip *clip); + void addClip(QAbstractAnimationClip *clip); + void removeClip(QAbstractAnimationClip *clip); protected: explicit QAbstractClipBlendNode(Qt3DCore::QNode *parent = nullptr); diff --git a/src/animation/frontend/qabstractclipblendnode_p.h b/src/animation/frontend/qabstractclipblendnode_p.h index 42e10f18c..3066682a5 100644 --- a/src/animation/frontend/qabstractclipblendnode_p.h +++ b/src/animation/frontend/qabstractclipblendnode_p.h @@ -54,7 +54,7 @@ QT_BEGIN_NAMESPACE namespace Qt3DAnimation { -class QAnimationClip; +class QAbstractAnimationClip; class QAbstractClipBlendNode; class QAbstractClipBlendNodePrivate : public Qt3DCore::QNodePrivate @@ -63,7 +63,7 @@ public: QAbstractClipBlendNodePrivate(); Q_DECLARE_PUBLIC(QAbstractClipBlendNode) - QVector m_clips; + QVector m_clips; }; } // namespace Qt3DAnimation diff --git a/src/animation/frontend/qadditiveblend.cpp b/src/animation/frontend/qadditiveblend.cpp index 7b181848a..977f36919 100644 --- a/src/animation/frontend/qadditiveblend.cpp +++ b/src/animation/frontend/qadditiveblend.cpp @@ -36,7 +36,6 @@ #include "qadditiveblend.h" #include "qadditiveblend_p.h" -#include #include QT_BEGIN_NAMESPACE diff --git a/src/animation/frontend/qanimationaspect.cpp b/src/animation/frontend/qanimationaspect.cpp index a47a18552..1f0c43e09 100644 --- a/src/animation/frontend/qanimationaspect.cpp +++ b/src/animation/frontend/qanimationaspect.cpp @@ -39,7 +39,7 @@ #include "qanimationaspect.h" #include "qanimationaspect_p.h" -#include +#include #include #include #include @@ -88,12 +88,12 @@ QAnimationAspect::QAnimationAspect(QAnimationAspectPrivate &dd, QObject *parent) { setObjectName(QStringLiteral("Animation Aspect")); Q_D(QAnimationAspect); - qRegisterMetaType(); + qRegisterMetaType(); qRegisterMetaType(); - registerBackendType( - QSharedPointer>::create(d->m_handler.data(), - d->m_handler->animationClipManager())); + registerBackendType( + QSharedPointer>::create(d->m_handler.data(), + d->m_handler->animationClipLoaderManager())); registerBackendType( QSharedPointer>::create(d->m_handler.data(), d->m_handler->clipAnimatorManager())); diff --git a/src/animation/frontend/qanimationclip.cpp b/src/animation/frontend/qanimationclip.cpp deleted file mode 100644 index 56fe3978c..000000000 --- a/src/animation/frontend/qanimationclip.cpp +++ /dev/null @@ -1,120 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). -** Contact: http://www.qt-project.org/legal -** -** 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 "qanimationclip.h" -#include "qanimationclip_p.h" -#include - -QT_BEGIN_NAMESPACE - -namespace Qt3DAnimation { - -QAnimationClipPrivate::QAnimationClipPrivate() - : Qt3DCore::QNodePrivate() - , m_duration(0.0f) -{ -} - -void QAnimationClipPrivate::setDuration(float duration) -{ - if (qFuzzyCompare(duration, m_duration)) - return; - - Q_Q(QAnimationClip); - bool wasBlocked = q->blockNotifications(true); - m_duration = duration; - emit q->durationChanged(duration); - q->blockNotifications(wasBlocked); -} - -QAnimationClip::QAnimationClip(Qt3DCore::QNode *parent) - : Qt3DCore::QNode(*new QAnimationClipPrivate, parent) -{ -} - -QAnimationClip::QAnimationClip(QAnimationClipPrivate &dd, Qt3DCore::QNode *parent) - : Qt3DCore::QNode(dd, parent) -{ -} - -QAnimationClip::~QAnimationClip() -{ -} - -QUrl QAnimationClip::source() const -{ - Q_D(const QAnimationClip); - return d->m_source; -} - -float QAnimationClip::duration() const -{ - Q_D(const QAnimationClip); - return d->m_duration; -} - -void QAnimationClip::setSource(QUrl source) -{ - Q_D(QAnimationClip); - if (d->m_source == source) - return; - - d->m_source = source; - emit sourceChanged(source); -} - -void QAnimationClip::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) -{ - Q_D(QAnimationClip); - if (change->type() == Qt3DCore::PropertyUpdated) { - Qt3DCore::QPropertyUpdatedChangePtr e = qSharedPointerCast(change); - if (e->propertyName() == QByteArrayLiteral("duration")) - d->setDuration(e->value().toFloat()); - } -} - -Qt3DCore::QNodeCreatedChangeBasePtr QAnimationClip::createNodeCreationChange() const -{ - auto creationChange = Qt3DCore::QNodeCreatedChangePtr::create(this); - auto &data = creationChange->data; - Q_D(const QAnimationClip); - data.source = d->m_source; - return creationChange; -} - -} // namespace Qt3DAnimation - -QT_END_NAMESPACE diff --git a/src/animation/frontend/qanimationclip.h b/src/animation/frontend/qanimationclip.h deleted file mode 100644 index 55b1910fa..000000000 --- a/src/animation/frontend/qanimationclip.h +++ /dev/null @@ -1,83 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). -** Contact: http://www.qt-project.org/legal -** -** 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$ -** -****************************************************************************/ - -#ifndef QT3DANIMATION_QANIMATIONCLIP_H -#define QT3DANIMATION_QANIMATIONCLIP_H - -#include -#include -#include - -QT_BEGIN_NAMESPACE - -namespace Qt3DAnimation { - -class QAnimationClipPrivate; - -class QT3DANIMATIONSHARED_EXPORT QAnimationClip : public Qt3DCore::QNode -{ - Q_OBJECT - Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged) - Q_PROPERTY(float duration READ duration NOTIFY durationChanged) - -public: - explicit QAnimationClip(Qt3DCore::QNode *parent = nullptr); - ~QAnimationClip(); - - QUrl source() const; - float duration() const; - -public Q_SLOTS: - void setSource(QUrl source); - -Q_SIGNALS: - void sourceChanged(QUrl source); - void durationChanged(float duration); - -protected: - QAnimationClip(QAnimationClipPrivate &dd, Qt3DCore::QNode *parent = nullptr); - void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) Q_DECL_OVERRIDE; - -private: - Q_DECLARE_PRIVATE(QAnimationClip) - Qt3DCore::QNodeCreatedChangeBasePtr createNodeCreationChange() const Q_DECL_OVERRIDE; -}; - -} // namespace Qt3DAnimation - -QT_END_NAMESPACE - -#endif // QT3DANIMATION_QANIMATIONCLIP_H diff --git a/src/animation/frontend/qanimationclip_p.h b/src/animation/frontend/qanimationclip_p.h deleted file mode 100644 index 5e3df0e6e..000000000 --- a/src/animation/frontend/qanimationclip_p.h +++ /dev/null @@ -1,84 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). -** Contact: http://www.qt-project.org/legal -** -** 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$ -** -****************************************************************************/ - -#ifndef QT3DANIMATION_QANIMATIONCLIP_P_H -#define QT3DANIMATION_QANIMATIONCLIP_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of other Qt classes. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include -#include "qanimationclip.h" - -QT_BEGIN_NAMESPACE - -namespace Qt3DAnimation { - -class QAnimationClipPrivate : public Qt3DCore::QNodePrivate -{ -public: - QAnimationClipPrivate(); - - Q_DECLARE_PUBLIC(QAnimationClip) - - void setDuration(float duration); - - QUrl m_source; - - // Set from the backend - float m_duration; -}; - -struct QAnimationClipData -{ - QUrl source; - bool running; -}; - -} // namespace Qt3DAnimation - - -QT_END_NAMESPACE - -#endif // QT3DANIMATION_QANIMATIONCLIP_P_H diff --git a/src/animation/frontend/qanimationcliploader.cpp b/src/animation/frontend/qanimationcliploader.cpp new file mode 100644 index 000000000..3ee527f2d --- /dev/null +++ b/src/animation/frontend/qanimationcliploader.cpp @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** 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 "qanimationcliploader.h" +#include "qanimationcliploader_p.h" +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { + +QAnimationClipLoaderPrivate::QAnimationClipLoaderPrivate() + : QAbstractAnimationClipPrivate() + , m_source() +{ +} + +QAnimationClipLoader::QAnimationClipLoader(Qt3DCore::QNode *parent) + : QAbstractAnimationClip(*new QAnimationClipLoaderPrivate, parent) +{ +} + +QAnimationClipLoader::QAnimationClipLoader(QAnimationClipLoaderPrivate &dd, Qt3DCore::QNode *parent) + : QAbstractAnimationClip(dd, parent) +{ +} + +QAnimationClipLoader::~QAnimationClipLoader() +{ +} + +QUrl QAnimationClipLoader::source() const +{ + Q_D(const QAnimationClipLoader); + return d->m_source; +} + +void QAnimationClipLoader::setSource(QUrl source) +{ + Q_D(QAnimationClipLoader); + if (d->m_source == source) + return; + + d->m_source = source; + emit sourceChanged(source); +} + +Qt3DCore::QNodeCreatedChangeBasePtr QAnimationClipLoader::createNodeCreationChange() const +{ + auto creationChange = Qt3DCore::QNodeCreatedChangePtr::create(this); + auto &data = creationChange->data; + Q_D(const QAnimationClipLoader); + data.source = d->m_source; + return creationChange; +} + +} // namespace Qt3DAnimation + +QT_END_NAMESPACE diff --git a/src/animation/frontend/qanimationcliploader.h b/src/animation/frontend/qanimationcliploader.h new file mode 100644 index 000000000..f580e83d8 --- /dev/null +++ b/src/animation/frontend/qanimationcliploader.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** 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$ +** +****************************************************************************/ + +#ifndef QT3DANIMATION_QANIMATIONCLIP_H +#define QT3DANIMATION_QANIMATIONCLIP_H + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { + +class QAnimationClipLoaderPrivate; + +class QT3DANIMATIONSHARED_EXPORT QAnimationClipLoader : public QAbstractAnimationClip +{ + Q_OBJECT + Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged) + +public: + explicit QAnimationClipLoader(Qt3DCore::QNode *parent = nullptr); + ~QAnimationClipLoader(); + + QUrl source() const; + +public Q_SLOTS: + void setSource(QUrl source); + +Q_SIGNALS: + void sourceChanged(QUrl source); + +protected: + QAnimationClipLoader(QAnimationClipLoaderPrivate &dd, Qt3DCore::QNode *parent = nullptr); + +private: + Q_DECLARE_PRIVATE(QAnimationClipLoader) + Qt3DCore::QNodeCreatedChangeBasePtr createNodeCreationChange() const Q_DECL_OVERRIDE; +}; + +} // namespace Qt3DAnimation + +QT_END_NAMESPACE + +#endif // QT3DANIMATION_QANIMATIONCLIP_H diff --git a/src/animation/frontend/qanimationcliploader_p.h b/src/animation/frontend/qanimationcliploader_p.h new file mode 100644 index 000000000..9d1c89e52 --- /dev/null +++ b/src/animation/frontend/qanimationcliploader_p.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** 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$ +** +****************************************************************************/ + +#ifndef QT3DANIMATION_QANIMATIONCLIP_P_H +#define QT3DANIMATION_QANIMATIONCLIP_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include "qanimationcliploader.h" + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { + +class QAnimationClipLoaderPrivate : public QAbstractAnimationClipPrivate +{ +public: + QAnimationClipLoaderPrivate(); + + Q_DECLARE_PUBLIC(QAnimationClipLoader) + + QUrl m_source; +}; + +struct QAnimationClipLoaderData +{ + QUrl source; +}; + +} // namespace Qt3DAnimation + + +QT_END_NAMESPACE + +#endif // QT3DANIMATION_QANIMATIONCLIP_P_H diff --git a/src/animation/frontend/qclipanimator.cpp b/src/animation/frontend/qclipanimator.cpp index 683d2a8dd..4dcc4b578 100644 --- a/src/animation/frontend/qclipanimator.cpp +++ b/src/animation/frontend/qclipanimator.cpp @@ -39,7 +39,7 @@ #include "qclipanimator.h" #include "qclipanimator_p.h" -#include +#include #include QT_BEGIN_NAMESPACE @@ -66,13 +66,13 @@ QClipAnimator::~QClipAnimator() { } -QAnimationClip *QClipAnimator::clip() const +QAbstractAnimationClip *QClipAnimator::clip() const { Q_D(const QClipAnimator); return d->m_clip; } -void QClipAnimator::setClip(QAnimationClip *clip) +void QClipAnimator::setClip(QAbstractAnimationClip *clip) { Q_D(QClipAnimator); if (d->m_clip == clip) diff --git a/src/animation/frontend/qclipanimator.h b/src/animation/frontend/qclipanimator.h index 78fe9b6b5..311ac4ab0 100644 --- a/src/animation/frontend/qclipanimator.h +++ b/src/animation/frontend/qclipanimator.h @@ -47,25 +47,26 @@ QT_BEGIN_NAMESPACE namespace Qt3DAnimation { -class QAnimationClip; +class QAbstractAnimationClip; +class QChannelMapper; class QClipAnimatorPrivate; class QT3DANIMATIONSHARED_EXPORT QClipAnimator : public Qt3DAnimation::QAbstractClipAnimator { Q_OBJECT - Q_PROPERTY(Qt3DAnimation::QAnimationClip *clip READ clip WRITE setClip NOTIFY clipChanged) + Q_PROPERTY(Qt3DAnimation::QAbstractAnimationClip *clip READ clip WRITE setClip NOTIFY clipChanged) public: explicit QClipAnimator(Qt3DCore::QNode *parent = nullptr); ~QClipAnimator(); - Qt3DAnimation::QAnimationClip *clip() const; + Qt3DAnimation::QAbstractAnimationClip *clip() const; public Q_SLOTS: - void setClip(Qt3DAnimation::QAnimationClip *clip); + void setClip(Qt3DAnimation::QAbstractAnimationClip *clip); Q_SIGNALS: - void clipChanged(Qt3DAnimation::QAnimationClip *clip); + void clipChanged(Qt3DAnimation::QAbstractAnimationClip *clip); protected: QClipAnimator(QClipAnimatorPrivate &dd, Qt3DCore::QNode *parent = nullptr); diff --git a/src/animation/frontend/qclipanimator_p.h b/src/animation/frontend/qclipanimator_p.h index 7057ee065..fe40ed442 100644 --- a/src/animation/frontend/qclipanimator_p.h +++ b/src/animation/frontend/qclipanimator_p.h @@ -52,12 +52,13 @@ // #include -#include QT_BEGIN_NAMESPACE namespace Qt3DAnimation { +class QAbstractAnimationClip; + class QClipAnimatorPrivate : public Qt3DAnimation::QAbstractClipAnimatorPrivate { public: @@ -65,7 +66,7 @@ public: Q_DECLARE_PUBLIC(QClipAnimator) - QAnimationClip *m_clip; + QAbstractAnimationClip *m_clip; }; struct QClipAnimatorData : public QAbstractClipAnimatorData diff --git a/src/animation/frontend/qclipblendnodecreatedchange.cpp b/src/animation/frontend/qclipblendnodecreatedchange.cpp index 9e9104066..72266ade4 100644 --- a/src/animation/frontend/qclipblendnodecreatedchange.cpp +++ b/src/animation/frontend/qclipblendnodecreatedchange.cpp @@ -37,7 +37,7 @@ #include "qclipblendnodecreatedchange.h" #include "qclipblendnodecreatedchange_p.h" #include -#include +#include QT_BEGIN_NAMESPACE diff --git a/src/animation/frontend/qlerpblend.cpp b/src/animation/frontend/qlerpblend.cpp index 661c70ef0..a25272793 100644 --- a/src/animation/frontend/qlerpblend.cpp +++ b/src/animation/frontend/qlerpblend.cpp @@ -36,7 +36,6 @@ #include "qlerpblend.h" #include "qlerpblend_p.h" -#include #include QT_BEGIN_NAMESPACE diff --git a/src/quick3d/imports/animation/qt3dquick3danimationplugin.cpp b/src/quick3d/imports/animation/qt3dquick3danimationplugin.cpp index d47e3c1bc..53cc0f5ce 100644 --- a/src/quick3d/imports/animation/qt3dquick3danimationplugin.cpp +++ b/src/quick3d/imports/animation/qt3dquick3danimationplugin.cpp @@ -39,7 +39,8 @@ #include "qt3dquick3danimationplugin.h" #include -#include +#include +#include #include #include #include @@ -69,12 +70,13 @@ void Qt3DQuick3DAnimationPlugin::registerTypes(const char *uri) Qt3DAnimation::Quick::Quick3DAnimation_initialize(); // @uri Qt3D.Animation - qmlRegisterType(uri, 2, 9, "AnimationClip"); qmlRegisterUncreatableType(uri, 2, 9, "AbstractClipAnimator", QStringLiteral("QAbstractClipAnimator is abstract")); qmlRegisterType(uri, 2, 9, "ClipAnimator"); qmlRegisterType(uri, 2, 9, "BlendedClipAnimator"); qmlRegisterType(uri, 2, 9, "ChannelMapping"); qmlRegisterType(uri, 2, 9, "ChannelMapping"); + qmlRegisterUncreatableType(uri, 2, 9, "AbstractAnimationClip", QStringLiteral("QAbstractAnimationClip is abstract")); + qmlRegisterType(uri, 2, 9, "AnimationClip"); qmlRegisterExtendedType(uri, 2, 9, "ChannelMapper"); qmlRegisterExtendedUncreatableType Quick3DAbstractClipBlendNode::clipList() +QQmlListProperty Quick3DAbstractClipBlendNode::clipList() { - return QQmlListProperty(this, 0, - &Quick3DAbstractClipBlendNode::appendClip, - &Quick3DAbstractClipBlendNode::clipCount, - &Quick3DAbstractClipBlendNode::clipAt, - &Quick3DAbstractClipBlendNode::clearClips); + return QQmlListProperty(this, 0, + &Quick3DAbstractClipBlendNode::appendClip, + &Quick3DAbstractClipBlendNode::clipCount, + &Quick3DAbstractClipBlendNode::clipAt, + &Quick3DAbstractClipBlendNode::clearClips); } -void Quick3DAbstractClipBlendNode::appendClip(QQmlListProperty *list, QAnimationClip *clip) +void Quick3DAbstractClipBlendNode::appendClip(QQmlListProperty *list, QAbstractAnimationClip *clip) { Quick3DAbstractClipBlendNode *extension = qobject_cast(list->object); extension->parentAbstractClipBlendNode()->addClip(clip); } -QAnimationClip *Quick3DAbstractClipBlendNode::clipAt(QQmlListProperty *list, int index) +QAbstractAnimationClip *Quick3DAbstractClipBlendNode::clipAt(QQmlListProperty *list, int index) { Quick3DAbstractClipBlendNode *extension = qobject_cast(list->object); return extension->parentAbstractClipBlendNode()->clips().at(index); } -int Quick3DAbstractClipBlendNode::clipCount(QQmlListProperty *list) +int Quick3DAbstractClipBlendNode::clipCount(QQmlListProperty *list) { Quick3DAbstractClipBlendNode *extension = qobject_cast(list->object); return extension->parentAbstractClipBlendNode()->clips().count(); } -void Quick3DAbstractClipBlendNode::clearClips(QQmlListProperty *list) +void Quick3DAbstractClipBlendNode::clearClips(QQmlListProperty *list) { Quick3DAbstractClipBlendNode *extension = qobject_cast(list->object); - const QVector clips = extension->parentAbstractClipBlendNode()->clips(); - for (QAnimationClip *clip : clips) + const QVector clips = extension->parentAbstractClipBlendNode()->clips(); + for (QAbstractAnimationClip *clip : clips) extension->parentAbstractClipBlendNode()->removeClip(clip); } diff --git a/src/quick3d/quick3danimation/items/quick3dabstractclipblendnode_p.h b/src/quick3d/quick3danimation/items/quick3dabstractclipblendnode_p.h index bfb1825a7..8524600f4 100644 --- a/src/quick3d/quick3danimation/items/quick3dabstractclipblendnode_p.h +++ b/src/quick3d/quick3danimation/items/quick3dabstractclipblendnode_p.h @@ -53,7 +53,7 @@ #include #include -#include +#include #include QT_BEGIN_NAMESPACE @@ -65,19 +65,19 @@ namespace Quick { class QT3DQUICKANIMATIONSHARED_PRIVATE_EXPORT Quick3DAbstractClipBlendNode : public QObject { Q_OBJECT - Q_PROPERTY(QQmlListProperty clips READ clipList CONSTANT) + Q_PROPERTY(QQmlListProperty clips READ clipList CONSTANT) public: explicit Quick3DAbstractClipBlendNode(QObject *parent = nullptr); inline QAbstractClipBlendNode *parentAbstractClipBlendNode() const { return qobject_cast(parent()); } - QQmlListProperty clipList(); + QQmlListProperty clipList(); private: - static void appendClip(QQmlListProperty *list, QAnimationClip *clip); - static QAnimationClip *clipAt(QQmlListProperty *list, int index); - static int clipCount(QQmlListProperty *list); - static void clearClips(QQmlListProperty *list); + static void appendClip(QQmlListProperty *list, QAbstractAnimationClip *clip); + static QAbstractAnimationClip *clipAt(QQmlListProperty *list, int index); + static int clipCount(QQmlListProperty *list); + static void clearClips(QQmlListProperty *list); }; } // Quick diff --git a/tests/auto/animation/additiveblend/tst_additiveblend.cpp b/tests/auto/animation/additiveblend/tst_additiveblend.cpp index 31c103166..c94efedd8 100644 --- a/tests/auto/animation/additiveblend/tst_additiveblend.cpp +++ b/tests/auto/animation/additiveblend/tst_additiveblend.cpp @@ -29,7 +29,7 @@ #include #include -#include +#include #include #include #include @@ -57,7 +57,7 @@ private Q_SLOTS: { // GIVEN Qt3DAnimation::QAdditiveBlend additiveBlend; - Qt3DAnimation::QAnimationClip clip; + Qt3DAnimation::QAnimationClipLoader clip; additiveBlend.setBlendFactor(0.8f); additiveBlend.addClip(&clip); diff --git a/tests/auto/animation/animation.pro b/tests/auto/animation/animation.pro index 2f3776aaf..859f6c04f 100644 --- a/tests/auto/animation/animation.pro +++ b/tests/auto/animation/animation.pro @@ -2,7 +2,7 @@ TEMPLATE = subdirs SUBDIRS += \ qanimationaspect \ - qanimationclip \ + qanimationcliploader \ qclipanimator \ qblendedclipanimator \ qchannelmapping \ @@ -10,7 +10,7 @@ SUBDIRS += \ qtConfig(private_tests) { SUBDIRS += \ - animationclip \ + animationcliploader \ qabstractclipblendnode \ fcurve \ functionrangefinder \ diff --git a/tests/auto/animation/animationclip/animationclip.pro b/tests/auto/animation/animationclip/animationclip.pro deleted file mode 100644 index 09d9f2523..000000000 --- a/tests/auto/animation/animationclip/animationclip.pro +++ /dev/null @@ -1,12 +0,0 @@ -TEMPLATE = app - -TARGET = tst_animationclip - -QT += core-private 3dcore 3dcore-private 3danimation 3danimation-private testlib - -CONFIG += testcase - -SOURCES += \ - tst_animationclip.cpp - -include(../../core/common/common.pri) diff --git a/tests/auto/animation/animationclip/tst_animationclip.cpp b/tests/auto/animation/animationclip/tst_animationclip.cpp deleted file mode 100644 index 1a61dec2c..000000000 --- a/tests/auto/animation/animationclip/tst_animationclip.cpp +++ /dev/null @@ -1,155 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt3D module of the Qt Toolkit. -** -** $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 -#include -#include -#include -#include -#include -#include -#include -#include -#include - -class tst_AnimationClip: public Qt3DCore::QBackendNodeTester -{ - Q_OBJECT - -private Q_SLOTS: - void checkPeerPropertyMirroring() - { - // GIVEN - Qt3DAnimation::Animation::AnimationClip backendClip; - Qt3DAnimation::Animation::Handler handler; - backendClip.setHandler(&handler); - Qt3DAnimation::QAnimationClip clip; - - clip.setSource(QUrl::fromLocalFile("walk.qlip")); - - // WHEN - simulateInitialization(&clip, &backendClip); - - // THEN - QCOMPARE(backendClip.peerId(), clip.id()); - QCOMPARE(backendClip.isEnabled(), clip.isEnabled()); - QCOMPARE(backendClip.source(), clip.source()); - } - - void checkInitialAndCleanedUpState() - { - // GIVEN - Qt3DAnimation::Animation::AnimationClip backendClip; - Qt3DAnimation::Animation::Handler handler; - backendClip.setHandler(&handler); - - // THEN - QVERIFY(backendClip.peerId().isNull()); - QCOMPARE(backendClip.isEnabled(), false); - QCOMPARE(backendClip.source(), QUrl()); - QCOMPARE(backendClip.duration(), 0.0f); - - // GIVEN - Qt3DAnimation::QAnimationClip clip; - clip.setSource(QUrl::fromLocalFile("walk.qlip")); - - // WHEN - simulateInitialization(&clip, &backendClip); - backendClip.setSource(QUrl::fromLocalFile("run.qlip")); - backendClip.cleanup(); - - // THEN - QCOMPARE(backendClip.source(), QUrl()); - QCOMPARE(backendClip.isEnabled(), false); - QCOMPARE(backendClip.duration(), 0.0f); - } - - void checkPropertyChanges() - { - // GIVEN - Qt3DAnimation::Animation::AnimationClip backendClip; - Qt3DAnimation::Animation::Handler handler; - backendClip.setHandler(&handler); - Qt3DCore::QPropertyUpdatedChangePtr updateChange; - - // WHEN - updateChange.reset(new Qt3DCore::QPropertyUpdatedChange(Qt3DCore::QNodeId())); - updateChange->setPropertyName("enabled"); - updateChange->setValue(true); - backendClip.sceneChangeEvent(updateChange); - - // THEN - QCOMPARE(backendClip.isEnabled(), true); - - // WHEN - const QUrl newSource = QUrl::fromLocalFile("fallover.qlip"); - updateChange.reset(new Qt3DCore::QPropertyUpdatedChange(Qt3DCore::QNodeId())); - updateChange->setPropertyName("source"); - updateChange->setValue(newSource); - backendClip.sceneChangeEvent(updateChange); - - // THEN - QCOMPARE(backendClip.source(), newSource); - } - - void checkDurationPropertyBackendNotification() - { - // GIVEN - TestArbiter arbiter; - Qt3DAnimation::Animation::AnimationClip backendClip; - backendClip.setEnabled(true); - Qt3DCore::QBackendNodePrivate::get(&backendClip)->setArbiter(&arbiter); - - // WHEN - backendClip.setDuration(64.0f); - - // THEN - QCOMPARE(backendClip.duration(), 64.0f); - QCOMPARE(arbiter.events.count(), 1); - Qt3DCore::QPropertyUpdatedChangePtr change = arbiter.events.first().staticCast(); - QCOMPARE(change->propertyName(), "duration"); - QCOMPARE(change->value().toFloat(), backendClip.duration()); - QCOMPARE(Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(change.data())->m_isIntermediate, - false); - - arbiter.events.clear(); - - // WHEN - backendClip.setDuration(64.0f); - - // THEN - QCOMPARE(backendClip.duration(), 64.0f); - QCOMPARE(arbiter.events.count(), 0); - - arbiter.events.clear(); - } -}; - -QTEST_APPLESS_MAIN(tst_AnimationClip) - -#include "tst_animationclip.moc" diff --git a/tests/auto/animation/animationcliploader/animationcliploader.pro b/tests/auto/animation/animationcliploader/animationcliploader.pro new file mode 100644 index 000000000..b1bc6dbcc --- /dev/null +++ b/tests/auto/animation/animationcliploader/animationcliploader.pro @@ -0,0 +1,12 @@ +TEMPLATE = app + +TARGET = tst_animationcliploader + +QT += core-private 3dcore 3dcore-private 3danimation 3danimation-private testlib + +CONFIG += testcase + +SOURCES += \ + tst_animationcliploader.cpp + +include(../../core/common/common.pri) diff --git a/tests/auto/animation/animationcliploader/tst_animationcliploader.cpp b/tests/auto/animation/animationcliploader/tst_animationcliploader.cpp new file mode 100644 index 000000000..8c001b5f7 --- /dev/null +++ b/tests/auto/animation/animationcliploader/tst_animationcliploader.cpp @@ -0,0 +1,155 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class tst_AnimationClipLoader: public Qt3DCore::QBackendNodeTester +{ + Q_OBJECT + +private Q_SLOTS: + void checkPeerPropertyMirroring() + { + // GIVEN + Qt3DAnimation::Animation::AnimationClipLoader backendClip; + Qt3DAnimation::Animation::Handler handler; + backendClip.setHandler(&handler); + Qt3DAnimation::QAnimationClipLoader clip; + + clip.setSource(QUrl::fromLocalFile("walk.qlip")); + + // WHEN + simulateInitialization(&clip, &backendClip); + + // THEN + QCOMPARE(backendClip.peerId(), clip.id()); + QCOMPARE(backendClip.isEnabled(), clip.isEnabled()); + QCOMPARE(backendClip.source(), clip.source()); + } + + void checkInitialAndCleanedUpState() + { + // GIVEN + Qt3DAnimation::Animation::AnimationClipLoader backendClip; + Qt3DAnimation::Animation::Handler handler; + backendClip.setHandler(&handler); + + // THEN + QVERIFY(backendClip.peerId().isNull()); + QCOMPARE(backendClip.isEnabled(), false); + QCOMPARE(backendClip.source(), QUrl()); + QCOMPARE(backendClip.duration(), 0.0f); + + // GIVEN + Qt3DAnimation::QAnimationClipLoader clip; + clip.setSource(QUrl::fromLocalFile("walk.qlip")); + + // WHEN + simulateInitialization(&clip, &backendClip); + backendClip.setSource(QUrl::fromLocalFile("run.qlip")); + backendClip.cleanup(); + + // THEN + QCOMPARE(backendClip.source(), QUrl()); + QCOMPARE(backendClip.isEnabled(), false); + QCOMPARE(backendClip.duration(), 0.0f); + } + + void checkPropertyChanges() + { + // GIVEN + Qt3DAnimation::Animation::AnimationClipLoader backendClip; + Qt3DAnimation::Animation::Handler handler; + backendClip.setHandler(&handler); + Qt3DCore::QPropertyUpdatedChangePtr updateChange; + + // WHEN + updateChange.reset(new Qt3DCore::QPropertyUpdatedChange(Qt3DCore::QNodeId())); + updateChange->setPropertyName("enabled"); + updateChange->setValue(true); + backendClip.sceneChangeEvent(updateChange); + + // THEN + QCOMPARE(backendClip.isEnabled(), true); + + // WHEN + const QUrl newSource = QUrl::fromLocalFile("fallover.qlip"); + updateChange.reset(new Qt3DCore::QPropertyUpdatedChange(Qt3DCore::QNodeId())); + updateChange->setPropertyName("source"); + updateChange->setValue(newSource); + backendClip.sceneChangeEvent(updateChange); + + // THEN + QCOMPARE(backendClip.source(), newSource); + } + + void checkDurationPropertyBackendNotification() + { + // GIVEN + TestArbiter arbiter; + Qt3DAnimation::Animation::AnimationClipLoader backendClip; + backendClip.setEnabled(true); + Qt3DCore::QBackendNodePrivate::get(&backendClip)->setArbiter(&arbiter); + + // WHEN + backendClip.setDuration(64.0f); + + // THEN + QCOMPARE(backendClip.duration(), 64.0f); + QCOMPARE(arbiter.events.count(), 1); + Qt3DCore::QPropertyUpdatedChangePtr change = arbiter.events.first().staticCast(); + QCOMPARE(change->propertyName(), "duration"); + QCOMPARE(change->value().toFloat(), backendClip.duration()); + QCOMPARE(Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(change.data())->m_isIntermediate, + false); + + arbiter.events.clear(); + + // WHEN + backendClip.setDuration(64.0f); + + // THEN + QCOMPARE(backendClip.duration(), 64.0f); + QCOMPARE(arbiter.events.count(), 0); + + arbiter.events.clear(); + } +}; + +QTEST_APPLESS_MAIN(tst_AnimationClipLoader) + +#include "tst_animationcliploader.moc" diff --git a/tests/auto/animation/blendedclipanimator/tst_blendedclipanimator.cpp b/tests/auto/animation/blendedclipanimator/tst_blendedclipanimator.cpp index 04cc1026e..5c0cef708 100644 --- a/tests/auto/animation/blendedclipanimator/tst_blendedclipanimator.cpp +++ b/tests/auto/animation/blendedclipanimator/tst_blendedclipanimator.cpp @@ -28,7 +28,7 @@ #include #include -#include +#include #include #include #include diff --git a/tests/auto/animation/clipanimator/tst_clipanimator.cpp b/tests/auto/animation/clipanimator/tst_clipanimator.cpp index 77f067973..b5173e56d 100644 --- a/tests/auto/animation/clipanimator/tst_clipanimator.cpp +++ b/tests/auto/animation/clipanimator/tst_clipanimator.cpp @@ -28,7 +28,7 @@ #include #include -#include +#include #include #include #include @@ -49,7 +49,7 @@ private Q_SLOTS: Qt3DAnimation::Animation::ClipAnimator backendAnimator; backendAnimator.setHandler(&handler); Qt3DAnimation::QClipAnimator animator; - auto clip = new Qt3DAnimation::QAnimationClip(); + auto clip = new Qt3DAnimation::QAnimationClipLoader(); animator.setClip(clip); animator.setLoops(10); @@ -81,7 +81,7 @@ private Q_SLOTS: // GIVEN Qt3DAnimation::QClipAnimator animator; - auto clip = new Qt3DAnimation::QAnimationClip(); + auto clip = new Qt3DAnimation::QAnimationClipLoader(); animator.setClip(clip); animator.setRunning(true); animator.setLoops(25); @@ -116,7 +116,7 @@ private Q_SLOTS: QCOMPARE(backendAnimator.isEnabled(), true); // WHEN - auto newClip = new Qt3DAnimation::QAnimationClip(); + auto newClip = new Qt3DAnimation::QAnimationClipLoader(); updateChange.reset(new Qt3DCore::QPropertyUpdatedChange(Qt3DCore::QNodeId())); updateChange->setPropertyName("clip"); updateChange->setValue(QVariant::fromValue(newClip->id())); diff --git a/tests/auto/animation/clipblendnode/tst_clipblendnode.cpp b/tests/auto/animation/clipblendnode/tst_clipblendnode.cpp index 085979267..d8163f13f 100644 --- a/tests/auto/animation/clipblendnode/tst_clipblendnode.cpp +++ b/tests/auto/animation/clipblendnode/tst_clipblendnode.cpp @@ -29,7 +29,7 @@ #include #include -#include +#include #include #include #include @@ -78,7 +78,7 @@ private Q_SLOTS: { // GIVEN Qt3DAnimation::QLerpBlend clipBlendNode; - Qt3DAnimation::QAnimationClip clip; + Qt3DAnimation::QAnimationClipLoader clip; clipBlendNode.addClip(&clip); QCoreApplication::processEvents(); @@ -133,7 +133,7 @@ private Q_SLOTS: } { // WHEN - Qt3DAnimation::QAnimationClip clip; + Qt3DAnimation::QAnimationClipLoader clip; // To geneate the type_info in the QNodePrivate of clip Qt3DCore::QNodeCreatedChangeGenerator generator(&clip); diff --git a/tests/auto/animation/lerpblend/tst_lerpblend.cpp b/tests/auto/animation/lerpblend/tst_lerpblend.cpp index 5f494d9ec..b268fb42f 100644 --- a/tests/auto/animation/lerpblend/tst_lerpblend.cpp +++ b/tests/auto/animation/lerpblend/tst_lerpblend.cpp @@ -29,7 +29,7 @@ #include #include -#include +#include #include #include #include @@ -57,7 +57,7 @@ private Q_SLOTS: { // GIVEN Qt3DAnimation::QLerpBlend lerpBlend; - Qt3DAnimation::QAnimationClip clip; + Qt3DAnimation::QAnimationClipLoader clip; lerpBlend.setBlendFactor(0.8f); lerpBlend.addClip(&clip); diff --git a/tests/auto/animation/qabstractclipblendnode/tst_qabstractclipblendnode.cpp b/tests/auto/animation/qabstractclipblendnode/tst_qabstractclipblendnode.cpp index e2d963310..f5f1e73d4 100644 --- a/tests/auto/animation/qabstractclipblendnode/tst_qabstractclipblendnode.cpp +++ b/tests/auto/animation/qabstractclipblendnode/tst_qabstractclipblendnode.cpp @@ -29,7 +29,7 @@ #include #include -#include +#include #include #include #include @@ -76,7 +76,7 @@ private Q_SLOTS: { // WHEN - Qt3DAnimation::QAnimationClip newValue; + Qt3DAnimation::QAnimationClipLoader newValue; abstractClipBlendNode.addClip(&newValue); // THEN @@ -103,7 +103,7 @@ private Q_SLOTS: { // WHEN - Qt3DAnimation::QAnimationClip clip; + Qt3DAnimation::QAnimationClipLoader clip; abstractClipBlendNode.addClip(&clip); QCOMPARE(abstractClipBlendNode.clips().size(), 1); @@ -118,7 +118,7 @@ private Q_SLOTS: // GIVEN TestArbiter arbiter; TestClipBlendNode abstractClipBlendNode; - Qt3DAnimation::QAnimationClip clip; + Qt3DAnimation::QAnimationClipLoader clip; arbiter.setArbiterOnNode(&abstractClipBlendNode); { diff --git a/tests/auto/animation/qadditiveblend/tst_qadditiveblend.cpp b/tests/auto/animation/qadditiveblend/tst_qadditiveblend.cpp index 27acf2b47..369ca0078 100644 --- a/tests/auto/animation/qadditiveblend/tst_qadditiveblend.cpp +++ b/tests/auto/animation/qadditiveblend/tst_qadditiveblend.cpp @@ -29,7 +29,7 @@ #include #include -#include +#include #include #include #include @@ -84,8 +84,8 @@ private Q_SLOTS: { // GIVEN Qt3DAnimation::QAdditiveBlend addBlend; - Qt3DAnimation::QAnimationClip clip1; - Qt3DAnimation::QAnimationClip clip2; + Qt3DAnimation::QAnimationClipLoader clip1; + Qt3DAnimation::QAnimationClipLoader clip2; addBlend.addClip(&clip1); addBlend.addClip(&clip2); diff --git a/tests/auto/animation/qanimationclip/qanimationclip.pro b/tests/auto/animation/qanimationclip/qanimationclip.pro deleted file mode 100644 index 5a9678496..000000000 --- a/tests/auto/animation/qanimationclip/qanimationclip.pro +++ /dev/null @@ -1,12 +0,0 @@ -TEMPLATE = app - -TARGET = tst_qanimationclip - -QT += 3dcore 3dcore-private 3danimation 3danimation-private testlib - -CONFIG += testcase - -SOURCES += \ - tst_qanimationclip.cpp - -include(../../core/common/common.pri) diff --git a/tests/auto/animation/qanimationclip/tst_qanimationclip.cpp b/tests/auto/animation/qanimationclip/tst_qanimationclip.cpp deleted file mode 100644 index 8c83f6530..000000000 --- a/tests/auto/animation/qanimationclip/tst_qanimationclip.cpp +++ /dev/null @@ -1,166 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt3D module of the Qt Toolkit. -** -** $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 -#include -#include -#include -#include -#include -#include -#include -#include - -class tst_QAnimationClip : public QObject -{ - Q_OBJECT - -private Q_SLOTS: - void checkDefaultConstruction() - { - // GIVEN - Qt3DAnimation::QAnimationClip clip; - - // THEN - QCOMPARE(clip.source(), QUrl()); - QCOMPARE(clip.duration(), 0.0f); - } - - void checkPropertyChanges() - { - // GIVEN - Qt3DAnimation::QAnimationClip clip; - - { - // WHEN - QSignalSpy spy(&clip, SIGNAL(sourceChanged(QUrl))); - const QUrl newValue(QStringLiteral("qrc:/walk.qlip")); - clip.setSource(newValue); - - // THEN - QVERIFY(spy.isValid()); - QCOMPARE(clip.source(), newValue); - QCOMPARE(spy.count(), 1); - - // WHEN - spy.clear(); - clip.setSource(newValue); - - // THEN - QCOMPARE(clip.source(), newValue); - QCOMPARE(spy.count(), 0); - } - } - - void checkCreationData() - { - // GIVEN - Qt3DAnimation::QAnimationClip clip; - - clip.setSource(QUrl(QStringLiteral("http://someRemoteURL.com"))); - - // WHEN - QVector creationChanges; - - { - Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&clip); - creationChanges = creationChangeGenerator.creationChanges(); - } - - // THEN - { - QCOMPARE(creationChanges.size(), 1); - - const auto creationChangeData = qSharedPointerCast>(creationChanges.first()); - const Qt3DAnimation::QAnimationClipData data = creationChangeData->data; - - QCOMPARE(clip.id(), creationChangeData->subjectId()); - QCOMPARE(clip.isEnabled(), true); - QCOMPARE(clip.isEnabled(), creationChangeData->isNodeEnabled()); - QCOMPARE(clip.metaObject(), creationChangeData->metaObject()); - QCOMPARE(clip.source(), data.source); - } - - // WHEN - clip.setEnabled(false); - - { - Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&clip); - creationChanges = creationChangeGenerator.creationChanges(); - } - - // THEN - { - QCOMPARE(creationChanges.size(), 1); - - const auto creationChangeData = qSharedPointerCast>(creationChanges.first()); - - QCOMPARE(clip.id(), creationChangeData->subjectId()); - QCOMPARE(clip.isEnabled(), false); - QCOMPARE(clip.isEnabled(), creationChangeData->isNodeEnabled()); - QCOMPARE(clip.metaObject(), creationChangeData->metaObject()); - } - } - - void checkSourceUpdate() - { - // GIVEN - TestArbiter arbiter; - Qt3DAnimation::QAnimationClip clip; - arbiter.setArbiterOnNode(&clip); - - { - // WHEN - clip.setSource(QUrl(QStringLiteral("qrc:/toyplane.qlip"))); - QCoreApplication::processEvents(); - - // THEN - QCOMPARE(arbiter.events.size(), 1); - auto change = arbiter.events.first().staticCast(); - QCOMPARE(change->propertyName(), "source"); - QCOMPARE(change->type(), Qt3DCore::PropertyUpdated); - - arbiter.events.clear(); - } - - { - // WHEN - clip.setSource(QStringLiteral("qrc:/toyplane.qlip")); - QCoreApplication::processEvents(); - - // THEN - QCOMPARE(arbiter.events.size(), 0); - } - - } -}; - -QTEST_MAIN(tst_QAnimationClip) - -#include "tst_qanimationclip.moc" diff --git a/tests/auto/animation/qanimationcliploader/qanimationcliploader.pro b/tests/auto/animation/qanimationcliploader/qanimationcliploader.pro new file mode 100644 index 000000000..d6ef54df6 --- /dev/null +++ b/tests/auto/animation/qanimationcliploader/qanimationcliploader.pro @@ -0,0 +1,12 @@ +TEMPLATE = app + +TARGET = tst_qanimationclip + +QT += 3dcore 3dcore-private 3danimation 3danimation-private testlib + +CONFIG += testcase + +SOURCES += \ + tst_qanimationcliploader.cpp + +include(../../core/common/common.pri) diff --git a/tests/auto/animation/qanimationcliploader/tst_qanimationcliploader.cpp b/tests/auto/animation/qanimationcliploader/tst_qanimationcliploader.cpp new file mode 100644 index 000000000..352587d51 --- /dev/null +++ b/tests/auto/animation/qanimationcliploader/tst_qanimationcliploader.cpp @@ -0,0 +1,166 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $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 +#include +#include +#include +#include +#include +#include +#include +#include + +class tst_QAnimationClipLoader : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void checkDefaultConstruction() + { + // GIVEN + Qt3DAnimation::QAnimationClipLoader clip; + + // THEN + QCOMPARE(clip.source(), QUrl()); + QCOMPARE(clip.duration(), 0.0f); + } + + void checkPropertyChanges() + { + // GIVEN + Qt3DAnimation::QAnimationClipLoader clip; + + { + // WHEN + QSignalSpy spy(&clip, SIGNAL(sourceChanged(QUrl))); + const QUrl newValue(QStringLiteral("qrc:/walk.qlip")); + clip.setSource(newValue); + + // THEN + QVERIFY(spy.isValid()); + QCOMPARE(clip.source(), newValue); + QCOMPARE(spy.count(), 1); + + // WHEN + spy.clear(); + clip.setSource(newValue); + + // THEN + QCOMPARE(clip.source(), newValue); + QCOMPARE(spy.count(), 0); + } + } + + void checkCreationData() + { + // GIVEN + Qt3DAnimation::QAnimationClipLoader clip; + + clip.setSource(QUrl(QStringLiteral("http://someRemoteURL.com"))); + + // WHEN + QVector creationChanges; + + { + Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&clip); + creationChanges = creationChangeGenerator.creationChanges(); + } + + // THEN + { + QCOMPARE(creationChanges.size(), 1); + + const auto creationChangeData = qSharedPointerCast>(creationChanges.first()); + const Qt3DAnimation::QAnimationClipLoaderData data = creationChangeData->data; + + QCOMPARE(clip.id(), creationChangeData->subjectId()); + QCOMPARE(clip.isEnabled(), true); + QCOMPARE(clip.isEnabled(), creationChangeData->isNodeEnabled()); + QCOMPARE(clip.metaObject(), creationChangeData->metaObject()); + QCOMPARE(clip.source(), data.source); + } + + // WHEN + clip.setEnabled(false); + + { + Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&clip); + creationChanges = creationChangeGenerator.creationChanges(); + } + + // THEN + { + QCOMPARE(creationChanges.size(), 1); + + const auto creationChangeData = qSharedPointerCast>(creationChanges.first()); + + QCOMPARE(clip.id(), creationChangeData->subjectId()); + QCOMPARE(clip.isEnabled(), false); + QCOMPARE(clip.isEnabled(), creationChangeData->isNodeEnabled()); + QCOMPARE(clip.metaObject(), creationChangeData->metaObject()); + } + } + + void checkSourceUpdate() + { + // GIVEN + TestArbiter arbiter; + Qt3DAnimation::QAnimationClipLoader clip; + arbiter.setArbiterOnNode(&clip); + + { + // WHEN + clip.setSource(QUrl(QStringLiteral("qrc:/toyplane.qlip"))); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 1); + auto change = arbiter.events.first().staticCast(); + QCOMPARE(change->propertyName(), "source"); + QCOMPARE(change->type(), Qt3DCore::PropertyUpdated); + + arbiter.events.clear(); + } + + { + // WHEN + clip.setSource(QStringLiteral("qrc:/toyplane.qlip")); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 0); + } + + } +}; + +QTEST_MAIN(tst_QAnimationClipLoader) + +#include "tst_qanimationcliploader.moc" diff --git a/tests/auto/animation/qblendedclipanimator/tst_qblendedclipanimator.cpp b/tests/auto/animation/qblendedclipanimator/tst_qblendedclipanimator.cpp index 42997d8aa..d8c18bac9 100644 --- a/tests/auto/animation/qblendedclipanimator/tst_qblendedclipanimator.cpp +++ b/tests/auto/animation/qblendedclipanimator/tst_qblendedclipanimator.cpp @@ -28,9 +28,7 @@ #include -#include #include -#include #include #include #include diff --git a/tests/auto/animation/qclipanimator/tst_qclipanimator.cpp b/tests/auto/animation/qclipanimator/tst_qclipanimator.cpp index d210d4365..084e78809 100644 --- a/tests/auto/animation/qclipanimator/tst_qclipanimator.cpp +++ b/tests/auto/animation/qclipanimator/tst_qclipanimator.cpp @@ -28,10 +28,10 @@ #include -#include +#include #include #include -#include +#include #include #include #include @@ -47,7 +47,7 @@ class tst_QClipAnimator : public QObject private Q_SLOTS: void initTestCase() { - qRegisterMetaType(); + qRegisterMetaType(); qRegisterMetaType(); } @@ -57,7 +57,7 @@ private Q_SLOTS: Qt3DAnimation::QClipAnimator animator; // THEN - QCOMPARE(animator.clip(), static_cast(nullptr)); + QCOMPARE(animator.clip(), static_cast(nullptr)); QCOMPARE(animator.channelMapper(), static_cast(nullptr)); QCOMPARE(animator.loops(), 1); } @@ -69,8 +69,8 @@ private Q_SLOTS: { // WHEN - QSignalSpy spy(&animator, SIGNAL(clipChanged(Qt3DAnimation::QAnimationClip *))); - auto newValue = new Qt3DAnimation::QAnimationClip(); + QSignalSpy spy(&animator, SIGNAL(clipChanged(Qt3DAnimation::QAbstractAnimationClip *))); + auto newValue = new Qt3DAnimation::QAnimationClipLoader(); animator.setClip(newValue); // THEN @@ -134,7 +134,7 @@ private Q_SLOTS: { // GIVEN Qt3DAnimation::QClipAnimator animator; - auto clip = new Qt3DAnimation::QAnimationClip(); + auto clip = new Qt3DAnimation::QAnimationClipLoader(); animator.setClip(clip); auto mapper = new Qt3DAnimation::QChannelMapper(); animator.setChannelMapper(mapper); @@ -187,7 +187,7 @@ private Q_SLOTS: // GIVEN TestArbiter arbiter; Qt3DAnimation::QClipAnimator animator; - auto clip = new Qt3DAnimation::QAnimationClip(); + auto clip = new Qt3DAnimation::QAnimationClipLoader(); arbiter.setArbiterOnNode(&animator); { diff --git a/tests/auto/animation/qlerpblend/tst_qlerpblend.cpp b/tests/auto/animation/qlerpblend/tst_qlerpblend.cpp index 6bd6bb324..25e403007 100644 --- a/tests/auto/animation/qlerpblend/tst_qlerpblend.cpp +++ b/tests/auto/animation/qlerpblend/tst_qlerpblend.cpp @@ -29,7 +29,7 @@ #include #include -#include +#include #include #include #include @@ -84,8 +84,8 @@ private Q_SLOTS: { // GIVEN Qt3DAnimation::QLerpBlend lerpBlend; - Qt3DAnimation::QAnimationClip clip1; - Qt3DAnimation::QAnimationClip clip2; + Qt3DAnimation::QAnimationClipLoader clip1; + Qt3DAnimation::QAnimationClipLoader clip2; lerpBlend.addClip(&clip1); lerpBlend.addClip(&clip2); -- cgit v1.2.3 From d9d2f46e402a29c9e52279ec257f76320e699c9b Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Thu, 16 Feb 2017 18:31:57 +0000 Subject: Add Status property to QAnimationClipLoader Task-number: QTBUG-58898 Change-Id: I4c384c88c4846bc664dee1e050cc14f1dc9fd3fa Reviewed-by: Kevin Ottens --- src/animation/backend/animationcliploader.cpp | 20 ++++++++++++ src/animation/backend/animationcliploader_p.h | 4 +++ src/animation/frontend/qanimationcliploader.cpp | 38 ++++++++++++++++++++++ src/animation/frontend/qanimationcliploader.h | 11 +++++++ src/animation/frontend/qanimationcliploader_p.h | 3 ++ .../tst_animationcliploader.cpp | 34 +++++++++++++++++++ .../tst_qanimationcliploader.cpp | 36 +++++++++++++++++++- 7 files changed, 145 insertions(+), 1 deletion(-) diff --git a/src/animation/backend/animationcliploader.cpp b/src/animation/backend/animationcliploader.cpp index 96323885c..88d615a04 100644 --- a/src/animation/backend/animationcliploader.cpp +++ b/src/animation/backend/animationcliploader.cpp @@ -55,6 +55,7 @@ namespace Animation { AnimationClipLoader::AnimationClipLoader() : BackendNode(ReadWrite) , m_source() + , m_status(QAnimationClipLoader::NotReady) , m_name() , m_objectName() , m_channelGroups() @@ -76,12 +77,25 @@ void AnimationClipLoader::cleanup() setEnabled(false); m_handler = nullptr; m_source.clear(); + m_status = QAnimationClipLoader::NotReady; m_channelGroups.clear(); m_duration = 0.0f; clearData(); } +void AnimationClipLoader::setStatus(QAnimationClipLoader::Status status) +{ + if (status != m_status) { + m_status = status; + Qt3DCore::QPropertyUpdatedChangePtr e = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId()); + e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll); + e->setPropertyName("status"); + e->setValue(QVariant::fromValue(m_status)); + notifyObservers(e); + } +} + void AnimationClipLoader::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) { switch (e->type()) { @@ -114,6 +128,7 @@ void AnimationClipLoader::loadAnimation() QFile file(filePath); if (!file.open(QIODevice::ReadOnly)) { qWarning() << "Could not find animation clip:" << filePath; + setStatus(QAnimationClipLoader::Error); return; } @@ -147,6 +162,11 @@ void AnimationClipLoader::loadAnimation() m_channelCount = findChannelCount(); + if (qFuzzyIsNull(t) || m_channelCount == 0) + setStatus(QAnimationClipLoader::Error); + else + setStatus(QAnimationClipLoader::Ready); + qCDebug(Jobs) << "Loaded animation data:" << *this; } diff --git a/src/animation/backend/animationcliploader_p.h b/src/animation/backend/animationcliploader_p.h index 28dcb5994..c6f942dcd 100644 --- a/src/animation/backend/animationcliploader_p.h +++ b/src/animation/backend/animationcliploader_p.h @@ -49,6 +49,7 @@ // #include +#include #include #include @@ -67,6 +68,8 @@ public: void cleanup(); void setSource(const QUrl &source) { m_source = source; } QUrl source() const { return m_source; } + void setStatus(QAnimationClipLoader::Status status); + QAnimationClipLoader::Status status() const { return m_status; } void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_OVERRIDE; QString name() const { return m_name; } @@ -87,6 +90,7 @@ private: int findChannelCount(); QUrl m_source; + QAnimationClipLoader::Status m_status; QString m_name; QString m_objectName; diff --git a/src/animation/frontend/qanimationcliploader.cpp b/src/animation/frontend/qanimationcliploader.cpp index 3ee527f2d..e361552ae 100644 --- a/src/animation/frontend/qanimationcliploader.cpp +++ b/src/animation/frontend/qanimationcliploader.cpp @@ -45,9 +45,31 @@ namespace Qt3DAnimation { QAnimationClipLoaderPrivate::QAnimationClipLoaderPrivate() : QAbstractAnimationClipPrivate() , m_source() + , m_status(QAnimationClipLoader::NotReady) { } +void QAnimationClipLoaderPrivate::setStatus(QAnimationClipLoader::Status status) +{ + Q_Q(QAnimationClipLoader); + if (status != m_status) { + m_status = status; + const bool blocked = q->blockNotifications(true); + emit q->statusChanged(m_status); + q->blockNotifications(blocked); + } +} + +/*! + \enum QAnimationClipLoader::Status + + This enum identifies the status of animation clip. + + \value NotReady The clip has not been loaded yet + \value Ready The clip was successfully loaded + \value Error An error occurred while loading the clip +*/ + QAnimationClipLoader::QAnimationClipLoader(Qt3DCore::QNode *parent) : QAbstractAnimationClip(*new QAnimationClipLoaderPrivate, parent) { @@ -68,6 +90,12 @@ QUrl QAnimationClipLoader::source() const return d->m_source; } +QAnimationClipLoader::Status QAnimationClipLoader::status() const +{ + Q_D(const QAnimationClipLoader); + return d->m_status; +} + void QAnimationClipLoader::setSource(QUrl source) { Q_D(QAnimationClipLoader); @@ -78,6 +106,16 @@ void QAnimationClipLoader::setSource(QUrl source) emit sourceChanged(source); } +void QAnimationClipLoader::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) +{ + Q_D(QAnimationClipLoader); + if (change->type() == Qt3DCore::PropertyUpdated) { + const Qt3DCore::QPropertyUpdatedChangePtr e = qSharedPointerCast(change); + if (e->propertyName() == QByteArrayLiteral("status")) + d->setStatus(static_cast(e->value().toInt())); + } +} + Qt3DCore::QNodeCreatedChangeBasePtr QAnimationClipLoader::createNodeCreationChange() const { auto creationChange = Qt3DCore::QNodeCreatedChangePtr::create(this); diff --git a/src/animation/frontend/qanimationcliploader.h b/src/animation/frontend/qanimationcliploader.h index f580e83d8..d8bf1052a 100644 --- a/src/animation/frontend/qanimationcliploader.h +++ b/src/animation/frontend/qanimationcliploader.h @@ -51,21 +51,32 @@ class QT3DANIMATIONSHARED_EXPORT QAnimationClipLoader : public QAbstractAnimatio { Q_OBJECT Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged) + Q_PROPERTY(Status status READ status NOTIFY statusChanged) public: explicit QAnimationClipLoader(Qt3DCore::QNode *parent = nullptr); ~QAnimationClipLoader(); + enum Status { + NotReady = 0, + Ready, + Error + }; + Q_ENUM(Status) // LCOV_EXCL_LINE + QUrl source() const; + Status status() const; public Q_SLOTS: void setSource(QUrl source); Q_SIGNALS: void sourceChanged(QUrl source); + void statusChanged(Status status); protected: QAnimationClipLoader(QAnimationClipLoaderPrivate &dd, Qt3DCore::QNode *parent = nullptr); + void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) Q_DECL_OVERRIDE; private: Q_DECLARE_PRIVATE(QAnimationClipLoader) diff --git a/src/animation/frontend/qanimationcliploader_p.h b/src/animation/frontend/qanimationcliploader_p.h index 9d1c89e52..9b8d4c173 100644 --- a/src/animation/frontend/qanimationcliploader_p.h +++ b/src/animation/frontend/qanimationcliploader_p.h @@ -60,9 +60,12 @@ class QAnimationClipLoaderPrivate : public QAbstractAnimationClipPrivate public: QAnimationClipLoaderPrivate(); + void setStatus(QAnimationClipLoader::Status status); + Q_DECLARE_PUBLIC(QAnimationClipLoader) QUrl m_source; + QAnimationClipLoader::Status m_status; }; struct QAnimationClipLoaderData diff --git a/tests/auto/animation/animationcliploader/tst_animationcliploader.cpp b/tests/auto/animation/animationcliploader/tst_animationcliploader.cpp index 8c001b5f7..35c0d5e54 100644 --- a/tests/auto/animation/animationcliploader/tst_animationcliploader.cpp +++ b/tests/auto/animation/animationcliploader/tst_animationcliploader.cpp @@ -73,6 +73,7 @@ private Q_SLOTS: QCOMPARE(backendClip.isEnabled(), false); QCOMPARE(backendClip.source(), QUrl()); QCOMPARE(backendClip.duration(), 0.0f); + QCOMPARE(backendClip.status(), Qt3DAnimation::QAnimationClipLoader::NotReady); // GIVEN Qt3DAnimation::QAnimationClipLoader clip; @@ -87,6 +88,7 @@ private Q_SLOTS: QCOMPARE(backendClip.source(), QUrl()); QCOMPARE(backendClip.isEnabled(), false); QCOMPARE(backendClip.duration(), 0.0f); + QCOMPARE(backendClip.status(), Qt3DAnimation::QAnimationClipLoader::NotReady); } void checkPropertyChanges() @@ -148,6 +150,38 @@ private Q_SLOTS: arbiter.events.clear(); } + + void checkStatusPropertyBackendNotification() + { + // GIVEN + TestArbiter arbiter; + Qt3DAnimation::Animation::AnimationClipLoader backendClip; + backendClip.setEnabled(true); + Qt3DCore::QBackendNodePrivate::get(&backendClip)->setArbiter(&arbiter); + + // WHEN + backendClip.setStatus(Qt3DAnimation::QAnimationClipLoader::Error); + + // THEN + QCOMPARE(backendClip.status(), Qt3DAnimation::QAnimationClipLoader::Error); + QCOMPARE(arbiter.events.count(), 1); + Qt3DCore::QPropertyUpdatedChangePtr change = arbiter.events.first().staticCast(); + QCOMPARE(change->propertyName(), "status"); + QCOMPARE(change->value().value(), backendClip.status()); + QCOMPARE(Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(change.data())->m_isIntermediate, + false); + + arbiter.events.clear(); + + // WHEN + backendClip.setStatus(Qt3DAnimation::QAnimationClipLoader::Error); + + // THEN + QCOMPARE(backendClip.status(), Qt3DAnimation::QAnimationClipLoader::Error); + QCOMPARE(arbiter.events.count(), 0); + + arbiter.events.clear(); + } }; QTEST_APPLESS_MAIN(tst_AnimationClipLoader) diff --git a/tests/auto/animation/qanimationcliploader/tst_qanimationcliploader.cpp b/tests/auto/animation/qanimationcliploader/tst_qanimationcliploader.cpp index 352587d51..968ad8764 100644 --- a/tests/auto/animation/qanimationcliploader/tst_qanimationcliploader.cpp +++ b/tests/auto/animation/qanimationcliploader/tst_qanimationcliploader.cpp @@ -37,7 +37,7 @@ #include #include -class tst_QAnimationClipLoader : public QObject +class tst_QAnimationClipLoader : public Qt3DAnimation::QAnimationClipLoader { Q_OBJECT @@ -50,6 +50,7 @@ private Q_SLOTS: // THEN QCOMPARE(clip.source(), QUrl()); QCOMPARE(clip.duration(), 0.0f); + QCOMPARE(clip.status(), Qt3DAnimation::QAnimationClipLoader::NotReady); } void checkPropertyChanges() @@ -159,6 +160,39 @@ private Q_SLOTS: } } + + void checkStatusPropertyUpdate() + { + // GIVEN + qRegisterMetaType("Status"); + TestArbiter arbiter; + arbiter.setArbiterOnNode(this); + QSignalSpy spy(this, SIGNAL(statusChanged(Status))); + const Qt3DAnimation::QAnimationClipLoader::Status newStatus = Qt3DAnimation::QAnimationClipLoader::Error; + + // THEN + QVERIFY(spy.isValid()); + + // WHEN + Qt3DCore::QPropertyUpdatedChangePtr valueChange(new Qt3DCore::QPropertyUpdatedChange(Qt3DCore::QNodeId())); + valueChange->setPropertyName("status"); + valueChange->setValue(QVariant::fromValue(newStatus)); + sceneChangeEvent(valueChange); + + // THEN + QCOMPARE(spy.count(), 1); + QCOMPARE(arbiter.events.size(), 0); + QCOMPARE(status(), newStatus); + + // WHEN + spy.clear(); + sceneChangeEvent(valueChange); + + // THEN + QCOMPARE(spy.count(), 0); + QCOMPARE(arbiter.events.size(), 0); + QCOMPARE(status(), newStatus); + } }; QTEST_MAIN(tst_QAnimationClipLoader) -- cgit v1.2.3 From de28bb3aafdfc2dec80aa65cd426bf2b74718358 Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Wed, 22 Feb 2017 10:21:05 +0000 Subject: Rename QLerpBlend to QLerpClipBlend Also rename backend class accordingly. Task-number: QTBUG-58904 Change-Id: I3a8d3898507e5055c2727e4bb1b19b06fdba988b Reviewed-by: Kevin Ottens --- src/animation/backend/backend.pri | 8 +- src/animation/backend/buildblendtreesjob.cpp | 2 +- .../backend/evaluateblendclipanimatorjob.cpp | 2 +- src/animation/backend/lerpblend.cpp | 84 ---------- src/animation/backend/lerpblend_p.h | 83 --------- src/animation/backend/lerpclipblend.cpp | 84 ++++++++++ src/animation/backend/lerpclipblend_p.h | 83 +++++++++ src/animation/frontend/frontend.pri | 10 +- src/animation/frontend/qanimationaspect.cpp | 10 +- src/animation/frontend/qlerpblend.cpp | 172 ------------------- src/animation/frontend/qlerpblend.h | 78 --------- src/animation/frontend/qlerpblend_p.h | 79 --------- src/animation/frontend/qlerpclipblend.cpp | 172 +++++++++++++++++++ src/animation/frontend/qlerpclipblend.h | 78 +++++++++ src/animation/frontend/qlerpclipblend_p.h | 79 +++++++++ .../animation/qt3dquick3danimationplugin.cpp | 4 +- tests/auto/animation/animation.pro | 4 +- .../tst_blendedclipanimator.cpp | 4 +- .../animation/clipblendnode/tst_clipblendnode.cpp | 10 +- .../tst_clipblendnodevisitor.cpp | 42 ++--- tests/auto/animation/lerpblend/lerpblend.pro | 11 -- tests/auto/animation/lerpblend/tst_lerpblend.cpp | 149 ----------------- .../auto/animation/lerpclipblend/lerpclipblend.pro | 11 ++ .../animation/lerpclipblend/tst_lerpclipblend.cpp | 149 +++++++++++++++++ .../tst_qblendedclipanimator.cpp | 10 +- tests/auto/animation/qlerpblend/qlerpblend.pro | 11 -- tests/auto/animation/qlerpblend/tst_qlerpblend.cpp | 185 --------------------- .../animation/qlerpclipblend/qlerpclipblend.pro | 12 ++ .../qlerpclipblend/tst_qlerpclipblend.cpp | 185 +++++++++++++++++++++ 29 files changed, 906 insertions(+), 905 deletions(-) delete mode 100644 src/animation/backend/lerpblend.cpp delete mode 100644 src/animation/backend/lerpblend_p.h create mode 100644 src/animation/backend/lerpclipblend.cpp create mode 100644 src/animation/backend/lerpclipblend_p.h delete mode 100644 src/animation/frontend/qlerpblend.cpp delete mode 100644 src/animation/frontend/qlerpblend.h delete mode 100644 src/animation/frontend/qlerpblend_p.h create mode 100644 src/animation/frontend/qlerpclipblend.cpp create mode 100644 src/animation/frontend/qlerpclipblend.h create mode 100644 src/animation/frontend/qlerpclipblend_p.h delete mode 100644 tests/auto/animation/lerpblend/lerpblend.pro delete mode 100644 tests/auto/animation/lerpblend/tst_lerpblend.cpp create mode 100644 tests/auto/animation/lerpclipblend/lerpclipblend.pro create mode 100644 tests/auto/animation/lerpclipblend/tst_lerpclipblend.cpp delete mode 100644 tests/auto/animation/qlerpblend/qlerpblend.pro delete mode 100644 tests/auto/animation/qlerpblend/tst_qlerpblend.cpp create mode 100644 tests/auto/animation/qlerpclipblend/qlerpclipblend.pro create mode 100644 tests/auto/animation/qlerpclipblend/tst_qlerpclipblend.cpp diff --git a/src/animation/backend/backend.pri b/src/animation/backend/backend.pri index eab1f035b..ab0d242dc 100644 --- a/src/animation/backend/backend.pri +++ b/src/animation/backend/backend.pri @@ -19,13 +19,13 @@ HEADERS += \ $$PWD/findrunningclipanimatorsjob_p.h \ $$PWD/evaluateclipanimatorjob_p.h \ $$PWD/clipblendnode_p.h \ - $$PWD/lerpblend_p.h \ $$PWD/clipblendnodevisitor_p.h \ $$PWD/animationutils_p.h \ $$PWD/buildblendtreesjob_p.h \ $$PWD/evaluateblendclipanimatorjob_p.h \ $$PWD/additiveblend_p.h \ - $$PWD/animationcliploader_p.h + $$PWD/animationcliploader_p.h \ + $$PWD/lerpclipblend_p.h SOURCES += \ $$PWD/handler.cpp \ @@ -41,11 +41,11 @@ SOURCES += \ $$PWD/findrunningclipanimatorsjob.cpp \ $$PWD/evaluateclipanimatorjob.cpp \ $$PWD/clipblendnode.cpp \ - $$PWD/lerpblend.cpp \ $$PWD/managers.cpp \ $$PWD/clipblendnodevisitor.cpp \ $$PWD/animationutils.cpp \ $$PWD/buildblendtreesjob.cpp \ $$PWD/evaluateblendclipanimatorjob.cpp \ $$PWD/additiveblend.cpp \ - $$PWD/animationcliploader.cpp + $$PWD/animationcliploader.cpp \ + $$PWD/lerpclipblend.cpp diff --git a/src/animation/backend/buildblendtreesjob.cpp b/src/animation/backend/buildblendtreesjob.cpp index f57bf5201..f5d4036d2 100644 --- a/src/animation/backend/buildblendtreesjob.cpp +++ b/src/animation/backend/buildblendtreesjob.cpp @@ -39,7 +39,7 @@ #include #include #include -#include +#include #include QT_BEGIN_NAMESPACE diff --git a/src/animation/backend/evaluateblendclipanimatorjob.cpp b/src/animation/backend/evaluateblendclipanimatorjob.cpp index 51dcd6c14..e2ba523bc 100644 --- a/src/animation/backend/evaluateblendclipanimatorjob.cpp +++ b/src/animation/backend/evaluateblendclipanimatorjob.cpp @@ -39,7 +39,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/animation/backend/lerpblend.cpp b/src/animation/backend/lerpblend.cpp deleted file mode 100644 index f4423aee9..000000000 --- a/src/animation/backend/lerpblend.cpp +++ /dev/null @@ -1,84 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). -** Contact: http://www.qt-project.org/legal -** -** 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 "lerpblend_p.h" -#include -#include -#include - -QT_BEGIN_NAMESPACE - -namespace Qt3DAnimation { - -namespace Animation { - -LerpBlend::LerpBlend() - : ClipBlendNode(ClipBlendNode::LerpBlendType) - , m_blendFactor(0.0f) -{ -} - -LerpBlend::~LerpBlend() -{ -} - -void LerpBlend::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) -{ - if (e->type() == Qt3DCore::PropertyUpdated) { - Qt3DCore::QPropertyUpdatedChangePtr change = qSharedPointerCast(e); - if (change->propertyName() == QByteArrayLiteral("blendFactor")) - m_blendFactor = change->value().toFloat(); - } -} - -float LerpBlend::blend(float value1, float value2) const -{ - return ((1.0f - m_blendFactor) * value1) + (m_blendFactor * value2); -} - -void LerpBlend::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) -{ - ClipBlendNode::initializeFromPeer(change); - const auto creationChangeData = qSharedPointerCast>(change); - const Qt3DAnimation::QLerpBlendData cloneData = creationChangeData->data; - m_blendFactor = cloneData.blendFactor; -} - -} // Animation - -} // Qt3DAnimation - -QT_END_NAMESPACE diff --git a/src/animation/backend/lerpblend_p.h b/src/animation/backend/lerpblend_p.h deleted file mode 100644 index 6538b38e3..000000000 --- a/src/animation/backend/lerpblend_p.h +++ /dev/null @@ -1,83 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). -** Contact: http://www.qt-project.org/legal -** -** 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$ -** -****************************************************************************/ - -#ifndef QT3DANIMATION_ANIMATION_LERPBLEND_P_H -#define QT3DANIMATION_ANIMATION_LERPBLEND_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of other Qt classes. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include - -QT_BEGIN_NAMESPACE - -namespace Qt3DAnimation { - -namespace Animation { - -class Q_AUTOTEST_EXPORT LerpBlend : public ClipBlendNode -{ -public: - LerpBlend(); - ~LerpBlend(); - - inline float blendFactor() const { return m_blendFactor; } - void setBlendFactor(float blendFactor) { m_blendFactor = blendFactor; } // For unit tests - - void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_FINAL; - float blend(float value1, float value2) const Q_DECL_FINAL; - -private: - void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL; - - float m_blendFactor; -}; - -} // Animation - -} // Qt3DAnimation - -QT_END_NAMESPACE - -#endif // QT3DANIMATION_ANIMATION_LERPBLEND_P_H diff --git a/src/animation/backend/lerpclipblend.cpp b/src/animation/backend/lerpclipblend.cpp new file mode 100644 index 000000000..1121f0324 --- /dev/null +++ b/src/animation/backend/lerpclipblend.cpp @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** 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 "lerpclipblend_p.h" +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { + +namespace Animation { + +LerpClipBlend::LerpClipBlend() + : ClipBlendNode(ClipBlendNode::LerpBlendType) + , m_blendFactor(0.0f) +{ +} + +LerpClipBlend::~LerpClipBlend() +{ +} + +void LerpClipBlend::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) +{ + if (e->type() == Qt3DCore::PropertyUpdated) { + Qt3DCore::QPropertyUpdatedChangePtr change = qSharedPointerCast(e); + if (change->propertyName() == QByteArrayLiteral("blendFactor")) + m_blendFactor = change->value().toFloat(); + } +} + +float LerpClipBlend::blend(float value1, float value2) const +{ + return ((1.0f - m_blendFactor) * value1) + (m_blendFactor * value2); +} + +void LerpClipBlend::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) +{ + ClipBlendNode::initializeFromPeer(change); + const auto creationChangeData = qSharedPointerCast>(change); + const Qt3DAnimation::QLerpClipBlendData cloneData = creationChangeData->data; + m_blendFactor = cloneData.blendFactor; +} + +} // Animation + +} // Qt3DAnimation + +QT_END_NAMESPACE diff --git a/src/animation/backend/lerpclipblend_p.h b/src/animation/backend/lerpclipblend_p.h new file mode 100644 index 000000000..8b925b5b6 --- /dev/null +++ b/src/animation/backend/lerpclipblend_p.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** 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$ +** +****************************************************************************/ + +#ifndef QT3DANIMATION_ANIMATION_LERPCLIPBLEND_P_H +#define QT3DANIMATION_ANIMATION_LERPCLIPBLEND_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { + +namespace Animation { + +class Q_AUTOTEST_EXPORT LerpClipBlend : public ClipBlendNode +{ +public: + LerpClipBlend(); + ~LerpClipBlend(); + + inline float blendFactor() const { return m_blendFactor; } + void setBlendFactor(float blendFactor) { m_blendFactor = blendFactor; } // For unit tests + + void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_FINAL; + float blend(float value1, float value2) const Q_DECL_FINAL; + +private: + void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL; + + float m_blendFactor; +}; + +} // Animation + +} // Qt3DAnimation + +QT_END_NAMESPACE + +#endif // QT3DANIMATION_ANIMATION_LERPCLIPBLEND_P_H diff --git a/src/animation/frontend/frontend.pri b/src/animation/frontend/frontend.pri index d31193a04..ce9bee2cf 100644 --- a/src/animation/frontend/frontend.pri +++ b/src/animation/frontend/frontend.pri @@ -15,8 +15,6 @@ HEADERS += \ $$PWD/qchannelmapper_p.h \ $$PWD/qchannelmapping.h \ $$PWD/qchannelmapping_p.h \ - $$PWD/qlerpblend.h \ - $$PWD/qlerpblend_p.h \ $$PWD/qclipblendnodecreatedchange.h \ $$PWD/qclipblendnodecreatedchange_p.h \ $$PWD/qadditiveblend.h \ @@ -36,7 +34,9 @@ HEADERS += \ $$PWD/qvertexblendanimation.h \ $$PWD/qvertexblendanimation_p.h \ $$PWD/qanimationcliploader.h \ - $$PWD/qanimationcliploader_p.h + $$PWD/qanimationcliploader_p.h \ + $$PWD/qlerpclipblend.h \ + $$PWD/qlerpclipblend_p.h SOURCES += \ $$PWD/qanimationaspect.cpp \ @@ -47,7 +47,6 @@ SOURCES += \ $$PWD/qblendedclipanimator.cpp \ $$PWD/qchannelmapper.cpp \ $$PWD/qchannelmapping.cpp \ - $$PWD/qlerpblend.cpp \ $$PWD/qclipblendnodecreatedchange.cpp \ $$PWD/qadditiveblend.cpp \ $$PWD/qanimationcontroller.cpp \ @@ -57,6 +56,7 @@ SOURCES += \ $$PWD/qabstractanimation.cpp \ $$PWD/qmorphtarget.cpp \ $$PWD/qvertexblendanimation.cpp \ - $$PWD/qanimationcliploader.cpp + $$PWD/qanimationcliploader.cpp \ + $$PWD/qlerpclipblend.cpp INCLUDEPATH += $$PWD diff --git a/src/animation/frontend/qanimationaspect.cpp b/src/animation/frontend/qanimationaspect.cpp index 1f0c43e09..2fac063c2 100644 --- a/src/animation/frontend/qanimationaspect.cpp +++ b/src/animation/frontend/qanimationaspect.cpp @@ -44,12 +44,12 @@ #include #include #include -#include +#include #include #include #include #include -#include +#include #include QT_BEGIN_NAMESPACE @@ -106,9 +106,9 @@ QAnimationAspect::QAnimationAspect(QAnimationAspectPrivate &dd, QObject *parent) registerBackendType( QSharedPointer>::create(d->m_handler.data(), d->m_handler->channelMapperManager())); - registerBackendType( - QSharedPointer>::create(d->m_handler.data(), - d->m_handler->clipBlendNodeManager())); + registerBackendType( + QSharedPointer>::create(d->m_handler.data(), + d->m_handler->clipBlendNodeManager())); registerBackendType( QSharedPointer>::create(d->m_handler.data(), d->m_handler->clipBlendNodeManager())); diff --git a/src/animation/frontend/qlerpblend.cpp b/src/animation/frontend/qlerpblend.cpp deleted file mode 100644 index a25272793..000000000 --- a/src/animation/frontend/qlerpblend.cpp +++ /dev/null @@ -1,172 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). -** Contact: http://www.qt-project.org/legal -** -** 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 "qlerpblend.h" -#include "qlerpblend_p.h" -#include - -QT_BEGIN_NAMESPACE - -namespace Qt3DAnimation { - -/*! - \qmltype LerpBlend - \instantiates Qt3DAnimation::QLerpBlend - \inqmlmodule Qt3D.Animation - - \brief Performs a linear interpolation of two animation clips based on a - normalized factor - - \since 5.9 - - LerpBlend can be useful to create advanced animation effects based on - individual animation clips. For instance, given a player character,, lerp - blending could be used to combine a walking animation clip with an injured - animation clip based on a blend factor that increases the more the player - gets injured. This would then allow with blend factor == 0 to have a non - injured walking player, with blend factor == 1 a fully injured player, with - blend factor == 0.5 a partially walking and injured player. - - \sa BlendedClipAnimator -*/ - -/*! - \class Qt3DAnimation::QLerpBlend - \inmodule Qt3DAnimation - \inherits Qt3DAnimation::QAbstractClipBlendNode - - \brief Performs a linear interpolation of two animation clips based on a - normalized factor - - \since 5.9 - - QLerpBlend can be useful to create advanced animation effects based on - individual animation clips. For instance, given a player character,, lerp - blending could be used to combine a walking animation clip with an injured - animation clip based on a blend factor that increases the more the player - gets injured. This would then allow with blend factor == 0 to have a non - injured walking player, with blend factor == 1 a fully injured player, with - blend factor == 0.5 a partially walking and injured player. - - \sa QBlendedClipAnimator -*/ - -QLerpBlendPrivate::QLerpBlendPrivate() - : QAbstractClipBlendNodePrivate() - , m_blendFactor(0.0f) -{ -} - -QLerpBlend::QLerpBlend(Qt3DCore::QNode *parent) - : QAbstractClipBlendNode(*new QLerpBlendPrivate(), parent) -{ -} - -QLerpBlend::QLerpBlend(QLerpBlendPrivate &dd, Qt3DCore::QNode *parent) - : QAbstractClipBlendNode(dd, parent) -{ -} - -QLerpBlend::~QLerpBlend() -{ -} - -Qt3DCore::QNodeCreatedChangeBasePtr QLerpBlend::createNodeCreationChange() const -{ - Q_D(const QLerpBlend); - auto creationChange = QClipBlendNodeCreatedChangePtr::create(this); - QLerpBlendData &data = creationChange->data; - data.blendFactor = d->m_blendFactor; - return creationChange; -} - -/*! - \qmlproperty real LerpBlend::blendFactor - - Specifies the blending factor between 0 and 1 to control the blending of - two animation clips. -*/ -/*! - \property QLerpBlend::blendFactor - - Specifies the blending factor between 0 and 1 to control the blending of - two animation clips. - */ -float QLerpBlend::blendFactor() const -{ - Q_D(const QLerpBlend); - return d->m_blendFactor; -} - -void QLerpBlend::setBlendFactor(float blendFactor) -{ - Q_D(QLerpBlend); - if (d->m_blendFactor == blendFactor) - return; - - d->m_blendFactor = blendFactor; - emit blendFactorChanged(blendFactor); -} - -/*! - \qmlproperty list LerpBlend::clips - - Holds the list of AnimationClip nodes against which the blending is performed. - - \note Only the two first AnimationClip are used, subsequent ones are ignored -*/ - - -/*! - \fn void QLerpBlend::addClip(QAnimationClip *clip); - Adds a \a clip to the blending node's clips list. - - \note Only the two first AnimationClip are used, subsequent ones are ignored - */ - -/*! - \fn void QLerpBlend::removeClip(QAnimationClip *clip); - Removes a \a clip from the blending node's clips list. - */ - -/*! - \fn QVector QLerpBlend::clips() const; - Returns the list of QAnimationClip against which the blending is performed. - */ - -} // Qt3DAnimation - -QT_END_NAMESPACE diff --git a/src/animation/frontend/qlerpblend.h b/src/animation/frontend/qlerpblend.h deleted file mode 100644 index 58fad7ff1..000000000 --- a/src/animation/frontend/qlerpblend.h +++ /dev/null @@ -1,78 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). -** Contact: http://www.qt-project.org/legal -** -** 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$ -** -****************************************************************************/ - -#ifndef QT3DANIMATION_QLERPBLEND_H -#define QT3DANIMATION_QLERPBLEND_H - -#include - -QT_BEGIN_NAMESPACE - -namespace Qt3DAnimation { - -class QLerpBlendPrivate; - -class QT3DANIMATIONSHARED_EXPORT QLerpBlend : public QAbstractClipBlendNode -{ - Q_OBJECT - Q_PROPERTY(float blendFactor READ blendFactor WRITE setBlendFactor NOTIFY blendFactorChanged) - -public: - explicit QLerpBlend(Qt3DCore::QNode *parent = nullptr); - ~QLerpBlend(); - - float blendFactor() const; - -public Q_SLOTS: - void setBlendFactor(float blendFactor); - -Q_SIGNALS: - void blendFactorChanged(float blendFactor); - -protected: - explicit QLerpBlend(QLerpBlendPrivate &dd, Qt3DCore::QNode *parent = nullptr); - -private: - Q_DECLARE_PRIVATE(QLerpBlend) - Qt3DCore::QNodeCreatedChangeBasePtr createNodeCreationChange() const Q_DECL_OVERRIDE; -}; - -} // Qt3DAnimation - -QT_END_NAMESPACE - - -#endif // QT3DANIMATION_QLERPBLEND_H diff --git a/src/animation/frontend/qlerpblend_p.h b/src/animation/frontend/qlerpblend_p.h deleted file mode 100644 index 035e6cf79..000000000 --- a/src/animation/frontend/qlerpblend_p.h +++ /dev/null @@ -1,79 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). -** Contact: http://www.qt-project.org/legal -** -** 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$ -** -****************************************************************************/ - -#ifndef QT3DANIMATION_QLERPBLEND_P_H -#define QT3DANIMATION_QLERPBLEND_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of other Qt classes. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include -#include -#include "qlerpblend.h" - -QT_BEGIN_NAMESPACE - -namespace Qt3DAnimation { - -class QLerpBlend; - -class QLerpBlendPrivate : public QAbstractClipBlendNodePrivate -{ -public: - QLerpBlendPrivate(); - - Q_DECLARE_PUBLIC(QLerpBlend) - float m_blendFactor; -}; - -struct QLerpBlendData -{ - float blendFactor; -}; - -} // Qt3DAnimation - -QT_END_NAMESPACE - -#endif // QT3DANIMATION_QLERPBLEND_P_H diff --git a/src/animation/frontend/qlerpclipblend.cpp b/src/animation/frontend/qlerpclipblend.cpp new file mode 100644 index 000000000..cb6df6235 --- /dev/null +++ b/src/animation/frontend/qlerpclipblend.cpp @@ -0,0 +1,172 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** 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 "qlerpclipblend.h" +#include "qlerpclipblend_p.h" +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { + +/*! + \qmltype LerpBlend + \instantiates Qt3DAnimation::QLerpClipBlend + \inqmlmodule Qt3D.Animation + + \brief Performs a linear interpolation of two animation clips based on a + normalized factor + + \since 5.9 + + LerpBlend can be useful to create advanced animation effects based on + individual animation clips. For instance, given a player character,, lerp + blending could be used to combine a walking animation clip with an injured + animation clip based on a blend factor that increases the more the player + gets injured. This would then allow with blend factor == 0 to have a non + injured walking player, with blend factor == 1 a fully injured player, with + blend factor == 0.5 a partially walking and injured player. + + \sa BlendedClipAnimator +*/ + +/*! + \class Qt3DAnimation::QLerpClipBlend + \inmodule Qt3DAnimation + \inherits Qt3DAnimation::QAbstractClipBlendNode + + \brief Performs a linear interpolation of two animation clips based on a + normalized factor + + \since 5.9 + + QLerpClipBlend can be useful to create advanced animation effects based on + individual animation clips. For instance, given a player character,, lerp + blending could be used to combine a walking animation clip with an injured + animation clip based on a blend factor that increases the more the player + gets injured. This would then allow with blend factor == 0 to have a non + injured walking player, with blend factor == 1 a fully injured player, with + blend factor == 0.5 a partially walking and injured player. + + \sa QBlendedClipAnimator +*/ + +QLerpClipBlendPrivate::QLerpClipBlendPrivate() + : QAbstractClipBlendNodePrivate() + , m_blendFactor(0.0f) +{ +} + +QLerpClipBlend::QLerpClipBlend(Qt3DCore::QNode *parent) + : QAbstractClipBlendNode(*new QLerpClipBlendPrivate(), parent) +{ +} + +QLerpClipBlend::QLerpClipBlend(QLerpClipBlendPrivate &dd, Qt3DCore::QNode *parent) + : QAbstractClipBlendNode(dd, parent) +{ +} + +QLerpClipBlend::~QLerpClipBlend() +{ +} + +Qt3DCore::QNodeCreatedChangeBasePtr QLerpClipBlend::createNodeCreationChange() const +{ + Q_D(const QLerpClipBlend); + auto creationChange = QClipBlendNodeCreatedChangePtr::create(this); + QLerpClipBlendData &data = creationChange->data; + data.blendFactor = d->m_blendFactor; + return creationChange; +} + +/*! + \qmlproperty real LerpBlend::blendFactor + + Specifies the blending factor between 0 and 1 to control the blending of + two animation clips. +*/ +/*! + \property QLerpClipBlend::blendFactor + + Specifies the blending factor between 0 and 1 to control the blending of + two animation clips. + */ +float QLerpClipBlend::blendFactor() const +{ + Q_D(const QLerpClipBlend); + return d->m_blendFactor; +} + +void QLerpClipBlend::setBlendFactor(float blendFactor) +{ + Q_D(QLerpClipBlend); + if (d->m_blendFactor == blendFactor) + return; + + d->m_blendFactor = blendFactor; + emit blendFactorChanged(blendFactor); +} + +/*! + \qmlproperty list LerpBlend::clips + + Holds the list of AnimationClip nodes against which the blending is performed. + + \note Only the two first AnimationClip are used, subsequent ones are ignored +*/ + + +/*! + \fn void QLerpClipBlend::addClip(QAbstractAnimationClip *clip); + Adds a \a clip to the blending node's clips list. + + \note Only the two first AnimationClip are used, subsequent ones are ignored + */ + +/*! + \fn void QLerpClipBlend::removeClip(QAbstractAnimationClip *clip); + Removes a \a clip from the blending node's clips list. + */ + +/*! + \fn QVector QLerpClipBlend::clips() const; + Returns the list of QAnimationClip against which the blending is performed. + */ + +} // Qt3DAnimation + +QT_END_NAMESPACE diff --git a/src/animation/frontend/qlerpclipblend.h b/src/animation/frontend/qlerpclipblend.h new file mode 100644 index 000000000..83d1201cb --- /dev/null +++ b/src/animation/frontend/qlerpclipblend.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** 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$ +** +****************************************************************************/ + +#ifndef QT3DANIMATION_QLERPCLIPBLEND_H +#define QT3DANIMATION_QLERPCLIPBLEND_H + +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { + +class QLerpClipBlendPrivate; + +class QT3DANIMATIONSHARED_EXPORT QLerpClipBlend : public QAbstractClipBlendNode +{ + Q_OBJECT + Q_PROPERTY(float blendFactor READ blendFactor WRITE setBlendFactor NOTIFY blendFactorChanged) + +public: + explicit QLerpClipBlend(Qt3DCore::QNode *parent = nullptr); + ~QLerpClipBlend(); + + float blendFactor() const; + +public Q_SLOTS: + void setBlendFactor(float blendFactor); + +Q_SIGNALS: + void blendFactorChanged(float blendFactor); + +protected: + explicit QLerpClipBlend(QLerpClipBlendPrivate &dd, Qt3DCore::QNode *parent = nullptr); + +private: + Q_DECLARE_PRIVATE(QLerpClipBlend) + Qt3DCore::QNodeCreatedChangeBasePtr createNodeCreationChange() const Q_DECL_OVERRIDE; +}; + +} // Qt3DAnimation + +QT_END_NAMESPACE + + +#endif // QT3DANIMATION_QLERPCLIPBLEND_H diff --git a/src/animation/frontend/qlerpclipblend_p.h b/src/animation/frontend/qlerpclipblend_p.h new file mode 100644 index 000000000..eeae948bf --- /dev/null +++ b/src/animation/frontend/qlerpclipblend_p.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** 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$ +** +****************************************************************************/ + +#ifndef QT3DANIMATION_QLERPBLEND_P_H +#define QT3DANIMATION_QLERPBLEND_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include "qlerpclipblend.h" + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { + +class QLerpClipBlend; + +class QLerpClipBlendPrivate : public QAbstractClipBlendNodePrivate +{ +public: + QLerpClipBlendPrivate(); + + Q_DECLARE_PUBLIC(QLerpClipBlend) + float m_blendFactor; +}; + +struct QLerpClipBlendData +{ + float blendFactor; +}; + +} // Qt3DAnimation + +QT_END_NAMESPACE + +#endif // QT3DANIMATION_QLERPBLEND_P_H diff --git a/src/quick3d/imports/animation/qt3dquick3danimationplugin.cpp b/src/quick3d/imports/animation/qt3dquick3danimationplugin.cpp index 53cc0f5ce..6f52de389 100644 --- a/src/quick3d/imports/animation/qt3dquick3danimationplugin.cpp +++ b/src/quick3d/imports/animation/qt3dquick3danimationplugin.cpp @@ -44,7 +44,7 @@ #include #include #include -#include +#include #include #include @@ -81,8 +81,8 @@ void Qt3DQuick3DAnimationPlugin::registerTypes(const char *uri) Qt3DAnimation::Animation::Quick::Quick3DChannelMapper>(uri, 2, 9, "ChannelMapper"); qmlRegisterExtendedUncreatableType(uri, 2, 9, "AbstractClipBlendNode", QStringLiteral("QAbstractClipBlendNode is abstract")); - qmlRegisterType(uri, 2, 9, "LerpBlend"); qmlRegisterType(uri, 2, 9, "AdditiveBlend"); + qmlRegisterType(uri, 2, 9, "LerpClipBlend"); qmlRegisterUncreatableType(uri, 2, 9, "AbstractAnimation", QStringLiteral("AbstractAnimation is abstract")); qmlRegisterExtendedType(uri, 2, 9, "KeyframeAnimation"); diff --git a/tests/auto/animation/animation.pro b/tests/auto/animation/animation.pro index 859f6c04f..e62c431d6 100644 --- a/tests/auto/animation/animation.pro +++ b/tests/auto/animation/animation.pro @@ -19,10 +19,10 @@ qtConfig(private_tests) { blendedclipanimator \ channelmapper \ channelmapping \ - qlerpblend \ + qlerpclipblend \ clipblendnodemanager \ clipblendnode \ - lerpblend \ + lerpclipblend \ clipblendnodevisitor \ qadditiveblend \ additiveblend diff --git a/tests/auto/animation/blendedclipanimator/tst_blendedclipanimator.cpp b/tests/auto/animation/blendedclipanimator/tst_blendedclipanimator.cpp index 5c0cef708..2b26fbfce 100644 --- a/tests/auto/animation/blendedclipanimator/tst_blendedclipanimator.cpp +++ b/tests/auto/animation/blendedclipanimator/tst_blendedclipanimator.cpp @@ -39,7 +39,7 @@ #include #include -#include +#include #include #include #include @@ -99,7 +99,7 @@ private Q_SLOTS: // GIVEN Qt3DAnimation::QBlendedClipAnimator blendedClipAnimator; Qt3DAnimation::QChannelMapper mapper; - Qt3DAnimation::QLerpBlend blendTree; + Qt3DAnimation::QLerpClipBlend blendTree; blendedClipAnimator.setRunning(true); blendedClipAnimator.setBlendTree(&blendTree); blendedClipAnimator.setChannelMapper(&mapper); diff --git a/tests/auto/animation/clipblendnode/tst_clipblendnode.cpp b/tests/auto/animation/clipblendnode/tst_clipblendnode.cpp index d8163f13f..3e0ebf4f6 100644 --- a/tests/auto/animation/clipblendnode/tst_clipblendnode.cpp +++ b/tests/auto/animation/clipblendnode/tst_clipblendnode.cpp @@ -28,7 +28,7 @@ #include -#include +#include #include #include #include @@ -77,7 +77,7 @@ private Q_SLOTS: void checkInitializeFromPeer() { // GIVEN - Qt3DAnimation::QLerpBlend clipBlendNode; + Qt3DAnimation::QLerpClipBlend clipBlendNode; Qt3DAnimation::QAnimationClipLoader clip; clipBlendNode.addClip(&clip); @@ -153,7 +153,7 @@ private Q_SLOTS: } { // WHEN - Qt3DAnimation::QLerpBlend clipBlendChild; + Qt3DAnimation::QLerpClipBlend clipBlendChild; // Will be destroyed when manager is destroyed TestClipBlendNode *backenChildClipBlendNode = new TestClipBlendNode(); backendClipBlendNode.setClipBlendNodeManager(&manager); @@ -182,8 +182,8 @@ private Q_SLOTS: // GIVEN TestClipBlendNode *backendClipBlendNode = new TestClipBlendNode(); TestClipBlendNode *backendChildClipBlendNode = new TestClipBlendNode(); - Qt3DAnimation::QLerpBlend clipBlendParent; - Qt3DAnimation::QLerpBlend childClipBlend(&clipBlendParent); + Qt3DAnimation::QLerpClipBlend clipBlendParent; + Qt3DAnimation::QLerpClipBlend childClipBlend(&clipBlendParent); Qt3DAnimation::Animation::ClipBlendNodeManager manager; backendClipBlendNode->setClipBlendNodeManager(&manager); backendChildClipBlendNode->setClipBlendNodeManager(&manager); diff --git a/tests/auto/animation/clipblendnodevisitor/tst_clipblendnodevisitor.cpp b/tests/auto/animation/clipblendnodevisitor/tst_clipblendnodevisitor.cpp index 78f0f1202..77f835985 100644 --- a/tests/auto/animation/clipblendnodevisitor/tst_clipblendnodevisitor.cpp +++ b/tests/auto/animation/clipblendnodevisitor/tst_clipblendnodevisitor.cpp @@ -31,8 +31,8 @@ #include #include #include -#include -#include +#include +#include #include "qbackendnodetester.h" class tst_ClipBlendNodeVisitor : public Qt3DCore::QBackendNodeTester @@ -43,17 +43,17 @@ private Q_SLOTS: void checkVisitAllNodes() { // GIVEN - Qt3DAnimation::QLerpBlend rootBlendNode; - Qt3DAnimation::QLerpBlend childBlendNode1(&rootBlendNode); - Qt3DAnimation::QLerpBlend childBlendNode2(&rootBlendNode); - Qt3DAnimation::QLerpBlend childBlendNode11(&childBlendNode1); - Qt3DAnimation::QLerpBlend childBlendNode12(&childBlendNode1); - - Qt3DAnimation::Animation::LerpBlend *backendRootBlendNode = new Qt3DAnimation::Animation::LerpBlend(); - Qt3DAnimation::Animation::LerpBlend *backendChildBlendNode1 = new Qt3DAnimation::Animation::LerpBlend(); - Qt3DAnimation::Animation::LerpBlend *backendChildBlendNode2 = new Qt3DAnimation::Animation::LerpBlend(); - Qt3DAnimation::Animation::LerpBlend *backendChildBlendNode11 = new Qt3DAnimation::Animation::LerpBlend(); - Qt3DAnimation::Animation::LerpBlend *backendChildBlendNode12 = new Qt3DAnimation::Animation::LerpBlend(); + Qt3DAnimation::QLerpClipBlend rootBlendNode; + Qt3DAnimation::QLerpClipBlend childBlendNode1(&rootBlendNode); + Qt3DAnimation::QLerpClipBlend childBlendNode2(&rootBlendNode); + Qt3DAnimation::QLerpClipBlend childBlendNode11(&childBlendNode1); + Qt3DAnimation::QLerpClipBlend childBlendNode12(&childBlendNode1); + + Qt3DAnimation::Animation::LerpClipBlend *backendRootBlendNode = new Qt3DAnimation::Animation::LerpClipBlend(); + Qt3DAnimation::Animation::LerpClipBlend *backendChildBlendNode1 = new Qt3DAnimation::Animation::LerpClipBlend(); + Qt3DAnimation::Animation::LerpClipBlend *backendChildBlendNode2 = new Qt3DAnimation::Animation::LerpClipBlend(); + Qt3DAnimation::Animation::LerpClipBlend *backendChildBlendNode11 = new Qt3DAnimation::Animation::LerpClipBlend(); + Qt3DAnimation::Animation::LerpClipBlend *backendChildBlendNode12 = new Qt3DAnimation::Animation::LerpClipBlend(); Qt3DAnimation::Animation::ClipBlendNodeManager manager; backendRootBlendNode->setClipBlendNodeManager(&manager); @@ -112,9 +112,9 @@ private Q_SLOTS: void checkDoesntCrashIfRootNodeIsNotFound() { // GIVEN - Qt3DAnimation::QLerpBlend rootBlendNode; + Qt3DAnimation::QLerpClipBlend rootBlendNode; - Qt3DAnimation::Animation::LerpBlend *backendRootBlendNode = new Qt3DAnimation::Animation::LerpBlend(); + Qt3DAnimation::Animation::LerpClipBlend *backendRootBlendNode = new Qt3DAnimation::Animation::LerpClipBlend(); Qt3DAnimation::Animation::ClipBlendNodeManager manager; backendRootBlendNode->setClipBlendNodeManager(&manager); @@ -139,13 +139,13 @@ private Q_SLOTS: void checkDoesntCrashIfChildNodeIsNotFound() { // GIVEN - Qt3DAnimation::QLerpBlend rootBlendNode; - Qt3DAnimation::QLerpBlend childBlendNode1(&rootBlendNode); - Qt3DAnimation::QLerpBlend childBlendNode2(&rootBlendNode); + Qt3DAnimation::QLerpClipBlend rootBlendNode; + Qt3DAnimation::QLerpClipBlend childBlendNode1(&rootBlendNode); + Qt3DAnimation::QLerpClipBlend childBlendNode2(&rootBlendNode); - Qt3DAnimation::Animation::LerpBlend *backendRootBlendNode = new Qt3DAnimation::Animation::LerpBlend(); - Qt3DAnimation::Animation::LerpBlend *backendChildBlendNode1 = new Qt3DAnimation::Animation::LerpBlend(); - Qt3DAnimation::Animation::LerpBlend *backendChildBlendNode2 = new Qt3DAnimation::Animation::LerpBlend(); + Qt3DAnimation::Animation::LerpClipBlend *backendRootBlendNode = new Qt3DAnimation::Animation::LerpClipBlend(); + Qt3DAnimation::Animation::LerpClipBlend *backendChildBlendNode1 = new Qt3DAnimation::Animation::LerpClipBlend(); + Qt3DAnimation::Animation::LerpClipBlend *backendChildBlendNode2 = new Qt3DAnimation::Animation::LerpClipBlend(); Qt3DAnimation::Animation::ClipBlendNodeManager manager; backendRootBlendNode->setClipBlendNodeManager(&manager); diff --git a/tests/auto/animation/lerpblend/lerpblend.pro b/tests/auto/animation/lerpblend/lerpblend.pro deleted file mode 100644 index bc2cc383b..000000000 --- a/tests/auto/animation/lerpblend/lerpblend.pro +++ /dev/null @@ -1,11 +0,0 @@ -TEMPLATE = app - -TARGET = tst_lerpblend - -QT += 3dcore 3dcore-private 3danimation 3danimation-private testlib - -CONFIG += testcase - -SOURCES += tst_lerpblend.cpp - -include(../../core/common/common.pri) diff --git a/tests/auto/animation/lerpblend/tst_lerpblend.cpp b/tests/auto/animation/lerpblend/tst_lerpblend.cpp deleted file mode 100644 index b268fb42f..000000000 --- a/tests/auto/animation/lerpblend/tst_lerpblend.cpp +++ /dev/null @@ -1,149 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 Paul Lemire -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt3D module of the Qt Toolkit. -** -** $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 -#include -#include -#include -#include -#include -#include "qbackendnodetester.h" - -class tst_LerpBlend : public Qt3DCore::QBackendNodeTester -{ - Q_OBJECT - -private Q_SLOTS: - - void checkInitialState() - { - // GIVEN - Qt3DAnimation::Animation::LerpBlend backendLerpBlend; - - // THEN - QCOMPARE(backendLerpBlend.isEnabled(), false); - QVERIFY(backendLerpBlend.peerId().isNull()); - QCOMPARE(backendLerpBlend.blendFactor(), 0.0f); - QCOMPARE(backendLerpBlend.blendType(), Qt3DAnimation::Animation::ClipBlendNode::LerpBlendType); - } - - void checkInitializeFromPeer() - { - // GIVEN - Qt3DAnimation::QLerpBlend lerpBlend; - Qt3DAnimation::QAnimationClipLoader clip; - lerpBlend.setBlendFactor(0.8f); - lerpBlend.addClip(&clip); - - { - // WHEN - Qt3DAnimation::Animation::LerpBlend backendLerpBlend; - simulateInitialization(&lerpBlend, &backendLerpBlend); - - // THEN - QCOMPARE(backendLerpBlend.isEnabled(), true); - QCOMPARE(backendLerpBlend.peerId(), lerpBlend.id()); - QCOMPARE(backendLerpBlend.blendFactor(), 0.8f); - QCOMPARE(backendLerpBlend.clipIds().size(), 1); - QCOMPARE(backendLerpBlend.clipIds().first(), clip.id()); - } - { - // WHEN - Qt3DAnimation::Animation::LerpBlend backendLerpBlend; - lerpBlend.setEnabled(false); - simulateInitialization(&lerpBlend, &backendLerpBlend); - - // THEN - QCOMPARE(backendLerpBlend.peerId(), lerpBlend.id()); - QCOMPARE(backendLerpBlend.isEnabled(), false); - } - } - - void checkSceneChangeEvents() - { - // GIVEN - Qt3DAnimation::Animation::LerpBlend backendLerpBlend; - { - // WHEN - const bool newValue = false; - const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId()); - change->setPropertyName("enabled"); - change->setValue(newValue); - backendLerpBlend.sceneChangeEvent(change); - - // THEN - QCOMPARE(backendLerpBlend.isEnabled(), newValue); - } - { - // WHEN - const float newValue = 0.883f; - const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId()); - change->setPropertyName("blendFactor"); - change->setValue(QVariant::fromValue(newValue)); - backendLerpBlend.sceneChangeEvent(change); - - // THEN - QCOMPARE(backendLerpBlend.blendFactor(), newValue); - } - } - - void checkBlend_data() - { - QTest::addColumn("value1"); - QTest::addColumn("value2"); - QTest::addColumn("blendFactor"); - QTest::addColumn("result"); - - QTest::newRow("0_blending") << 8.0f << 5.0f << 0.0f << 8.0f; - QTest::newRow("0.5_blending") << 8.0f << 5.0f << 0.5f << 6.5f; - QTest::newRow("1_blending") << 8.0f << 5.0f << 1.0f << 5.0f; - } - - void checkBlend() - { - // GIVEN - QFETCH(float, value1); - QFETCH(float, value2); - QFETCH(float, blendFactor); - QFETCH(float, result); - Qt3DAnimation::Animation::LerpBlend lerpBlend; - - // WHEN - lerpBlend.setBlendFactor(blendFactor); - const float computed = lerpBlend.blend(value1, value2); - - // THEN - QCOMPARE(computed, result); - } - -}; - -QTEST_MAIN(tst_LerpBlend) - -#include "tst_lerpblend.moc" diff --git a/tests/auto/animation/lerpclipblend/lerpclipblend.pro b/tests/auto/animation/lerpclipblend/lerpclipblend.pro new file mode 100644 index 000000000..e5447cccf --- /dev/null +++ b/tests/auto/animation/lerpclipblend/lerpclipblend.pro @@ -0,0 +1,11 @@ +TEMPLATE = app + +TARGET = tst_lerpclipblend + +QT += 3dcore 3dcore-private 3danimation 3danimation-private testlib + +CONFIG += testcase + +SOURCES += tst_lerpclipblend.cpp + +include(../../core/common/common.pri) diff --git a/tests/auto/animation/lerpclipblend/tst_lerpclipblend.cpp b/tests/auto/animation/lerpclipblend/tst_lerpclipblend.cpp new file mode 100644 index 000000000..18eaa064e --- /dev/null +++ b/tests/auto/animation/lerpclipblend/tst_lerpclipblend.cpp @@ -0,0 +1,149 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Paul Lemire +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $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 +#include +#include +#include +#include +#include +#include "qbackendnodetester.h" + +class tst_LerpClipBlend : public Qt3DCore::QBackendNodeTester +{ + Q_OBJECT + +private Q_SLOTS: + + void checkInitialState() + { + // GIVEN + Qt3DAnimation::Animation::LerpClipBlend backendLerpBlend; + + // THEN + QCOMPARE(backendLerpBlend.isEnabled(), false); + QVERIFY(backendLerpBlend.peerId().isNull()); + QCOMPARE(backendLerpBlend.blendFactor(), 0.0f); + QCOMPARE(backendLerpBlend.blendType(), Qt3DAnimation::Animation::ClipBlendNode::LerpBlendType); + } + + void checkInitializeFromPeer() + { + // GIVEN + Qt3DAnimation::QLerpClipBlend lerpBlend; + Qt3DAnimation::QAnimationClipLoader clip; + lerpBlend.setBlendFactor(0.8f); + lerpBlend.addClip(&clip); + + { + // WHEN + Qt3DAnimation::Animation::LerpClipBlend backendLerpBlend; + simulateInitialization(&lerpBlend, &backendLerpBlend); + + // THEN + QCOMPARE(backendLerpBlend.isEnabled(), true); + QCOMPARE(backendLerpBlend.peerId(), lerpBlend.id()); + QCOMPARE(backendLerpBlend.blendFactor(), 0.8f); + QCOMPARE(backendLerpBlend.clipIds().size(), 1); + QCOMPARE(backendLerpBlend.clipIds().first(), clip.id()); + } + { + // WHEN + Qt3DAnimation::Animation::LerpClipBlend backendLerpBlend; + lerpBlend.setEnabled(false); + simulateInitialization(&lerpBlend, &backendLerpBlend); + + // THEN + QCOMPARE(backendLerpBlend.peerId(), lerpBlend.id()); + QCOMPARE(backendLerpBlend.isEnabled(), false); + } + } + + void checkSceneChangeEvents() + { + // GIVEN + Qt3DAnimation::Animation::LerpClipBlend backendLerpBlend; + { + // WHEN + const bool newValue = false; + const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId()); + change->setPropertyName("enabled"); + change->setValue(newValue); + backendLerpBlend.sceneChangeEvent(change); + + // THEN + QCOMPARE(backendLerpBlend.isEnabled(), newValue); + } + { + // WHEN + const float newValue = 0.883f; + const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId()); + change->setPropertyName("blendFactor"); + change->setValue(QVariant::fromValue(newValue)); + backendLerpBlend.sceneChangeEvent(change); + + // THEN + QCOMPARE(backendLerpBlend.blendFactor(), newValue); + } + } + + void checkBlend_data() + { + QTest::addColumn("value1"); + QTest::addColumn("value2"); + QTest::addColumn("blendFactor"); + QTest::addColumn("result"); + + QTest::newRow("0_blending") << 8.0f << 5.0f << 0.0f << 8.0f; + QTest::newRow("0.5_blending") << 8.0f << 5.0f << 0.5f << 6.5f; + QTest::newRow("1_blending") << 8.0f << 5.0f << 1.0f << 5.0f; + } + + void checkBlend() + { + // GIVEN + QFETCH(float, value1); + QFETCH(float, value2); + QFETCH(float, blendFactor); + QFETCH(float, result); + Qt3DAnimation::Animation::LerpClipBlend lerpBlend; + + // WHEN + lerpBlend.setBlendFactor(blendFactor); + const float computed = lerpBlend.blend(value1, value2); + + // THEN + QCOMPARE(computed, result); + } + +}; + +QTEST_MAIN(tst_LerpClipBlend) + +#include "tst_lerpclipblend.moc" diff --git a/tests/auto/animation/qblendedclipanimator/tst_qblendedclipanimator.cpp b/tests/auto/animation/qblendedclipanimator/tst_qblendedclipanimator.cpp index d8c18bac9..3ab8e007b 100644 --- a/tests/auto/animation/qblendedclipanimator/tst_qblendedclipanimator.cpp +++ b/tests/auto/animation/qblendedclipanimator/tst_qblendedclipanimator.cpp @@ -30,7 +30,7 @@ #include #include #include -#include +#include #include #include #include @@ -71,7 +71,7 @@ private Q_SLOTS: { // WHEN QSignalSpy spy(&blendedClipAnimator, SIGNAL(blendTreeChanged(QAbstractClipBlendNode *))); - Qt3DAnimation::QLerpBlend newValue; + Qt3DAnimation::QLerpClipBlend newValue; blendedClipAnimator.setBlendTree(&newValue); // THEN @@ -152,7 +152,7 @@ private Q_SLOTS: // GIVEN Qt3DAnimation::QBlendedClipAnimator blendedClipAnimator; Qt3DAnimation::QChannelMapper channelMapper; - Qt3DAnimation::QLerpBlend blendRoot; + Qt3DAnimation::QLerpClipBlend blendRoot; blendedClipAnimator.setBlendTree(&blendRoot); blendedClipAnimator.setChannelMapper(&channelMapper); @@ -214,7 +214,7 @@ private Q_SLOTS: TestArbiter arbiter; Qt3DAnimation::QBlendedClipAnimator blendedClipAnimator; arbiter.setArbiterOnNode(&blendedClipAnimator); - Qt3DAnimation::QLerpBlend blendRoot; + Qt3DAnimation::QLerpClipBlend blendRoot; { // WHEN @@ -249,7 +249,7 @@ private Q_SLOTS: { // WHEN - Qt3DAnimation::QLerpBlend blendRoot; + Qt3DAnimation::QLerpClipBlend blendRoot; blendedClipAnimator.setBlendTree(&blendRoot); QCOMPARE(blendedClipAnimator.blendTree(), &blendRoot); diff --git a/tests/auto/animation/qlerpblend/qlerpblend.pro b/tests/auto/animation/qlerpblend/qlerpblend.pro deleted file mode 100644 index f5bdc848f..000000000 --- a/tests/auto/animation/qlerpblend/qlerpblend.pro +++ /dev/null @@ -1,11 +0,0 @@ -TEMPLATE = app - -TARGET = tst_qlerpblend - -QT += 3dcore 3dcore-private 3danimation 3danimation-private testlib - -CONFIG += testcase - -SOURCES += tst_qlerpblend.cpp - -include(../../core/common/common.pri) diff --git a/tests/auto/animation/qlerpblend/tst_qlerpblend.cpp b/tests/auto/animation/qlerpblend/tst_qlerpblend.cpp deleted file mode 100644 index 25e403007..000000000 --- a/tests/auto/animation/qlerpblend/tst_qlerpblend.cpp +++ /dev/null @@ -1,185 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 Paul Lemire -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt3D module of the Qt Toolkit. -** -** $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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "testpostmanarbiter.h" - -class tst_QLerpBlend : public QObject -{ - Q_OBJECT - -private Q_SLOTS: - - void checkDefaultConstruction() - { - // GIVEN - Qt3DAnimation::QLerpBlend lerpBlend; - - // THEN - QCOMPARE(lerpBlend.blendFactor(), 0.0f); - } - - void checkPropertyChanges() - { - // GIVEN - Qt3DAnimation::QLerpBlend lerpBlend; - - { - // WHEN - QSignalSpy spy(&lerpBlend, SIGNAL(blendFactorChanged(float))); - const float newValue = 0.5f; - lerpBlend.setBlendFactor(newValue); - - // THEN - QVERIFY(spy.isValid()); - QCOMPARE(lerpBlend.blendFactor(), newValue); - QCOMPARE(spy.count(), 1); - - // WHEN - spy.clear(); - lerpBlend.setBlendFactor(newValue); - - // THEN - QCOMPARE(lerpBlend.blendFactor(), newValue); - QCOMPARE(spy.count(), 0); - } - } - - void checkCreationData() - { - // GIVEN - Qt3DAnimation::QLerpBlend lerpBlend; - Qt3DAnimation::QAnimationClipLoader clip1; - Qt3DAnimation::QAnimationClipLoader clip2; - - lerpBlend.addClip(&clip1); - lerpBlend.addClip(&clip2); - lerpBlend.setBlendFactor(0.8f); - - - // WHEN - QVector creationChanges; - - { - Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&lerpBlend); - creationChanges = creationChangeGenerator.creationChanges(); - } - - // THEN - { - QCOMPARE(creationChanges.size(), 3); // 1 + 2 clips - - const auto creationChangeData = qSharedPointerCast>(creationChanges.first()); - const Qt3DAnimation::QLerpBlendData cloneData = creationChangeData->data; - - QCOMPARE(lerpBlend.blendFactor(), cloneData.blendFactor); - QCOMPARE(lerpBlend.id(), creationChangeData->subjectId()); - QCOMPARE(lerpBlend.isEnabled(), true); - QCOMPARE(lerpBlend.isEnabled(), creationChangeData->isNodeEnabled()); - QCOMPARE(lerpBlend.metaObject(), creationChangeData->metaObject()); - QCOMPARE(creationChangeData->clips().size(), 2); - QCOMPARE(creationChangeData->clips().first(), clip1.id()); - QCOMPARE(creationChangeData->clips().last(), clip2.id()); - QCOMPARE(creationChangeData->parentClipBlendNodeId(), Qt3DCore::QNodeId()); - } - - // WHEN - lerpBlend.setEnabled(false); - - { - Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&lerpBlend); - creationChanges = creationChangeGenerator.creationChanges(); - } - - // THEN - { - QCOMPARE(creationChanges.size(), 3); // 1 + 2 clips - - const auto creationChangeData = qSharedPointerCast>(creationChanges.first()); - const Qt3DAnimation::QLerpBlendData cloneData = creationChangeData->data; - - QCOMPARE(lerpBlend.blendFactor(), cloneData.blendFactor); - QCOMPARE(lerpBlend.id(), creationChangeData->subjectId()); - QCOMPARE(lerpBlend.isEnabled(), false); - QCOMPARE(lerpBlend.isEnabled(), creationChangeData->isNodeEnabled()); - QCOMPARE(lerpBlend.metaObject(), creationChangeData->metaObject()); - QCOMPARE(creationChangeData->clips().size(), 2); - QCOMPARE(creationChangeData->clips().first(), clip1.id()); - QCOMPARE(creationChangeData->clips().last(), clip2.id()); - QCOMPARE(creationChangeData->parentClipBlendNodeId(), Qt3DCore::QNodeId()); - } - } - - void checkBlendFactorUpdate() - { - // GIVEN - TestArbiter arbiter; - Qt3DAnimation::QLerpBlend lerpBlend; - arbiter.setArbiterOnNode(&lerpBlend); - - { - // WHEN - lerpBlend.setBlendFactor(0.4f); - QCoreApplication::processEvents(); - - // THEN - QCOMPARE(arbiter.events.size(), 1); - auto change = arbiter.events.first().staticCast(); - QCOMPARE(change->propertyName(), "blendFactor"); - QCOMPARE(change->value().value(), lerpBlend.blendFactor()); - QCOMPARE(change->type(), Qt3DCore::PropertyUpdated); - - arbiter.events.clear(); - } - - { - // WHEN - lerpBlend.setBlendFactor(0.4f); - QCoreApplication::processEvents(); - - // THEN - QCOMPARE(arbiter.events.size(), 0); - } - - } - -}; - -QTEST_MAIN(tst_QLerpBlend) - -#include "tst_qlerpblend.moc" diff --git a/tests/auto/animation/qlerpclipblend/qlerpclipblend.pro b/tests/auto/animation/qlerpclipblend/qlerpclipblend.pro new file mode 100644 index 000000000..3c26dbb19 --- /dev/null +++ b/tests/auto/animation/qlerpclipblend/qlerpclipblend.pro @@ -0,0 +1,12 @@ +TEMPLATE = app + +TARGET = tst_qlerpclipblend + +QT += 3dcore 3dcore-private 3danimation 3danimation-private testlib + +CONFIG += testcase + +SOURCES += \ + tst_qlerpclipblend.cpp + +include(../../core/common/common.pri) diff --git a/tests/auto/animation/qlerpclipblend/tst_qlerpclipblend.cpp b/tests/auto/animation/qlerpclipblend/tst_qlerpclipblend.cpp new file mode 100644 index 000000000..5f3bdeccf --- /dev/null +++ b/tests/auto/animation/qlerpclipblend/tst_qlerpclipblend.cpp @@ -0,0 +1,185 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Paul Lemire +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "testpostmanarbiter.h" + +class tst_QLerpClipBlend : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + + void checkDefaultConstruction() + { + // GIVEN + Qt3DAnimation::QLerpClipBlend lerpBlend; + + // THEN + QCOMPARE(lerpBlend.blendFactor(), 0.0f); + } + + void checkPropertyChanges() + { + // GIVEN + Qt3DAnimation::QLerpClipBlend lerpBlend; + + { + // WHEN + QSignalSpy spy(&lerpBlend, SIGNAL(blendFactorChanged(float))); + const float newValue = 0.5f; + lerpBlend.setBlendFactor(newValue); + + // THEN + QVERIFY(spy.isValid()); + QCOMPARE(lerpBlend.blendFactor(), newValue); + QCOMPARE(spy.count(), 1); + + // WHEN + spy.clear(); + lerpBlend.setBlendFactor(newValue); + + // THEN + QCOMPARE(lerpBlend.blendFactor(), newValue); + QCOMPARE(spy.count(), 0); + } + } + + void checkCreationData() + { + // GIVEN + Qt3DAnimation::QLerpClipBlend lerpBlend; + Qt3DAnimation::QAnimationClipLoader clip1; + Qt3DAnimation::QAnimationClipLoader clip2; + + lerpBlend.addClip(&clip1); + lerpBlend.addClip(&clip2); + lerpBlend.setBlendFactor(0.8f); + + + // WHEN + QVector creationChanges; + + { + Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&lerpBlend); + creationChanges = creationChangeGenerator.creationChanges(); + } + + // THEN + { + QCOMPARE(creationChanges.size(), 3); // 1 + 2 clips + + const auto creationChangeData = qSharedPointerCast>(creationChanges.first()); + const Qt3DAnimation::QLerpClipBlendData cloneData = creationChangeData->data; + + QCOMPARE(lerpBlend.blendFactor(), cloneData.blendFactor); + QCOMPARE(lerpBlend.id(), creationChangeData->subjectId()); + QCOMPARE(lerpBlend.isEnabled(), true); + QCOMPARE(lerpBlend.isEnabled(), creationChangeData->isNodeEnabled()); + QCOMPARE(lerpBlend.metaObject(), creationChangeData->metaObject()); + QCOMPARE(creationChangeData->clips().size(), 2); + QCOMPARE(creationChangeData->clips().first(), clip1.id()); + QCOMPARE(creationChangeData->clips().last(), clip2.id()); + QCOMPARE(creationChangeData->parentClipBlendNodeId(), Qt3DCore::QNodeId()); + } + + // WHEN + lerpBlend.setEnabled(false); + + { + Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&lerpBlend); + creationChanges = creationChangeGenerator.creationChanges(); + } + + // THEN + { + QCOMPARE(creationChanges.size(), 3); // 1 + 2 clips + + const auto creationChangeData = qSharedPointerCast>(creationChanges.first()); + const Qt3DAnimation::QLerpClipBlendData cloneData = creationChangeData->data; + + QCOMPARE(lerpBlend.blendFactor(), cloneData.blendFactor); + QCOMPARE(lerpBlend.id(), creationChangeData->subjectId()); + QCOMPARE(lerpBlend.isEnabled(), false); + QCOMPARE(lerpBlend.isEnabled(), creationChangeData->isNodeEnabled()); + QCOMPARE(lerpBlend.metaObject(), creationChangeData->metaObject()); + QCOMPARE(creationChangeData->clips().size(), 2); + QCOMPARE(creationChangeData->clips().first(), clip1.id()); + QCOMPARE(creationChangeData->clips().last(), clip2.id()); + QCOMPARE(creationChangeData->parentClipBlendNodeId(), Qt3DCore::QNodeId()); + } + } + + void checkBlendFactorUpdate() + { + // GIVEN + TestArbiter arbiter; + Qt3DAnimation::QLerpClipBlend lerpBlend; + arbiter.setArbiterOnNode(&lerpBlend); + + { + // WHEN + lerpBlend.setBlendFactor(0.4f); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 1); + auto change = arbiter.events.first().staticCast(); + QCOMPARE(change->propertyName(), "blendFactor"); + QCOMPARE(change->value().value(), lerpBlend.blendFactor()); + QCOMPARE(change->type(), Qt3DCore::PropertyUpdated); + + arbiter.events.clear(); + } + + { + // WHEN + lerpBlend.setBlendFactor(0.4f); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 0); + } + + } + +}; + +QTEST_MAIN(tst_QLerpClipBlend) + +#include "tst_qlerpclipblend.moc" -- cgit v1.2.3 From 28938073a228a38c2a5beccdb3357b5a8c172def Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Wed, 22 Feb 2017 13:59:57 +0000 Subject: Rename QAdditiveBlend -> QAdditiveClipBlend Also rename backend type accordingly. Task-number: QTBUG-58903 Change-Id: Ia1ad670937487dd84768e79d8c2be59ed3b6d0a5 Reviewed-by: Kevin Ottens --- src/animation/backend/additiveblend.cpp | 85 ---------- src/animation/backend/additiveblend_p.h | 83 --------- src/animation/backend/additiveclipblend.cpp | 85 ++++++++++ src/animation/backend/additiveclipblend_p.h | 83 +++++++++ src/animation/backend/backend.pri | 8 +- src/animation/frontend/frontend.pri | 10 +- src/animation/frontend/qadditiveblend.cpp | 174 ------------------- src/animation/frontend/qadditiveblend.h | 76 --------- src/animation/frontend/qadditiveblend_p.h | 78 --------- src/animation/frontend/qadditiveclipblend.cpp | 174 +++++++++++++++++++ src/animation/frontend/qadditiveclipblend.h | 76 +++++++++ src/animation/frontend/qadditiveclipblend_p.h | 78 +++++++++ src/animation/frontend/qanimationaspect.cpp | 10 +- .../animation/qt3dquick3danimationplugin.cpp | 4 +- .../auto/animation/additiveblend/additiveblend.pro | 12 -- .../animation/additiveblend/tst_additiveblend.cpp | 148 ----------------- .../additiveclipblend/additiveclipblend.pro | 12 ++ .../additiveclipblend/tst_additiveclipblend.cpp | 148 +++++++++++++++++ tests/auto/animation/animation.pro | 4 +- .../animation/qadditiveblend/qadditiveblend.pro | 12 -- .../qadditiveblend/tst_qadditiveblend.cpp | 185 --------------------- .../qadditiveclipblend/qadditiveclipblend.pro | 12 ++ .../qadditiveclipblend/tst_qadditiveclipblend.cpp | 185 +++++++++++++++++++++ 23 files changed, 871 insertions(+), 871 deletions(-) delete mode 100644 src/animation/backend/additiveblend.cpp delete mode 100644 src/animation/backend/additiveblend_p.h create mode 100644 src/animation/backend/additiveclipblend.cpp create mode 100644 src/animation/backend/additiveclipblend_p.h delete mode 100644 src/animation/frontend/qadditiveblend.cpp delete mode 100644 src/animation/frontend/qadditiveblend.h delete mode 100644 src/animation/frontend/qadditiveblend_p.h create mode 100644 src/animation/frontend/qadditiveclipblend.cpp create mode 100644 src/animation/frontend/qadditiveclipblend.h create mode 100644 src/animation/frontend/qadditiveclipblend_p.h delete mode 100644 tests/auto/animation/additiveblend/additiveblend.pro delete mode 100644 tests/auto/animation/additiveblend/tst_additiveblend.cpp create mode 100644 tests/auto/animation/additiveclipblend/additiveclipblend.pro create mode 100644 tests/auto/animation/additiveclipblend/tst_additiveclipblend.cpp delete mode 100644 tests/auto/animation/qadditiveblend/qadditiveblend.pro delete mode 100644 tests/auto/animation/qadditiveblend/tst_qadditiveblend.cpp create mode 100644 tests/auto/animation/qadditiveclipblend/qadditiveclipblend.pro create mode 100644 tests/auto/animation/qadditiveclipblend/tst_qadditiveclipblend.cpp diff --git a/src/animation/backend/additiveblend.cpp b/src/animation/backend/additiveblend.cpp deleted file mode 100644 index 6364e54a7..000000000 --- a/src/animation/backend/additiveblend.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). -** Contact: http://www.qt-project.org/legal -** -** 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 "additiveblend_p.h" -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE - -namespace Qt3DAnimation { - -namespace Animation { - -AdditiveBlend::AdditiveBlend() - : ClipBlendNode(ClipBlendNode::AdditiveBlendType) - , m_blendFactor(0.0f) -{ -} - -AdditiveBlend::~AdditiveBlend() -{ -} - -void AdditiveBlend::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) -{ - if (e->type() == Qt3DCore::PropertyUpdated) { - Qt3DCore::QPropertyUpdatedChangePtr change = qSharedPointerCast(e); - if (change->propertyName() == QByteArrayLiteral("blendFactor")) - m_blendFactor = change->value().toFloat(); - } -} - -float AdditiveBlend::blend(float value1, float value2) const -{ - return value1 + (m_blendFactor * value2); -} - -void AdditiveBlend::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) -{ - ClipBlendNode::initializeFromPeer(change); - const auto creationChangeData = qSharedPointerCast>(change); - const Qt3DAnimation::QAdditiveBlendData cloneData = creationChangeData->data; - m_blendFactor = cloneData.blendFactor; -} - -} // Animation - -} // Qt3DAnimation - -QT_END_NAMESPACE diff --git a/src/animation/backend/additiveblend_p.h b/src/animation/backend/additiveblend_p.h deleted file mode 100644 index d67e95b51..000000000 --- a/src/animation/backend/additiveblend_p.h +++ /dev/null @@ -1,83 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). -** Contact: http://www.qt-project.org/legal -** -** 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$ -** -****************************************************************************/ - -#ifndef QT3DANIMATION_ANIMATION_ADDITIVEBLEND_P_H -#define QT3DANIMATION_ANIMATION_ADDITIVEBLEND_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of other Qt classes. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include - -QT_BEGIN_NAMESPACE - -namespace Qt3DAnimation { - -namespace Animation { - -class Q_AUTOTEST_EXPORT AdditiveBlend : public ClipBlendNode -{ -public: - AdditiveBlend(); - ~AdditiveBlend(); - - inline float blendFactor() const { return m_blendFactor; } - void setBlendFactor(float blendFactor) { m_blendFactor = blendFactor; } // For unit tests - - void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_FINAL; - float blend(float value1, float value2) const Q_DECL_FINAL; - -private: - void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL; - - float m_blendFactor; -}; - -} // Animation - -} // Qt3DAnimation - -QT_END_NAMESPACE - -#endif // QT3DANIMATION_ANIMATION_ADDITIVEBLEND_P_H diff --git a/src/animation/backend/additiveclipblend.cpp b/src/animation/backend/additiveclipblend.cpp new file mode 100644 index 000000000..ea7db4621 --- /dev/null +++ b/src/animation/backend/additiveclipblend.cpp @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** 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 "additiveclipblend_p.h" +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { + +namespace Animation { + +AdditiveClipBlend::AdditiveClipBlend() + : ClipBlendNode(ClipBlendNode::AdditiveBlendType) + , m_blendFactor(0.0f) +{ +} + +AdditiveClipBlend::~AdditiveClipBlend() +{ +} + +void AdditiveClipBlend::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) +{ + if (e->type() == Qt3DCore::PropertyUpdated) { + Qt3DCore::QPropertyUpdatedChangePtr change = qSharedPointerCast(e); + if (change->propertyName() == QByteArrayLiteral("blendFactor")) + m_blendFactor = change->value().toFloat(); + } +} + +float AdditiveClipBlend::blend(float value1, float value2) const +{ + return value1 + (m_blendFactor * value2); +} + +void AdditiveClipBlend::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) +{ + ClipBlendNode::initializeFromPeer(change); + const auto creationChangeData = qSharedPointerCast>(change); + const Qt3DAnimation::QAdditiveClipBlendData cloneData = creationChangeData->data; + m_blendFactor = cloneData.blendFactor; +} + +} // Animation + +} // Qt3DAnimation + +QT_END_NAMESPACE diff --git a/src/animation/backend/additiveclipblend_p.h b/src/animation/backend/additiveclipblend_p.h new file mode 100644 index 000000000..8664eb549 --- /dev/null +++ b/src/animation/backend/additiveclipblend_p.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** 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$ +** +****************************************************************************/ + +#ifndef QT3DANIMATION_ANIMATION_ADDITIVECLIPBLEND_P_H +#define QT3DANIMATION_ANIMATION_ADDITIVECLIPBLEND_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { + +namespace Animation { + +class Q_AUTOTEST_EXPORT AdditiveClipBlend : public ClipBlendNode +{ +public: + AdditiveClipBlend(); + ~AdditiveClipBlend(); + + inline float blendFactor() const { return m_blendFactor; } + void setBlendFactor(float blendFactor) { m_blendFactor = blendFactor; } // For unit tests + + void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_FINAL; + float blend(float value1, float value2) const Q_DECL_FINAL; + +private: + void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL; + + float m_blendFactor; +}; + +} // Animation + +} // Qt3DAnimation + +QT_END_NAMESPACE + +#endif // QT3DANIMATION_ANIMATION_ADDITIVECLIPBLEND_P_H diff --git a/src/animation/backend/backend.pri b/src/animation/backend/backend.pri index ab0d242dc..bb69eb473 100644 --- a/src/animation/backend/backend.pri +++ b/src/animation/backend/backend.pri @@ -23,9 +23,9 @@ HEADERS += \ $$PWD/animationutils_p.h \ $$PWD/buildblendtreesjob_p.h \ $$PWD/evaluateblendclipanimatorjob_p.h \ - $$PWD/additiveblend_p.h \ $$PWD/animationcliploader_p.h \ - $$PWD/lerpclipblend_p.h + $$PWD/lerpclipblend_p.h \ + $$PWD/additiveclipblend_p.h SOURCES += \ $$PWD/handler.cpp \ @@ -46,6 +46,6 @@ SOURCES += \ $$PWD/animationutils.cpp \ $$PWD/buildblendtreesjob.cpp \ $$PWD/evaluateblendclipanimatorjob.cpp \ - $$PWD/additiveblend.cpp \ $$PWD/animationcliploader.cpp \ - $$PWD/lerpclipblend.cpp + $$PWD/lerpclipblend.cpp \ + $$PWD/additiveclipblend.cpp diff --git a/src/animation/frontend/frontend.pri b/src/animation/frontend/frontend.pri index ce9bee2cf..01f74eedd 100644 --- a/src/animation/frontend/frontend.pri +++ b/src/animation/frontend/frontend.pri @@ -17,8 +17,6 @@ HEADERS += \ $$PWD/qchannelmapping_p.h \ $$PWD/qclipblendnodecreatedchange.h \ $$PWD/qclipblendnodecreatedchange_p.h \ - $$PWD/qadditiveblend.h \ - $$PWD/qadditiveblend_p.h \ $$PWD/qanimationcontroller.h \ $$PWD/qanimationcontroller_p.h \ $$PWD/qanimationgroup.h \ @@ -36,7 +34,9 @@ HEADERS += \ $$PWD/qanimationcliploader.h \ $$PWD/qanimationcliploader_p.h \ $$PWD/qlerpclipblend.h \ - $$PWD/qlerpclipblend_p.h + $$PWD/qlerpclipblend_p.h \ + $$PWD/qadditiveclipblend.h \ + $$PWD/qadditiveclipblend_p.h SOURCES += \ $$PWD/qanimationaspect.cpp \ @@ -48,7 +48,6 @@ SOURCES += \ $$PWD/qchannelmapper.cpp \ $$PWD/qchannelmapping.cpp \ $$PWD/qclipblendnodecreatedchange.cpp \ - $$PWD/qadditiveblend.cpp \ $$PWD/qanimationcontroller.cpp \ $$PWD/qanimationgroup.cpp \ $$PWD/qkeyframeanimation.cpp \ @@ -57,6 +56,7 @@ SOURCES += \ $$PWD/qmorphtarget.cpp \ $$PWD/qvertexblendanimation.cpp \ $$PWD/qanimationcliploader.cpp \ - $$PWD/qlerpclipblend.cpp + $$PWD/qlerpclipblend.cpp \ + $$PWD/qadditiveclipblend.cpp INCLUDEPATH += $$PWD diff --git a/src/animation/frontend/qadditiveblend.cpp b/src/animation/frontend/qadditiveblend.cpp deleted file mode 100644 index 977f36919..000000000 --- a/src/animation/frontend/qadditiveblend.cpp +++ /dev/null @@ -1,174 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). -** Contact: http://www.qt-project.org/legal -** -** 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 "qadditiveblend.h" -#include "qadditiveblend_p.h" -#include - -QT_BEGIN_NAMESPACE - -namespace Qt3DAnimation { - - -/*! - \qmltype AdditiveBlend - \instantiates Qt3DAnimation::QAdditiveBlend - \inqmlmodule Qt3D.Animation - - \brief Performs an addition of two animation clips based on a - normalized factor - - \since 5.9 - - AdditiveBlend can be useful to create advanced animation effects based on - individual animation clips. For instance, given a player character, additive - blending could be used to combine a walking animation clip with an injured - animation clip based on a blend factor that increases the more the player - gets injured. This would then allow with blend factor == 0 to have a non - injured walking player, with blend factor == 1 a fully injured player, with - blend factor == 0.5 a partially walking and injured player. - - \sa BlendedClipAnimator -*/ - -/*! - \class Qt3DAnimation::QAdditiveBlend - \inmodule Qt3DAnimation - \inherits Qt3DAnimation::QAbstractClipBlendNode - - \brief Performs an addition of two animation clips based on a - normalized factor - - \since 5.9 - - QAdditiveBlend can be useful to create advanced animation effects based on - individual animation clips. For instance, given a player character, additive - blending could be used to combine a walking animation clip with an injured - animation clip based on a blend factor that increases the more the player - gets injured. This would then allow with blend factor == 0 to have a non - injured walking player, with blend factor == 1 a fully injured player, with - blend factor == 0.5 a partially walking and injured player. - - \sa QBlendedClipAnimator -*/ - -QAdditiveBlendPrivate::QAdditiveBlendPrivate() - : QAbstractClipBlendNodePrivate() - , m_blendFactor(0.0f) -{ -} - -QAdditiveBlend::QAdditiveBlend(Qt3DCore::QNode *parent) - : QAbstractClipBlendNode(*new QAdditiveBlendPrivate(), parent) -{ -} - -QAdditiveBlend::QAdditiveBlend(QAdditiveBlendPrivate &dd, Qt3DCore::QNode *parent) - : QAbstractClipBlendNode(dd, parent) -{ -} - -QAdditiveBlend::~QAdditiveBlend() -{ -} - -Qt3DCore::QNodeCreatedChangeBasePtr QAdditiveBlend::createNodeCreationChange() const -{ - Q_D(const QAdditiveBlend); - auto creationChange = QClipBlendNodeCreatedChangePtr::create(this); - QAdditiveBlendData &data = creationChange->data; - data.blendFactor = d->m_blendFactor; - return creationChange; -} - -/*! - \qmlproperty real AdditiveBlend::blendFactor - - Specifies the blending factor between 0 and 1 to control the blending of - two animation clips. -*/ -/*! - \property QAdditiveBlend::blendFactor - - Specifies the blending factor between 0 and 1 to control the blending of - two animation clips. - */ -float QAdditiveBlend::blendFactor() const -{ - Q_D(const QAdditiveBlend); - return d->m_blendFactor; -} - -void QAdditiveBlend::setBlendFactor(float blendFactor) -{ - Q_D(QAdditiveBlend); - if (d->m_blendFactor == blendFactor) - return; - - d->m_blendFactor = blendFactor; - emit blendFactorChanged(blendFactor); -} - -/*! - \qmlproperty list AdditiveBlend::clips - - Holds the list of AnimationClip nodes against which the blending is performed. - - \note Only the two first AnimationClip are used, subsequent ones are ignored -*/ - - -/*! - \fn void QAdditiveBlend::addClip(QAnimationClip *clip); - Adds a \a clip to the blending node's clips list. - - \note Only the two first AnimationClip are used, subsequent ones are ignored - */ - -/*! - \fn void QAdditiveBlend::removeClip(QAnimationClip *clip); - Removes a \a clip from the blending node's clips list. - */ - -/*! - \fn QVector QAdditiveBlend::clips() const; - Returns the list of QAnimationClip against which the blending is performed. - */ - - -} // Qt3DAnimation - -QT_END_NAMESPACE diff --git a/src/animation/frontend/qadditiveblend.h b/src/animation/frontend/qadditiveblend.h deleted file mode 100644 index 76075988b..000000000 --- a/src/animation/frontend/qadditiveblend.h +++ /dev/null @@ -1,76 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). -** Contact: http://www.qt-project.org/legal -** -** 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$ -** -****************************************************************************/ - -#ifndef QT3DANIMATION_QADDITIVEBLEND_H -#define QT3DANIMATION_QADDITIVEBLEND_H - -#include - -QT_BEGIN_NAMESPACE - -namespace Qt3DAnimation { - -class QAdditiveBlendPrivate; - -class QT3DANIMATIONSHARED_EXPORT QAdditiveBlend : public QAbstractClipBlendNode -{ - Q_OBJECT - Q_PROPERTY(float blendFactor READ blendFactor WRITE setBlendFactor NOTIFY blendFactorChanged) -public: - explicit QAdditiveBlend(Qt3DCore::QNode *parent = nullptr); - ~QAdditiveBlend(); - - float blendFactor() const; - -public Q_SLOTS: - void setBlendFactor(float blendFactor); - -Q_SIGNALS: - void blendFactorChanged(float blendFactor); - -protected: - explicit QAdditiveBlend(QAdditiveBlendPrivate &dd, Qt3DCore::QNode *parent = nullptr); - -private: - Q_DECLARE_PRIVATE(QAdditiveBlend) - Qt3DCore::QNodeCreatedChangeBasePtr createNodeCreationChange() const Q_DECL_OVERRIDE; -}; - -} // Qt3DAnimation - -QT_END_NAMESPACE - -#endif // QT3DANIMATION_QADDITIVEBLEND_H diff --git a/src/animation/frontend/qadditiveblend_p.h b/src/animation/frontend/qadditiveblend_p.h deleted file mode 100644 index e21872098..000000000 --- a/src/animation/frontend/qadditiveblend_p.h +++ /dev/null @@ -1,78 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). -** Contact: http://www.qt-project.org/legal -** -** 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$ -** -****************************************************************************/ - -#ifndef QT3DANIMATION_QADDITIVEBLEND_P_H -#define QT3DANIMATION_QADDITIVEBLEND_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of other Qt classes. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include -#include - -QT_BEGIN_NAMESPACE - -namespace Qt3DAnimation { - -class QAdditiveBlend; - -class QAdditiveBlendPrivate : public QAbstractClipBlendNodePrivate -{ -public: - QAdditiveBlendPrivate(); - - Q_DECLARE_PUBLIC(QAdditiveBlend) - float m_blendFactor; -}; - -struct QAdditiveBlendData -{ - float blendFactor; -}; - -} // Qt3DAnimation - -QT_END_NAMESPACE - -#endif // QT3DANIMATION_QADDITIVEBLEND_P_H diff --git a/src/animation/frontend/qadditiveclipblend.cpp b/src/animation/frontend/qadditiveclipblend.cpp new file mode 100644 index 000000000..90cc92e55 --- /dev/null +++ b/src/animation/frontend/qadditiveclipblend.cpp @@ -0,0 +1,174 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** 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 "qadditiveclipblend.h" +#include "qadditiveclipblend_p.h" +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { + + +/*! + \qmltype AdditiveClipBlend + \instantiates Qt3DAnimation::QAdditiveClipBlend + \inqmlmodule Qt3D.Animation + + \brief Performs an addition of two animation clips based on a + normalized factor + + \since 5.9 + + AdditiveClipBlend can be useful to create advanced animation effects based on + individual animation clips. For instance, given a player character, additive + blending could be used to combine a walking animation clip with an injured + animation clip based on a blend factor that increases the more the player + gets injured. This would then allow with blend factor == 0 to have a non + injured walking player, with blend factor == 1 a fully injured player, with + blend factor == 0.5 a partially walking and injured player. + + \sa BlendedClipAnimator +*/ + +/*! + \class Qt3DAnimation::QAdditiveClipBlend + \inmodule Qt3DAnimation + \inherits Qt3DAnimation::QAbstractClipBlendNode + + \brief Performs an addition of two animation clips based on a + normalized factor + + \since 5.9 + + QAdditiveClipBlend can be useful to create advanced animation effects based on + individual animation clips. For instance, given a player character, additive + blending could be used to combine a walking animation clip with an injured + animation clip based on a blend factor that increases the more the player + gets injured. This would then allow with blend factor == 0 to have a non + injured walking player, with blend factor == 1 a fully injured player, with + blend factor == 0.5 a partially walking and injured player. + + \sa QBlendedClipAnimator +*/ + +QAdditiveClipBlendPrivate::QAdditiveClipBlendPrivate() + : QAbstractClipBlendNodePrivate() + , m_blendFactor(0.0f) +{ +} + +QAdditiveClipBlend::QAdditiveClipBlend(Qt3DCore::QNode *parent) + : QAbstractClipBlendNode(*new QAdditiveClipBlendPrivate(), parent) +{ +} + +QAdditiveClipBlend::QAdditiveClipBlend(QAdditiveClipBlendPrivate &dd, Qt3DCore::QNode *parent) + : QAbstractClipBlendNode(dd, parent) +{ +} + +QAdditiveClipBlend::~QAdditiveClipBlend() +{ +} + +Qt3DCore::QNodeCreatedChangeBasePtr QAdditiveClipBlend::createNodeCreationChange() const +{ + Q_D(const QAdditiveClipBlend); + auto creationChange = QClipBlendNodeCreatedChangePtr::create(this); + QAdditiveClipBlendData &data = creationChange->data; + data.blendFactor = d->m_blendFactor; + return creationChange; +} + +/*! + \qmlproperty real AdditiveClipBlend::blendFactor + + Specifies the blending factor between 0 and 1 to control the blending of + two animation clips. +*/ +/*! + \property QAdditiveClipBlend::blendFactor + + Specifies the blending factor between 0 and 1 to control the blending of + two animation clips. + */ +float QAdditiveClipBlend::blendFactor() const +{ + Q_D(const QAdditiveClipBlend); + return d->m_blendFactor; +} + +void QAdditiveClipBlend::setBlendFactor(float blendFactor) +{ + Q_D(QAdditiveClipBlend); + if (d->m_blendFactor == blendFactor) + return; + + d->m_blendFactor = blendFactor; + emit blendFactorChanged(blendFactor); +} + +/*! + \qmlproperty list AdditiveClipBlend::clips + + Holds the list of AnimationClip nodes against which the blending is performed. + + \note Only the two first AnimationClip are used, subsequent ones are ignored +*/ + + +/*! + \fn void QAdditiveClipBlend::addClip(QAnimationClip *clip); + Adds a \a clip to the blending node's clips list. + + \note Only the two first AnimationClip are used, subsequent ones are ignored + */ + +/*! + \fn void QAdditiveClipBlend::removeClip(QAnimationClip *clip); + Removes a \a clip from the blending node's clips list. + */ + +/*! + \fn QVector QAdditiveClipBlend::clips() const; + Returns the list of QAnimationClip against which the blending is performed. + */ + + +} // Qt3DAnimation + +QT_END_NAMESPACE diff --git a/src/animation/frontend/qadditiveclipblend.h b/src/animation/frontend/qadditiveclipblend.h new file mode 100644 index 000000000..eb1de9abb --- /dev/null +++ b/src/animation/frontend/qadditiveclipblend.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** 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$ +** +****************************************************************************/ + +#ifndef QT3DANIMATION_QADDITIVECLIPBLEND_H +#define QT3DANIMATION_QADDITIVECLIPBLEND_H + +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { + +class QAdditiveClipBlendPrivate; + +class QT3DANIMATIONSHARED_EXPORT QAdditiveClipBlend : public QAbstractClipBlendNode +{ + Q_OBJECT + Q_PROPERTY(float blendFactor READ blendFactor WRITE setBlendFactor NOTIFY blendFactorChanged) +public: + explicit QAdditiveClipBlend(Qt3DCore::QNode *parent = nullptr); + ~QAdditiveClipBlend(); + + float blendFactor() const; + +public Q_SLOTS: + void setBlendFactor(float blendFactor); + +Q_SIGNALS: + void blendFactorChanged(float blendFactor); + +protected: + explicit QAdditiveClipBlend(QAdditiveClipBlendPrivate &dd, Qt3DCore::QNode *parent = nullptr); + +private: + Q_DECLARE_PRIVATE(QAdditiveClipBlend) + Qt3DCore::QNodeCreatedChangeBasePtr createNodeCreationChange() const Q_DECL_OVERRIDE; +}; + +} // Qt3DAnimation + +QT_END_NAMESPACE + +#endif // QT3DANIMATION_QADDITIVECLIPBLEND_H diff --git a/src/animation/frontend/qadditiveclipblend_p.h b/src/animation/frontend/qadditiveclipblend_p.h new file mode 100644 index 000000000..0506fc459 --- /dev/null +++ b/src/animation/frontend/qadditiveclipblend_p.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** 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$ +** +****************************************************************************/ + +#ifndef QT3DANIMATION_QADDITIVEBLEND_P_H +#define QT3DANIMATION_QADDITIVEBLEND_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { + +class QAdditiveClipBlend; + +class QAdditiveClipBlendPrivate : public QAbstractClipBlendNodePrivate +{ +public: + QAdditiveClipBlendPrivate(); + + Q_DECLARE_PUBLIC(QAdditiveClipBlend) + float m_blendFactor; +}; + +struct QAdditiveClipBlendData +{ + float blendFactor; +}; + +} // Qt3DAnimation + +QT_END_NAMESPACE + +#endif // QT3DANIMATION_QADDITIVEBLEND_P_H diff --git a/src/animation/frontend/qanimationaspect.cpp b/src/animation/frontend/qanimationaspect.cpp index 2fac063c2..56dd012ed 100644 --- a/src/animation/frontend/qanimationaspect.cpp +++ b/src/animation/frontend/qanimationaspect.cpp @@ -45,12 +45,12 @@ #include #include #include -#include +#include #include #include #include #include -#include +#include QT_BEGIN_NAMESPACE @@ -109,9 +109,9 @@ QAnimationAspect::QAnimationAspect(QAnimationAspectPrivate &dd, QObject *parent) registerBackendType( QSharedPointer>::create(d->m_handler.data(), d->m_handler->clipBlendNodeManager())); - registerBackendType( - QSharedPointer>::create(d->m_handler.data(), - d->m_handler->clipBlendNodeManager())); + registerBackendType( + QSharedPointer>::create(d->m_handler.data(), + d->m_handler->clipBlendNodeManager())); } /*! \internal */ diff --git a/src/quick3d/imports/animation/qt3dquick3danimationplugin.cpp b/src/quick3d/imports/animation/qt3dquick3danimationplugin.cpp index 6f52de389..29b4fe076 100644 --- a/src/quick3d/imports/animation/qt3dquick3danimationplugin.cpp +++ b/src/quick3d/imports/animation/qt3dquick3danimationplugin.cpp @@ -45,7 +45,7 @@ #include #include #include -#include +#include #include #include @@ -81,8 +81,8 @@ void Qt3DQuick3DAnimationPlugin::registerTypes(const char *uri) Qt3DAnimation::Animation::Quick::Quick3DChannelMapper>(uri, 2, 9, "ChannelMapper"); qmlRegisterExtendedUncreatableType(uri, 2, 9, "AbstractClipBlendNode", QStringLiteral("QAbstractClipBlendNode is abstract")); - qmlRegisterType(uri, 2, 9, "AdditiveBlend"); qmlRegisterType(uri, 2, 9, "LerpClipBlend"); + qmlRegisterType(uri, 2, 9, "AdditiveClipBlend"); qmlRegisterUncreatableType(uri, 2, 9, "AbstractAnimation", QStringLiteral("AbstractAnimation is abstract")); qmlRegisterExtendedType(uri, 2, 9, "KeyframeAnimation"); diff --git a/tests/auto/animation/additiveblend/additiveblend.pro b/tests/auto/animation/additiveblend/additiveblend.pro deleted file mode 100644 index e61417c73..000000000 --- a/tests/auto/animation/additiveblend/additiveblend.pro +++ /dev/null @@ -1,12 +0,0 @@ -TEMPLATE = app - -TARGET = tst_additiveblend - -QT += 3dcore 3dcore-private 3danimation 3danimation-private testlib - -CONFIG += testcase - -SOURCES += \ - tst_additiveblend.cpp - -include(../../core/common/common.pri) diff --git a/tests/auto/animation/additiveblend/tst_additiveblend.cpp b/tests/auto/animation/additiveblend/tst_additiveblend.cpp deleted file mode 100644 index c94efedd8..000000000 --- a/tests/auto/animation/additiveblend/tst_additiveblend.cpp +++ /dev/null @@ -1,148 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 Paul Lemire -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt3D module of the Qt Toolkit. -** -** $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 -#include -#include -#include -#include -#include -#include "qbackendnodetester.h" - -class tst_AdditiveBlend : public Qt3DCore::QBackendNodeTester -{ - Q_OBJECT - -private Q_SLOTS: - - void checkInitialState() - { - // GIVEN - Qt3DAnimation::Animation::AdditiveBlend backendAdditiveBlend; - - // THEN - QCOMPARE(backendAdditiveBlend.isEnabled(), false); - QVERIFY(backendAdditiveBlend.peerId().isNull()); - QCOMPARE(backendAdditiveBlend.blendFactor(), 0.0f); - QCOMPARE(backendAdditiveBlend.blendType(), Qt3DAnimation::Animation::ClipBlendNode::AdditiveBlendType); - } - - void checkInitializeFromPeer() - { - // GIVEN - Qt3DAnimation::QAdditiveBlend additiveBlend; - Qt3DAnimation::QAnimationClipLoader clip; - additiveBlend.setBlendFactor(0.8f); - additiveBlend.addClip(&clip); - - { - // WHEN - Qt3DAnimation::Animation::AdditiveBlend backendAdditiveBlend; - simulateInitialization(&additiveBlend, &backendAdditiveBlend); - - // THEN - QCOMPARE(backendAdditiveBlend.isEnabled(), true); - QCOMPARE(backendAdditiveBlend.peerId(), additiveBlend.id()); - QCOMPARE(backendAdditiveBlend.blendFactor(), 0.8f); - QCOMPARE(backendAdditiveBlend.clipIds().size(), 1); - QCOMPARE(backendAdditiveBlend.clipIds().first(), clip.id()); - } - { - // WHEN - Qt3DAnimation::Animation::AdditiveBlend backendAdditiveBlend; - additiveBlend.setEnabled(false); - simulateInitialization(&additiveBlend, &backendAdditiveBlend); - - // THEN - QCOMPARE(backendAdditiveBlend.peerId(), additiveBlend.id()); - QCOMPARE(backendAdditiveBlend.isEnabled(), false); - } - } - - void checkSceneChangeEvents() - { - // GIVEN - Qt3DAnimation::Animation::AdditiveBlend backendAdditiveBlend; - { - // WHEN - const bool newValue = false; - const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId()); - change->setPropertyName("enabled"); - change->setValue(newValue); - backendAdditiveBlend.sceneChangeEvent(change); - - // THEN - QCOMPARE(backendAdditiveBlend.isEnabled(), newValue); - } - { - // WHEN - const float newValue = 0.883f; - const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId()); - change->setPropertyName("blendFactor"); - change->setValue(QVariant::fromValue(newValue)); - backendAdditiveBlend.sceneChangeEvent(change); - - // THEN - QCOMPARE(backendAdditiveBlend.blendFactor(), newValue); - } - } - - void checkBlend_data() - { - QTest::addColumn("value1"); - QTest::addColumn("value2"); - QTest::addColumn("blendFactor"); - QTest::addColumn("result"); - - QTest::newRow("0_blending") << 8.0f << 5.0f << 0.0f << 8.0f; - QTest::newRow("0.5_blending") << 8.0f << 5.0f << 0.5f << 10.5f; - QTest::newRow("1_blending") << 8.0f << 5.0f << 1.0f << 13.0f; - } - - void checkBlend() - { - // GIVEN - QFETCH(float, value1); - QFETCH(float, value2); - QFETCH(float, blendFactor); - QFETCH(float, result); - Qt3DAnimation::Animation::AdditiveBlend addBlend; - - // WHEN - addBlend.setBlendFactor(blendFactor); - const float computed = addBlend.blend(value1, value2); - - // THEN - QCOMPARE(computed, result); - } -}; - -QTEST_MAIN(tst_AdditiveBlend) - -#include "tst_additiveblend.moc" diff --git a/tests/auto/animation/additiveclipblend/additiveclipblend.pro b/tests/auto/animation/additiveclipblend/additiveclipblend.pro new file mode 100644 index 000000000..09b2e1156 --- /dev/null +++ b/tests/auto/animation/additiveclipblend/additiveclipblend.pro @@ -0,0 +1,12 @@ +TEMPLATE = app + +TARGET = tst_additiveclipblend + +QT += 3dcore 3dcore-private 3danimation 3danimation-private testlib + +CONFIG += testcase + +SOURCES += \ + tst_additiveclipblend.cpp + +include(../../core/common/common.pri) diff --git a/tests/auto/animation/additiveclipblend/tst_additiveclipblend.cpp b/tests/auto/animation/additiveclipblend/tst_additiveclipblend.cpp new file mode 100644 index 000000000..4875d67cc --- /dev/null +++ b/tests/auto/animation/additiveclipblend/tst_additiveclipblend.cpp @@ -0,0 +1,148 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Paul Lemire +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $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 +#include +#include +#include +#include +#include +#include "qbackendnodetester.h" + +class tst_AdditiveClipBlend : public Qt3DCore::QBackendNodeTester +{ + Q_OBJECT + +private Q_SLOTS: + + void checkInitialState() + { + // GIVEN + Qt3DAnimation::Animation::AdditiveClipBlend backendAdditiveBlend; + + // THEN + QCOMPARE(backendAdditiveBlend.isEnabled(), false); + QVERIFY(backendAdditiveBlend.peerId().isNull()); + QCOMPARE(backendAdditiveBlend.blendFactor(), 0.0f); + QCOMPARE(backendAdditiveBlend.blendType(), Qt3DAnimation::Animation::ClipBlendNode::AdditiveBlendType); + } + + void checkInitializeFromPeer() + { + // GIVEN + Qt3DAnimation::QAdditiveClipBlend additiveBlend; + Qt3DAnimation::QAnimationClipLoader clip; + additiveBlend.setBlendFactor(0.8f); + additiveBlend.addClip(&clip); + + { + // WHEN + Qt3DAnimation::Animation::AdditiveClipBlend backendAdditiveBlend; + simulateInitialization(&additiveBlend, &backendAdditiveBlend); + + // THEN + QCOMPARE(backendAdditiveBlend.isEnabled(), true); + QCOMPARE(backendAdditiveBlend.peerId(), additiveBlend.id()); + QCOMPARE(backendAdditiveBlend.blendFactor(), 0.8f); + QCOMPARE(backendAdditiveBlend.clipIds().size(), 1); + QCOMPARE(backendAdditiveBlend.clipIds().first(), clip.id()); + } + { + // WHEN + Qt3DAnimation::Animation::AdditiveClipBlend backendAdditiveBlend; + additiveBlend.setEnabled(false); + simulateInitialization(&additiveBlend, &backendAdditiveBlend); + + // THEN + QCOMPARE(backendAdditiveBlend.peerId(), additiveBlend.id()); + QCOMPARE(backendAdditiveBlend.isEnabled(), false); + } + } + + void checkSceneChangeEvents() + { + // GIVEN + Qt3DAnimation::Animation::AdditiveClipBlend backendAdditiveBlend; + { + // WHEN + const bool newValue = false; + const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId()); + change->setPropertyName("enabled"); + change->setValue(newValue); + backendAdditiveBlend.sceneChangeEvent(change); + + // THEN + QCOMPARE(backendAdditiveBlend.isEnabled(), newValue); + } + { + // WHEN + const float newValue = 0.883f; + const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId()); + change->setPropertyName("blendFactor"); + change->setValue(QVariant::fromValue(newValue)); + backendAdditiveBlend.sceneChangeEvent(change); + + // THEN + QCOMPARE(backendAdditiveBlend.blendFactor(), newValue); + } + } + + void checkBlend_data() + { + QTest::addColumn("value1"); + QTest::addColumn("value2"); + QTest::addColumn("blendFactor"); + QTest::addColumn("result"); + + QTest::newRow("0_blending") << 8.0f << 5.0f << 0.0f << 8.0f; + QTest::newRow("0.5_blending") << 8.0f << 5.0f << 0.5f << 10.5f; + QTest::newRow("1_blending") << 8.0f << 5.0f << 1.0f << 13.0f; + } + + void checkBlend() + { + // GIVEN + QFETCH(float, value1); + QFETCH(float, value2); + QFETCH(float, blendFactor); + QFETCH(float, result); + Qt3DAnimation::Animation::AdditiveClipBlend addBlend; + + // WHEN + addBlend.setBlendFactor(blendFactor); + const float computed = addBlend.blend(value1, value2); + + // THEN + QCOMPARE(computed, result); + } +}; + +QTEST_MAIN(tst_AdditiveClipBlend) + +#include "tst_additiveclipblend.moc" diff --git a/tests/auto/animation/animation.pro b/tests/auto/animation/animation.pro index e62c431d6..e756290f7 100644 --- a/tests/auto/animation/animation.pro +++ b/tests/auto/animation/animation.pro @@ -24,6 +24,6 @@ qtConfig(private_tests) { clipblendnode \ lerpclipblend \ clipblendnodevisitor \ - qadditiveblend \ - additiveblend + qadditiveclipblend \ + additiveclipblend } diff --git a/tests/auto/animation/qadditiveblend/qadditiveblend.pro b/tests/auto/animation/qadditiveblend/qadditiveblend.pro deleted file mode 100644 index b3f2a4599..000000000 --- a/tests/auto/animation/qadditiveblend/qadditiveblend.pro +++ /dev/null @@ -1,12 +0,0 @@ -TEMPLATE = app - -TARGET = tst_qadditiveblend - -QT += 3dcore 3dcore-private 3danimation 3danimation-private testlib - -CONFIG += testcase - -SOURCES += \ - tst_qadditiveblend.cpp - -include(../../core/common/common.pri) diff --git a/tests/auto/animation/qadditiveblend/tst_qadditiveblend.cpp b/tests/auto/animation/qadditiveblend/tst_qadditiveblend.cpp deleted file mode 100644 index 369ca0078..000000000 --- a/tests/auto/animation/qadditiveblend/tst_qadditiveblend.cpp +++ /dev/null @@ -1,185 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 Paul Lemire -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt3D module of the Qt Toolkit. -** -** $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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "testpostmanarbiter.h" - -class tst_QAdditiveBlend : public QObject -{ - Q_OBJECT - -private Q_SLOTS: - - void checkDefaultConstruction() - { - // GIVEN - Qt3DAnimation::QAdditiveBlend addBlend; - - // THEN - QCOMPARE(addBlend.blendFactor(), 0.0f); - } - - void checkPropertyChanges() - { - // GIVEN - Qt3DAnimation::QAdditiveBlend addBlend; - - { - // WHEN - QSignalSpy spy(&addBlend, SIGNAL(blendFactorChanged(float))); - const float newValue = 0.5f; - addBlend.setBlendFactor(newValue); - - // THEN - QVERIFY(spy.isValid()); - QCOMPARE(addBlend.blendFactor(), newValue); - QCOMPARE(spy.count(), 1); - - // WHEN - spy.clear(); - addBlend.setBlendFactor(newValue); - - // THEN - QCOMPARE(addBlend.blendFactor(), newValue); - QCOMPARE(spy.count(), 0); - } - } - - void checkCreationData() - { - // GIVEN - Qt3DAnimation::QAdditiveBlend addBlend; - Qt3DAnimation::QAnimationClipLoader clip1; - Qt3DAnimation::QAnimationClipLoader clip2; - - addBlend.addClip(&clip1); - addBlend.addClip(&clip2); - addBlend.setBlendFactor(0.8f); - - - // WHEN - QVector creationChanges; - - { - Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&addBlend); - creationChanges = creationChangeGenerator.creationChanges(); - } - - // THEN - { - QCOMPARE(creationChanges.size(), 3); // 1 + 2 clips - - const auto creationChangeData = qSharedPointerCast>(creationChanges.first()); - const Qt3DAnimation::QAdditiveBlendData cloneData = creationChangeData->data; - - QCOMPARE(addBlend.blendFactor(), cloneData.blendFactor); - QCOMPARE(addBlend.id(), creationChangeData->subjectId()); - QCOMPARE(addBlend.isEnabled(), true); - QCOMPARE(addBlend.isEnabled(), creationChangeData->isNodeEnabled()); - QCOMPARE(addBlend.metaObject(), creationChangeData->metaObject()); - QCOMPARE(creationChangeData->clips().size(), 2); - QCOMPARE(creationChangeData->clips().first(), clip1.id()); - QCOMPARE(creationChangeData->clips().last(), clip2.id()); - QCOMPARE(creationChangeData->parentClipBlendNodeId(), Qt3DCore::QNodeId()); - } - - // WHEN - addBlend.setEnabled(false); - - { - Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&addBlend); - creationChanges = creationChangeGenerator.creationChanges(); - } - - // THEN - { - QCOMPARE(creationChanges.size(), 3); // 1 + 2 clips - - const auto creationChangeData = qSharedPointerCast>(creationChanges.first()); - const Qt3DAnimation::QAdditiveBlendData cloneData = creationChangeData->data; - - QCOMPARE(addBlend.blendFactor(), cloneData.blendFactor); - QCOMPARE(addBlend.id(), creationChangeData->subjectId()); - QCOMPARE(addBlend.isEnabled(), false); - QCOMPARE(addBlend.isEnabled(), creationChangeData->isNodeEnabled()); - QCOMPARE(addBlend.metaObject(), creationChangeData->metaObject()); - QCOMPARE(creationChangeData->clips().size(), 2); - QCOMPARE(creationChangeData->clips().first(), clip1.id()); - QCOMPARE(creationChangeData->clips().last(), clip2.id()); - QCOMPARE(creationChangeData->parentClipBlendNodeId(), Qt3DCore::QNodeId()); - } - } - - void checkBlendFactorUpdate() - { - // GIVEN - TestArbiter arbiter; - Qt3DAnimation::QAdditiveBlend addBlend; - arbiter.setArbiterOnNode(&addBlend); - - { - // WHEN - addBlend.setBlendFactor(0.4f); - QCoreApplication::processEvents(); - - // THEN - QCOMPARE(arbiter.events.size(), 1); - auto change = arbiter.events.first().staticCast(); - QCOMPARE(change->propertyName(), "blendFactor"); - QCOMPARE(change->value().value(), addBlend.blendFactor()); - QCOMPARE(change->type(), Qt3DCore::PropertyUpdated); - - arbiter.events.clear(); - } - - { - // WHEN - addBlend.setBlendFactor(0.4f); - QCoreApplication::processEvents(); - - // THEN - QCOMPARE(arbiter.events.size(), 0); - } - - } - -}; - -QTEST_MAIN(tst_QAdditiveBlend) - -#include "tst_qadditiveblend.moc" diff --git a/tests/auto/animation/qadditiveclipblend/qadditiveclipblend.pro b/tests/auto/animation/qadditiveclipblend/qadditiveclipblend.pro new file mode 100644 index 000000000..e5c6797ee --- /dev/null +++ b/tests/auto/animation/qadditiveclipblend/qadditiveclipblend.pro @@ -0,0 +1,12 @@ +TEMPLATE = app + +TARGET = tst_qadditiveclipblend + +QT += 3dcore 3dcore-private 3danimation 3danimation-private testlib + +CONFIG += testcase + +SOURCES += \ + tst_qadditiveclipblend.cpp + +include(../../core/common/common.pri) diff --git a/tests/auto/animation/qadditiveclipblend/tst_qadditiveclipblend.cpp b/tests/auto/animation/qadditiveclipblend/tst_qadditiveclipblend.cpp new file mode 100644 index 000000000..f0e40ca67 --- /dev/null +++ b/tests/auto/animation/qadditiveclipblend/tst_qadditiveclipblend.cpp @@ -0,0 +1,185 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Paul Lemire +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "testpostmanarbiter.h" + +class tst_QAdditiveClipBlend : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + + void checkDefaultConstruction() + { + // GIVEN + Qt3DAnimation::QAdditiveClipBlend addBlend; + + // THEN + QCOMPARE(addBlend.blendFactor(), 0.0f); + } + + void checkPropertyChanges() + { + // GIVEN + Qt3DAnimation::QAdditiveClipBlend addBlend; + + { + // WHEN + QSignalSpy spy(&addBlend, SIGNAL(blendFactorChanged(float))); + const float newValue = 0.5f; + addBlend.setBlendFactor(newValue); + + // THEN + QVERIFY(spy.isValid()); + QCOMPARE(addBlend.blendFactor(), newValue); + QCOMPARE(spy.count(), 1); + + // WHEN + spy.clear(); + addBlend.setBlendFactor(newValue); + + // THEN + QCOMPARE(addBlend.blendFactor(), newValue); + QCOMPARE(spy.count(), 0); + } + } + + void checkCreationData() + { + // GIVEN + Qt3DAnimation::QAdditiveClipBlend addBlend; + Qt3DAnimation::QAnimationClipLoader clip1; + Qt3DAnimation::QAnimationClipLoader clip2; + + addBlend.addClip(&clip1); + addBlend.addClip(&clip2); + addBlend.setBlendFactor(0.8f); + + + // WHEN + QVector creationChanges; + + { + Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&addBlend); + creationChanges = creationChangeGenerator.creationChanges(); + } + + // THEN + { + QCOMPARE(creationChanges.size(), 3); // 1 + 2 clips + + const auto creationChangeData = qSharedPointerCast>(creationChanges.first()); + const Qt3DAnimation::QAdditiveClipBlendData cloneData = creationChangeData->data; + + QCOMPARE(addBlend.blendFactor(), cloneData.blendFactor); + QCOMPARE(addBlend.id(), creationChangeData->subjectId()); + QCOMPARE(addBlend.isEnabled(), true); + QCOMPARE(addBlend.isEnabled(), creationChangeData->isNodeEnabled()); + QCOMPARE(addBlend.metaObject(), creationChangeData->metaObject()); + QCOMPARE(creationChangeData->clips().size(), 2); + QCOMPARE(creationChangeData->clips().first(), clip1.id()); + QCOMPARE(creationChangeData->clips().last(), clip2.id()); + QCOMPARE(creationChangeData->parentClipBlendNodeId(), Qt3DCore::QNodeId()); + } + + // WHEN + addBlend.setEnabled(false); + + { + Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&addBlend); + creationChanges = creationChangeGenerator.creationChanges(); + } + + // THEN + { + QCOMPARE(creationChanges.size(), 3); // 1 + 2 clips + + const auto creationChangeData = qSharedPointerCast>(creationChanges.first()); + const Qt3DAnimation::QAdditiveClipBlendData cloneData = creationChangeData->data; + + QCOMPARE(addBlend.blendFactor(), cloneData.blendFactor); + QCOMPARE(addBlend.id(), creationChangeData->subjectId()); + QCOMPARE(addBlend.isEnabled(), false); + QCOMPARE(addBlend.isEnabled(), creationChangeData->isNodeEnabled()); + QCOMPARE(addBlend.metaObject(), creationChangeData->metaObject()); + QCOMPARE(creationChangeData->clips().size(), 2); + QCOMPARE(creationChangeData->clips().first(), clip1.id()); + QCOMPARE(creationChangeData->clips().last(), clip2.id()); + QCOMPARE(creationChangeData->parentClipBlendNodeId(), Qt3DCore::QNodeId()); + } + } + + void checkBlendFactorUpdate() + { + // GIVEN + TestArbiter arbiter; + Qt3DAnimation::QAdditiveClipBlend addBlend; + arbiter.setArbiterOnNode(&addBlend); + + { + // WHEN + addBlend.setBlendFactor(0.4f); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 1); + auto change = arbiter.events.first().staticCast(); + QCOMPARE(change->propertyName(), "blendFactor"); + QCOMPARE(change->value().value(), addBlend.blendFactor()); + QCOMPARE(change->type(), Qt3DCore::PropertyUpdated); + + arbiter.events.clear(); + } + + { + // WHEN + addBlend.setBlendFactor(0.4f); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 0); + } + + } + +}; + +QTEST_MAIN(tst_QAdditiveClipBlend) + +#include "tst_qadditiveclipblend.moc" -- cgit v1.2.3 From 3624ddb7beeff87196cf1ccc6684dd05457945e1 Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Wed, 22 Feb 2017 15:23:33 +0000 Subject: Add startClip and endClip properties to QLerpClipBlend Task-number: QTBUG-58904 Change-Id: I67a28b5f311d0065e8ca81df692de33ef1aeefcf Reviewed-by: Kevin Ottens --- src/animation/backend/lerpclipblend.cpp | 8 + src/animation/backend/lerpclipblend_p.h | 8 + src/animation/frontend/qlerpclipblend.cpp | 83 +++++++++ src/animation/frontend/qlerpclipblend.h | 8 + src/animation/frontend/qlerpclipblend_p.h | 4 + .../qlerpclipblend/tst_qlerpclipblend.cpp | 197 +++++++++++++++++++-- 6 files changed, 298 insertions(+), 10 deletions(-) diff --git a/src/animation/backend/lerpclipblend.cpp b/src/animation/backend/lerpclipblend.cpp index 1121f0324..7e10a5174 100644 --- a/src/animation/backend/lerpclipblend.cpp +++ b/src/animation/backend/lerpclipblend.cpp @@ -47,6 +47,8 @@ namespace Animation { LerpClipBlend::LerpClipBlend() : ClipBlendNode(ClipBlendNode::LerpBlendType) + , m_startClipId() + , m_endClipId() , m_blendFactor(0.0f) { } @@ -61,6 +63,10 @@ void LerpClipBlend::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Qt3DCore::QPropertyUpdatedChangePtr change = qSharedPointerCast(e); if (change->propertyName() == QByteArrayLiteral("blendFactor")) m_blendFactor = change->value().toFloat(); + else if (change->propertyName() == QByteArrayLiteral("startClip")) + m_startClipId = change->value().value(); + else if (change->propertyName() == QByteArrayLiteral("endClip")) + m_endClipId = change->value().value(); } } @@ -74,6 +80,8 @@ void LerpClipBlend::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr ClipBlendNode::initializeFromPeer(change); const auto creationChangeData = qSharedPointerCast>(change); const Qt3DAnimation::QLerpClipBlendData cloneData = creationChangeData->data; + m_startClipId = cloneData.startClipId; + m_endClipId = cloneData.endClipId; m_blendFactor = cloneData.blendFactor; } diff --git a/src/animation/backend/lerpclipblend_p.h b/src/animation/backend/lerpclipblend_p.h index 8b925b5b6..8d2a9839b 100644 --- a/src/animation/backend/lerpclipblend_p.h +++ b/src/animation/backend/lerpclipblend_p.h @@ -65,12 +65,20 @@ public: inline float blendFactor() const { return m_blendFactor; } void setBlendFactor(float blendFactor) { m_blendFactor = blendFactor; } // For unit tests + inline Qt3DCore::QNodeId startClipId() const { return m_startClipId; } + void setStartClipId(Qt3DCore::QNodeId startClipId) { m_startClipId = startClipId; } // For unit tests + + inline Qt3DCore::QNodeId endClipId() const { return m_endClipId; } + void setEndClipId(Qt3DCore::QNodeId endClipId) { m_endClipId = endClipId; } // For unit tests + void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_FINAL; float blend(float value1, float value2) const Q_DECL_FINAL; private: void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL; + Qt3DCore::QNodeId m_startClipId; + Qt3DCore::QNodeId m_endClipId; float m_blendFactor; }; diff --git a/src/animation/frontend/qlerpclipblend.cpp b/src/animation/frontend/qlerpclipblend.cpp index cb6df6235..3b26adbaa 100644 --- a/src/animation/frontend/qlerpclipblend.cpp +++ b/src/animation/frontend/qlerpclipblend.cpp @@ -86,6 +86,8 @@ namespace Qt3DAnimation { QLerpClipBlendPrivate::QLerpClipBlendPrivate() : QAbstractClipBlendNodePrivate() + , m_startClip(nullptr) + , m_endClip(nullptr) , m_blendFactor(0.0f) { } @@ -109,6 +111,8 @@ Qt3DCore::QNodeCreatedChangeBasePtr QLerpClipBlend::createNodeCreationChange() c Q_D(const QLerpClipBlend); auto creationChange = QClipBlendNodeCreatedChangePtr::create(this); QLerpClipBlendData &data = creationChange->data; + data.startClipId = Qt3DCore::qIdForNode(d->m_startClip); + data.endClipId = Qt3DCore::qIdForNode(d->m_endClip); data.blendFactor = d->m_blendFactor; return creationChange; } @@ -131,9 +135,50 @@ float QLerpClipBlend::blendFactor() const return d->m_blendFactor; } +/*! + \qmlproperty AbstractClipBlendNode LerpClipBlend::startClip + + Holds the sub-tree that should be used as the start clip for this + lerp blend node. That is, the clip returned by this blend node when + the blendFactor is set to a value of 0. +*/ +/*! + \property QLerpClipBlend::startClip + + Holds the sub-tree that should be used as the start clip for this + lerp blend node. That is, the clip returned by this blend node when + the blendFactor is set to a value of 0. +*/ +Qt3DAnimation::QAbstractClipBlendNode *QLerpClipBlend::startClip() const +{ + Q_D(const QLerpClipBlend); + return d->m_startClip; +} + +/*! + \qmlproperty AbstractClipBlendNode LerpClipBlend::endClip + + Holds the sub-tree that should be used as the end clip for this + lerp blend node. That is, the clip returned by this blend node when + the blendFactor is set to a value of 1. +*/ +/*! + \property QLerpClipBlend::endClip + + Holds the sub-tree that should be used as the start clip for this + lerp blend node. That is, the clip returned by this blend node when + the blendFactor is set to a value of 1. +*/ +Qt3DAnimation::QAbstractClipBlendNode *QLerpClipBlend::endClip() const +{ + Q_D(const QLerpClipBlend); + return d->m_endClip; +} + void QLerpClipBlend::setBlendFactor(float blendFactor) { Q_D(QLerpClipBlend); + if (d->m_blendFactor == blendFactor) return; @@ -141,6 +186,44 @@ void QLerpClipBlend::setBlendFactor(float blendFactor) emit blendFactorChanged(blendFactor); } +void QLerpClipBlend::setStartClip(Qt3DAnimation::QAbstractClipBlendNode *startClip) +{ + Q_D(QLerpClipBlend); + if (d->m_startClip == startClip) + return; + + if (d->m_startClip) + d->unregisterDestructionHelper(d->m_startClip); + + if (startClip && !startClip->parent()) + startClip->setParent(this); + d->m_startClip = startClip; + + // Ensures proper bookkeeping + if (d->m_startClip) + d->registerDestructionHelper(d->m_startClip, &QLerpClipBlend::setStartClip, d->m_startClip); + emit startClipChanged(startClip); +} + +void QLerpClipBlend::setEndClip(Qt3DAnimation::QAbstractClipBlendNode *endClip) +{ + Q_D(QLerpClipBlend); + if (d->m_endClip == endClip) + return; + + if (d->m_endClip) + d->unregisterDestructionHelper(d->m_endClip); + + if (endClip && !endClip->parent()) + endClip->setParent(this); + d->m_endClip = endClip; + + // Ensures proper bookkeeping + if (d->m_endClip) + d->registerDestructionHelper(d->m_endClip, &QLerpClipBlend::setEndClip, d->m_endClip); + emit endClipChanged(endClip); +} + /*! \qmlproperty list LerpBlend::clips diff --git a/src/animation/frontend/qlerpclipblend.h b/src/animation/frontend/qlerpclipblend.h index 83d1201cb..f6707a5a5 100644 --- a/src/animation/frontend/qlerpclipblend.h +++ b/src/animation/frontend/qlerpclipblend.h @@ -48,6 +48,8 @@ class QLerpClipBlendPrivate; class QT3DANIMATIONSHARED_EXPORT QLerpClipBlend : public QAbstractClipBlendNode { Q_OBJECT + Q_PROPERTY(Qt3DAnimation::QAbstractClipBlendNode *startClip READ startClip WRITE setStartClip NOTIFY startClipChanged) + Q_PROPERTY(Qt3DAnimation::QAbstractClipBlendNode *endClip READ endClip WRITE setEndClip NOTIFY endClipChanged) Q_PROPERTY(float blendFactor READ blendFactor WRITE setBlendFactor NOTIFY blendFactorChanged) public: @@ -55,12 +57,18 @@ public: ~QLerpClipBlend(); float blendFactor() const; + Qt3DAnimation::QAbstractClipBlendNode *startClip() const; + Qt3DAnimation::QAbstractClipBlendNode *endClip() const; public Q_SLOTS: void setBlendFactor(float blendFactor); + void setStartClip(Qt3DAnimation::QAbstractClipBlendNode * startClip); + void setEndClip(Qt3DAnimation::QAbstractClipBlendNode * endClip); Q_SIGNALS: void blendFactorChanged(float blendFactor); + void startClipChanged(Qt3DAnimation::QAbstractClipBlendNode * startClip); + void endClipChanged(Qt3DAnimation::QAbstractClipBlendNode * endClip); protected: explicit QLerpClipBlend(QLerpClipBlendPrivate &dd, Qt3DCore::QNode *parent = nullptr); diff --git a/src/animation/frontend/qlerpclipblend_p.h b/src/animation/frontend/qlerpclipblend_p.h index eeae948bf..eee597059 100644 --- a/src/animation/frontend/qlerpclipblend_p.h +++ b/src/animation/frontend/qlerpclipblend_p.h @@ -64,11 +64,15 @@ public: QLerpClipBlendPrivate(); Q_DECLARE_PUBLIC(QLerpClipBlend) + QAbstractClipBlendNode *m_startClip; + QAbstractClipBlendNode *m_endClip; float m_blendFactor; }; struct QLerpClipBlendData { + Qt3DCore::QNodeId startClipId; + Qt3DCore::QNodeId endClipId; float blendFactor; }; diff --git a/tests/auto/animation/qlerpclipblend/tst_qlerpclipblend.cpp b/tests/auto/animation/qlerpclipblend/tst_qlerpclipblend.cpp index 5f3bdeccf..d6b449fdb 100644 --- a/tests/auto/animation/qlerpclipblend/tst_qlerpclipblend.cpp +++ b/tests/auto/animation/qlerpclipblend/tst_qlerpclipblend.cpp @@ -44,6 +44,10 @@ class tst_QLerpClipBlend : public QObject Q_OBJECT private Q_SLOTS: + void initTestCase() + { + qRegisterMetaType(); + } void checkDefaultConstruction() { @@ -52,6 +56,8 @@ private Q_SLOTS: // THEN QCOMPARE(lerpBlend.blendFactor(), 0.0f); + QCOMPARE(lerpBlend.startClip(), static_cast(nullptr)); + QCOMPARE(lerpBlend.endClip(), static_cast(nullptr)); } void checkPropertyChanges() @@ -78,17 +84,57 @@ private Q_SLOTS: QCOMPARE(lerpBlend.blendFactor(), newValue); QCOMPARE(spy.count(), 0); } + + { + // WHEN + QSignalSpy spy(&lerpBlend, SIGNAL(startClipChanged(Qt3DAnimation::QAbstractClipBlendNode*))); + auto newValue = new Qt3DAnimation::QLerpClipBlend(); + lerpBlend.setStartClip(newValue); + + // THEN + QVERIFY(spy.isValid()); + QCOMPARE(lerpBlend.startClip(), newValue); + QCOMPARE(spy.count(), 1); + + // WHEN + spy.clear(); + lerpBlend.setStartClip(newValue); + + // THEN + QCOMPARE(lerpBlend.startClip(), newValue); + QCOMPARE(spy.count(), 0); + } + + { + // WHEN + QSignalSpy spy(&lerpBlend, SIGNAL(endClipChanged(Qt3DAnimation::QAbstractClipBlendNode*))); + auto newValue = new Qt3DAnimation::QLerpClipBlend(); + lerpBlend.setEndClip(newValue); + + // THEN + QVERIFY(spy.isValid()); + QCOMPARE(lerpBlend.endClip(), newValue); + QCOMPARE(spy.count(), 1); + + // WHEN + spy.clear(); + lerpBlend.setEndClip(newValue); + + // THEN + QCOMPARE(lerpBlend.endClip(), newValue); + QCOMPARE(spy.count(), 0); + } } void checkCreationData() { // GIVEN Qt3DAnimation::QLerpClipBlend lerpBlend; - Qt3DAnimation::QAnimationClipLoader clip1; - Qt3DAnimation::QAnimationClipLoader clip2; + Qt3DAnimation::QLerpClipBlend startClip; + Qt3DAnimation::QLerpClipBlend endClip; - lerpBlend.addClip(&clip1); - lerpBlend.addClip(&clip2); + lerpBlend.setStartClip(&startClip); + lerpBlend.setEndClip(&endClip); lerpBlend.setBlendFactor(0.8f); @@ -112,9 +158,8 @@ private Q_SLOTS: QCOMPARE(lerpBlend.isEnabled(), true); QCOMPARE(lerpBlend.isEnabled(), creationChangeData->isNodeEnabled()); QCOMPARE(lerpBlend.metaObject(), creationChangeData->metaObject()); - QCOMPARE(creationChangeData->clips().size(), 2); - QCOMPARE(creationChangeData->clips().first(), clip1.id()); - QCOMPARE(creationChangeData->clips().last(), clip2.id()); + QCOMPARE(cloneData.startClipId, startClip.id()); + QCOMPARE(cloneData.endClipId, endClip.id()); QCOMPARE(creationChangeData->parentClipBlendNodeId(), Qt3DCore::QNodeId()); } @@ -138,9 +183,8 @@ private Q_SLOTS: QCOMPARE(lerpBlend.isEnabled(), false); QCOMPARE(lerpBlend.isEnabled(), creationChangeData->isNodeEnabled()); QCOMPARE(lerpBlend.metaObject(), creationChangeData->metaObject()); - QCOMPARE(creationChangeData->clips().size(), 2); - QCOMPARE(creationChangeData->clips().first(), clip1.id()); - QCOMPARE(creationChangeData->clips().last(), clip2.id()); + QCOMPARE(cloneData.startClipId, startClip.id()); + QCOMPARE(cloneData.endClipId, endClip.id()); QCOMPARE(creationChangeData->parentClipBlendNodeId(), Qt3DCore::QNodeId()); } } @@ -178,6 +222,139 @@ private Q_SLOTS: } + void checkStartClipUpdate() + { + // GIVEN + TestArbiter arbiter; + Qt3DAnimation::QLerpClipBlend lerpBlend; + arbiter.setArbiterOnNode(&lerpBlend); + auto startClip = new Qt3DAnimation::QLerpClipBlend(); + + { + // WHEN + lerpBlend.setStartClip(startClip); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 1); + auto change = arbiter.events.first().staticCast(); + QCOMPARE(change->propertyName(), "startClip"); + QCOMPARE(change->value().value(), lerpBlend.startClip()->id()); + QCOMPARE(change->type(), Qt3DCore::PropertyUpdated); + + arbiter.events.clear(); + } + + { + // WHEN + lerpBlend.setStartClip(startClip); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 0); + } + } + + void checkEndClipUpdate() + { + // GIVEN + TestArbiter arbiter; + Qt3DAnimation::QLerpClipBlend lerpBlend; + arbiter.setArbiterOnNode(&lerpBlend); + auto endClip = new Qt3DAnimation::QLerpClipBlend(); + + { + // WHEN + lerpBlend.setEndClip(endClip); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 1); + auto change = arbiter.events.first().staticCast(); + QCOMPARE(change->propertyName(), "endClip"); + QCOMPARE(change->value().value(), lerpBlend.endClip()->id()); + QCOMPARE(change->type(), Qt3DCore::PropertyUpdated); + + arbiter.events.clear(); + } + + { + // WHEN + lerpBlend.setEndClip(endClip); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 0); + } + } + + void checkStartClipBookkeeping() + { + // GIVEN + QScopedPointer lerpBlend(new Qt3DAnimation::QLerpClipBlend); + { + // WHEN + Qt3DAnimation::QLerpClipBlend clip; + lerpBlend->setStartClip(&clip); + + // THEN + QCOMPARE(clip.parent(), lerpBlend.data()); + QCOMPARE(lerpBlend->startClip(), &clip); + } + // THEN (Should not crash and clip be unset) + QVERIFY(lerpBlend->startClip() == nullptr); + + { + // WHEN + Qt3DAnimation::QLerpClipBlend someOtherLerpBlend; + QScopedPointer clip(new Qt3DAnimation::QLerpClipBlend(&someOtherLerpBlend)); + lerpBlend->setStartClip(clip.data()); + + // THEN + QCOMPARE(clip->parent(), &someOtherLerpBlend); + QCOMPARE(lerpBlend->startClip(), clip.data()); + + // WHEN + lerpBlend.reset(); + clip.reset(); + + // THEN Should not crash when the effect is destroyed (tests for failed removal of destruction helper) + } + } + + void checkEndClipBookkeeping() + { + // GIVEN + QScopedPointer lerpBlend(new Qt3DAnimation::QLerpClipBlend); + { + // WHEN + Qt3DAnimation::QLerpClipBlend clip; + lerpBlend->setEndClip(&clip); + + // THEN + QCOMPARE(clip.parent(), lerpBlend.data()); + QCOMPARE(lerpBlend->endClip(), &clip); + } + // THEN (Should not crash and clip be unset) + QVERIFY(lerpBlend->endClip() == nullptr); + + { + // WHEN + Qt3DAnimation::QLerpClipBlend someOtherLerpBlend; + QScopedPointer clip(new Qt3DAnimation::QLerpClipBlend(&someOtherLerpBlend)); + lerpBlend->setEndClip(clip.data()); + + // THEN + QCOMPARE(clip->parent(), &someOtherLerpBlend); + QCOMPARE(lerpBlend->endClip(), clip.data()); + + // WHEN + lerpBlend.reset(); + clip.reset(); + + // THEN Should not crash when the effect is destroyed (tests for failed removal of destruction helper) + } + } }; QTEST_MAIN(tst_QLerpClipBlend) -- cgit v1.2.3 From 87cf108f5da481d9a4eeb5d0fbb7145ecef4863e Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Thu, 23 Feb 2017 09:27:58 +0000 Subject: Rename blendFactor on QAdditiveClipBlend to additiveFactor Likewise for the backend node. Task-number: QTBUG-58903 Change-Id: I2a2d084f80cf5b36a2ba6c1c03f511a1f74a2f62 Reviewed-by: Kevin Ottens --- src/animation/backend/additiveclipblend.cpp | 10 ++++----- src/animation/backend/additiveclipblend_p.h | 6 ++--- src/animation/frontend/qadditiveclipblend.cpp | 20 ++++++++--------- src/animation/frontend/qadditiveclipblend.h | 8 +++---- src/animation/frontend/qadditiveclipblend_p.h | 4 ++-- .../additiveclipblend/tst_additiveclipblend.cpp | 12 +++++----- .../qadditiveclipblend/tst_qadditiveclipblend.cpp | 26 +++++++++++----------- 7 files changed, 43 insertions(+), 43 deletions(-) diff --git a/src/animation/backend/additiveclipblend.cpp b/src/animation/backend/additiveclipblend.cpp index ea7db4621..a361001ad 100644 --- a/src/animation/backend/additiveclipblend.cpp +++ b/src/animation/backend/additiveclipblend.cpp @@ -48,7 +48,7 @@ namespace Animation { AdditiveClipBlend::AdditiveClipBlend() : ClipBlendNode(ClipBlendNode::AdditiveBlendType) - , m_blendFactor(0.0f) + , m_additiveFactor(0.0f) { } @@ -60,14 +60,14 @@ void AdditiveClipBlend::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) { if (e->type() == Qt3DCore::PropertyUpdated) { Qt3DCore::QPropertyUpdatedChangePtr change = qSharedPointerCast(e); - if (change->propertyName() == QByteArrayLiteral("blendFactor")) - m_blendFactor = change->value().toFloat(); + if (change->propertyName() == QByteArrayLiteral("additiveFactor")) + m_additiveFactor = change->value().toFloat(); } } float AdditiveClipBlend::blend(float value1, float value2) const { - return value1 + (m_blendFactor * value2); + return value1 + (m_additiveFactor * value2); } void AdditiveClipBlend::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) @@ -75,7 +75,7 @@ void AdditiveClipBlend::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBas ClipBlendNode::initializeFromPeer(change); const auto creationChangeData = qSharedPointerCast>(change); const Qt3DAnimation::QAdditiveClipBlendData cloneData = creationChangeData->data; - m_blendFactor = cloneData.blendFactor; + m_additiveFactor = cloneData.additiveFactor; } } // Animation diff --git a/src/animation/backend/additiveclipblend_p.h b/src/animation/backend/additiveclipblend_p.h index 8664eb549..036992f06 100644 --- a/src/animation/backend/additiveclipblend_p.h +++ b/src/animation/backend/additiveclipblend_p.h @@ -62,8 +62,8 @@ public: AdditiveClipBlend(); ~AdditiveClipBlend(); - inline float blendFactor() const { return m_blendFactor; } - void setBlendFactor(float blendFactor) { m_blendFactor = blendFactor; } // For unit tests + inline float additiveFactor() const { return m_additiveFactor; } + void setAdditiveFactor(float additiveFactor) { m_additiveFactor = additiveFactor; } // For unit tests void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_FINAL; float blend(float value1, float value2) const Q_DECL_FINAL; @@ -71,7 +71,7 @@ public: private: void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL; - float m_blendFactor; + float m_additiveFactor; }; } // Animation diff --git a/src/animation/frontend/qadditiveclipblend.cpp b/src/animation/frontend/qadditiveclipblend.cpp index 90cc92e55..4f43f17e3 100644 --- a/src/animation/frontend/qadditiveclipblend.cpp +++ b/src/animation/frontend/qadditiveclipblend.cpp @@ -87,7 +87,7 @@ namespace Qt3DAnimation { QAdditiveClipBlendPrivate::QAdditiveClipBlendPrivate() : QAbstractClipBlendNodePrivate() - , m_blendFactor(0.0f) + , m_additiveFactor(0.0f) { } @@ -110,36 +110,36 @@ Qt3DCore::QNodeCreatedChangeBasePtr QAdditiveClipBlend::createNodeCreationChange Q_D(const QAdditiveClipBlend); auto creationChange = QClipBlendNodeCreatedChangePtr::create(this); QAdditiveClipBlendData &data = creationChange->data; - data.blendFactor = d->m_blendFactor; + data.additiveFactor = d->m_additiveFactor; return creationChange; } /*! - \qmlproperty real AdditiveClipBlend::blendFactor + \qmlproperty real AdditiveClipBlend::additiveFactor Specifies the blending factor between 0 and 1 to control the blending of two animation clips. */ /*! - \property QAdditiveClipBlend::blendFactor + \property QAdditiveClipBlend::additiveFactor Specifies the blending factor between 0 and 1 to control the blending of two animation clips. */ -float QAdditiveClipBlend::blendFactor() const +float QAdditiveClipBlend::additiveFactor() const { Q_D(const QAdditiveClipBlend); - return d->m_blendFactor; + return d->m_additiveFactor; } -void QAdditiveClipBlend::setBlendFactor(float blendFactor) +void QAdditiveClipBlend::setAdditiveFactor(float additiveFactor) { Q_D(QAdditiveClipBlend); - if (d->m_blendFactor == blendFactor) + if (d->m_additiveFactor == additiveFactor) return; - d->m_blendFactor = blendFactor; - emit blendFactorChanged(blendFactor); + d->m_additiveFactor = additiveFactor; + emit additiveFactorChanged(additiveFactor); } /*! diff --git a/src/animation/frontend/qadditiveclipblend.h b/src/animation/frontend/qadditiveclipblend.h index eb1de9abb..839a891f0 100644 --- a/src/animation/frontend/qadditiveclipblend.h +++ b/src/animation/frontend/qadditiveclipblend.h @@ -48,18 +48,18 @@ class QAdditiveClipBlendPrivate; class QT3DANIMATIONSHARED_EXPORT QAdditiveClipBlend : public QAbstractClipBlendNode { Q_OBJECT - Q_PROPERTY(float blendFactor READ blendFactor WRITE setBlendFactor NOTIFY blendFactorChanged) + Q_PROPERTY(float additiveFactor READ additiveFactor WRITE setAdditiveFactor NOTIFY additiveFactorChanged) public: explicit QAdditiveClipBlend(Qt3DCore::QNode *parent = nullptr); ~QAdditiveClipBlend(); - float blendFactor() const; + float additiveFactor() const; public Q_SLOTS: - void setBlendFactor(float blendFactor); + void setAdditiveFactor(float additiveFactor); Q_SIGNALS: - void blendFactorChanged(float blendFactor); + void additiveFactorChanged(float additiveFactor); protected: explicit QAdditiveClipBlend(QAdditiveClipBlendPrivate &dd, Qt3DCore::QNode *parent = nullptr); diff --git a/src/animation/frontend/qadditiveclipblend_p.h b/src/animation/frontend/qadditiveclipblend_p.h index 0506fc459..93dc0dae4 100644 --- a/src/animation/frontend/qadditiveclipblend_p.h +++ b/src/animation/frontend/qadditiveclipblend_p.h @@ -63,12 +63,12 @@ public: QAdditiveClipBlendPrivate(); Q_DECLARE_PUBLIC(QAdditiveClipBlend) - float m_blendFactor; + float m_additiveFactor; }; struct QAdditiveClipBlendData { - float blendFactor; + float additiveFactor; }; } // Qt3DAnimation diff --git a/tests/auto/animation/additiveclipblend/tst_additiveclipblend.cpp b/tests/auto/animation/additiveclipblend/tst_additiveclipblend.cpp index 4875d67cc..211da5788 100644 --- a/tests/auto/animation/additiveclipblend/tst_additiveclipblend.cpp +++ b/tests/auto/animation/additiveclipblend/tst_additiveclipblend.cpp @@ -49,7 +49,7 @@ private Q_SLOTS: // THEN QCOMPARE(backendAdditiveBlend.isEnabled(), false); QVERIFY(backendAdditiveBlend.peerId().isNull()); - QCOMPARE(backendAdditiveBlend.blendFactor(), 0.0f); + QCOMPARE(backendAdditiveBlend.additiveFactor(), 0.0f); QCOMPARE(backendAdditiveBlend.blendType(), Qt3DAnimation::Animation::ClipBlendNode::AdditiveBlendType); } @@ -58,7 +58,7 @@ private Q_SLOTS: // GIVEN Qt3DAnimation::QAdditiveClipBlend additiveBlend; Qt3DAnimation::QAnimationClipLoader clip; - additiveBlend.setBlendFactor(0.8f); + additiveBlend.setAdditiveFactor(0.8f); additiveBlend.addClip(&clip); { @@ -69,7 +69,7 @@ private Q_SLOTS: // THEN QCOMPARE(backendAdditiveBlend.isEnabled(), true); QCOMPARE(backendAdditiveBlend.peerId(), additiveBlend.id()); - QCOMPARE(backendAdditiveBlend.blendFactor(), 0.8f); + QCOMPARE(backendAdditiveBlend.additiveFactor(), 0.8f); QCOMPARE(backendAdditiveBlend.clipIds().size(), 1); QCOMPARE(backendAdditiveBlend.clipIds().first(), clip.id()); } @@ -104,12 +104,12 @@ private Q_SLOTS: // WHEN const float newValue = 0.883f; const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId()); - change->setPropertyName("blendFactor"); + change->setPropertyName("additiveFactor"); change->setValue(QVariant::fromValue(newValue)); backendAdditiveBlend.sceneChangeEvent(change); // THEN - QCOMPARE(backendAdditiveBlend.blendFactor(), newValue); + QCOMPARE(backendAdditiveBlend.additiveFactor(), newValue); } } @@ -135,7 +135,7 @@ private Q_SLOTS: Qt3DAnimation::Animation::AdditiveClipBlend addBlend; // WHEN - addBlend.setBlendFactor(blendFactor); + addBlend.setAdditiveFactor(blendFactor); const float computed = addBlend.blend(value1, value2); // THEN diff --git a/tests/auto/animation/qadditiveclipblend/tst_qadditiveclipblend.cpp b/tests/auto/animation/qadditiveclipblend/tst_qadditiveclipblend.cpp index f0e40ca67..cded4b569 100644 --- a/tests/auto/animation/qadditiveclipblend/tst_qadditiveclipblend.cpp +++ b/tests/auto/animation/qadditiveclipblend/tst_qadditiveclipblend.cpp @@ -51,7 +51,7 @@ private Q_SLOTS: Qt3DAnimation::QAdditiveClipBlend addBlend; // THEN - QCOMPARE(addBlend.blendFactor(), 0.0f); + QCOMPARE(addBlend.additiveFactor(), 0.0f); } void checkPropertyChanges() @@ -61,21 +61,21 @@ private Q_SLOTS: { // WHEN - QSignalSpy spy(&addBlend, SIGNAL(blendFactorChanged(float))); + QSignalSpy spy(&addBlend, SIGNAL(additiveFactorChanged(float))); const float newValue = 0.5f; - addBlend.setBlendFactor(newValue); + addBlend.setAdditiveFactor(newValue); // THEN QVERIFY(spy.isValid()); - QCOMPARE(addBlend.blendFactor(), newValue); + QCOMPARE(addBlend.additiveFactor(), newValue); QCOMPARE(spy.count(), 1); // WHEN spy.clear(); - addBlend.setBlendFactor(newValue); + addBlend.setAdditiveFactor(newValue); // THEN - QCOMPARE(addBlend.blendFactor(), newValue); + QCOMPARE(addBlend.additiveFactor(), newValue); QCOMPARE(spy.count(), 0); } } @@ -89,7 +89,7 @@ private Q_SLOTS: addBlend.addClip(&clip1); addBlend.addClip(&clip2); - addBlend.setBlendFactor(0.8f); + addBlend.setAdditiveFactor(0.8f); // WHEN @@ -107,7 +107,7 @@ private Q_SLOTS: const auto creationChangeData = qSharedPointerCast>(creationChanges.first()); const Qt3DAnimation::QAdditiveClipBlendData cloneData = creationChangeData->data; - QCOMPARE(addBlend.blendFactor(), cloneData.blendFactor); + QCOMPARE(addBlend.additiveFactor(), cloneData.additiveFactor); QCOMPARE(addBlend.id(), creationChangeData->subjectId()); QCOMPARE(addBlend.isEnabled(), true); QCOMPARE(addBlend.isEnabled(), creationChangeData->isNodeEnabled()); @@ -133,7 +133,7 @@ private Q_SLOTS: const auto creationChangeData = qSharedPointerCast>(creationChanges.first()); const Qt3DAnimation::QAdditiveClipBlendData cloneData = creationChangeData->data; - QCOMPARE(addBlend.blendFactor(), cloneData.blendFactor); + QCOMPARE(addBlend.additiveFactor(), cloneData.additiveFactor); QCOMPARE(addBlend.id(), creationChangeData->subjectId()); QCOMPARE(addBlend.isEnabled(), false); QCOMPARE(addBlend.isEnabled(), creationChangeData->isNodeEnabled()); @@ -154,14 +154,14 @@ private Q_SLOTS: { // WHEN - addBlend.setBlendFactor(0.4f); + addBlend.setAdditiveFactor(0.4f); QCoreApplication::processEvents(); // THEN QCOMPARE(arbiter.events.size(), 1); auto change = arbiter.events.first().staticCast(); - QCOMPARE(change->propertyName(), "blendFactor"); - QCOMPARE(change->value().value(), addBlend.blendFactor()); + QCOMPARE(change->propertyName(), "additiveFactor"); + QCOMPARE(change->value().value(), addBlend.additiveFactor()); QCOMPARE(change->type(), Qt3DCore::PropertyUpdated); arbiter.events.clear(); @@ -169,7 +169,7 @@ private Q_SLOTS: { // WHEN - addBlend.setBlendFactor(0.4f); + addBlend.setAdditiveFactor(0.4f); QCoreApplication::processEvents(); // THEN -- cgit v1.2.3 From 7253d10a1026be03eab83edd628b72455d7bcd28 Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Thu, 23 Feb 2017 10:51:33 +0000 Subject: Add baseClip and additiveClip properties to QAdditiveClipBlend Also added corresponding backend node properties. Task-number: QTBUG-58903 Change-Id: I4b441e305c1ddfc062b215b713a6b894960cdd4b Reviewed-by: Kevin Ottens --- src/animation/backend/additiveclipblend.cpp | 8 + src/animation/backend/additiveclipblend_p.h | 8 + src/animation/frontend/qadditiveclipblend.cpp | 55 ++++++ src/animation/frontend/qadditiveclipblend.h | 8 + src/animation/frontend/qadditiveclipblend_p.h | 4 + .../additiveclipblend/tst_additiveclipblend.cpp | 30 ++++ .../qadditiveclipblend/tst_qadditiveclipblend.cpp | 199 +++++++++++++++++++-- 7 files changed, 301 insertions(+), 11 deletions(-) diff --git a/src/animation/backend/additiveclipblend.cpp b/src/animation/backend/additiveclipblend.cpp index a361001ad..4100c8b53 100644 --- a/src/animation/backend/additiveclipblend.cpp +++ b/src/animation/backend/additiveclipblend.cpp @@ -48,6 +48,8 @@ namespace Animation { AdditiveClipBlend::AdditiveClipBlend() : ClipBlendNode(ClipBlendNode::AdditiveBlendType) + , m_baseClipId() + , m_additiveClipId() , m_additiveFactor(0.0f) { } @@ -62,6 +64,10 @@ void AdditiveClipBlend::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Qt3DCore::QPropertyUpdatedChangePtr change = qSharedPointerCast(e); if (change->propertyName() == QByteArrayLiteral("additiveFactor")) m_additiveFactor = change->value().toFloat(); + else if (change->propertyName() == QByteArrayLiteral("baseClip")) + m_baseClipId = change->value().value(); + else if (change->propertyName() == QByteArrayLiteral("additiveClip")) + m_additiveClipId = change->value().value(); } } @@ -75,6 +81,8 @@ void AdditiveClipBlend::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBas ClipBlendNode::initializeFromPeer(change); const auto creationChangeData = qSharedPointerCast>(change); const Qt3DAnimation::QAdditiveClipBlendData cloneData = creationChangeData->data; + m_baseClipId = cloneData.baseClipId; + m_additiveClipId = cloneData.additiveClipId; m_additiveFactor = cloneData.additiveFactor; } diff --git a/src/animation/backend/additiveclipblend_p.h b/src/animation/backend/additiveclipblend_p.h index 036992f06..bbb318de4 100644 --- a/src/animation/backend/additiveclipblend_p.h +++ b/src/animation/backend/additiveclipblend_p.h @@ -62,6 +62,12 @@ public: AdditiveClipBlend(); ~AdditiveClipBlend(); + inline Qt3DCore::QNodeId baseClipId() const { return m_baseClipId; } + void setBaseClipId(Qt3DCore::QNodeId baseClipId) { m_baseClipId = baseClipId; } // For unit tests + + inline Qt3DCore::QNodeId additiveClipId() const { return m_additiveClipId; } + void setAdditiveClipId(Qt3DCore::QNodeId additiveClipId) { m_additiveClipId = additiveClipId; } // For unit tests + inline float additiveFactor() const { return m_additiveFactor; } void setAdditiveFactor(float additiveFactor) { m_additiveFactor = additiveFactor; } // For unit tests @@ -71,6 +77,8 @@ public: private: void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL; + Qt3DCore::QNodeId m_baseClipId; + Qt3DCore::QNodeId m_additiveClipId; float m_additiveFactor; }; diff --git a/src/animation/frontend/qadditiveclipblend.cpp b/src/animation/frontend/qadditiveclipblend.cpp index 4f43f17e3..ee207eb42 100644 --- a/src/animation/frontend/qadditiveclipblend.cpp +++ b/src/animation/frontend/qadditiveclipblend.cpp @@ -87,6 +87,8 @@ namespace Qt3DAnimation { QAdditiveClipBlendPrivate::QAdditiveClipBlendPrivate() : QAbstractClipBlendNodePrivate() + , m_baseClip(nullptr) + , m_additiveClip(nullptr) , m_additiveFactor(0.0f) { } @@ -110,6 +112,8 @@ Qt3DCore::QNodeCreatedChangeBasePtr QAdditiveClipBlend::createNodeCreationChange Q_D(const QAdditiveClipBlend); auto creationChange = QClipBlendNodeCreatedChangePtr::create(this); QAdditiveClipBlendData &data = creationChange->data; + data.baseClipId = Qt3DCore::qIdForNode(d->m_baseClip); + data.additiveClipId = Qt3DCore::qIdForNode(d->m_additiveClip); data.additiveFactor = d->m_additiveFactor; return creationChange; } @@ -132,6 +136,18 @@ float QAdditiveClipBlend::additiveFactor() const return d->m_additiveFactor; } +QAbstractClipBlendNode *QAdditiveClipBlend::baseClip() const +{ + Q_D(const QAdditiveClipBlend); + return d->m_baseClip; +} + +QAbstractClipBlendNode *QAdditiveClipBlend::additiveClip() const +{ + Q_D(const QAdditiveClipBlend); + return d->m_additiveClip; +} + void QAdditiveClipBlend::setAdditiveFactor(float additiveFactor) { Q_D(QAdditiveClipBlend); @@ -142,6 +158,45 @@ void QAdditiveClipBlend::setAdditiveFactor(float additiveFactor) emit additiveFactorChanged(additiveFactor); } +void QAdditiveClipBlend::setBaseClip(QAbstractClipBlendNode *baseClip) +{ + Q_D(QAdditiveClipBlend); + if (d->m_baseClip == baseClip) + return; + + if (d->m_baseClip) + d->unregisterDestructionHelper(d->m_baseClip); + + if (baseClip && !baseClip->parent()) + baseClip->setParent(this); + d->m_baseClip = baseClip; + + // Ensures proper bookkeeping + if (d->m_baseClip) + d->registerDestructionHelper(d->m_baseClip, &QAdditiveClipBlend::setBaseClip, d->m_baseClip); + + emit baseClipChanged(baseClip); +} + +void QAdditiveClipBlend::setAdditiveClip(QAbstractClipBlendNode *additiveClip) +{ + Q_D(QAdditiveClipBlend); + if (d->m_additiveClip == additiveClip) + return; + + if (d->m_additiveClip) + d->unregisterDestructionHelper(d->m_additiveClip); + + if (additiveClip && !additiveClip->parent()) + additiveClip->setParent(this); + d->m_additiveClip = additiveClip; + + // Ensures proper bookkeeping + if (d->m_additiveClip) + d->registerDestructionHelper(d->m_additiveClip, &QAdditiveClipBlend::setAdditiveClip, d->m_additiveClip); + emit additiveClipChanged(additiveClip); +} + /*! \qmlproperty list AdditiveClipBlend::clips diff --git a/src/animation/frontend/qadditiveclipblend.h b/src/animation/frontend/qadditiveclipblend.h index 839a891f0..11731c702 100644 --- a/src/animation/frontend/qadditiveclipblend.h +++ b/src/animation/frontend/qadditiveclipblend.h @@ -48,18 +48,26 @@ class QAdditiveClipBlendPrivate; class QT3DANIMATIONSHARED_EXPORT QAdditiveClipBlend : public QAbstractClipBlendNode { Q_OBJECT + Q_PROPERTY(Qt3DAnimation::QAbstractClipBlendNode *baseClip READ baseClip WRITE setBaseClip NOTIFY baseClipChanged) + Q_PROPERTY(Qt3DAnimation::QAbstractClipBlendNode *additiveClip READ additiveClip WRITE setAdditiveClip NOTIFY additiveClipChanged) Q_PROPERTY(float additiveFactor READ additiveFactor WRITE setAdditiveFactor NOTIFY additiveFactorChanged) public: explicit QAdditiveClipBlend(Qt3DCore::QNode *parent = nullptr); ~QAdditiveClipBlend(); float additiveFactor() const; + Qt3DAnimation::QAbstractClipBlendNode *baseClip() const; + Qt3DAnimation::QAbstractClipBlendNode *additiveClip() const; public Q_SLOTS: void setAdditiveFactor(float additiveFactor); + void setBaseClip(Qt3DAnimation::QAbstractClipBlendNode *baseClip); + void setAdditiveClip(Qt3DAnimation::QAbstractClipBlendNode *additiveClip); Q_SIGNALS: void additiveFactorChanged(float additiveFactor); + void baseClipChanged(Qt3DAnimation::QAbstractClipBlendNode *baseClip); + void additiveClipChanged(Qt3DAnimation::QAbstractClipBlendNode *additiveClip); protected: explicit QAdditiveClipBlend(QAdditiveClipBlendPrivate &dd, Qt3DCore::QNode *parent = nullptr); diff --git a/src/animation/frontend/qadditiveclipblend_p.h b/src/animation/frontend/qadditiveclipblend_p.h index 93dc0dae4..0c408c9ff 100644 --- a/src/animation/frontend/qadditiveclipblend_p.h +++ b/src/animation/frontend/qadditiveclipblend_p.h @@ -63,11 +63,15 @@ public: QAdditiveClipBlendPrivate(); Q_DECLARE_PUBLIC(QAdditiveClipBlend) + Qt3DAnimation::QAbstractClipBlendNode *m_baseClip; + Qt3DAnimation::QAbstractClipBlendNode *m_additiveClip; float m_additiveFactor; }; struct QAdditiveClipBlendData { + Qt3DCore::QNodeId baseClipId; + Qt3DCore::QNodeId additiveClipId; float additiveFactor; }; diff --git a/tests/auto/animation/additiveclipblend/tst_additiveclipblend.cpp b/tests/auto/animation/additiveclipblend/tst_additiveclipblend.cpp index 211da5788..e6777cd6a 100644 --- a/tests/auto/animation/additiveclipblend/tst_additiveclipblend.cpp +++ b/tests/auto/animation/additiveclipblend/tst_additiveclipblend.cpp @@ -49,6 +49,8 @@ private Q_SLOTS: // THEN QCOMPARE(backendAdditiveBlend.isEnabled(), false); QVERIFY(backendAdditiveBlend.peerId().isNull()); + QCOMPARE(backendAdditiveBlend.baseClipId(), Qt3DCore::QNodeId()); + QCOMPARE(backendAdditiveBlend.additiveClipId(), Qt3DCore::QNodeId()); QCOMPARE(backendAdditiveBlend.additiveFactor(), 0.0f); QCOMPARE(backendAdditiveBlend.blendType(), Qt3DAnimation::Animation::ClipBlendNode::AdditiveBlendType); } @@ -57,7 +59,11 @@ private Q_SLOTS: { // GIVEN Qt3DAnimation::QAdditiveClipBlend additiveBlend; + Qt3DAnimation::QAdditiveClipBlend baseClip; + Qt3DAnimation::QAdditiveClipBlend additiveClip; Qt3DAnimation::QAnimationClipLoader clip; + additiveBlend.setBaseClip(&baseClip); + additiveBlend.setAdditiveClip(&additiveClip); additiveBlend.setAdditiveFactor(0.8f); additiveBlend.addClip(&clip); @@ -69,6 +75,8 @@ private Q_SLOTS: // THEN QCOMPARE(backendAdditiveBlend.isEnabled(), true); QCOMPARE(backendAdditiveBlend.peerId(), additiveBlend.id()); + QCOMPARE(backendAdditiveBlend.baseClipId(), baseClip.id()); + QCOMPARE(backendAdditiveBlend.additiveClipId(), additiveClip.id()); QCOMPARE(backendAdditiveBlend.additiveFactor(), 0.8f); QCOMPARE(backendAdditiveBlend.clipIds().size(), 1); QCOMPARE(backendAdditiveBlend.clipIds().first(), clip.id()); @@ -111,6 +119,28 @@ private Q_SLOTS: // THEN QCOMPARE(backendAdditiveBlend.additiveFactor(), newValue); } + { + // WHEN + const Qt3DAnimation::QAdditiveClipBlend newValue; + const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId()); + change->setPropertyName("baseClip"); + change->setValue(QVariant::fromValue(newValue.id())); + backendAdditiveBlend.sceneChangeEvent(change); + + // THEN + QCOMPARE(backendAdditiveBlend.baseClipId(), newValue.id()); + } + { + // WHEN + const Qt3DAnimation::QAdditiveClipBlend newValue; + const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId()); + change->setPropertyName("additiveClip"); + change->setValue(QVariant::fromValue(newValue.id())); + backendAdditiveBlend.sceneChangeEvent(change); + + // THEN + QCOMPARE(backendAdditiveBlend.additiveClipId(), newValue.id()); + } } void checkBlend_data() diff --git a/tests/auto/animation/qadditiveclipblend/tst_qadditiveclipblend.cpp b/tests/auto/animation/qadditiveclipblend/tst_qadditiveclipblend.cpp index cded4b569..536853b1f 100644 --- a/tests/auto/animation/qadditiveclipblend/tst_qadditiveclipblend.cpp +++ b/tests/auto/animation/qadditiveclipblend/tst_qadditiveclipblend.cpp @@ -44,6 +44,10 @@ class tst_QAdditiveClipBlend : public QObject Q_OBJECT private Q_SLOTS: + void initTestCase() + { + qRegisterMetaType(); + } void checkDefaultConstruction() { @@ -52,6 +56,8 @@ private Q_SLOTS: // THEN QCOMPARE(addBlend.additiveFactor(), 0.0f); + QCOMPARE(addBlend.baseClip(), static_cast(nullptr)); + QCOMPARE(addBlend.additiveClip(), static_cast(nullptr)); } void checkPropertyChanges() @@ -78,17 +84,57 @@ private Q_SLOTS: QCOMPARE(addBlend.additiveFactor(), newValue); QCOMPARE(spy.count(), 0); } + + { + // WHEN + QSignalSpy spy(&addBlend, SIGNAL(baseClipChanged(Qt3DAnimation::QAbstractClipBlendNode*))); + auto newValue = new Qt3DAnimation::QAdditiveClipBlend(); + addBlend.setBaseClip(newValue); + + // THEN + QVERIFY(spy.isValid()); + QCOMPARE(addBlend.baseClip(), newValue); + QCOMPARE(spy.count(), 1); + + // WHEN + spy.clear(); + addBlend.setBaseClip(newValue); + + // THEN + QCOMPARE(addBlend.baseClip(), newValue); + QCOMPARE(spy.count(), 0); + } + + { + // WHEN + QSignalSpy spy(&addBlend, SIGNAL(additiveClipChanged(Qt3DAnimation::QAbstractClipBlendNode*))); + auto newValue = new Qt3DAnimation::QAdditiveClipBlend(); + addBlend.setAdditiveClip(newValue); + + // THEN + QVERIFY(spy.isValid()); + QCOMPARE(addBlend.additiveClip(), newValue); + QCOMPARE(spy.count(), 1); + + // WHEN + spy.clear(); + addBlend.setAdditiveClip(newValue); + + // THEN + QCOMPARE(addBlend.additiveClip(), newValue); + QCOMPARE(spy.count(), 0); + } } void checkCreationData() { // GIVEN Qt3DAnimation::QAdditiveClipBlend addBlend; - Qt3DAnimation::QAnimationClipLoader clip1; - Qt3DAnimation::QAnimationClipLoader clip2; + Qt3DAnimation::QAdditiveClipBlend baseClip; + Qt3DAnimation::QAdditiveClipBlend additiveClip; - addBlend.addClip(&clip1); - addBlend.addClip(&clip2); + addBlend.setBaseClip(&baseClip); + addBlend.setAdditiveClip(&additiveClip); addBlend.setAdditiveFactor(0.8f); @@ -112,9 +158,8 @@ private Q_SLOTS: QCOMPARE(addBlend.isEnabled(), true); QCOMPARE(addBlend.isEnabled(), creationChangeData->isNodeEnabled()); QCOMPARE(addBlend.metaObject(), creationChangeData->metaObject()); - QCOMPARE(creationChangeData->clips().size(), 2); - QCOMPARE(creationChangeData->clips().first(), clip1.id()); - QCOMPARE(creationChangeData->clips().last(), clip2.id()); + QCOMPARE(cloneData.baseClipId, baseClip.id()); + QCOMPARE(cloneData.additiveClipId, additiveClip.id()); QCOMPARE(creationChangeData->parentClipBlendNodeId(), Qt3DCore::QNodeId()); } @@ -138,14 +183,13 @@ private Q_SLOTS: QCOMPARE(addBlend.isEnabled(), false); QCOMPARE(addBlend.isEnabled(), creationChangeData->isNodeEnabled()); QCOMPARE(addBlend.metaObject(), creationChangeData->metaObject()); - QCOMPARE(creationChangeData->clips().size(), 2); - QCOMPARE(creationChangeData->clips().first(), clip1.id()); - QCOMPARE(creationChangeData->clips().last(), clip2.id()); + QCOMPARE(cloneData.baseClipId, baseClip.id()); + QCOMPARE(cloneData.additiveClipId, additiveClip.id()); QCOMPARE(creationChangeData->parentClipBlendNodeId(), Qt3DCore::QNodeId()); } } - void checkBlendFactorUpdate() + void checkAdditiveFactorUpdate() { // GIVEN TestArbiter arbiter; @@ -178,6 +222,139 @@ private Q_SLOTS: } + void checkBaseClipUpdate() + { + // GIVEN + TestArbiter arbiter; + Qt3DAnimation::QAdditiveClipBlend addBlend; + arbiter.setArbiterOnNode(&addBlend); + auto baseClip = new Qt3DAnimation::QAdditiveClipBlend(); + + { + // WHEN + addBlend.setBaseClip(baseClip); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 1); + auto change = arbiter.events.first().staticCast(); + QCOMPARE(change->propertyName(), "baseClip"); + QCOMPARE(change->value().value(), addBlend.baseClip()->id()); + QCOMPARE(change->type(), Qt3DCore::PropertyUpdated); + + arbiter.events.clear(); + } + + { + // WHEN + addBlend.setBaseClip(baseClip); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 0); + } + } + + void checkAdditiveClipUpdate() + { + // GIVEN + TestArbiter arbiter; + Qt3DAnimation::QAdditiveClipBlend addBlend; + arbiter.setArbiterOnNode(&addBlend); + auto additiveClip = new Qt3DAnimation::QAdditiveClipBlend(); + + { + // WHEN + addBlend.setAdditiveClip(additiveClip); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 1); + auto change = arbiter.events.first().staticCast(); + QCOMPARE(change->propertyName(), "additiveClip"); + QCOMPARE(change->value().value(), addBlend.additiveClip()->id()); + QCOMPARE(change->type(), Qt3DCore::PropertyUpdated); + + arbiter.events.clear(); + } + + { + // WHEN + addBlend.setAdditiveClip(additiveClip); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 0); + } + } + + void checkBaseClipBookkeeping() + { + // GIVEN + QScopedPointer additiveBlend(new Qt3DAnimation::QAdditiveClipBlend); + { + // WHEN + Qt3DAnimation::QAdditiveClipBlend clip; + additiveBlend->setBaseClip(&clip); + + // THEN + QCOMPARE(clip.parent(), additiveBlend.data()); + QCOMPARE(additiveBlend->baseClip(), &clip); + } + // THEN (Should not crash and clip be unset) + QVERIFY(additiveBlend->baseClip() == nullptr); + + { + // WHEN + Qt3DAnimation::QAdditiveClipBlend someOtherAdditiveBlend; + QScopedPointer clip(new Qt3DAnimation::QAdditiveClipBlend(&someOtherAdditiveBlend)); + additiveBlend->setBaseClip(clip.data()); + + // THEN + QCOMPARE(clip->parent(), &someOtherAdditiveBlend); + QCOMPARE(additiveBlend->baseClip(), clip.data()); + + // WHEN + additiveBlend.reset(); + clip.reset(); + + // THEN Should not crash when the effect is destroyed (tests for failed removal of destruction helper) + } + } + + void checkAdditiveClipBookkeeping() + { + // GIVEN + QScopedPointer additiveBlend(new Qt3DAnimation::QAdditiveClipBlend); + { + // WHEN + Qt3DAnimation::QAdditiveClipBlend clip; + additiveBlend->setAdditiveClip(&clip); + + // THEN + QCOMPARE(clip.parent(), additiveBlend.data()); + QCOMPARE(additiveBlend->additiveClip(), &clip); + } + // THEN (Should not crash and clip be unset) + QVERIFY(additiveBlend->additiveClip() == nullptr); + + { + // WHEN + Qt3DAnimation::QAdditiveClipBlend someOtherAdditiveBlend; + QScopedPointer clip(new Qt3DAnimation::QAdditiveClipBlend(&someOtherAdditiveBlend)); + additiveBlend->setAdditiveClip(clip.data()); + + // THEN + QCOMPARE(clip->parent(), &someOtherAdditiveBlend); + QCOMPARE(additiveBlend->additiveClip(), clip.data()); + + // WHEN + additiveBlend.reset(); + clip.reset(); + + // THEN Should not crash when the effect is destroyed (tests for failed removal of destruction helper) + } + } }; QTEST_MAIN(tst_QAdditiveClipBlend) -- cgit v1.2.3 From f4601e86d20a39c9d41500bd8378e990f4739506 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Tue, 7 Feb 2017 11:25:02 +0200 Subject: Update multiviewport example MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I57ea393e3abc5de2230f464d612d36a8075fa979 Reviewed-by: Tomi Korpipää Reviewed-by: Paul Lemire --- examples/qt3d/multiviewport/Gear_scene.dae | 288 +++++++++++++++++++++ .../qt3d/multiviewport/QuadViewportFrameGraph.qml | 1 + examples/qt3d/multiviewport/main.qml | 60 +++-- examples/qt3d/multiviewport/multiviewport.qrc | 3 +- 4 files changed, 323 insertions(+), 29 deletions(-) create mode 100644 examples/qt3d/multiviewport/Gear_scene.dae diff --git a/examples/qt3d/multiviewport/Gear_scene.dae b/examples/qt3d/multiviewport/Gear_scene.dae new file mode 100644 index 000000000..af013e15f --- /dev/null +++ b/examples/qt3d/multiviewport/Gear_scene.dae @@ -0,0 +1,288 @@ + + + + + Blender User + Blender 2.77.0 commit date:2016-04-05, commit time:18:12, hash:abf6f08 + + 2017-02-14T13:30:26 + 2017-02-14T13:30:26 + + Z_UP + + + + + + 1 1 1 + 1 + 0 + 0.001599967 + + + + + 9.99987e-4 + 0 + 0.1 + 0.1 + 0.1 + 1 + 1 + 2 + 0 + 1 + 1 + 1 + 1 + 1 + 0 + 512 + 2 + 40 + 0.5 + 0.04999995 + 25 + 1 + 2 + 0 + 0 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 0 + 1 + 1 + 1 + 3 + 0 + 0 + 0 + 0 + 2 + 1 + 1 + 1 + 3 + 0.15 + 45 + 1 + 1 + 0 + 1 + 1 + 0 + + + + + + + + + + + + 0 0 0 1 + + + 0 0 0 1 + + + 0.1670472 0.1755583 0.3843743 1 + + + 0.1418384 0.1865893 0.25 1 + + + 25 + + + 1 + + + + + + + + + + + 0 0 0 1 + + + 0 0 0 1 + + + 1 0.7120508 0.786501 1 + + + 0.0699499 0.0699499 0.0699499 1 + + + 9 + + + 1 + + + + + + + + + + + + + + + + + + + 0 1.716105 -0.1212262 0 1.716105 0.1212257 0.4441608 1.65763 -0.1212262 0.4441608 1.65763 0.1212257 0.8580526 1.486191 -0.1212261 0.8580526 1.486191 0.1212257 1.21347 1.213469 -0.1212261 1.21347 1.21347 0.1212258 1.486191 0.8580523 -0.1212261 1.486191 0.8580526 0.1212258 1.65763 0.4441605 -0.121226 1.65763 0.4441609 0.121226 1.716105 -1.4297e-7 -0.121226 1.716105 2.26106e-7 0.121226 1.65763 -0.4441608 -0.121226 1.65763 -0.4441605 0.121226 1.486191 -0.8580526 -0.1212258 1.486191 -0.8580523 0.1212261 1.21347 -1.213469 -0.1212258 1.21347 -1.213469 0.1212261 0.858053 -1.486191 -0.1212257 0.858053 -1.48619 0.1212261 0.4441614 -1.65763 -0.1212257 0.4441613 -1.65763 0.1212262 6.97226e-7 -1.716105 -0.1212257 6.94056e-7 -1.716105 0.1212262 -0.4441601 -1.657631 -0.1212257 -0.44416 -1.65763 0.1212262 -0.8580519 -1.486191 -0.1212257 -0.8580519 -1.486191 0.1212261 -1.213469 -1.213471 -0.1212258 -1.213469 -1.21347 0.1212261 -1.48619 -0.8580533 -0.1212258 -1.48619 -0.858053 0.1212261 -1.65763 -0.4441617 -0.121226 -1.65763 -0.4441613 0.121226 -1.716105 -1.05017e-6 -0.121226 -1.716105 -6.81092e-7 0.121226 -1.65763 0.4441595 -0.121226 -1.65763 0.4441598 0.121226 -1.486191 0.8580515 -0.1212261 -1.486191 0.8580518 0.1212258 -1.21347 1.213469 -0.1212261 -1.21347 1.213469 0.1212258 -0.8580536 1.48619 -0.1212261 -0.8580536 1.48619 0.1212257 -0.444162 1.65763 -0.1212262 -0.4441621 1.65763 0.1212257 0.2021923 2.977016 -0.1825115 0.5752056 2.927908 -0.1825114 0.5752056 2.927908 0.1825106 0.2021923 2.977016 0.1825106 1.663612 2.477075 0.1825107 1.663612 2.477075 -0.1825113 1.962096 2.24804 -0.1825113 1.962096 2.24804 0.1825107 2.679268 1.313404 0.1825109 2.679268 1.313404 -0.1825112 2.823245 0.965811 -0.1825112 2.823245 0.9658113 0.1825109 2.977016 -0.2021918 0.182511 2.977016 -0.2021921 -0.182511 2.927908 -0.5752054 -0.182511 2.927908 -0.5752052 0.1825111 2.477076 -1.663611 0.1825113 2.477076 -1.663611 -0.1825108 2.24804 -1.962096 -0.1825108 2.24804 -1.962096 0.1825113 1.313405 -2.679267 0.1825114 1.313405 -2.679267 -0.1825106 0.9658122 -2.823245 -0.1825107 0.9658122 -2.823245 0.1825114 -0.2021911 -2.977015 0.1825115 -0.2021911 -2.977016 -0.1825106 -0.5752044 -2.927908 -0.1825106 -0.5752044 -2.927908 0.1825114 -1.66361 -2.477076 0.1825113 -1.66361 -2.477076 -0.1825107 -1.962095 -2.248041 -0.1825107 -1.962095 -2.24804 0.1825113 -2.679267 -1.313405 0.1825112 -2.679267 -1.313405 -0.1825109 -2.823245 -0.9658125 -0.1825109 -2.823245 -0.9658122 0.1825112 -2.977016 0.202191 0.182511 -2.977016 0.2021908 -0.182511 -2.927908 0.575204 -0.1825111 -2.927908 0.5752043 0.182511 -2.477076 1.66361 0.1825108 -2.477076 1.66361 -0.1825113 -2.248041 1.962095 -0.1825113 -2.248041 1.962095 0.1825108 -1.313406 2.679267 0.1825106 -1.313406 2.679267 -0.1825114 -0.9658132 2.823245 -0.1825114 -0.9658132 2.823245 0.1825107 0 2.161408 -0.3803721 0.5594135 2.087759 -0.3803721 0.5594135 2.08776 0.3803715 0 2.161408 0.3803715 1.080704 1.871834 -0.380372 1.080704 1.871834 0.3803715 1.528346 1.528346 -0.3803719 1.528346 1.528346 0.3803716 1.871834 1.080703 -0.380372 1.871834 1.080704 0.3803716 2.087759 0.5594132 -0.3803719 2.087759 0.5594137 0.3803718 2.161408 -1.38025e-7 -0.3803718 2.161408 3.28751e-7 0.3803718 2.087759 -0.5594136 -0.3803718 2.087759 -0.5594131 0.3803719 1.871834 -1.080704 -0.3803716 1.871834 -1.080703 0.380372 1.528346 -1.528346 -0.3803716 1.528346 -1.528345 0.3803719 1.080704 -1.871834 -0.3803715 1.080704 -1.871833 0.380372 0.5594142 -2.087759 -0.3803715 0.5594142 -2.087759 0.3803721 8.54689e-7 -2.161408 -0.3803715 8.54689e-7 -2.161407 0.3803721 -0.5594125 -2.08776 -0.3803715 -0.5594125 -2.087759 0.3803721 -1.080703 -1.871835 -0.3803715 -1.080703 -1.871834 0.380372 -1.528345 -1.528347 -0.3803716 -1.528345 -1.528347 0.3803719 -1.871834 -1.080705 -0.3803716 -1.871834 -1.080704 0.380372 -2.087759 -0.5594147 -0.3803718 -2.087759 -0.5594142 0.3803719 -2.161408 -1.30607e-6 -0.3803718 -2.161408 -8.39296e-7 0.3803718 -2.08776 0.559412 -0.3803719 -2.08776 0.5594125 0.3803718 -1.871834 1.080702 -0.380372 -1.871834 1.080703 0.3803716 -1.528347 1.528345 -0.3803719 -1.528347 1.528345 0.3803716 -1.080705 1.871833 -0.380372 -1.080705 1.871834 0.3803715 -0.559415 2.087759 -0.3803721 -0.559415 2.087759 0.3803715 0 1.727341 -0.380372 0.4470689 1.668483 -0.380372 0.4470689 1.668484 0.3803715 0 1.727342 0.3803715 0.8636707 1.495921 -0.380372 0.8636708 1.495922 0.3803715 1.221415 1.221415 -0.3803719 1.221415 1.221415 0.3803716 1.495922 0.8636704 -0.3803719 1.495922 0.8636708 0.3803716 1.668484 0.4470686 -0.3803719 1.668484 0.4470691 0.3803717 1.727342 -1.90216e-7 -0.3803718 1.727342 2.7656e-7 0.3803718 1.668484 -0.4470691 -0.3803718 1.668484 -0.4470686 0.3803719 1.495922 -0.8636708 -0.3803716 1.495922 -0.8636703 0.3803719 1.221415 -1.221415 -0.3803716 1.221415 -1.221414 0.3803719 0.8636711 -1.495922 -0.3803715 0.8636711 -1.495921 0.380372 0.4470695 -1.668484 -0.3803715 0.4470695 -1.668483 0.380372 7.01378e-7 -1.727342 -0.3803715 6.98116e-7 -1.727341 0.380372 -0.4470682 -1.668484 -0.3803715 -0.4470682 -1.668484 0.380372 -0.8636701 -1.495922 -0.3803715 -0.8636701 -1.495922 0.380372 -1.221414 -1.221416 -0.3803716 -1.221414 -1.221415 0.3803719 -1.495921 -0.8636716 -0.3803716 -1.495921 -0.8636711 0.3803719 -1.668483 -0.4470699 -0.3803717 -1.668483 -0.4470694 0.3803719 -1.727342 -1.10383e-6 -0.3803718 -1.727342 -6.37055e-7 0.3803718 -1.668484 0.4470676 -0.3803719 -1.668484 0.447068 0.3803718 -1.495922 0.8636695 -0.3803719 -1.495922 0.8636701 0.3803716 -1.221416 1.221414 -0.3803719 -1.221416 1.221414 0.3803716 -0.8636718 1.495921 -0.380372 -0.8636718 1.495921 0.3803715 -0.4470702 1.668483 -0.380372 -0.4470703 1.668484 0.3803715 -0.4470703 1.668484 -4.333671 -0.4470702 1.668483 -5.094414 -0.8636718 1.495921 -4.333671 -0.8636718 1.495921 -5.094414 -1.221416 1.221414 -4.333671 -1.221416 1.221414 -5.094414 -1.495922 0.8636701 -4.333671 -1.495922 0.8636695 -5.094414 -1.668484 0.447068 -4.333671 -1.668484 0.4470676 -5.094414 -1.727342 -6.37055e-7 -4.333671 -1.727342 -1.10383e-6 -5.094414 -1.668483 -0.4470694 -4.33367 -1.668483 -0.4470699 -5.094414 -1.495921 -0.8636711 -4.33367 -1.495921 -0.8636716 -5.094414 -1.221414 -1.221415 -4.33367 -1.221414 -1.221416 -5.094414 -0.8636701 -1.495922 -4.33367 -0.8636701 -1.495922 -5.094414 -0.4470682 -1.668484 -4.33367 -0.4470682 -1.668484 -5.094414 6.98116e-7 -1.727341 -4.33367 7.01378e-7 -1.727342 -5.094414 0.4470695 -1.668483 -4.33367 0.4470695 -1.668484 -5.094414 0.8636711 -1.495921 -4.33367 0.8636711 -1.495922 -5.094414 1.221415 -1.221414 -4.33367 1.221415 -1.221415 -5.094414 1.495922 -0.8636703 -4.33367 1.495922 -0.8636708 -5.094414 1.668484 -0.4470686 -4.33367 1.668484 -0.4470691 -5.094414 1.727342 2.7656e-7 -4.333671 1.727342 -1.90216e-7 -5.094414 1.668484 0.4470691 -4.333671 1.668484 0.4470686 -5.094414 1.495922 0.8636708 -4.333671 1.495922 0.8636704 -5.094414 1.221415 1.221415 -4.333671 1.221415 1.221415 -5.094414 0.8636708 1.495922 -4.333671 0.8636707 1.495921 -5.094414 0 1.727342 -4.333671 0.4470689 1.668484 -4.333671 0.4470689 1.668483 -5.094414 0 1.727341 -5.094414 -0.559415 2.087759 -4.333671 -0.559415 2.087759 -5.094414 -1.080705 1.871834 -4.333671 -1.080705 1.871833 -5.094414 -1.528347 1.528345 -4.333671 -1.528347 1.528345 -5.094414 -1.871834 1.080703 -4.333671 -1.871834 1.080702 -5.094414 -2.08776 0.5594125 -4.333671 -2.08776 0.559412 -5.094414 -2.161408 -8.39296e-7 -4.333671 -2.161408 -1.30607e-6 -5.094414 -2.087759 -0.5594142 -4.33367 -2.087759 -0.5594147 -5.094414 -1.871834 -1.080704 -4.33367 -1.871834 -1.080705 -5.094414 -1.528345 -1.528347 -4.33367 -1.528345 -1.528347 -5.094414 -1.080703 -1.871834 -4.33367 -1.080703 -1.871835 -5.094414 -0.5594125 -2.087759 -4.33367 -0.5594125 -2.08776 -5.094414 8.54689e-7 -2.161407 -4.33367 8.54689e-7 -2.161408 -5.094414 0.5594142 -2.087759 -4.33367 0.5594142 -2.087759 -5.094414 1.080704 -1.871833 -4.33367 1.080704 -1.871834 -5.094414 1.528346 -1.528345 -4.33367 1.528346 -1.528346 -5.094414 1.871834 -1.080703 -4.33367 1.871834 -1.080704 -5.094414 2.087759 -0.5594131 -4.33367 2.087759 -0.5594136 -5.094414 2.161408 3.28751e-7 -4.333671 2.161408 -1.38025e-7 -5.094414 2.087759 0.5594137 -4.333671 2.087759 0.5594132 -5.094414 1.871834 1.080704 -4.333671 1.871834 1.080703 -5.094414 1.528346 1.528346 -4.333671 1.528346 1.528346 -5.094414 1.080704 1.871834 -4.333671 1.080704 1.871834 -5.094414 0 2.161408 -4.333671 0.5594135 2.08776 -4.333671 0.5594135 2.087759 -5.094414 0 2.161408 -5.094414 -0.9658132 2.823245 -4.531531 -0.9658132 2.823245 -4.896553 -1.313406 2.679267 -4.896553 -1.313406 2.679267 -4.531531 -2.248041 1.962095 -4.531531 -2.248041 1.962095 -4.896553 -2.477076 1.66361 -4.896553 -2.477076 1.66361 -4.531531 -2.927908 0.5752043 -4.531531 -2.927908 0.575204 -4.896553 -2.977016 0.2021908 -4.896553 -2.977016 0.202191 -4.531531 -2.823245 -0.9658122 -4.531531 -2.823245 -0.9658125 -4.896553 -2.679267 -1.313405 -4.896553 -2.679267 -1.313405 -4.531531 -1.962095 -2.24804 -4.531531 -1.962095 -2.248041 -4.896553 -1.66361 -2.477076 -4.896553 -1.66361 -2.477076 -4.531531 -0.5752044 -2.927908 -4.531531 -0.5752044 -2.927908 -4.896553 -0.2021911 -2.977016 -4.896553 -0.2021911 -2.977015 -4.531531 0.9658122 -2.823245 -4.531531 0.9658122 -2.823245 -4.896553 1.313405 -2.679267 -4.896553 1.313405 -2.679267 -4.531531 2.24804 -1.962096 -4.531531 2.24804 -1.962096 -4.896553 2.477076 -1.663611 -4.896553 2.477076 -1.663611 -4.531531 2.927908 -0.5752052 -4.531531 2.927908 -0.5752054 -4.896553 2.977016 -0.2021921 -4.896553 2.977016 -0.2021918 -4.531531 2.823245 0.9658113 -4.531531 2.823245 0.965811 -4.896553 2.679268 1.313404 -4.896553 2.679268 1.313404 -4.531531 1.962096 2.24804 -4.531531 1.962096 2.24804 -4.896553 1.663612 2.477075 -4.896553 1.663612 2.477075 -4.531531 0.2021923 2.977016 -4.531531 0.5752056 2.927908 -4.531531 0.5752056 2.927908 -4.896553 0.2021923 2.977016 -4.896553 -0.4441621 1.65763 -4.592816 -0.444162 1.65763 -4.835268 -0.8580536 1.48619 -4.592816 -0.8580536 1.48619 -4.835268 -1.21347 1.213469 -4.592816 -1.21347 1.213469 -4.835268 -1.486191 0.8580518 -4.592816 -1.486191 0.8580515 -4.835268 -1.65763 0.4441598 -4.592816 -1.65763 0.4441595 -4.835268 -1.716105 -6.81092e-7 -4.592816 -1.716105 -1.05017e-6 -4.835268 -1.65763 -0.4441613 -4.592816 -1.65763 -0.4441617 -4.835268 -1.48619 -0.858053 -4.592816 -1.48619 -0.8580533 -4.835268 -1.213469 -1.21347 -4.592816 -1.213469 -1.213471 -4.835268 -0.8580519 -1.486191 -4.592816 -0.8580519 -1.486191 -4.835268 -0.44416 -1.65763 -4.592816 -0.4441601 -1.657631 -4.835268 6.94056e-7 -1.716105 -4.592816 6.97226e-7 -1.716105 -4.835268 0.4441613 -1.65763 -4.592816 0.4441614 -1.65763 -4.835268 0.858053 -1.48619 -4.592816 0.858053 -1.486191 -4.835268 1.21347 -1.213469 -4.592816 1.21347 -1.213469 -4.835268 1.486191 -0.8580523 -4.592816 1.486191 -0.8580526 -4.835268 1.65763 -0.4441605 -4.592816 1.65763 -0.4441608 -4.835268 1.716105 2.26105e-7 -4.592816 1.716105 -1.4297e-7 -4.835268 1.65763 0.4441609 -4.592816 1.65763 0.4441605 -4.835268 1.486191 0.8580526 -4.592816 1.486191 0.8580523 -4.835268 1.21347 1.21347 -4.592816 1.21347 1.213469 -4.835268 0.8580526 1.486191 -4.592816 0.8580526 1.486191 -4.835268 0.4441608 1.65763 -4.592816 0.4441608 1.65763 -4.835268 0 1.716105 -4.592816 0 1.716105 -4.835268 + + + + + + + + + + -0.01879328 -0.9998235 5.59449e-7 0.3826835 0.9238795 -5.55441e-7 -0.1829222 0.1403609 -0.9730561 0.7933536 0.6087613 -4.1658e-7 0.140361 0.1829219 -0.9730562 0.991445 0.1305257 0 0.2285959 -0.03009504 0.9730561 0.9238798 -0.382683 2.0829e-7 -0.6936928 -0.7202711 5.59449e-7 0.6087616 -0.7933534 5.5544e-7 -0.875269 -0.4836364 0 0.1305263 -0.9914448 5.55441e-7 -0.7202709 0.6936929 0 -0.3826826 -0.9238799 0 0.2285957 -0.03009516 -0.9730562 -0.7933528 -0.6087622 4.1658e-7 0.08823454 -0.2130171 0.9730562 -0.991445 -0.1305263 0 -0.8564761 0.516187 -3.72966e-7 -0.9238798 0.3826829 -2.0829e-7 0.24062 0.9706195 -7.28718e-7 -0.6087623 0.7933527 -5.55441e-7 0 1.46636e-7 1 0.08823466 -0.2130174 -0.9730561 -0.1305267 0.9914449 -1.11088e-6 0 0 -1 0.1305266 0.9914448 0 0.608762 0.7933529 0 0.9238802 0.382682 -2.17008e-7 0.991445 -0.1305258 0 0.7933524 -0.6087626 4.34015e-7 0.3826837 -0.9238795 0 -0.1305254 -0.991445 0 -0.6087611 -0.7933536 0 -0.9238792 -0.3826844 4.34015e-7 -0.9914448 0.1305267 0 -0.793354 0.6087607 -4.34016e-7 -0.3826838 0.9238794 -1.73606e-6 0.2769269 -0.960891 1.16595e-6 0.1403613 0.1829224 0.9730561 -0.1829223 0.140361 0.9730561 -0.2130172 -0.08823513 -0.9730562 0.8564752 -0.5161884 0 0.9706194 -0.2406198 3.8865e-7 0.5161871 0.856476 -1.5546e-6 -0.2130174 -0.0882343 0.9730561 -0.03009492 -0.2285959 -0.9730561 0.6936926 0.7202712 0 -0.4836364 0.8752691 -5.59449e-7 -0.0300951 -0.2285957 0.9730561 0.1829221 -0.1403613 -0.9730561 -0.2769267 0.9608911 -9.32415e-7 -0.9998234 0.0187931 0 -0.960891 -0.2769271 1.86483e-7 0.1829221 -0.1403613 0.9730561 0.2130174 0.08823454 -0.9730562 -0.08823478 0.2130174 -0.9730561 0.03009521 0.2285956 -0.9730562 -0.5161871 -0.8564759 3.72966e-7 -0.2406198 -0.9706196 6.2938e-7 0.2130172 0.08823478 0.9730561 -0.08823442 0.2130174 0.9730561 0.0300951 0.2285959 0.9730562 -0.2285959 0.03009504 -0.9730561 0.4836364 -0.8752691 3.8865e-7 0.7202711 -0.6936927 0 0.875269 0.4836366 0 -0.9706194 0.2406201 0 -0.2285957 0.03009527 0.9730561 -0.1403611 -0.1829223 -0.9730562 0.9998234 -0.01879364 0 0.960891 0.2769271 0 0.01879322 0.9998234 -6.52691e-7 -0.140361 -0.182922 0.9730562 1.53575e-7 -1.5457e-7 -1 0 1.37317e-7 1 0 0 -1 0 2.19515e-7 1 1.53575e-7 -1.49214e-7 -1 -3.07149e-7 1.21602e-7 1 -1.22733e-7 0 -1 0 1.36431e-7 1 0 -2.05836e-7 -1 -1.22733e-7 2.11049e-7 1 1.22733e-7 -2.13097e-7 -1 0 0 1 0 0 -1 0 2.13097e-7 1 -1.22733e-7 -2.11049e-7 -1 0 1.93171e-7 1 -2.30362e-7 -1.36431e-7 -1 -2.45466e-7 0 1 -1.22733e-7 0 -1 0 1.49214e-7 1 1.53575e-7 -1.91938e-7 -1 0 0 1 0 -1.37317e-7 -1 0 1.37317e-7 1 0 -2.05976e-7 -1 -1.53575e-7 0 1 0 0 -1 0 1.41747e-7 1 -1.22733e-7 -1.30282e-7 -1 1.53575e-7 1.21602e-7 1 -1.22733e-7 -1.34431e-7 -1 2.45466e-7 0 1 1.53575e-7 0 -1 -1.22733e-7 2.11049e-7 1 1.22733e-7 0 -1 -3.07149e-7 2.57561e-7 1 1.53575e-7 -2.57561e-7 -1 0 0 1 -1.22733e-7 -2.11049e-7 -1 0 1.9317e-7 1 2.45466e-7 0 -1 0 1.57619e-7 1 1.53575e-7 -1.21602e-7 -1 0 1.49214e-7 1 0 -1.41747e-7 -1 0 0 1 0 0 -1 0 2.05975e-7 1 -0.1304058 -0.9905301 -0.04294776 -0.1304053 -0.9905301 0.04295009 -0.3823302 -0.9230272 -0.042948 -0.3823306 -0.923027 0.04294902 -0.6082 -0.7926213 -0.04294753 -0.6081995 -0.7926214 0.04294854 -0.7926219 -0.6081991 -0.04294753 -0.7926216 -0.6081996 0.04294747 -0.9230272 -0.3823302 -0.04294818 -0.9230273 -0.3823298 0.0429483 -0.9905301 -0.1304059 -0.04294842 -0.9905302 -0.1304052 0.0429483 -0.9905301 0.1304061 -0.0429483 -0.9905301 0.1304053 0.04294836 -0.923027 0.3823306 -0.04294806 -0.923027 0.3823307 0.04294812 -0.7926213 0.6081997 -0.04294806 -0.7926222 0.6081987 0.04294759 -0.6081999 0.7926212 -0.042948 -0.6081998 0.7926213 0.04294759 -0.3823305 0.923027 -0.04294806 -0.3823304 0.923027 0.04294806 -0.1304058 0.99053 -0.04294925 -0.1304063 0.9905301 0.04294794 0.1304051 0.9905302 -0.04294872 0.1304053 0.9905302 0.042948 0.38233 0.9230272 -0.0429486 0.38233 0.9230273 0.04294753 0.6081991 0.7926217 -0.0429489 0.608199 0.7926219 0.04294812 0.7926213 0.6082 -0.04294866 0.7926207 0.6082006 0.04294776 0.9230269 0.3823311 -0.04294788 0.9230268 0.3823311 0.04294776 0.99053 0.1304064 -0.04294842 0.9905299 0.1304069 0.04294776 0.9905301 -0.1304064 -0.04294824 0.9905301 -0.1304054 0.04294842 0.9230271 -0.3823303 -0.04294812 0.9230275 -0.3823295 0.04294818 0.7926216 -0.6081995 -0.04294759 0.7926223 -0.6081985 0.04294872 0.6082003 -0.792621 -0.04294705 0.6082004 -0.7926208 0.04294806 0.3823308 -0.9230269 -0.04294836 0.3823305 -0.923027 0.04294872 0.1304059 -0.9905301 -0.04294806 0.1304057 -0.9905301 0.04294878 0.1304057 -0.99053 0.04294884 0.1304063 -0.99053 -0.04294806 0.3823306 -0.923027 0.04294872 0.3823307 -0.9230269 -0.04294836 0.6082006 -0.7926207 0.04294806 0.6082007 -0.7926207 -0.04294705 0.7926217 -0.6081992 0.04294872 0.7926223 -0.6081987 -0.04294764 0.9230274 -0.3823298 0.04294818 0.9230276 -0.3823291 -0.04294812 0.9905303 -0.1304045 0.04294836 0.99053 -0.1304064 -0.0429483 0.9905299 0.1304072 0.04294782 0.99053 0.1304064 -0.0429486 0.9230267 0.3823315 0.04294788 0.9230272 0.3823303 -0.04294782 0.7926213 0.6082 0.04294776 0.7926208 0.6082003 -0.04294866 0.6081993 0.7926218 0.04294812 0.6081989 0.792622 -0.04294896 0.3823297 0.9230274 0.04294753 0.3823306 0.923027 -0.0429486 0.1304053 0.9905302 0.042948 0.1304049 0.9905302 -0.04294878 -0.1304061 0.99053 0.042948 -0.1304054 0.9905301 -0.04294931 -0.3823313 0.9230267 0.042948 -0.3823297 0.9230274 -0.04294806 -0.6081994 0.7926216 0.04294806 -0.6081993 0.7926217 -0.042948 -0.792622 0.6081991 0.04294753 -0.7926219 0.6081991 -0.04294806 -0.9230272 0.3823301 0.04294806 -0.9230273 0.38233 -0.042948 -0.9905303 0.1304044 0.04294824 -0.9905301 0.1304059 -0.04294824 -0.9905301 -0.1304056 0.0429483 -0.9905301 -0.1304054 -0.04294842 -0.9230272 -0.3823303 0.04294836 -0.9230271 -0.3823304 -0.04294806 -0.7926214 -0.6081998 0.04294753 -0.7926222 -0.6081988 -0.04294747 -0.6081997 -0.7926214 0.04294854 -0.6081992 -0.7926218 -0.04294753 -0.3823313 -0.9230268 0.04294902 -0.3823304 -0.9230272 -0.04294806 -0.1304056 -0.9905301 0.042948 -0.1304057 -0.9905301 -0.04294776 -4.9093e-7 0 1 -9.81861e-7 0 -1 9.81864e-7 0 1 0 0 -1 1.2286e-6 0 1 -9.21448e-7 0 1 1.96373e-6 0 -1 1.96373e-6 0 1 6.14299e-7 -1.03024e-6 -1 1.53575e-6 1.03024e-6 1 -1.8429e-6 0 -1 1.2286e-6 0 1 9.81864e-7 0 -1 4.90932e-7 0 1 -7.36399e-7 0 -1 4.90932e-7 0 1 -2.4572e-6 0 -1 -1.2286e-6 0 -1 -9.21449e-7 0 1 0 8.52388e-7 1 1.2286e-6 0 -1 -1.2286e-6 0 1 0 -8.52388e-7 -1 -1.2286e-6 0 -1 -0.1403611 -0.182922 0.9730562 0.01879322 0.9998234 -6.52691e-7 0.9608911 0.2769268 0 0.9998234 -0.01879352 0 -0.1403591 -0.1829223 -0.9730564 -0.228595 0.03009504 0.9730563 -0.9706194 0.2406204 0 0.8752692 0.4836361 0 0.7202715 -0.6936922 0 0.4836365 -0.8752691 3.8865e-7 -0.2285958 0.0300942 -0.9730562 0.03009432 0.2285957 0.9730562 -0.08823329 0.2130173 0.9730563 0.2130165 0.0882346 0.9730563 -0.2406201 -0.9706194 6.29381e-7 -0.5161867 -0.8564761 3.72966e-7 0.03009527 0.2285957 -0.9730562 -0.0882337 0.2130175 -0.9730562 0.2130171 0.08823478 -0.9730562 0.1829222 -0.1403613 0.9730561 -0.960891 -0.2769271 1.86483e-7 -0.9998234 0.01879316 0 -0.2769262 0.9608913 -9.32415e-7 0.1829237 -0.140361 -0.973056 -0.03009533 -0.2285959 0.9730561 -0.483636 0.8752692 -5.59449e-7 0.6936928 0.720271 0 -0.0300939 -0.2285958 -0.9730563 -0.2130177 -0.08823454 0.9730561 0.516188 0.8564753 -1.5546e-6 0.9706196 -0.2406192 3.88649e-7 0.8564758 -0.5161873 0 -0.2130172 -0.08823472 -0.9730563 -0.1829218 0.1403609 0.9730563 0.1403613 0.1829223 0.9730561 0.2769266 -0.9608911 1.16595e-6 -0.3826829 0.9238798 -1.73606e-6 -0.7933541 0.6087604 -4.34015e-7 -0.9914447 0.1305279 0 -0.9238793 -0.3826841 4.34015e-7 -0.608762 -0.793353 0 -0.1305256 -0.991445 0 0.3826844 -0.9238792 0 0.7933535 -0.6087613 4.34015e-7 0.991445 -0.1305255 0 0.9238792 0.3826845 -2.17008e-7 0.6087608 0.7933539 0 0.1305264 0.9914448 0 -1.86961e-7 -3.09913e-7 -1 -0.1305266 0.9914448 -1.11088e-6 0.08823472 -0.2130173 -0.9730561 -3.73923e-7 0 1 -0.6087617 0.7933532 -5.5544e-7 0.2406198 0.9706196 -7.28719e-7 -0.9238798 0.382683 -2.0829e-7 -0.8564758 0.5161873 -3.72966e-7 -0.9914449 -0.1305261 0 0.08823502 -0.2130172 0.9730561 -0.7933532 -0.6087617 4.1658e-7 0.228596 -0.03009539 -0.9730561 -0.3826834 -0.9238796 0 0.1305264 -0.9914449 5.5544e-7 -0.8752689 -0.4836367 0 0.608762 -0.793353 5.5544e-7 -0.6936929 -0.720271 5.59449e-7 0.9238799 -0.3826828 2.0829e-7 0.228595 -0.03009402 0.9730564 0.9914449 0.130526 0 0.1403608 0.182922 -0.9730562 0.7933534 0.6087614 -4.1658e-7 -0.1829222 0.1403611 -0.9730561 0.3826833 0.9238796 -5.5544e-7 -0.01879328 -0.9998234 5.59449e-7 -0.01879328 -0.9998235 7.77299e-7 0.3826834 0.9238796 -5.5544e-7 -0.1829221 0.1403608 -0.9730563 0.7933528 0.6087622 -2.7772e-7 0.140361 0.1829218 -0.9730562 0.9914448 0.1305268 0 0.2285957 -0.03009492 0.9730563 0.9238798 -0.382683 2.7772e-7 -0.6936925 -0.7202714 3.8865e-7 0.608762 -0.793353 5.55441e-7 -0.8752691 -0.4836363 3.8865e-7 0.1305263 -0.9914449 5.5544e-7 -0.7202709 0.6936929 0 -0.382683 -0.9238798 5.55441e-7 0.2285959 -0.03009527 -0.9730561 -0.7933531 -0.6087617 2.7772e-7 0.08823484 -0.2130172 0.9730561 -0.9914448 -0.1305268 0 -0.8564757 0.5161874 0 -0.9238798 0.3826829 -2.7772e-7 0.2406199 0.9706194 -5.82759e-7 -0.6087619 0.7933531 -5.5544e-7 0 0 1 0 0 1 0 0 1 0 2.48521e-7 1 0 2.6039e-7 1 -7.17165e-7 -5.04991e-7 1 0 0 1 0 1.49144e-7 1 7.17168e-7 -5.04992e-7 1 -3.9138e-7 3.49168e-7 1 -2.02593e-7 0 1 -1.43433e-7 0 1 0 1.29623e-7 1 3.79863e-7 0 1 0 2.1901e-7 1 0 0 1 0 1.94599e-7 1 -1.9569e-7 1.5633e-7 1 0 1.4789e-7 1 0 0 1 0 1.4789e-7 1 0.08823472 -0.2130174 -0.9730561 -0.1305263 0.991445 0 0 -1.96436e-7 -1 -1.43433e-7 -4.83314e-7 -1 -5.73734e-7 -4.64944e-7 -1 1.14747e-6 0 -1 0 -2.87214e-7 -1 1.43434e-7 -4.32337e-7 -1 0 -2.5483e-7 -1 0 -4.32338e-7 -1 0 0 -1 -4.303e-7 0 -1 2.02593e-7 -3.1266e-7 -1 2.15151e-7 -4.83316e-7 -1 0 -1.42021e-7 -1 0 0 -1 0 -2.27338e-7 -1 0 -2.02617e-7 -1 1.9569e-7 0 -1 -2.44612e-7 2.46331e-7 -1 0 0 -1 0 -1.93568e-7 -1 0 -1.44275e-7 -1 0.1305265 0.9914448 0 0.6087612 0.7933536 0 0.9238795 0.3826835 -2.17008e-7 0.9914449 -0.1305266 0 0.7933536 -0.6087611 0 0.382683 -0.9238797 0 -0.1305252 -0.991445 0 -0.9238795 -0.3826836 2.17008e-7 -0.991445 0.1305258 0 -0.7933536 0.6087613 -4.34015e-7 -0.3826829 0.9238798 0 0.2769267 -0.9608911 7.45932e-7 0.140361 0.182922 0.9730563 -0.1829221 0.140361 0.9730562 -0.2130172 -0.08823466 -0.9730562 0.8564758 -0.5161873 1.86483e-7 0.9706195 -0.2406198 0 0.516187 0.856476 -3.72966e-7 -0.2130174 -0.08823472 0.9730561 -0.03009504 -0.2285959 -0.9730561 0.6936926 0.7202712 -3.72966e-7 -0.483636 0.8752692 -3.88649e-7 -0.03009492 -0.2285954 0.9730563 0.1829221 -0.1403615 -0.9730561 -0.2769263 0.9608912 -3.8865e-7 -0.9998235 0.01879322 0 -0.960891 -0.2769269 0 0.1829221 -0.140361 0.9730561 0.2130175 0.08823436 -0.9730561 -0.08823484 0.2130169 -0.9730563 0.03009516 0.2285953 -0.9730563 -0.5161873 -0.8564758 7.773e-7 -0.2406198 -0.9706194 6.80137e-7 0.2130174 0.0882349 0.9730561 -0.08823472 0.2130174 0.9730562 0.0300951 0.2285957 0.9730561 -0.2285957 0.0300948 -0.9730561 0.4836359 -0.8752694 5.59449e-7 0.7202714 -0.6936924 3.72966e-7 0.8752689 0.4836366 -3.72966e-7 -0.9706194 0.2406201 0 -0.2285959 0.0300951 0.9730562 -0.1403609 -0.1829223 -0.9730562 0.9998235 -0.01879346 0 0.960891 0.2769271 -1.86483e-7 0.0187931 0.9998234 -9.71624e-7 -0.1403609 -0.182922 0.9730562 0 0 -1 0 2.05975e-7 1 0 -1.27959e-7 -1 1.53575e-7 0 1 0 0 -1 1.22733e-7 1.30282e-7 1 -3.07149e-7 0 -1 0 1.34431e-7 1 1.53575e-7 -1.99693e-7 -1 0 0 1 0 -2.57561e-7 -1 1.22733e-7 0 1 0 2.57561e-7 1 0 -1.93171e-7 -1 1.22733e-7 2.11049e-7 1 0 -1.34431e-7 -1 0 0 1 0 -1.49214e-7 -1 0 0 1 0 0 -1 0 1.41747e-7 1 0 -2.05975e-7 -1 1.53575e-7 0 1 0 -1.37317e-7 -1 0 1.37317e-7 1 -1.53575e-7 -1.91939e-7 -1 0 0 1 3.0715e-7 -1.21602e-7 -1 -1.22733e-7 1.30282e-7 1 0 -1.36431e-7 -1 1.53575e-7 0 1 0 -2.11049e-7 -1 0 1.93171e-7 1 -1.53575e-7 0 -1 1.22733e-7 2.13097e-7 1 -1.22733e-7 -2.13097e-7 -1 0 0 1 0 -1.93171e-7 -1 1.22733e-7 2.11049e-7 1 1.53575e-7 0 -1 0 0 1 -1.22733e-7 -1.30282e-7 -1 1.22733e-7 0 1 0 0 -1 -1.53575e-7 1.91938e-7 1 -1.53574e-7 -1.5457e-7 -1 0 1.37317e-7 1 -0.1304059 -0.9905301 -0.042948 -0.1304053 -0.9905301 0.042948 -0.3823303 -0.9230271 -0.04294854 -0.3823304 -0.9230271 0.04294764 -0.6081998 -0.7926214 -0.04294705 -0.6081994 -0.7926216 0.04294747 -0.792621 -0.6082004 -0.04294764 -0.7926214 -0.6081995 0.04294878 -0.923027 -0.3823306 -0.04294788 -0.9230268 -0.3823311 0.04294836 -0.9905301 -0.1304059 -0.04294824 -0.9905301 -0.1304059 0.04294842 -0.9905301 0.1304053 -0.04294842 -0.9905301 0.1304059 0.04294824 -0.9230272 0.3823302 -0.04294836 -0.923027 0.3823305 0.04294788 -0.7926219 0.6081991 -0.04294782 -0.7926211 0.6082 0.04294764 -0.6081999 0.7926213 -0.042948 -0.6081998 0.7926213 0.042948 -0.3823305 0.923027 -0.04294919 -0.3823305 0.923027 0.04294836 -0.1304062 0.9905301 -0.042948 -0.1304062 0.9905301 0.042948 0.1304051 0.9905301 -0.04294902 0.130405 0.9905301 0.042948 0.3823301 0.9230273 -0.042948 0.3823301 0.9230272 0.042948 0.6081991 0.7926217 -0.04294806 0.6081992 0.7926219 0.04294753 0.7926213 0.6081999 -0.042948 0.7926218 0.6081994 0.04294699 0.9230272 0.3823303 -0.04294818 0.9230272 0.3823301 0.0429477 0.9905301 0.1304062 -0.04294782 0.99053 0.1304063 0.04294836 0.9905301 -0.130405 -0.04294836 0.99053 -0.1304061 0.04294824 0.9230276 -0.3823292 -0.0429483 0.9230275 -0.3823294 0.04294866 0.7926223 -0.6081985 -0.042948 0.7926216 -0.6081994 0.042948 0.6082006 -0.7926207 -0.04294753 0.6082006 -0.7926207 0.04294806 0.3823308 -0.923027 -0.04294699 0.3823308 -0.923027 0.04294705 0.1304059 -0.99053 -0.04294788 0.1304057 -0.99053 0.0429489 0.1304056 -0.9905301 0.0429489 0.1304056 -0.9905301 -0.04294788 0.3823315 -0.9230266 0.04294705 0.3823305 -0.9230271 -0.04294705 0.6081998 -0.7926213 0.04294806 0.6082012 -0.7926202 -0.04294753 0.7926216 -0.6081994 0.04294806 0.7926216 -0.6081994 -0.04294806 0.9230276 -0.3823291 0.04294866 0.9230277 -0.382329 -0.04294806 0.9905303 -0.1304045 -0.04294824 0.9905301 0.130406 0.04294842 0.9905301 0.1304064 -0.04294776 0.9230275 0.3823294 0.04294747 0.9230273 0.38233 -0.04294812 0.7926219 0.6081991 0.04294693 0.7926208 0.6082004 -0.042948 0.6081997 0.7926214 0.04294753 0.6081994 0.7926216 -0.04294806 0.3823303 0.9230271 0.042948 0.3823294 0.9230275 -0.04294806 0.1304051 0.9905302 0.042948 0.130405 0.9905301 -0.04294902 -0.1304063 0.99053 0.04294824 -0.1304066 0.99053 -0.042948 -0.3823299 0.9230273 0.04294836 -0.3823307 0.9230269 -0.04294919 -0.6081997 0.7926213 0.04294753 -0.6082 0.7926213 -0.042948 -0.7926222 0.6081987 0.04294764 -0.7926213 0.6081998 -0.04294788 -0.923027 0.3823308 0.04294794 -0.9230273 0.3823299 -0.04294836 -0.99053 0.1304062 0.04294824 -0.9905302 0.1304049 -0.04294848 -0.9905301 -0.1304057 0.04294854 -0.9905301 -0.130406 -0.04294836 -0.923027 -0.3823307 0.04294836 -0.9230275 -0.3823296 -0.04294788 -0.7926213 -0.6082 0.04294884 -0.792621 -0.6082003 -0.04294776 -0.6081987 -0.7926223 0.04294747 -0.6082006 -0.7926208 -0.04294705 -0.3823304 -0.9230271 0.04294764 -0.3823305 -0.923027 -0.04294854 -0.1304049 -0.9905301 0.04294997 -0.1304056 -0.9905301 -0.042948 -1.2286e-6 0 1 -9.81863e-7 0 1 -9.81864e-7 0 1 -6.14299e-7 0 -1 -2.76435e-6 0 1 0 -8.52388e-7 -1 -1.96373e-6 8.52388e-7 1 9.21448e-7 0 1 2.45466e-7 0 1 2.4572e-6 0 -1 -1.2286e-6 0 1 4.90932e-7 0 -1 4.90931e-7 0 1 1.2286e-6 0 -1 2.15005e-6 1.03024e-6 1 -1.96373e-6 0 -1 6.14299e-7 -1.03024e-6 -1 2.4572e-6 0 -1 -9.81863e-7 0 1 1.2286e-6 0 1 -9.81864e-7 0 1 1.22733e-6 0 -1 -0.1403608 -0.1829221 0.9730562 0.01879304 0.9998234 -9.71624e-7 0.960891 0.2769274 -1.86483e-7 0.9998234 -0.01879346 0 -0.1403608 -0.1829221 -0.9730562 -0.228596 0.03009521 0.9730561 -0.9706196 0.2406197 0 0.8752686 0.4836372 -3.72966e-7 0.7202708 -0.693693 3.72966e-7 0.4836356 -0.8752695 5.59449e-7 -0.2285957 0.03009402 -0.9730563 0.03009527 0.2285957 0.9730561 -0.08823466 0.2130174 0.9730562 0.2130175 0.08823478 0.9730561 -0.2406199 -0.9706194 6.80138e-7 -0.5161879 -0.8564754 7.77299e-7 0.03009402 0.2285954 -0.9730563 -0.08823359 0.2130171 -0.9730563 0.213018 0.08823454 -0.9730561 0.1829218 -0.140361 0.9730563 -0.9608913 -0.2769262 0 -0.9998234 0.01879316 0 -0.2769265 0.9608912 -3.8865e-7 0.1829214 -0.1403613 -0.9730563 -0.03009498 -0.2285956 0.9730563 -0.483637 0.8752687 -3.88649e-7 0.6936924 0.7202715 -3.72966e-7 -0.03009533 -0.2285958 -0.9730562 -0.2130172 -0.08823478 0.9730561 0.5161867 0.8564761 -3.72966e-7 0.9706194 -0.24062 0 0.856476 -0.5161871 1.86483e-7 -0.2130171 -0.08823454 -0.9730562 -0.182922 0.1403609 0.9730562 0.1403608 0.182922 0.9730563 0.2769268 -0.960891 7.45932e-7 -0.3826837 0.9238795 0 -0.793354 0.6087606 -4.34015e-7 -0.991445 0.1305255 0 -0.9238793 -0.3826841 2.17008e-7 -0.6087609 -0.7933537 0 -0.1305252 -0.991445 0 0.3826828 -0.9238799 0 0.7933524 -0.6087627 0 0.9914448 -0.1305275 0 0.9238802 0.3826821 -2.17007e-7 0.608762 0.793353 0 0.1305267 0.9914449 0 -1.83595e-5 -2.50351e-6 -1 -2.29494e-6 0 -1 -3.24149e-6 0 -1 1.62075e-6 -1.68886e-6 -1 -4.58988e-6 0 -1 2.41707e-6 0 -1 3.13104e-6 0 -1 0 -3.09913e-7 -1 -2.55394e-7 0 -1 -0.1305263 0.9914449 0 0.08823549 -0.2130174 -0.9730561 -1.14746e-6 0 1 4.58986e-6 0 1 4.58988e-6 -5.36789e-7 1 1.14747e-6 0 1 -7.82759e-7 0 1 -6.26208e-6 1.96673e-6 1 -3.24149e-6 0 1 -4.58986e-6 0 1 -1.62075e-6 0 1 2.55394e-7 5.98705e-7 1 1.62075e-6 0 1 3.13104e-6 0 1 3.73922e-7 1.60423e-7 1 0 0 1 0 1.60423e-7 1 -0.6087622 0.7933529 -5.5544e-7 0.2406199 0.9706194 -5.8276e-7 -0.92388 0.3826824 -2.7772e-7 -0.8564761 0.5161868 0 -0.9914448 -0.1305271 0 0.08823472 -0.2130173 0.9730561 -0.793353 -0.608762 2.7772e-7 0.2285964 -0.03009498 -0.9730561 -0.3826826 -0.9238799 5.55441e-7 -0.7202714 0.6936925 0 0.1305261 -0.991445 5.5544e-7 -0.8752695 -0.4836356 3.88649e-7 0.6087616 -0.7933533 5.5544e-7 -0.6936932 -0.7202706 3.88649e-7 0.9238796 -0.3826833 2.77721e-7 0.2285954 -0.03009444 0.9730563 0.9914448 0.1305269 0 0.1403619 0.182922 -0.9730561 0.7933532 0.6087616 -2.7772e-7 -0.1829216 0.1403608 -0.9730563 0.3826837 0.9238795 -5.5544e-7 -0.01879334 -0.9998235 7.77299e-7 + + + + + + + + + + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + + + + + + + + + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + + + + + + + + + + + + + + + + + 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 +

110 0 0 0 63 0 1 1 111 0 2 2 97 1 3 3 101 1 4 4 100 1 5 5 138 2 6 6 89 2 7 7 90 2 8 8 102 3 9 9 105 3 10 10 104 3 11 11 100 4 12 12 54 4 13 13 102 4 14 14 106 5 15 15 109 5 16 16 108 5 17 17 109 6 18 18 63 6 19 19 60 6 20 20 110 7 21 21 113 7 22 22 112 7 23 23 137 8 24 24 89 8 25 25 136 8 26 26 114 9 27 27 117 9 28 28 116 9 29 29 118 10 30 30 71 10 31 31 119 10 32 32 118 11 33 33 121 11 34 34 120 11 35 35 101 12 36 36 53 12 37 37 100 12 38 38 123 13 39 39 124 13 40 40 122 13 41 41 108 14 42 42 62 14 43 43 110 14 44 44 127 15 45 45 128 15 46 46 126 15 47 47 117 16 48 48 71 16 49 49 68 16 50 50 131 17 51 51 132 17 52 52 130 17 53 53 126 18 54 54 79 18 55 55 127 18 56 56 135 19 57 57 136 19 58 58 134 19 59 59 108 20 60 60 60 20 61 61 61 20 62 62 139 21 63 63 140 21 64 64 138 21 65 65 37 22 66 66 21 22 67 67 45 22 68 68 116 23 69 69 70 23 70 70 118 23 71 71 143 24 72 72 96 24 73 73 142 24 74 74 14 25 75 75 38 25 76 76 46 25 77 77 51 26 78 78 49 26 79 79 48 26 80 80 52 27 81 81 54 27 82 82 53 27 83 83 57 28 84 84 59 28 85 85 58 28 86 86 61 29 87 87 63 29 88 88 62 29 89 89 65 30 90 90 67 30 91 91 66 30 92 92 69 31 93 93 71 31 94 94 70 31 95 95 72 32 96 96 74 32 97 97 73 32 98 98 76 33 99 99 78 33 100 100 77 33 101 101 80 34 102 102 82 34 103 103 81 34 104 104 84 35 105 105 86 35 106 106 85 35 107 107 88 36 108 108 90 36 109 109 89 36 110 110 92 37 111 111 94 37 112 112 93 37 113 113 128 38 114 114 80 38 115 115 81 38 116 116 101 39 117 117 55 39 118 118 52 39 119 119 139 40 120 120 88 40 121 121 137 40 122 122 130 41 123 123 81 41 124 124 82 41 125 125 103 42 126 126 54 42 127 127 55 42 128 128 120 43 129 129 72 43 130 130 73 43 131 131 139 44 132 132 90 44 133 133 91 44 134 134 131 45 135 135 80 45 136 136 129 45 137 137 122 46 138 138 73 46 139 139 74 46 140 140 112 47 141 141 64 47 142 142 65 47 143 143 130 48 144 144 83 48 145 145 131 48 146 146 123 49 147 147 72 49 148 148 121 49 149 149 112 50 150 150 66 50 151 151 114 50 152 152 105 51 153 153 57 51 154 154 104 51 155 155 122 52 156 156 75 52 157 157 123 52 158 158 141 53 159 159 93 53 160 160 140 53 161 161 113 54 162 162 67 54 163 163 64 54 164 164 104 55 165 165 58 55 166 166 106 55 167 167 142 56 168 168 93 56 169 169 94 56 170 170 96 57 171 171 49 57 172 172 97 57 173 173 114 58 174 174 67 58 175 175 115 58 176 176 133 59 177 177 85 59 178 178 132 59 179 179 105 60 180 180 59 60 181 181 56 60 182 182 141 61 183 183 95 61 184 184 92 61 185 185 98 62 186 186 51 62 187 187 99 62 188 188 134 63 189 189 85 63 190 190 86 63 191 191 107 64 192 192 58 64 193 193 59 64 194 194 124 65 195 195 76 65 196 196 77 65 197 197 143 66 198 198 94 66 199 199 95 66 200 200 96 67 201 201 51 67 202 202 48 67 203 203 133 68 204 204 87 68 205 205 84 68 206 206 126 69 207 207 77 69 208 208 78 69 209 209 98 70 210 210 49 70 211 211 50 70 212 212 116 71 213 213 68 71 214 214 69 71 215 215 134 72 216 216 87 72 217 217 135 72 218 218 125 73 219 219 79 73 220 220 76 73 221 221 144 74 222 222 97 74 223 223 145 74 224 224 146 75 225 225 99 75 226 226 147 75 227 227 148 76 228 228 97 76 229 229 100 76 230 230 146 77 231 231 101 77 232 232 98 77 233 233 148 78 234 234 102 78 235 235 150 78 236 236 151 79 237 237 101 79 238 238 149 79 239 239 152 80 240 240 102 80 241 241 104 80 242 242 153 81 243 243 103 81 244 244 151 81 245 245 154 82 246 246 104 82 247 247 106 82 248 248 153 83 249 249 107 83 250 250 105 83 251 251 156 84 252 252 106 84 253 253 108 84 254 254 157 85 255 255 107 85 256 256 155 85 257 257 156 86 258 258 110 86 259 259 158 86 260 260 157 87 261 261 111 87 262 262 109 87 263 263 160 88 264 264 110 88 265 265 112 88 266 266 161 89 267 267 111 89 268 268 159 89 269 269 160 90 270 270 114 90 271 271 162 90 272 272 161 91 273 273 115 91 274 274 113 91 275 275 164 92 276 276 114 92 277 277 116 92 278 278 165 93 279 279 115 93 280 280 163 93 281 281 164 94 282 282 118 94 283 283 166 94 284 284 167 95 285 285 117 95 286 286 165 95 287 287 166 96 288 288 120 96 289 289 168 96 290 290 167 97 291 291 121 97 292 292 119 97 293 293 170 98 294 294 120 98 295 295 122 98 296 296 171 99 297 297 121 99 298 298 169 99 299 299 172 100 300 300 122 100 301 301 124 100 302 302 171 101 303 303 125 101 304 304 123 101 305 305 174 102 306 306 124 102 307 307 126 102 308 308 175 103 309 309 125 103 310 310 173 103 311 311 176 104 312 312 126 104 313 313 128 104 314 314 175 105 315 315 129 105 316 316 127 105 317 317 176 106 318 318 130 106 319 319 178 106 320 320 177 107 321 321 131 107 322 322 129 107 323 323 180 108 324 324 130 108 325 325 132 108 326 326 181 109 327 327 131 109 328 328 179 109 329 329 180 110 330 330 134 110 331 331 182 110 332 332 181 111 333 333 135 111 334 334 133 111 335 335 184 112 336 336 134 112 337 337 136 112 338 338 185 113 339 339 135 113 340 340 183 113 341 341 186 114 342 342 136 114 343 343 138 114 344 344 187 115 345 345 137 115 346 346 185 115 347 347 186 116 348 348 140 116 349 349 188 116 350 350 189 117 351 351 139 117 352 352 187 117 353 353 190 118 354 354 140 118 355 355 142 118 356 356 189 119 357 357 143 119 358 358 141 119 359 359 144 120 360 360 142 120 361 361 96 120 362 362 191 121 363 363 99 121 364 364 143 121 365 365 0 122 366 366 145 122 367 367 2 122 368 368 3 123 369 369 147 123 370 370 1 123 371 371 4 124 372 372 145 124 373 373 148 124 374 374 3 125 375 375 149 125 376 376 146 125 377 377 6 126 378 378 148 126 379 379 150 126 380 380 5 127 381 381 151 127 382 382 149 127 383 383 8 128 384 384 150 128 385 385 152 128 386 386 7 129 387 387 153 129 388 388 151 129 389 389 10 130 390 390 152 130 391 391 154 130 392 392 9 131 393 393 155 131 394 394 153 131 395 395 10 132 396 396 156 132 397 397 12 132 398 398 11 133 399 399 157 133 400 400 155 133 401 401 14 134 402 402 156 134 403 403 158 134 404 404 15 135 405 405 157 135 406 406 13 135 407 407 16 136 408 408 158 136 409 409 160 136 410 410 15 137 411 411 161 137 412 412 159 137 413 413 18 138 414 414 160 138 415 415 162 138 416 416 17 139 417 417 163 139 418 418 161 139 419 419 20 140 420 420 162 140 421 421 164 140 422 422 21 141 423 423 163 141 424 424 19 141 425 425 22 142 426 426 164 142 427 427 166 142 428 428 21 143 429 429 167 143 430 430 165 143 431 431 22 144 432 432 168 144 433 433 24 144 434 434 25 145 435 435 167 145 436 436 23 145 437 437 24 146 438 438 170 146 439 439 26 146 440 440 27 147 441 441 169 147 442 442 25 147 443 443 26 148 444 444 172 148 445 445 28 148 446 446 29 149 447 447 171 149 448 448 27 149 449 449 28 150 450 450 174 150 451 451 30 150 452 452 31 151 453 453 173 151 454 454 29 151 455 455 30 152 456 456 176 152 457 457 32 152 458 458 33 153 459 459 175 153 460 460 31 153 461 461 32 154 462 462 178 154 463 463 34 154 464 464 33 155 465 465 179 155 466 466 177 155 467 467 34 156 468 468 180 156 469 469 36 156 470 470 35 157 471 471 181 157 472 472 179 157 473 473 36 158 474 474 182 158 475 475 38 158 476 476 39 159 477 477 181 159 478 478 37 159 479 479 38 160 480 480 184 160 481 481 40 160 482 482 41 161 483 483 183 161 484 484 39 161 485 485 40 162 486 486 186 162 487 487 42 162 488 488 43 163 489 489 185 163 490 490 41 163 491 491 42 164 492 492 188 164 493 493 44 164 494 494 45 165 495 495 187 165 496 496 43 165 497 497 44 166 498 498 190 166 499 499 46 166 500 500 47 167 501 501 189 167 502 502 45 167 503 503 46 168 504 504 144 168 505 505 0 168 506 506 1 169 507 507 191 169 508 508 47 169 509 509 382 170 510 510 192 170 511 511 336 170 512 512 337 171 513 513 239 171 514 514 383 171 515 515 336 172 516 516 194 172 517 517 338 172 518 518 339 173 519 519 193 173 520 520 337 173 521 521 338 174 522 522 196 174 523 523 340 174 524 524 341 175 525 525 195 175 526 526 339 175 527 527 340 176 528 528 198 176 529 529 342 176 530 530 343 177 531 531 197 177 532 532 341 177 533 533 342 178 534 534 200 178 535 535 344 178 536 536 343 179 537 537 201 179 538 538 199 179 539 539 344 180 540 540 202 180 541 541 346 180 542 542 345 181 543 543 203 181 544 544 201 181 545 545 348 182 546 546 202 182 547 547 204 182 548 548 349 183 549 549 203 183 550 550 347 183 551 551 350 184 552 552 204 184 553 553 206 184 554 554 351 185 555 555 205 185 556 556 349 185 557 557 350 186 558 558 208 186 559 559 352 186 560 560 353 187 561 561 207 187 562 562 351 187 563 563 352 188 564 564 210 188 565 565 354 188 566 566 355 189 567 567 209 189 568 568 353 189 569 569 354 190 570 570 212 190 571 571 356 190 572 572 357 191 573 573 211 191 574 574 355 191 575 575 356 192 576 576 214 192 577 577 358 192 578 578 359 193 579 579 213 193 580 580 357 193 581 581 360 194 582 582 214 194 583 583 216 194 584 584 361 195 585 585 215 195 586 586 359 195 587 587 362 196 588 588 216 196 589 589 218 196 590 590 361 197 591 591 219 197 592 592 217 197 593 593 364 198 594 594 218 198 595 595 220 198 596 596 363 199 597 597 221 199 598 598 219 199 599 599 366 200 600 600 220 200 601 601 222 200 602 602 365 201 603 603 223 201 604 604 221 201 605 605 366 202 606 606 224 202 607 607 368 202 608 608 367 203 609 609 225 203 610 610 223 203 611 611 368 204 612 612 226 204 613 613 370 204 614 614 369 205 615 615 227 205 616 616 225 205 617 617 372 206 618 618 226 206 619 619 228 206 620 620 373 207 621 621 227 207 622 622 371 207 623 623 374 208 624 624 228 208 625 625 230 208 626 626 375 209 627 627 229 209 628 628 373 209 629 629 376 210 630 630 230 210 631 631 232 210 632 632 375 211 633 633 233 211 634 634 231 211 635 635 378 212 636 636 232 212 637 637 234 212 638 638 377 213 639 639 235 213 640 640 233 213 641 641 380 214 642 642 234 214 643 643 237 214 644 644 379 215 645 645 238 215 646 646 235 215 647 647 382 216 648 648 237 216 649 649 236 216 650 650 383 217 651 651 238 217 652 652 381 217 653 653 192 218 654 654 284 218 655 655 240 218 656 656 239 219 657 657 241 219 658 658 287 219 659 659 194 220 660 660 240 220 661 661 242 220 662 662 193 221 663 663 243 221 664 664 241 221 665 665 194 222 666 666 244 222 667 667 196 222 668 668 197 221 669 669 243 221 670 670 195 221 671 671 196 111 672 672 246 111 673 673 198 111 674 674 197 221 675 675 247 221 676 676 245 221 677 677 198 223 678 678 248 223 679 679 200 223 680 680 199 224 681 681 249 224 682 682 247 224 683 683 202 225 684 684 248 225 685 685 250 225 686 686 203 226 687 687 249 226 688 688 201 226 689 689 202 227 690 690 252 227 691 691 204 227 692 692 203 221 693 693 253 221 694 694 251 221 695 695 206 111 696 696 252 111 697 697 254 111 698 698 207 228 699 699 253 228 700 700 205 228 701 701 208 111 702 702 254 111 703 703 256 111 704 704 207 221 705 705 257 221 706 706 255 221 707 707 208 229 708 708 258 229 709 709 210 229 710 710 209 230 711 711 259 230 712 712 257 230 713 713 212 231 714 714 258 231 715 715 260 231 716 716 211 230 717 717 261 230 718 718 259 230 719 719 212 111 720 720 262 111 721 721 214 111 722 722 213 232 723 723 263 232 724 724 261 232 725 725 216 233 726 726 262 233 727 727 264 233 728 728 217 221 729 729 263 221 730 730 215 221 731 731 216 111 732 732 266 111 733 733 218 111 734 734 219 234 735 735 265 234 736 736 217 234 737 737 218 111 738 738 268 111 739 739 220 111 740 740 219 221 741 741 269 221 742 742 267 221 743 743 222 111 744 744 268 111 745 745 270 111 746 746 223 235 747 747 269 235 748 748 221 235 749 749 222 236 750 750 272 236 751 751 224 236 752 752 223 221 753 753 273 221 754 754 271 221 755 755 226 237 756 756 272 237 757 757 274 237 758 758 227 238 759 759 273 238 760 760 225 238 761 761 226 239 762 762 276 239 763 763 228 239 764 764 227 240 765 765 277 240 766 766 275 240 767 767 230 111 768 768 276 111 769 769 278 111 770 770 229 221 771 771 279 221 772 772 277 221 773 773 230 111 774 774 280 111 775 775 232 111 776 776 231 221 777 777 281 221 778 778 279 221 779 779 232 111 780 780 282 111 781 781 234 111 782 782 235 241 783 783 281 241 784 784 233 241 785 785 237 111 786 786 282 111 787 787 285 111 788 788 235 221 789 789 286 221 790 790 283 221 791 791 237 222 792 792 284 222 793 793 236 222 794 794 239 221 795 795 286 221 796 796 238 221 797 797 258 242 798 798 304 242 799 799 307 242 800 800 249 243 801 801 296 243 802 802 248 243 803 803 267 244 804 804 315 244 805 805 314 244 806 806 285 245 807 807 334 245 808 808 333 245 809 809 257 246 810 810 306 246 811 811 305 246 812 812 250 247 813 813 296 247 814 814 299 247 815 815 284 248 816 816 335 248 817 817 287 248 818 818 240 249 819 819 289 249 820 820 288 249 821 821 259 250 822 822 307 250 823 823 306 250 824 824 276 251 825 825 325 251 826 826 324 251 827 827 251 252 828 828 297 252 829 829 249 252 830 830 285 253 831 831 332 253 832 832 284 253 833 833 242 254 834 834 288 254 835 835 291 254 836 836 278 255 837 837 324 255 838 838 327 255 839 839 250 256 840 840 298 256 841 841 251 256 842 842 269 257 843 843 316 257 844 844 268 257 845 845 287 258 846 846 334 258 847 847 286 258 848 848 241 259 849 849 290 259 850 850 289 259 851 851 279 260 852 852 325 260 853 853 277 260 854 854 270 261 855 855 316 261 856 856 319 261 857 857 242 262 858 858 290 262 859 859 243 262 860 860 261 263 861 861 308 263 862 862 260 263 863 863 278 264 864 864 326 264 865 865 279 264 866 866 271 265 867 867 317 265 868 868 269 265 869 869 260 266 870 870 311 266 871 871 262 266 872 872 253 267 873 873 300 267 874 874 252 267 875 875 271 268 876 876 319 268 877 877 318 268 878 878 261 269 879 879 310 269 880 880 309 269 881 881 252 270 882 882 303 270 883 883 254 270 884 884 244 271 885 885 293 271 886 886 292 271 887 887 263 272 888 888 311 272 889 889 310 272 890 890 280 273 891 891 329 273 892 892 328 273 893 893 253 274 894 894 302 274 895 895 301 274 896 896 244 275 897 897 295 275 898 898 246 275 899 899 282 276 900 900 328 276 901 901 331 276 902 902 255 277 903 903 303 277 904 904 302 277 905 905 291 278 906 906 289 278 907 907 290 278 908 908 295 279 909 909 293 279 910 910 294 279 911 911 299 280 912 912 297 280 913 913 298 280 914 914 303 281 915 915 301 281 916 916 302 281 917 917 307 282 918 918 305 282 919 919 306 282 920 920 311 283 921 921 309 283 922 922 310 283 923 923 314 284 924 924 312 284 925 925 313 284 926 926 318 285 927 927 316 285 928 928 317 285 929 929 322 286 930 930 320 286 931 931 321 286 932 932 326 287 933 933 324 287 934 934 325 287 935 935 331 288 936 936 329 288 937 937 330 288 938 938 332 289 939 939 334 289 940 940 335 289 941 941 369 290 942 942 345 290 943 943 337 290 944 944 240 291 945 945 287 291 946 946 241 291 947 947 267 292 948 948 313 292 949 949 265 292 950 950 346 293 951 951 362 293 952 952 338 293 953 953 244 294 954 954 243 294 955 955 245 294 956 956 275 295 957 957 323 295 958 958 322 295 959 959 248 296 960 960 247 296 961 961 249 296 962 962 257 297 963 963 304 297 964 964 256 297 965 965 252 298 966 966 251 298 967 967 253 298 968 968 266 299 969 969 312 299 970 970 315 299 971 971 256 300 972 972 255 300 973 973 257 300 974 974 275 301 975 975 321 301 976 976 273 301 977 977 260 302 978 978 259 302 979 979 261 302 980 980 282 12 981 981 330 12 982 982 283 12 983 983 265 303 984 984 262 303 985 985 263 303 986 986 265 304 987 987 312 304 988 988 264 304 989 989 269 305 990 990 266 305 991 991 267 305 992 992 246 306 993 993 294 306 994 994 247 306 995 995 273 307 996 996 270 307 997 997 271 307 998 998 274 308 999 999 320 308 1000 1000 323 308 1001 1001 277 309 1002 1002 274 309 1003 1003 275 309 1004 1004 283 310 1005 1005 329 310 1006 1006 281 310 1007 1007 281 311 1008 1008 278 311 1009 1009 279 311 1010 1010 245 312 1011 1011 294 312 1012 1012 293 312 1013 1013 286 313 1014 1014 282 313 1015 1015 283 313 1016 1016 273 314 1017 1017 320 314 1018 1018 272 314 1019 1019 110 315 1020 1020 62 315 1021 1021 63 315 1022 1022 97 316 1023 1023 98 316 1024 1024 101 316 1025 1025 138 317 1026 1026 136 317 1027 1027 89 317 1028 1028 102 318 1029 1029 103 318 1030 1030 105 318 1031 1031 100 319 1032 1032 53 319 1033 1033 54 319 1034 1034 106 320 1035 1035 107 320 1036 1036 109 320 1037 1037 109 321 1038 1038 111 321 1039 1039 63 321 1040 1040 110 322 1041 1041 111 322 1042 1042 113 322 1043 1043 137 323 1044 1044 88 323 1045 1045 89 323 1046 1046 114 324 1047 1047 115 324 1048 1048 117 324 1049 1049 118 325 1050 1050 70 325 1051 1051 71 325 1052 1052 118 326 1053 1053 119 326 1054 1054 121 326 1055 1055 101 327 1056 1056 52 327 1057 1057 53 327 1058 1058 123 328 1059 1059 125 328 1060 1060 124 328 1061 1061 108 329 1062 1062 61 329 1063 1063 62 329 1064 1064 127 330 1065 1065 129 330 1066 1066 128 330 1067 1067 117 331 1068 1068 119 331 1069 1069 71 331 1070 1070 131 332 1071 1071 133 332 1072 1072 132 332 1073 1073 126 333 1074 1074 78 333 1075 1075 79 333 1076 1076 135 334 1077 1077 137 334 1078 1078 136 334 1079 1079 108 335 1080 1080 109 335 1081 1081 60 335 1082 1082 139 336 1083 1083 141 336 1084 1084 140 336 1085 1085 5 337 1086 1086 3 337 1087 1087 1 337 1088 1088 1 338 1089 1089 47 338 1090 1090 45 338 1091 1091 45 339 1092 1092 43 339 1093 1093 41 339 1094 1094 41 340 1095 1095 39 340 1096 1096 45 340 1097 1097 37 341 1098 1098 35 341 1099 1099 33 341 1100 1100 33 342 1101 1101 31 342 1102 1102 29 342 1103 1103 29 343 1104 1104 27 343 1105 1105 25 343 1106 1106 25 344 1107 1107 23 344 1108 1108 29 344 1109 1109 21 345 1110 1110 19 345 1111 1111 17 345 1112 1112 17 346 1113 1113 15 346 1114 1114 21 346 1115 1115 13 347 1116 1116 11 347 1117 1117 5 347 1118 1118 9 348 1119 1119 7 348 1120 1120 5 348 1121 1121 5 349 1122 1122 1 349 1123 1123 45 349 1124 1124 45 350 1125 1125 39 350 1126 1126 37 350 1127 1127 37 351 1128 1128 33 351 1129 1129 21 351 1130 1130 29 352 1131 1131 23 352 1132 1132 21 352 1133 1133 21 353 1134 1134 15 353 1135 1135 13 353 1136 1136 11 354 1137 1137 9 354 1138 1138 5 354 1139 1139 5 355 1140 1140 45 355 1141 1141 21 355 1142 1142 33 356 1143 1143 29 356 1144 1144 21 356 1145 1145 21 357 1146 1146 13 357 1147 1147 5 357 1148 1148 116 358 1149 1149 69 358 1150 1150 70 358 1151 1151 143 359 1152 1152 99 359 1153 1153 96 359 1154 1154 46 360 1155 1155 0 360 1156 1156 6 360 1157 1157 2 361 1158 1158 4 361 1159 1159 6 361 1160 1160 6 362 1161 1161 8 362 1162 1162 10 362 1163 1163 10 363 1164 1164 12 363 1165 1165 14 363 1166 1166 14 364 1167 1167 16 364 1168 1168 18 364 1169 1169 18 365 1170 1170 20 365 1171 1171 22 365 1172 1172 22 366 1173 1173 24 366 1174 1174 26 366 1175 1175 26 367 1176 1176 28 367 1177 1177 30 367 1178 1178 30 368 1179 1179 32 368 1180 1180 38 368 1181 1181 34 369 1182 1182 36 369 1183 1183 38 369 1184 1184 38 370 1185 1185 40 370 1186 1186 46 370 1187 1187 42 371 1188 1188 44 371 1189 1189 46 371 1190 1190 0 372 1191 1191 2 372 1192 1192 6 372 1193 1193 6 373 1194 1194 10 373 1195 1195 14 373 1196 1196 14 374 1197 1197 18 374 1198 1198 22 374 1199 1199 22 375 1200 1200 26 375 1201 1201 14 375 1202 1202 32 376 1203 1203 34 376 1204 1204 38 376 1205 1205 40 377 1206 1206 42 377 1207 1207 46 377 1208 1208 46 378 1209 1209 6 378 1210 1210 14 378 1211 1211 14 379 1212 1212 26 379 1213 1213 30 379 1214 1214 30 380 1215 1215 38 380 1216 1216 14 380 1217 1217 51 381 1218 1218 50 381 1219 1219 49 381 1220 1220 52 382 1221 1221 55 382 1222 1222 54 382 1223 1223 57 383 1224 1224 56 383 1225 1225 59 383 1226 1226 61 384 1227 1227 60 384 1228 1228 63 384 1229 1229 65 385 1230 1230 64 385 1231 1231 67 385 1232 1232 69 386 1233 1233 68 386 1234 1234 71 386 1235 1235 72 387 1236 1236 75 387 1237 1237 74 387 1238 1238 76 33 1239 1239 79 33 1240 1240 78 33 1241 1241 80 388 1242 1242 83 388 1243 1243 82 388 1244 1244 84 389 1245 1245 87 389 1246 1246 86 389 1247 1247 88 390 1248 1248 91 390 1249 1249 90 390 1250 1250 92 391 1251 1251 95 391 1252 1252 94 391 1253 1253 128 392 1254 1254 129 392 1255 1255 80 392 1256 1256 101 393 1257 1257 103 393 1258 1258 55 393 1259 1259 139 394 1260 1260 91 394 1261 1261 88 394 1262 1262 130 395 1263 1263 128 395 1264 1264 81 395 1265 1265 103 396 1266 1266 102 396 1267 1267 54 396 1268 1268 120 397 1269 1269 121 397 1270 1270 72 397 1271 1271 139 398 1272 1272 138 398 1273 1273 90 398 1274 1274 131 399 1275 1275 83 399 1276 1276 80 399 1277 1277 122 400 1278 1278 120 400 1279 1279 73 400 1280 1280 112 401 1281 1281 113 401 1282 1282 64 401 1283 1283 130 402 1284 1284 82 402 1285 1285 83 402 1286 1286 123 403 1287 1287 75 403 1288 1288 72 403 1289 1289 112 404 1290 1290 65 404 1291 1291 66 404 1292 1292 105 405 1293 1293 56 405 1294 1294 57 405 1295 1295 122 406 1296 1296 74 406 1297 1297 75 406 1298 1298 141 407 1299 1299 92 407 1300 1300 93 407 1301 1301 113 408 1302 1302 115 408 1303 1303 67 408 1304 1304 104 409 1305 1305 57 409 1306 1306 58 409 1307 1307 142 410 1308 1308 140 410 1309 1309 93 410 1310 1310 96 411 1311 1311 48 411 1312 1312 49 411 1313 1313 114 412 1314 1314 66 412 1315 1315 67 412 1316 1316 133 413 1317 1317 84 413 1318 1318 85 413 1319 1319 105 414 1320 1320 107 414 1321 1321 59 414 1322 1322 141 415 1323 1323 143 415 1324 1324 95 415 1325 1325 98 416 1326 1326 50 416 1327 1327 51 416 1328 1328 134 417 1329 1329 132 417 1330 1330 85 417 1331 1331 107 418 1332 1332 106 418 1333 1333 58 418 1334 1334 124 419 1335 1335 125 419 1336 1336 76 419 1337 1337 143 420 1338 1338 142 420 1339 1339 94 420 1340 1340 96 421 1341 1341 99 421 1342 1342 51 421 1343 1343 133 422 1344 1344 135 422 1345 1345 87 422 1346 1346 126 423 1347 1347 124 423 1348 1348 77 423 1349 1349 98 424 1350 1350 97 424 1351 1351 49 424 1352 1352 116 425 1353 1353 117 425 1354 1354 68 425 1355 1355 134 426 1356 1356 86 426 1357 1357 87 426 1358 1358 125 427 1359 1359 127 427 1360 1360 79 427 1361 1361 144 428 1362 1362 96 428 1363 1363 97 428 1364 1364 146 429 1365 1365 98 429 1366 1366 99 429 1367 1367 148 430 1368 1368 145 430 1369 1369 97 430 1370 1370 146 431 1371 1371 149 431 1372 1372 101 431 1373 1373 148 432 1374 1374 100 432 1375 1375 102 432 1376 1376 151 433 1377 1377 103 433 1378 1378 101 433 1379 1379 152 434 1380 1380 150 434 1381 1381 102 434 1382 1382 153 435 1383 1383 105 435 1384 1384 103 435 1385 1385 154 436 1386 1386 152 436 1387 1387 104 436 1388 1388 153 437 1389 1389 155 437 1390 1390 107 437 1391 1391 156 438 1392 1392 154 438 1393 1393 106 438 1394 1394 157 439 1395 1395 109 439 1396 1396 107 439 1397 1397 156 221 1398 1398 108 221 1399 1399 110 221 1400 1400 157 440 1401 1401 159 440 1402 1402 111 440 1403 1403 160 441 1404 1404 158 441 1405 1405 110 441 1406 1406 161 442 1407 1407 113 442 1408 1408 111 442 1409 1409 160 443 1410 1410 112 443 1411 1411 114 443 1412 1412 161 444 1413 1413 163 444 1414 1414 115 444 1415 1415 164 445 1416 1416 162 445 1417 1417 114 445 1418 1418 165 446 1419 1419 117 446 1420 1420 115 446 1421 1421 164 447 1422 1422 116 447 1423 1423 118 447 1424 1424 167 448 1425 1425 119 448 1426 1426 117 448 1427 1427 166 449 1428 1428 118 449 1429 1429 120 449 1430 1430 167 450 1431 1431 169 450 1432 1432 121 450 1433 1433 170 451 1434 1434 168 451 1435 1435 120 451 1436 1436 171 452 1437 1437 123 452 1438 1438 121 452 1439 1439 172 453 1440 1440 170 453 1441 1441 122 453 1442 1442 171 454 1443 1443 173 454 1444 1444 125 454 1445 1445 174 455 1446 1446 172 455 1447 1447 124 455 1448 1448 175 456 1449 1449 127 456 1450 1450 125 456 1451 1451 176 457 1452 1452 174 457 1453 1453 126 457 1454 1454 175 458 1455 1455 177 458 1456 1456 129 458 1457 1457 176 459 1458 1458 128 459 1459 1459 130 459 1460 1460 177 460 1461 1461 179 460 1462 1462 131 460 1463 1463 180 461 1464 1464 178 461 1465 1465 130 461 1466 1466 181 462 1467 1467 133 462 1468 1468 131 462 1469 1469 180 463 1470 1470 132 463 1471 1471 134 463 1472 1472 181 464 1473 1473 183 464 1474 1474 135 464 1475 1475 184 465 1476 1476 182 465 1477 1477 134 465 1478 1478 185 466 1479 1479 137 466 1480 1480 135 466 1481 1481 186 467 1482 1482 184 467 1483 1483 136 467 1484 1484 187 468 1485 1485 139 468 1486 1486 137 468 1487 1487 186 469 1488 1488 138 469 1489 1489 140 469 1490 1490 189 470 1491 1491 141 470 1492 1492 139 470 1493 1493 190 471 1494 1494 188 471 1495 1495 140 471 1496 1496 189 472 1497 1497 191 472 1498 1498 143 472 1499 1499 144 473 1500 1500 190 473 1501 1501 142 473 1502 1502 191 474 1503 1503 147 474 1504 1504 99 474 1505 1505 0 475 1506 1506 144 475 1507 1507 145 475 1508 1508 3 476 1509 1509 146 476 1510 1510 147 476 1511 1511 4 477 1512 1512 2 477 1513 1513 145 477 1514 1514 3 478 1515 1515 5 478 1516 1516 149 478 1517 1517 6 479 1518 1518 4 479 1519 1519 148 479 1520 1520 5 480 1521 1521 7 480 1522 1522 151 480 1523 1523 8 481 1524 1524 6 481 1525 1525 150 481 1526 1526 7 482 1527 1527 9 482 1528 1528 153 482 1529 1529 10 483 1530 1530 8 483 1531 1531 152 483 1532 1532 9 484 1533 1533 11 484 1534 1534 155 484 1535 1535 10 485 1536 1536 154 485 1537 1537 156 485 1538 1538 11 486 1539 1539 13 486 1540 1540 157 486 1541 1541 14 487 1542 1542 12 487 1543 1543 156 487 1544 1544 15 488 1545 1545 159 488 1546 1546 157 488 1547 1547 16 489 1548 1548 14 489 1549 1549 158 489 1550 1550 15 490 1551 1551 17 490 1552 1552 161 490 1553 1553 18 491 1554 1554 16 491 1555 1555 160 491 1556 1556 17 492 1557 1557 19 492 1558 1558 163 492 1559 1559 20 493 1560 1560 18 493 1561 1561 162 493 1562 1562 21 494 1563 1563 165 494 1564 1564 163 494 1565 1565 22 495 1566 1566 20 495 1567 1567 164 495 1568 1568 21 496 1569 1569 23 496 1570 1570 167 496 1571 1571 22 497 1572 1572 166 497 1573 1573 168 497 1574 1574 25 498 1575 1575 169 498 1576 1576 167 498 1577 1577 24 499 1578 1578 168 499 1579 1579 170 499 1580 1580 27 500 1581 1581 171 500 1582 1582 169 500 1583 1583 26 501 1584 1584 170 501 1585 1585 172 501 1586 1586 29 502 1587 1587 173 502 1588 1588 171 502 1589 1589 28 503 1590 1590 172 503 1591 1591 174 503 1592 1592 31 504 1593 1593 175 504 1594 1594 173 504 1595 1595 30 505 1596 1596 174 505 1597 1597 176 505 1598 1598 33 506 1599 1599 177 506 1600 1600 175 506 1601 1601 32 507 1602 1602 176 507 1603 1603 178 507 1604 1604 33 508 1605 1605 35 508 1606 1606 179 508 1607 1607 34 509 1608 1608 178 509 1609 1609 180 509 1610 1610 35 510 1611 1611 37 510 1612 1612 181 510 1613 1613 36 511 1614 1614 180 511 1615 1615 182 511 1616 1616 39 512 1617 1617 183 512 1618 1618 181 512 1619 1619 38 513 1620 1620 182 513 1621 1621 184 513 1622 1622 41 514 1623 1623 185 514 1624 1624 183 514 1625 1625 40 515 1626 1626 184 515 1627 1627 186 515 1628 1628 43 516 1629 1629 187 516 1630 1630 185 516 1631 1631 42 517 1632 1632 186 517 1633 1633 188 517 1634 1634 45 518 1635 1635 189 518 1636 1636 187 518 1637 1637 44 519 1638 1638 188 519 1639 1639 190 519 1640 1640 47 520 1641 1641 191 520 1642 1642 189 520 1643 1643 46 521 1644 1644 190 521 1645 1645 144 521 1646 1646 1 522 1647 1647 147 522 1648 1648 191 522 1649 1649 382 523 1650 1650 236 523 1651 1651 192 523 1652 1652 337 524 1653 1653 193 524 1654 1654 239 524 1655 1655 336 525 1656 1656 192 525 1657 1657 194 525 1658 1658 339 526 1659 1659 195 526 1660 1660 193 526 1661 1661 338 527 1662 1662 194 527 1663 1663 196 527 1664 1664 341 528 1665 1665 197 528 1666 1666 195 528 1667 1667 340 529 1668 1668 196 529 1669 1669 198 529 1670 1670 343 530 1671 1671 199 530 1672 1672 197 530 1673 1673 342 531 1674 1674 198 531 1675 1675 200 531 1676 1676 343 532 1677 1677 345 532 1678 1678 201 532 1679 1679 344 512 1680 1680 200 512 1681 1681 202 512 1682 1682 345 533 1683 1683 347 533 1684 1684 203 533 1685 1685 348 534 1686 1686 346 534 1687 1687 202 534 1688 1688 349 535 1689 1689 205 535 1690 1690 203 535 1691 1691 350 536 1692 1692 348 536 1693 1693 204 536 1694 1694 351 537 1695 1695 207 537 1696 1696 205 537 1697 1697 350 538 1698 1698 206 538 1699 1699 208 538 1700 1700 353 539 1701 1701 209 539 1702 1702 207 539 1703 1703 352 540 1704 1704 208 540 1705 1705 210 540 1706 1706 355 541 1707 1707 211 541 1708 1708 209 541 1709 1709 354 542 1710 1710 210 542 1711 1711 212 542 1712 1712 357 543 1713 1713 213 543 1714 1714 211 543 1715 1715 356 544 1716 1716 212 544 1717 1717 214 544 1718 1718 359 545 1719 1719 215 545 1720 1720 213 545 1721 1721 360 546 1722 1722 358 546 1723 1723 214 546 1724 1724 361 547 1725 1725 217 547 1726 1726 215 547 1727 1727 362 548 1728 1728 360 548 1729 1729 216 548 1730 1730 361 549 1731 1731 363 549 1732 1732 219 549 1733 1733 364 550 1734 1734 362 550 1735 1735 218 550 1736 1736 363 551 1737 1737 365 551 1738 1738 221 551 1739 1739 366 552 1740 1740 364 552 1741 1741 220 552 1742 1742 365 553 1743 1743 367 553 1744 1744 223 553 1745 1745 366 554 1746 1746 222 554 1747 1747 224 554 1748 1748 367 555 1749 1749 369 555 1750 1750 225 555 1751 1751 368 556 1752 1752 224 556 1753 1753 226 556 1754 1754 369 557 1755 1755 371 557 1756 1756 227 557 1757 1757 372 558 1758 1758 370 558 1759 1759 226 558 1760 1760 373 559 1761 1761 229 559 1762 1762 227 559 1763 1763 374 560 1764 1764 372 560 1765 1765 228 560 1766 1766 375 561 1767 1767 231 561 1768 1768 229 561 1769 1769 376 562 1770 1770 374 562 1771 1771 230 562 1772 1772 375 563 1773 1773 377 563 1774 1774 233 563 1775 1775 378 564 1776 1776 376 564 1777 1777 232 564 1778 1778 377 565 1779 1779 379 565 1780 1780 235 565 1781 1781 380 566 1782 1782 378 566 1783 1783 234 566 1784 1784 379 567 1785 1785 381 567 1786 1786 238 567 1787 1787 382 568 1788 1788 380 568 1789 1789 237 568 1790 1790 383 569 1791 1791 239 569 1792 1792 238 569 1793 1793 192 111 1794 1794 236 111 1795 1795 284 111 1796 1796 239 221 1797 1797 193 221 1798 1798 241 221 1799 1799 194 570 1800 1800 192 570 1801 1801 240 570 1802 1802 193 221 1803 1803 195 221 1804 1804 243 221 1805 1805 194 571 1806 1806 242 571 1807 1807 244 571 1808 1808 197 221 1809 1809 245 221 1810 1810 243 221 1811 1811 196 572 1812 1812 244 572 1813 1813 246 572 1814 1814 197 221 1815 1815 199 221 1816 1816 247 221 1817 1817 198 111 1818 1818 246 111 1819 1819 248 111 1820 1820 199 573 1821 1821 201 573 1822 1822 249 573 1823 1823 202 574 1824 1824 200 574 1825 1825 248 574 1826 1826 203 575 1827 1827 251 575 1828 1828 249 575 1829 1829 202 576 1830 1830 250 576 1831 1831 252 576 1832 1832 203 228 1833 1833 205 228 1834 1834 253 228 1835 1835 206 577 1836 1836 204 577 1837 1837 252 577 1838 1838 207 221 1839 1839 255 221 1840 1840 253 221 1841 1841 208 111 1842 1842 206 111 1843 1843 254 111 1844 1844 207 221 1845 1845 209 221 1846 1846 257 221 1847 1847 208 111 1848 1848 256 111 1849 1849 258 111 1850 1850 209 235 1851 1851 211 235 1852 1852 259 235 1853 1853 212 111 1854 1854 210 111 1855 1855 258 111 1856 1856 211 221 1857 1857 213 221 1858 1858 261 221 1859 1859 212 578 1860 1860 260 578 1861 1861 262 578 1862 1862 213 579 1863 1863 215 579 1864 1864 263 579 1865 1865 216 580 1866 1866 214 580 1867 1867 262 580 1868 1868 217 581 1869 1869 265 581 1870 1870 263 581 1871 1871 216 582 1872 1872 264 582 1873 1873 266 582 1874 1874 219 221 1875 1875 267 221 1876 1876 265 221 1877 1877 218 111 1878 1878 266 111 1879 1879 268 111 1880 1880 219 221 1881 1881 221 221 1882 1882 269 221 1883 1883 222 111 1884 1884 220 111 1885 1885 268 111 1886 1886 223 221 1887 1887 271 221 1888 1888 269 221 1889 1889 222 111 1890 1890 270 111 1891 1891 272 111 1892 1892 223 583 1893 1893 225 583 1894 1894 273 583 1895 1895 226 584 1896 1896 224 584 1897 1897 272 584 1898 1898 227 585 1899 1899 275 585 1900 1900 273 585 1901 1901 226 111 1902 1902 274 111 1903 1903 276 111 1904 1904 227 586 1905 1905 229 586 1906 1906 277 586 1907 1907 230 111 1908 1908 228 111 1909 1909 276 111 1910 1910 229 587 1911 1911 231 587 1912 1912 279 587 1913 1913 230 588 1914 1914 278 588 1915 1915 280 588 1916 1916 231 221 1917 1917 233 221 1918 1918 281 221 1919 1919 232 111 1920 1920 280 111 1921 1921 282 111 1922 1922 235 221 1923 1923 283 221 1924 1924 281 221 1925 1925 237 589 1926 1926 234 589 1927 1927 282 589 1928 1928 235 221 1929 1929 238 221 1930 1930 286 221 1931 1931 237 590 1932 1932 285 590 1933 1933 284 590 1934 1934 239 591 1935 1935 287 591 1936 1936 286 591 1937 1937 258 592 1938 1938 256 592 1939 1939 304 592 1940 1940 249 593 1941 1941 297 593 1942 1942 296 593 1943 1943 267 594 1944 1944 266 594 1945 1945 315 594 1946 1946 285 595 1947 1947 286 595 1948 1948 334 595 1949 1949 257 596 1950 1950 259 596 1951 1951 306 596 1952 1952 250 597 1953 1953 248 597 1954 1954 296 597 1955 1955 284 598 1956 1956 332 598 1957 1957 335 598 1958 1958 240 599 1959 1959 241 599 1960 1960 289 599 1961 1961 259 600 1962 1962 258 600 1963 1963 307 600 1964 1964 276 601 1965 1965 277 601 1966 1966 325 601 1967 1967 251 602 1968 1968 298 602 1969 1969 297 602 1970 1970 285 603 1971 1971 333 603 1972 1972 332 603 1973 1973 242 604 1974 1974 240 604 1975 1975 288 604 1976 1976 278 605 1977 1977 276 605 1978 1978 324 605 1979 1979 250 606 1980 1980 299 606 1981 1981 298 606 1982 1982 269 607 1983 1983 317 607 1984 1984 316 607 1985 1985 287 608 1986 1986 335 608 1987 1987 334 608 1988 1988 241 609 1989 1989 243 609 1990 1990 290 609 1991 1991 279 610 1992 1992 326 610 1993 1993 325 610 1994 1994 270 611 1995 1995 268 611 1996 1996 316 611 1997 1997 242 612 1998 1998 291 612 1999 1999 290 612 2000 2000 261 613 2001 2001 309 613 2002 2002 308 613 2003 2003 278 614 2004 2004 327 614 2005 2005 326 614 2006 2006 271 615 2007 2007 318 615 2008 2008 317 615 2009 2009 260 616 2010 2010 308 616 2011 2011 311 616 2012 2012 253 617 2013 2013 301 617 2014 2014 300 617 2015 2015 271 618 2016 2016 270 618 2017 2017 319 618 2018 2018 261 619 2019 2019 263 619 2020 2020 310 619 2021 2021 252 620 2022 2022 300 620 2023 2023 303 620 2024 2024 244 621 2025 2025 245 621 2026 2026 293 621 2027 2027 263 622 2028 2028 262 622 2029 2029 311 622 2030 2030 280 623 2031 2031 281 623 2032 2032 329 623 2033 2033 253 624 2034 2034 255 624 2035 2035 302 624 2036 2036 244 625 2037 2037 292 625 2038 2038 295 625 2039 2039 282 626 2040 2040 280 626 2041 2041 328 626 2042 2042 255 627 2043 2043 254 627 2044 2044 303 627 2045 2045 291 628 2046 2046 288 628 2047 2047 289 628 2048 2048 295 629 2049 2049 292 629 2050 2050 293 629 2051 2051 299 630 2052 2052 296 630 2053 2053 297 630 2054 2054 303 631 2055 2055 300 631 2056 2056 301 631 2057 2057 307 632 2058 2058 304 632 2059 2059 305 632 2060 2060 311 633 2061 2061 308 633 2062 2062 309 633 2063 2063 314 634 2064 2064 315 634 2065 2065 312 634 2066 2066 318 635 2067 2067 319 635 2068 2068 316 635 2069 2069 322 636 2070 2070 323 636 2071 2071 320 636 2072 2072 326 637 2073 2073 327 637 2074 2074 324 637 2075 2075 331 638 2076 2076 328 638 2077 2077 329 638 2078 2078 332 639 2079 2079 333 639 2080 2080 334 639 2081 2081 337 221 2082 2082 383 221 2083 2083 377 221 2084 2084 381 221 2085 2085 379 221 2086 2086 377 221 2087 2087 377 640 2088 2088 375 640 2089 2089 373 640 2090 2090 373 221 2091 2091 371 221 2092 2092 369 221 2093 2093 369 221 2094 2094 367 221 2095 2095 365 221 2096 2096 365 641 2097 2097 363 641 2098 2098 361 641 2099 2099 361 221 2100 2100 359 221 2101 2101 357 221 2102 2102 357 221 2103 2103 355 221 2104 2104 353 221 2105 2105 353 642 2106 2106 351 642 2107 2107 345 642 2108 2108 349 221 2109 2109 347 221 2110 2110 345 221 2111 2111 345 643 2112 2112 343 643 2113 2113 337 643 2114 2114 341 644 2115 2115 339 644 2116 2116 337 644 2117 2117 383 221 2118 2118 381 221 2119 2119 377 221 2120 2120 377 645 2121 2121 373 645 2122 2122 369 645 2123 2123 369 221 2124 2124 365 221 2125 2125 361 221 2126 2126 361 221 2127 2127 357 221 2128 2128 369 221 2129 2129 351 221 2130 2130 349 221 2131 2131 345 221 2132 2132 343 646 2133 2133 341 646 2134 2134 337 646 2135 2135 337 647 2136 2136 377 647 2137 2137 369 647 2138 2138 369 648 2139 2139 357 648 2140 2140 353 648 2141 2141 353 221 2142 2142 345 221 2143 2143 369 221 2144 2144 240 649 2145 2145 284 649 2146 2146 287 649 2147 2147 267 650 2148 2148 314 650 2149 2149 313 650 2150 2150 378 651 2151 2151 380 651 2152 2152 382 651 2153 2153 382 111 2154 2154 336 111 2155 2155 338 111 2156 2156 338 652 2157 2157 340 652 2158 2158 342 652 2159 2159 342 111 2160 2160 344 111 2161 2161 338 111 2162 2162 346 653 2163 2163 348 653 2164 2164 350 653 2165 2165 350 111 2166 2166 352 111 2167 2167 354 111 2168 2168 354 654 2169 2169 356 654 2170 2170 358 654 2171 2171 358 655 2172 2172 360 655 2173 2173 354 655 2174 2174 362 111 2175 2175 364 111 2176 2176 366 111 2177 2177 366 656 2178 2178 368 656 2179 2179 362 656 2180 2180 370 657 2181 2181 372 657 2182 2182 378 657 2183 2183 374 658 2184 2184 376 658 2185 2185 378 658 2186 2186 378 111 2187 2187 382 111 2188 2188 338 111 2189 2189 338 659 2190 2190 344 659 2191 2191 346 659 2192 2192 346 660 2193 2193 350 660 2194 2194 362 660 2195 2195 354 111 2196 2196 360 111 2197 2197 362 111 2198 2198 362 661 2199 2199 368 661 2200 2200 370 661 2201 2201 372 662 2202 2202 374 662 2203 2203 378 662 2204 2204 378 663 2205 2205 338 663 2206 2206 362 663 2207 2207 350 664 2208 2208 354 664 2209 2209 362 664 2210 2210 362 665 2211 2211 370 665 2212 2212 378 665 2213 2213 244 666 2214 2214 242 666 2215 2215 243 666 2216 2216 275 667 2217 2217 274 667 2218 2218 323 667 2219 2219 248 668 2220 2220 246 668 2221 2221 247 668 2222 2222 257 669 2223 2223 305 669 2224 2224 304 669 2225 2225 252 670 2226 2226 250 670 2227 2227 251 670 2228 2228 266 671 2229 2229 264 671 2230 2230 312 671 2231 2231 256 672 2232 2232 254 672 2233 2233 255 672 2234 2234 275 673 2235 2235 322 673 2236 2236 321 673 2237 2237 260 674 2238 2238 258 674 2239 2239 259 674 2240 2240 282 675 2241 2241 331 675 2242 2242 330 675 2243 2243 265 676 2244 2244 264 676 2245 2245 262 676 2246 2246 265 677 2247 2247 313 677 2248 2248 312 677 2249 2249 269 678 2250 2250 268 678 2251 2251 266 678 2252 2252 246 679 2253 2253 295 679 2254 2254 294 679 2255 2255 273 680 2256 2256 272 680 2257 2257 270 680 2258 2258 274 681 2259 2259 272 681 2260 2260 320 681 2261 2261 277 682 2262 2262 276 682 2263 2263 274 682 2264 2264 283 683 2265 2265 330 683 2266 2266 329 683 2267 2267 281 684 2268 2268 280 684 2269 2269 278 684 2270 2270 245 685 2271 2271 247 685 2272 2272 294 685 2273 2273 286 686 2274 2274 285 686 2275 2275 282 686 2276 2276 273 687 2277 2277 321 687 2278 2278 320 687 2279 2279

+
+
+
+ + + + -2.19174e-7 0.4819077 4.203599 0.07343411 0.3691794 4.203599 0.1844177 0.4452247 4.203599 0.2091228 0.3129754 4.203599 0.3407595 0.3407605 4.203599 0.3129744 0.2091238 4.203599 0.4452236 0.1844187 4.203599 0.3691784 0.07343518 4.203599 0.4819066 1.00945e-6 4.203599 0.3691784 -0.07343298 4.203599 0.4452237 -0.1844165 4.203599 0.3129743 -0.2091217 4.203599 0.3407595 -0.3407585 4.203599 0.2091227 -0.3129734 4.203599 0.1844176 -0.4452227 4.203599 0.07343411 -0.3691774 4.203599 -1.62683e-7 -0.4819056 4.203599 -0.07343423 -0.3691774 4.203599 -0.1844179 -0.4452224 4.203599 -0.209123 -0.3129732 4.203599 -0.3407597 -0.3407583 4.203599 -0.3129745 -0.2091215 4.203599 -0.4452238 -0.1844163 4.203599 -0.3691784 -0.0734328 4.203599 -0.4819066 1.515e-6 4.203599 -0.3691783 0.07343554 4.203599 -0.4452235 0.1844192 4.203599 -0.312974 0.2091242 4.203599 -0.340759 0.3407609 4.203599 -0.2091223 0.3129757 4.203599 -0.184417 0.445225 4.203599 -0.07343339 0.3691796 4.203599 0.07343411 0.3691797 5.490069 -2.19174e-7 0.4819079 5.490069 0.1844177 0.4452249 5.490069 0.2091228 0.3129755 5.490069 0.3407595 0.3407607 5.490069 0.3129744 0.209124 5.490069 0.4452236 0.184419 5.490069 0.3691784 0.07343536 5.490069 0.4819066 1.21904e-6 5.490069 0.3691784 -0.0734328 5.490069 0.4452237 -0.1844164 5.490069 0.3129743 -0.2091215 5.490069 0.3407595 -0.3407583 5.490069 0.2091227 -0.3129732 5.490069 0.1844176 -0.4452225 5.490069 0.07343411 -0.3691772 5.490069 -1.62683e-7 -0.4819054 5.490069 -0.07343423 -0.3691771 5.490069 -0.1844179 -0.4452223 5.490069 -0.209123 -0.312973 5.490069 -0.3407597 -0.340758 5.490069 -0.3129745 -0.2091213 5.490069 -0.4452238 -0.1844161 5.490069 -0.3691784 -0.07343256 5.490069 -0.4819066 1.72459e-6 5.490069 -0.3691783 0.07343578 5.490069 -0.4452235 0.1844194 5.490069 -0.312974 0.2091244 5.490069 -0.340759 0.3407611 5.490069 -0.2091223 0.312976 5.490069 -0.184417 0.4452251 5.490069 -0.07343339 0.3691799 5.490069 0 1.186742 -4.170899 0 1.20564 -4.105835 0.2315219 1.163939 -4.170899 0.2352089 1.182474 -4.105835 0.4541469 1.096406 -4.170899 0.4613789 1.113866 -4.105835 0.6593189 0.9867394 -4.170899 0.6698184 1.002453 -4.105835 0.8391538 0.8391528 -4.170899 0.852517 0.8525161 -4.105835 0.9867406 0.6593177 -4.170899 1.002454 0.6698173 -4.105835 1.096407 0.4541459 -4.170899 1.113867 0.4613779 -4.105835 1.16394 0.231521 -4.170899 1.182475 0.2352079 -4.105835 1.186743 -9.08944e-7 -4.170899 1.205641 -8.87903e-7 -4.105835 1.16394 -0.2315227 -4.170899 1.182475 -0.2352097 -4.105835 1.096407 -0.4541476 -4.170899 1.113867 -0.4613797 -4.105835 0.9867406 -0.6593198 -4.170899 1.002454 -0.6698192 -4.105835 0.8391538 -0.8391548 -4.170899 0.852517 -0.852518 -4.105835 0.6593189 -0.9867416 -4.170899 0.6698183 -1.002455 -4.105834 0.4541467 -1.096408 -4.170898 0.4613787 -1.113868 -4.105834 0.2315217 -1.163941 -4.170898 0.2352086 -1.182476 -4.105834 -3.81064e-7 -1.186744 -4.170898 -3.92848e-7 -1.205642 -4.105834 -0.2315224 -1.163941 -4.170898 -0.2352094 -1.182476 -4.105834 -0.4541473 -1.096408 -4.170898 -0.4613794 -1.113868 -4.105834 -0.6593195 -0.9867411 -4.170899 -0.6698189 -1.002454 -4.105834 -0.8391546 -0.8391542 -4.170899 -0.8525176 -0.8525175 -4.105835 -0.986741 -0.6593194 -4.170899 -1.002454 -0.6698186 -4.105835 -1.096408 -0.4541469 -4.170899 -1.113867 -0.4613789 -4.105835 -1.16394 -0.2315219 -4.170899 -1.182475 -0.2352088 -4.105835 -1.186743 1.35018e-7 -4.170899 -1.205641 1.85239e-7 -4.105835 -1.163939 0.2315225 -4.170899 -1.182475 0.2352092 -4.105835 -1.096407 0.4541467 -4.170899 -1.113867 0.4613792 -4.105835 -0.9867396 0.6593191 -4.170899 -1.002453 0.6698186 -4.105835 -0.8391526 0.839154 -4.170899 -0.8525159 0.8525171 -4.105835 -0.6593177 0.9867404 -4.170899 -0.669817 1.002454 -4.105835 -0.4541453 1.096407 -4.170899 -0.4613773 1.113867 -4.105835 -0.2315202 1.163939 -4.170899 -0.2352071 1.182474 -4.105835 0.231522 1.163941 4.203598 0.2352089 1.182476 4.138534 0 1.205642 4.138534 0 1.186744 4.203598 0.4541468 1.096408 4.203598 0.4613789 1.113868 4.138534 0.6593189 0.9867414 4.203599 0.6698184 1.002455 4.138534 0.8391538 0.8391548 4.203599 0.852517 0.852518 4.138535 0.9867405 0.6593199 4.203599 1.002454 0.6698193 4.138535 1.096407 0.4541478 4.203599 1.113867 0.4613798 4.138535 1.16394 0.231523 4.203599 1.182475 0.2352099 4.138535 1.186743 1.08865e-6 4.203599 1.205641 1.07528e-6 4.138535 1.16394 -0.2315208 4.203599 1.182475 -0.2352077 4.138535 1.096407 -0.4541456 4.203599 1.113867 -0.4613777 4.138535 0.9867405 -0.6593179 4.203599 1.002454 -0.6698173 4.138535 0.8391538 -0.8391528 4.203599 0.852517 -0.852516 4.138535 0.6593189 -0.9867395 4.203599 0.6698183 -1.002453 4.138535 0.4541466 -1.096406 4.203599 0.4613787 -1.113866 4.138535 0.2315217 -1.163939 4.203599 0.2352086 -1.182474 4.138535 -3.86838e-7 -1.186742 4.203599 -3.92848e-7 -1.20564 4.138535 -0.2315225 -1.163939 4.203599 -0.2352094 -1.182474 4.138535 -0.4541473 -1.096406 4.203599 -0.4613794 -1.113866 4.138535 -0.6593195 -0.986739 4.203599 -0.6698189 -1.002453 4.138535 -0.8391544 -0.8391523 4.203599 -0.8525176 -0.8525155 4.138535 -0.986741 -0.6593172 4.203599 -1.002454 -0.6698166 4.138535 -1.096408 -0.4541448 4.203599 -1.113867 -0.461377 4.138535 -1.16394 -0.2315199 4.203598 -1.182475 -0.2352069 4.138535 -1.186743 2.14697e-6 4.203599 -1.205641 2.14842e-6 4.138535 -1.163939 0.2315242 4.203599 -1.182475 0.2352111 4.138535 -1.096407 0.454149 4.203598 -1.113867 0.4613811 4.138535 -0.9867397 0.6593211 4.203599 -1.002453 0.6698206 4.138535 -0.8391526 0.8391559 4.203598 -0.8525159 0.8525191 4.138535 -0.6593176 0.9867424 4.203599 -0.669817 1.002456 4.138534 -0.4541451 1.096409 4.203598 -0.4613773 1.113869 4.138534 -0.2315202 1.163941 4.203598 -0.2352071 1.182476 4.138534 0.07343411 0.3691794 4.203599 0.07343411 0.3691794 4.203599 -2.19174e-7 0.4819077 4.203599 -2.19174e-7 0.4819077 4.203599 0.1844177 0.4452247 4.203599 0.1844177 0.4452247 4.203599 0.2091228 0.3129754 4.203599 0.2091228 0.3129754 4.203599 0.3407595 0.3407605 4.203599 0.3407595 0.3407605 4.203599 0.3129744 0.2091238 4.203599 0.3129744 0.2091238 4.203599 0.4452236 0.1844187 4.203599 0.4452236 0.1844187 4.203599 0.3691784 0.07343518 4.203599 0.3691784 0.07343518 4.203599 0.4819066 1.00945e-6 4.203599 0.4819066 1.00945e-6 4.203599 0.3691784 -0.07343298 4.203599 0.3691784 -0.07343298 4.203599 0.4452237 -0.1844165 4.203599 0.4452237 -0.1844165 4.203599 0.3129743 -0.2091217 4.203599 0.3129743 -0.2091217 4.203599 0.3407595 -0.3407585 4.203599 0.3407595 -0.3407585 4.203599 0.2091227 -0.3129734 4.203599 0.2091227 -0.3129734 4.203599 0.1844176 -0.4452227 4.203599 0.1844176 -0.4452227 4.203599 0.07343411 -0.3691774 4.203599 0.07343411 -0.3691774 4.203599 -1.62683e-7 -0.4819056 4.203599 -1.62683e-7 -0.4819056 4.203599 -0.07343423 -0.3691774 4.203599 -0.07343423 -0.3691774 4.203599 -0.1844179 -0.4452224 4.203599 -0.1844179 -0.4452224 4.203599 -0.209123 -0.3129732 4.203599 -0.209123 -0.3129732 4.203599 -0.3407597 -0.3407583 4.203599 -0.3407597 -0.3407583 4.203599 -0.3129745 -0.2091215 4.203599 -0.3129745 -0.2091215 4.203599 -0.4452238 -0.1844163 4.203599 -0.4452238 -0.1844163 4.203599 -0.3691784 -0.0734328 4.203599 -0.3691784 -0.0734328 4.203599 -0.4819066 1.515e-6 4.203599 -0.4819066 1.515e-6 4.203599 -0.3691783 0.07343554 4.203599 -0.3691783 0.07343554 4.203599 -0.4452235 0.1844192 4.203599 -0.4452235 0.1844192 4.203599 -0.312974 0.2091242 4.203599 -0.312974 0.2091242 4.203599 -0.340759 0.3407609 4.203599 -0.340759 0.3407609 4.203599 -0.2091223 0.3129757 4.203599 -0.2091223 0.3129757 4.203599 -0.184417 0.445225 4.203599 -0.184417 0.445225 4.203599 -0.07343339 0.3691796 4.203599 -0.07343339 0.3691796 4.203599 0.07343411 0.3691797 5.490069 0.07343411 0.3691797 5.490069 -2.19174e-7 0.4819079 5.490069 -2.19174e-7 0.4819079 5.490069 0.1844177 0.4452249 5.490069 0.1844177 0.4452249 5.490069 0.2091228 0.3129755 5.490069 0.2091228 0.3129755 5.490069 0.3407595 0.3407607 5.490069 0.3407595 0.3407607 5.490069 0.3129744 0.209124 5.490069 0.3129744 0.209124 5.490069 0.4452236 0.184419 5.490069 0.4452236 0.184419 5.490069 0.3691784 0.07343536 5.490069 0.3691784 0.07343536 5.490069 0.4819066 1.21904e-6 5.490069 0.4819066 1.21904e-6 5.490069 0.3691784 -0.0734328 5.490069 0.3691784 -0.0734328 5.490069 0.4452237 -0.1844164 5.490069 0.4452237 -0.1844164 5.490069 0.3129743 -0.2091215 5.490069 0.3129743 -0.2091215 5.490069 0.3407595 -0.3407583 5.490069 0.3407595 -0.3407583 5.490069 0.2091227 -0.3129732 5.490069 0.2091227 -0.3129732 5.490069 0.1844176 -0.4452225 5.490069 0.1844176 -0.4452225 5.490069 0.07343411 -0.3691772 5.490069 0.07343411 -0.3691772 5.490069 -1.62683e-7 -0.4819054 5.490069 -1.62683e-7 -0.4819054 5.490069 -0.07343423 -0.3691771 5.490069 -0.07343423 -0.3691771 5.490069 -0.1844179 -0.4452223 5.490069 -0.1844179 -0.4452223 5.490069 -0.209123 -0.312973 5.490069 -0.209123 -0.312973 5.490069 -0.3407597 -0.340758 5.490069 -0.3407597 -0.340758 5.490069 -0.3129745 -0.2091213 5.490069 -0.3129745 -0.2091213 5.490069 -0.4452238 -0.1844161 5.490069 -0.4452238 -0.1844161 5.490069 -0.3691784 -0.07343256 5.490069 -0.3691784 -0.07343256 5.490069 -0.4819066 1.72459e-6 5.490069 -0.4819066 1.72459e-6 5.490069 -0.3691783 0.07343578 5.490069 -0.3691783 0.07343578 5.490069 -0.4452235 0.1844194 5.490069 -0.4452235 0.1844194 5.490069 -0.312974 0.2091244 5.490069 -0.312974 0.2091244 5.490069 -0.340759 0.3407611 5.490069 -0.340759 0.3407611 5.490069 -0.2091223 0.312976 5.490069 -0.2091223 0.312976 5.490069 -0.184417 0.4452251 5.490069 -0.184417 0.4452251 5.490069 -0.07343339 0.3691799 5.490069 -0.07343339 0.3691799 5.490069 0 1.20564 -4.105835 0.2352089 1.182474 -4.105835 0.2315219 1.163939 -4.170899 0 1.186742 -4.170899 0.2352089 1.182476 4.138534 0 1.205642 4.138534 0 1.186744 4.203598 0.231522 1.163941 4.203598 0.4613789 1.113866 -4.105835 0.4541469 1.096406 -4.170899 0.4613789 1.113868 4.138534 0.4541468 1.096408 4.203598 0.6698184 1.002453 -4.105835 0.6593189 0.9867394 -4.170899 0.6698184 1.002455 4.138534 0.6593189 0.9867414 4.203599 0.852517 0.8525161 -4.105835 0.8391538 0.8391528 -4.170899 0.852517 0.852518 4.138535 0.8391538 0.8391548 4.203599 1.002454 0.6698173 -4.105835 0.9867406 0.6593177 -4.170899 1.002454 0.6698193 4.138535 0.9867405 0.6593199 4.203599 1.113867 0.4613779 -4.105835 1.096407 0.4541459 -4.170899 1.113867 0.4613798 4.138535 1.096407 0.4541478 4.203599 1.182475 0.2352079 -4.105835 1.16394 0.231521 -4.170899 1.182475 0.2352099 4.138535 1.16394 0.231523 4.203599 1.205641 -8.87903e-7 -4.105835 1.186743 -9.08944e-7 -4.170899 1.205641 1.07528e-6 4.138535 1.186743 1.08865e-6 4.203599 1.182475 -0.2352097 -4.105835 1.16394 -0.2315227 -4.170899 1.182475 -0.2352077 4.138535 1.16394 -0.2315208 4.203599 1.113867 -0.4613797 -4.105835 1.096407 -0.4541476 -4.170899 1.113867 -0.4613777 4.138535 1.096407 -0.4541456 4.203599 1.002454 -0.6698192 -4.105835 0.9867406 -0.6593198 -4.170899 1.002454 -0.6698173 4.138535 0.9867405 -0.6593179 4.203599 0.852517 -0.852518 -4.105835 0.8391538 -0.8391548 -4.170899 0.852517 -0.852516 4.138535 0.8391538 -0.8391528 4.203599 0.6698183 -1.002455 -4.105834 0.6593189 -0.9867416 -4.170899 0.6698183 -1.002453 4.138535 0.6593189 -0.9867395 4.203599 0.4613787 -1.113868 -4.105834 0.4541467 -1.096408 -4.170898 0.4613787 -1.113866 4.138535 0.4541466 -1.096406 4.203599 0.2352086 -1.182476 -4.105834 0.2315217 -1.163941 -4.170898 0.2352086 -1.182474 4.138535 0.2315217 -1.163939 4.203599 -3.92848e-7 -1.205642 -4.105834 -3.81064e-7 -1.186744 -4.170898 -3.92848e-7 -1.20564 4.138535 -3.86838e-7 -1.186742 4.203599 -0.2352094 -1.182476 -4.105834 -0.2315224 -1.163941 -4.170898 -0.2352094 -1.182474 4.138535 -0.2315225 -1.163939 4.203599 -0.4613794 -1.113868 -4.105834 -0.4541473 -1.096408 -4.170898 -0.4613794 -1.113866 4.138535 -0.4541473 -1.096406 4.203599 -0.6698189 -1.002454 -4.105834 -0.6593195 -0.9867411 -4.170899 -0.6698189 -1.002453 4.138535 -0.6593195 -0.986739 4.203599 -0.8525176 -0.8525175 -4.105835 -0.8391546 -0.8391542 -4.170899 -0.8525176 -0.8525155 4.138535 -0.8391544 -0.8391523 4.203599 -1.002454 -0.6698186 -4.105835 -0.986741 -0.6593194 -4.170899 -1.002454 -0.6698166 4.138535 -0.986741 -0.6593172 4.203599 -1.113867 -0.4613789 -4.105835 -1.096408 -0.4541469 -4.170899 -1.113867 -0.461377 4.138535 -1.096408 -0.4541448 4.203599 -1.182475 -0.2352088 -4.105835 -1.16394 -0.2315219 -4.170899 -1.182475 -0.2352069 4.138535 -1.16394 -0.2315199 4.203598 -1.205641 1.85239e-7 -4.105835 -1.186743 1.35018e-7 -4.170899 -1.205641 2.14842e-6 4.138535 -1.186743 2.14697e-6 4.203599 -1.182475 0.2352092 -4.105835 -1.163939 0.2315225 -4.170899 -1.182475 0.2352111 4.138535 -1.163939 0.2315242 4.203599 -1.113867 0.4613792 -4.105835 -1.096407 0.4541467 -4.170899 -1.113867 0.4613811 4.138535 -1.096407 0.454149 4.203598 -1.002453 0.6698186 -4.105835 -0.9867396 0.6593191 -4.170899 -1.002453 0.6698206 4.138535 -0.9867397 0.6593211 4.203599 -0.8525159 0.8525171 -4.105835 -0.8391526 0.839154 -4.170899 -0.8525159 0.8525191 4.138535 -0.8391526 0.8391559 4.203598 -0.669817 1.002454 -4.105835 -0.6593177 0.9867404 -4.170899 -0.669817 1.002456 4.138534 -0.6593176 0.9867424 4.203599 -0.4613773 1.113867 -4.105835 -0.4541453 1.096407 -4.170899 -0.4613773 1.113869 4.138534 -0.4541451 1.096409 4.203598 -0.2352071 1.182474 -4.105835 -0.2315202 1.163939 -4.170899 -0.2352071 1.182476 4.138534 -0.2315202 1.163941 4.203598 + + + + + + + + + + -0.1950772 0.9807879 0 0 1 0 0.3826816 0.9238803 0 0.5555732 0.8314677 0 0.7071068 0.7071068 0 0.8314677 0.5555732 0 0.9238803 0.3826816 0 0.9807879 0.1950772 0 1 0 0 0.9807879 -0.1950772 0 0.9238803 -0.3826816 0 0.8314677 -0.5555732 0 0.7071068 -0.7071068 0 0.5555732 -0.8314677 0 0.3826816 -0.9238803 0 0.1950772 -0.9807879 0 0 -1 0 -0.1950772 -0.9807879 0 -0.3826816 -0.9238803 0 -0.5555732 -0.8314677 0 -0.7071068 -0.7071068 0 -0.8314677 -0.5555732 0 -0.9238803 -0.3826816 0 -0.9807879 -0.1950772 0 -1 0 0 -0.9807879 0.1950772 0 -0.9238803 0.3826816 0 -0.8314677 0.5555732 0 -0.7071068 0.7071068 0 -0.5555732 0.8314677 0 -0.3826816 0.9238803 0 0.1836344 -0.9829947 0 0 0 1 0.1950772 0.9807879 0 -0.5458301 0.8378959 0 0.9784418 0.2065226 0 -0.8249261 -0.5652407 0 -0.2065226 -0.9784418 0 -0.1836048 0.9830002 0 0.9829947 -0.1836344 0 0.8378959 0.5458301 0 -0.9784418 -0.2065226 0 -0.5652407 -0.8249261 0 -0.5652407 0.8249261 0 0.2065226 0.9784418 0 0.8378959 -0.5458301 0 0.9830002 0.1836048 0 0.9829947 0.1836344 0 -0.9829947 0.1836344 0 -0.8378959 -0.5458301 0 -0.2065226 0.9784418 0 0.5652407 0.8249261 0 0.5652407 -0.8249261 0 0.9784418 -0.2065226 0 -0.8378959 0.5458301 0 -0.9829947 -0.1836344 0 0.1836344 0.9829947 0 0.2065226 -0.9784418 0 0.8249261 -0.5652407 0 -0.9784418 0.2065226 0 0.5458301 0.8378959 0 -0.1836344 -0.9829947 0 0.5458301 -0.8378959 0 -0.8249261 0.5652407 0 0.8249261 0.5652407 0 -0.5458301 -0.8378959 0 0 0.960316 -0.2789146 0.1873294 0.9418662 -0.2789189 0 0.960316 0.2789146 0.1873294 0.9418662 0.2789189 0.3674813 0.8872227 -0.2789147 0.3674813 0.8872227 0.2789147 0.5335108 0.7984807 -0.2789174 0.5335108 0.7984807 0.2789174 0.6790463 0.6790463 -0.2789126 0.6790463 0.6790463 0.2789126 0.7984807 0.5335108 -0.2789174 0.7984807 0.5335108 0.2789174 0.8872227 0.3674813 -0.2789147 0.8872227 0.3674813 0.2789147 0.9418662 0.1873294 -0.2789189 0.9418662 0.1873294 0.2789189 0.960316 0 -0.2789146 0.960316 0 0.2789146 0.9418662 -0.1873294 -0.2789189 0.9418662 -0.1873294 0.2789189 0.8872227 -0.3674813 -0.2789147 0.8872227 -0.3674813 0.2789147 0.7984807 -0.5335108 -0.2789174 0.7984807 -0.5335108 0.2789174 0.6790463 -0.6790463 -0.2789126 0.6790463 -0.6790463 0.2789126 0.5335108 -0.7984807 -0.2789174 0.5335108 -0.7984807 0.2789174 0.3674813 -0.8872227 -0.2789147 0.3674813 -0.8872227 0.2789147 0.1873294 -0.9418662 -0.2789189 0.1873294 -0.9418662 0.2789189 0 -0.960316 -0.2789146 0 -0.960316 0.2789146 -0.1873294 -0.9418662 -0.2789189 -0.1873294 -0.9418662 0.2789189 -0.3674813 -0.8872227 -0.2789147 -0.3674813 -0.8872227 0.2789147 -0.5335108 -0.7984807 -0.2789174 -0.5335108 -0.7984807 0.2789174 -0.6790463 -0.6790463 -0.2789126 -0.6790463 -0.6790463 0.2789126 -0.7984807 -0.5335108 -0.2789174 -0.7984807 -0.5335108 0.2789174 -0.8872227 -0.3674813 -0.2789147 -0.8872227 -0.3674813 0.2789147 -0.9418662 -0.1873294 -0.2789189 -0.9418662 -0.1873294 0.2789189 -0.960316 0 -0.2789146 -0.960316 0 0.2789146 -0.9418662 0.1873294 -0.2789189 -0.9418662 0.1873294 0.2789189 -0.8872227 0.3674813 -0.2789147 -0.8872227 0.3674813 0.2789147 -0.7984807 0.5335108 -0.2789174 -0.7984807 0.5335108 0.2789174 -0.6790463 0.6790463 -0.2789126 -0.6790463 0.6790463 0.2789126 -0.5335108 0.7984807 -0.2789174 -0.5335108 0.7984807 0.2789174 -0.3674813 0.8872227 -0.2789147 -0.3674813 0.8872227 0.2789147 -0.1873294 0.9418662 -0.2789189 -0.1873294 0.9418662 0.2789189 0 0 -1 + + + + + + + + + + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + + + + + + + + + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + + + + + + + + + + + + + + + + + 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 +

191 0 0 0 65 1 1 1 444 0 2 2 133 2 3 3 332 3 4 4 328 2 5 5 135 3 6 6 336 4 7 7 332 3 8 8 137 4 9 9 340 5 10 10 336 4 11 11 139 5 12 12 344 6 13 13 340 5 14 14 141 6 15 15 348 7 16 16 344 6 17 17 143 7 18 18 352 8 19 19 348 7 20 20 145 8 21 21 356 9 22 22 352 8 23 23 147 9 24 24 360 10 25 25 356 9 26 26 149 10 27 27 364 11 28 28 360 10 29 29 151 11 30 30 368 12 31 31 364 11 32 32 153 12 33 33 372 13 34 34 368 12 35 35 155 13 36 36 376 14 37 37 372 13 38 38 157 14 39 39 380 15 40 40 376 14 41 41 159 15 42 42 384 16 43 43 380 15 44 44 161 16 45 45 388 17 46 46 384 16 47 47 163 17 48 48 392 18 49 49 388 17 50 50 165 18 51 51 396 19 52 52 392 18 53 53 167 19 54 54 400 20 55 55 396 19 56 56 169 20 57 57 404 21 58 58 400 20 59 59 171 21 60 60 408 22 61 61 404 21 62 62 173 22 63 63 412 23 64 64 408 22 65 65 175 23 66 66 416 24 67 67 412 23 68 68 177 24 69 69 420 25 70 70 416 24 71 71 179 25 72 72 424 26 73 73 420 25 74 74 181 26 75 75 428 27 76 76 424 26 77 77 183 27 78 78 432 28 79 79 428 27 80 80 185 28 81 81 436 29 82 82 432 28 83 83 187 29 84 84 440 30 85 85 436 29 86 86 189 30 87 87 444 0 88 88 440 30 89 89 213 31 90 90 278 31 91 91 214 31 92 92 194 32 93 93 128 32 94 94 131 32 95 95 129 33 96 96 328 2 97 97 321 33 98 98 325 1 99 99 321 33 100 100 65 1 101 101 196 32 102 102 128 32 103 103 192 32 104 104 194 32 105 105 190 32 106 106 254 32 107 107 200 32 108 108 134 32 109 109 198 32 110 110 200 32 111 111 138 32 112 112 136 32 113 113 204 32 114 114 138 32 115 115 202 32 116 116 204 32 117 117 142 32 118 118 140 32 119 119 208 32 120 120 142 32 121 121 206 32 122 122 208 32 123 123 146 32 124 124 144 32 125 125 212 32 126 126 146 32 127 127 210 32 128 128 212 32 129 129 150 32 130 130 148 32 131 131 216 32 132 132 150 32 133 133 215 32 134 134 216 32 135 135 154 32 136 136 152 32 137 137 220 32 138 138 154 32 139 139 218 32 140 140 220 32 141 141 158 32 142 142 156 32 143 143 224 32 144 144 158 32 145 145 222 32 146 146 224 32 147 147 162 32 148 148 160 32 149 149 228 32 150 150 162 32 151 151 226 32 152 152 228 32 153 153 166 32 154 154 164 32 155 155 232 32 156 156 166 32 157 157 230 32 158 158 232 32 159 159 170 32 160 160 168 32 161 161 236 32 162 162 170 32 163 163 234 32 164 164 236 32 165 165 174 32 166 166 172 32 167 167 240 32 168 168 174 32 169 169 238 32 170 170 240 32 171 171 178 32 172 172 176 32 173 173 244 32 174 174 178 32 175 175 242 32 176 176 244 32 177 177 182 32 178 178 180 32 179 179 248 32 180 180 182 32 181 181 246 32 182 182 248 32 183 183 186 32 184 184 184 32 185 185 252 32 186 186 186 32 187 187 250 32 188 188 252 32 189 189 190 32 190 190 188 32 191 191 196 32 192 192 134 32 193 193 132 32 194 194 256 32 195 195 290 32 196 196 274 32 197 197 243 34 198 198 305 34 199 199 307 34 200 200 11 35 201 201 281 35 202 202 217 35 203 203 245 36 204 204 57 36 205 205 309 36 206 206 12 37 207 207 283 37 208 208 219 37 209 209 26 38 210 210 311 38 211 211 247 38 212 212 13 39 213 213 285 39 214 214 221 39 215 215 195 40 216 216 257 40 217 217 193 40 218 218 249 41 219 219 59 41 220 220 313 41 221 221 223 42 222 222 46 42 223 223 287 42 224 224 197 43 225 225 32 43 226 226 261 43 227 227 28 44 228 228 315 44 229 229 251 44 230 230 15 45 231 231 289 45 232 232 225 45 233 233 2 46 234 234 263 47 235 235 199 46 236 236 253 48 237 237 61 48 238 238 317 48 239 239 227 49 240 240 48 49 241 241 291 49 242 242 3 50 243 243 265 50 244 244 201 50 245 245 30 51 246 246 319 51 247 247 255 51 248 248 17 52 249 249 293 52 250 250 229 52 251 251 4 53 252 252 267 53 253 253 203 53 254 254 0 54 255 255 63 54 256 256 33 54 257 257 231 55 258 258 50 55 259 259 295 55 260 260 5 56 261 261 269 56 262 262 205 56 263 263 19 57 264 264 297 57 265 265 233 57 266 266 6 58 267 267 271 58 268 268 207 58 269 269 235 59 270 270 52 59 271 271 299 59 272 272 7 60 273 273 273 60 274 274 209 60 275 275 237 61 276 276 53 61 277 277 301 61 278 278 8 62 279 279 275 62 280 280 211 62 281 281 239 63 282 282 54 63 283 283 303 63 284 284 9 64 285 285 42 64 286 286 10 64 287 287 23 65 288 288 56 65 289 289 24 65 290 290 320 66 291 291 322 67 292 292 323 66 293 293 130 68 294 294 327 69 295 295 324 69 296 296 69 70 297 297 322 67 298 298 67 67 299 299 330 71 300 300 327 69 301 301 331 71 302 302 71 72 303 303 329 70 304 304 69 70 305 305 334 73 306 306 331 71 307 307 335 73 308 308 71 72 309 309 337 74 310 310 333 72 311 311 338 75 312 312 335 73 313 313 339 75 314 314 75 76 315 315 337 74 316 316 73 74 317 317 338 75 318 318 343 77 319 319 342 77 320 320 77 78 321 321 341 76 322 322 75 76 323 323 342 77 324 324 347 79 325 325 346 79 326 326 77 78 327 327 349 80 328 328 345 78 329 329 346 79 330 330 351 81 331 331 350 81 332 332 81 82 333 333 349 80 334 334 79 80 335 335 350 81 336 336 355 83 337 337 354 83 338 338 81 82 339 339 357 84 340 340 353 82 341 341 354 83 342 342 359 85 343 343 358 85 344 344 85 86 345 345 357 84 346 346 83 84 347 347 358 85 348 348 363 87 349 349 362 87 350 350 87 88 351 351 361 86 352 352 85 86 353 353 362 87 354 354 367 89 355 355 366 89 356 356 87 88 357 357 369 90 358 358 365 88 359 359 370 91 360 360 367 89 361 361 371 91 362 362 89 90 363 363 373 92 364 364 369 90 365 365 374 93 366 366 371 91 367 367 375 93 368 368 91 92 369 369 377 94 370 370 373 92 371 371 378 95 372 372 375 93 373 373 379 95 374 374 93 94 375 375 381 96 376 376 377 94 377 377 382 97 378 378 379 95 379 379 383 97 380 380 97 98 381 381 381 96 382 382 95 96 383 383 386 99 384 384 383 97 385 385 387 99 386 386 97 98 387 387 389 100 388 388 385 98 389 389 386 99 390 390 391 101 391 391 390 101 392 392 101 102 393 393 389 100 394 394 99 100 395 395 390 101 396 396 395 103 397 397 394 103 398 398 103 104 399 399 393 102 400 400 101 102 401 401 394 103 402 402 399 105 403 403 398 105 404 404 105 106 405 405 397 104 406 406 103 104 407 407 398 105 408 408 403 107 409 409 402 107 410 410 107 108 411 411 401 106 412 412 105 106 413 413 402 107 414 414 407 109 415 415 406 109 416 416 107 108 417 417 409 110 418 418 405 108 419 419 410 111 420 420 407 109 421 421 411 111 422 422 109 110 423 423 413 112 424 424 409 110 425 425 410 111 426 426 415 113 427 427 414 113 428 428 113 114 429 429 413 112 430 430 111 112 431 431 418 115 432 432 415 113 433 433 419 115 434 434 115 116 435 435 417 114 436 436 113 114 437 437 422 117 438 438 419 115 439 439 423 117 440 440 115 116 441 441 425 118 442 442 421 116 443 443 422 117 444 444 427 119 445 445 426 119 446 446 117 118 447 447 429 120 448 448 425 118 449 449 430 121 450 450 427 119 451 451 431 121 452 452 121 122 453 453 429 120 454 454 119 120 455 455 430 121 456 456 435 123 457 457 434 123 458 458 123 124 459 459 433 122 460 460 121 122 461 461 438 125 462 462 435 123 463 463 439 125 464 464 123 124 465 465 441 126 466 466 437 124 467 467 438 125 468 468 443 127 469 469 442 127 470 470 125 126 471 471 445 128 472 472 441 126 473 473 446 129 474 474 443 127 475 475 447 129 476 476 320 66 477 477 445 128 478 478 127 128 479 479 130 68 480 480 447 129 481 481 326 68 482 482 94 130 483 483 110 130 484 484 78 130 485 485 191 0 486 486 325 1 487 487 65 1 488 488 133 2 489 489 135 3 490 490 332 3 491 491 135 3 492 492 137 4 493 493 336 4 494 494 137 4 495 495 139 5 496 496 340 5 497 497 139 5 498 498 141 6 499 499 344 6 500 500 141 6 501 501 143 7 502 502 348 7 503 503 143 7 504 504 145 8 505 505 352 8 506 506 145 8 507 507 147 9 508 508 356 9 509 509 147 9 510 510 149 10 511 511 360 10 512 512 149 10 513 513 151 11 514 514 364 11 515 515 151 11 516 516 153 12 517 517 368 12 518 518 153 12 519 519 155 13 520 520 372 13 521 521 155 13 522 522 157 14 523 523 376 14 524 524 157 14 525 525 159 15 526 526 380 15 527 527 159 15 528 528 161 16 529 529 384 16 530 530 161 16 531 531 163 17 532 532 388 17 533 533 163 17 534 534 165 18 535 535 392 18 536 536 165 18 537 537 167 19 538 538 396 19 539 539 167 19 540 540 169 20 541 541 400 20 542 542 169 20 543 543 171 21 544 544 404 21 545 545 171 21 546 546 173 22 547 547 408 22 548 548 173 22 549 549 175 23 550 550 412 23 551 551 175 23 552 552 177 24 553 553 416 24 554 554 177 24 555 555 179 25 556 556 420 25 557 557 179 25 558 558 181 26 559 559 424 26 560 560 181 26 561 561 183 27 562 562 428 27 563 563 183 27 564 564 185 28 565 565 432 28 566 566 185 28 567 567 187 29 568 568 436 29 569 569 187 29 570 570 189 30 571 571 440 30 572 572 189 30 573 573 191 0 574 574 444 0 575 575 213 31 576 576 277 31 577 577 278 31 578 578 194 32 579 579 192 32 580 580 128 32 581 581 129 33 582 582 133 2 583 583 328 2 584 584 325 1 585 585 129 33 586 586 321 33 587 587 196 32 588 588 132 32 589 589 128 32 590 590 194 32 591 591 131 32 592 592 190 32 593 593 200 32 594 594 136 32 595 595 134 32 596 596 200 32 597 597 202 32 598 598 138 32 599 599 204 32 600 600 140 32 601 601 138 32 602 602 204 32 603 603 206 32 604 604 142 32 605 605 208 32 606 606 144 32 607 607 142 32 608 608 208 32 609 609 210 32 610 610 146 32 611 611 212 32 612 612 148 32 613 613 146 32 614 614 212 32 615 615 215 32 616 616 150 32 617 617 216 32 618 618 152 32 619 619 150 32 620 620 216 32 621 621 218 32 622 622 154 32 623 623 220 32 624 624 156 32 625 625 154 32 626 626 220 32 627 627 222 32 628 628 158 32 629 629 224 32 630 630 160 32 631 631 158 32 632 632 224 32 633 633 226 32 634 634 162 32 635 635 228 32 636 636 164 32 637 637 162 32 638 638 228 32 639 639 230 32 640 640 166 32 641 641 232 32 642 642 168 32 643 643 166 32 644 644 232 32 645 645 234 32 646 646 170 32 647 647 236 32 648 648 172 32 649 649 170 32 650 650 236 32 651 651 238 32 652 652 174 32 653 653 240 32 654 654 176 32 655 655 174 32 656 656 240 32 657 657 242 32 658 658 178 32 659 659 244 32 660 660 180 32 661 661 178 32 662 662 244 32 663 663 246 32 664 664 182 32 665 665 248 32 666 666 184 32 667 667 182 32 668 668 248 32 669 669 250 32 670 670 186 32 671 671 252 32 672 672 188 32 673 673 186 32 674 674 252 32 675 675 254 32 676 676 190 32 677 677 196 32 678 678 198 32 679 679 134 32 680 680 256 32 681 681 258 32 682 682 318 32 683 683 318 32 684 684 316 32 685 685 314 32 686 686 314 32 687 687 312 32 688 688 310 32 689 689 310 32 690 690 308 32 691 691 306 32 692 692 306 32 693 693 304 32 694 694 302 32 695 695 302 32 696 696 300 32 697 697 298 32 698 698 298 32 699 699 296 32 700 700 294 32 701 701 294 32 702 702 292 32 703 703 290 32 704 704 290 32 705 705 288 32 706 706 286 32 707 707 286 32 708 708 284 32 709 709 282 32 710 710 282 32 711 711 280 32 712 712 279 32 713 713 279 32 714 714 276 32 715 715 274 32 716 716 274 32 717 717 272 32 718 718 270 32 719 719 270 32 720 720 268 32 721 721 266 32 722 722 266 32 723 723 264 32 724 724 262 32 725 725 262 32 726 726 260 32 727 727 256 32 728 728 256 32 729 729 318 32 730 730 314 32 731 731 314 32 732 732 310 32 733 733 256 32 734 734 306 32 735 735 302 32 736 736 290 32 737 737 298 32 738 738 294 32 739 739 290 32 740 740 290 32 741 741 286 32 742 742 282 32 743 743 282 32 744 744 279 32 745 745 290 32 746 746 274 32 747 747 270 32 748 748 256 32 749 749 266 32 750 750 262 32 751 751 256 32 752 752 256 32 753 753 310 32 754 754 306 32 755 755 302 32 756 756 298 32 757 757 290 32 758 758 290 32 759 759 279 32 760 760 274 32 761 761 270 32 762 762 266 32 763 763 256 32 764 764 256 32 765 765 306 32 766 766 290 32 767 767 243 34 768 768 241 34 769 769 305 34 770 770 11 35 771 771 43 35 772 772 281 35 773 773 245 36 774 774 25 36 775 775 57 36 776 776 12 37 777 777 44 37 778 778 283 37 779 779 26 38 780 780 58 38 781 781 311 38 782 782 13 39 783 783 45 39 784 784 285 39 785 785 195 40 786 786 259 40 787 787 257 40 788 788 249 41 789 789 27 41 790 790 59 41 791 791 223 42 792 792 14 42 793 793 46 42 794 794 197 43 795 795 1 43 796 796 32 43 797 797 28 44 798 798 60 44 799 799 315 44 800 800 15 45 801 801 47 45 802 802 289 45 803 803 2 46 804 804 34 47 805 805 263 47 806 806 253 48 807 807 29 48 808 808 61 48 809 809 227 49 810 810 16 49 811 811 48 49 812 812 3 50 813 813 35 50 814 814 265 50 815 815 30 51 816 816 62 51 817 817 319 51 818 818 17 52 819 819 49 52 820 820 293 52 821 821 4 53 822 822 36 53 823 823 267 53 824 824 0 54 825 825 31 54 826 826 63 54 827 827 231 55 828 828 18 55 829 829 50 55 830 830 5 56 831 831 37 56 832 832 269 56 833 833 19 57 834 834 51 57 835 835 297 57 836 836 6 58 837 837 38 58 838 838 271 58 839 839 235 59 840 840 20 59 841 841 52 59 842 842 7 60 843 843 39 60 844 844 273 60 845 845 237 61 846 846 21 61 847 847 53 61 848 848 8 62 849 849 40 62 850 850 275 62 851 851 239 63 852 852 22 63 853 853 54 63 854 854 9 64 855 855 41 64 856 856 42 64 857 857 23 65 858 858 55 65 859 859 56 65 860 860 320 66 861 861 67 67 862 862 322 67 863 863 130 68 864 864 326 68 865 865 327 69 866 866 69 70 867 867 329 70 868 868 322 67 869 869 330 71 870 870 324 69 871 871 327 69 872 872 71 72 873 873 333 72 874 874 329 70 875 875 334 73 876 876 330 71 877 877 331 71 878 878 71 72 879 879 73 74 880 880 337 74 881 881 338 75 882 882 334 73 883 883 335 73 884 884 75 76 885 885 341 76 886 886 337 74 887 887 338 75 888 888 339 75 889 889 343 77 890 890 77 78 891 891 345 78 892 892 341 76 893 893 342 77 894 894 343 77 895 895 347 79 896 896 77 78 897 897 79 80 898 898 349 80 899 899 346 79 900 900 347 79 901 901 351 81 902 902 81 82 903 903 353 82 904 904 349 80 905 905 350 81 906 906 351 81 907 907 355 83 908 908 81 82 909 909 83 84 910 910 357 84 911 911 354 83 912 912 355 83 913 913 359 85 914 914 85 86 915 915 361 86 916 916 357 84 917 917 358 85 918 918 359 85 919 919 363 87 920 920 87 88 921 921 365 88 922 922 361 86 923 923 362 87 924 924 363 87 925 925 367 89 926 926 87 88 927 927 89 90 928 928 369 90 929 929 370 91 930 930 366 89 931 931 367 89 932 932 89 90 933 933 91 92 934 934 373 92 935 935 374 93 936 936 370 91 937 937 371 91 938 938 91 92 939 939 93 94 940 940 377 94 941 941 378 95 942 942 374 93 943 943 375 93 944 944 93 94 945 945 95 96 946 946 381 96 947 947 382 97 948 948 378 95 949 949 379 95 950 950 97 98 951 951 385 98 952 952 381 96 953 953 386 99 954 954 382 97 955 955 383 97 956 956 97 98 957 957 99 100 958 958 389 100 959 959 386 99 960 960 387 99 961 961 391 101 962 962 101 102 963 963 393 102 964 964 389 100 965 965 390 101 966 966 391 101 967 967 395 103 968 968 103 104 969 969 397 104 970 970 393 102 971 971 394 103 972 972 395 103 973 973 399 105 974 974 105 106 975 975 401 106 976 976 397 104 977 977 398 105 978 978 399 105 979 979 403 107 980 980 107 108 981 981 405 108 982 982 401 106 983 983 402 107 984 984 403 107 985 985 407 109 986 986 107 108 987 987 109 110 988 988 409 110 989 989 410 111 990 990 406 109 991 991 407 109 992 992 109 110 993 993 111 112 994 994 413 112 995 995 410 111 996 996 411 111 997 997 415 113 998 998 113 114 999 999 417 114 1000 1000 413 112 1001 1001 418 115 1002 1002 414 113 1003 1003 415 113 1004 1004 115 116 1005 1005 421 116 1006 1006 417 114 1007 1007 422 117 1008 1008 418 115 1009 1009 419 115 1010 1010 115 116 1011 1011 117 118 1012 1012 425 118 1013 1013 422 117 1014 1014 423 117 1015 1015 427 119 1016 1016 117 118 1017 1017 119 120 1018 1018 429 120 1019 1019 430 121 1020 1020 426 119 1021 1021 427 119 1022 1022 121 122 1023 1023 433 122 1024 1024 429 120 1025 1025 430 121 1026 1026 431 121 1027 1027 435 123 1028 1028 123 124 1029 1029 437 124 1030 1030 433 122 1031 1031 438 125 1032 1032 434 123 1033 1033 435 123 1034 1034 123 124 1035 1035 125 126 1036 1036 441 126 1037 1037 438 125 1038 1038 439 125 1039 1039 443 127 1040 1040 125 126 1041 1041 127 128 1042 1042 445 128 1043 1043 446 129 1044 1044 442 127 1045 1045 443 127 1046 1046 320 66 1047 1047 323 66 1048 1048 445 128 1049 1049 130 68 1050 1050 446 129 1051 1051 447 129 1052 1052 126 130 1053 1053 64 130 1054 1054 66 130 1055 1055 66 130 1056 1056 68 130 1057 1057 70 130 1058 1058 70 130 1059 1059 72 130 1060 1060 78 130 1061 1061 74 130 1062 1062 76 130 1063 1063 78 130 1064 1064 78 130 1065 1065 80 130 1066 1066 82 130 1067 1067 82 130 1068 1068 84 130 1069 1069 78 130 1070 1070 86 130 1071 1071 88 130 1072 1072 90 130 1073 1073 90 130 1074 1074 92 130 1075 1075 86 130 1076 1076 94 130 1077 1077 96 130 1078 1078 98 130 1079 1079 98 130 1080 1080 100 130 1081 1081 94 130 1082 1082 102 130 1083 1083 104 130 1084 1084 106 130 1085 1085 106 130 1086 1086 108 130 1087 1087 102 130 1088 1088 110 130 1089 1089 112 130 1090 1090 118 130 1091 1091 114 130 1092 1092 116 130 1093 1093 118 130 1094 1094 118 130 1095 1095 120 130 1096 1096 126 130 1097 1097 122 130 1098 1098 124 130 1099 1099 126 130 1100 1100 126 130 1101 1101 66 130 1102 1102 78 130 1103 1103 72 130 1104 1104 74 130 1105 1105 78 130 1106 1106 78 130 1107 1107 84 130 1108 1108 86 130 1109 1109 86 130 1110 1110 92 130 1111 1111 94 130 1112 1112 94 130 1113 1113 100 130 1114 1114 102 130 1115 1115 102 130 1116 1116 108 130 1117 1117 110 130 1118 1118 112 130 1119 1119 114 130 1120 1120 118 130 1121 1121 120 130 1122 1122 122 130 1123 1123 126 130 1124 1124 66 130 1125 1125 70 130 1126 1126 78 130 1127 1127 78 130 1128 1128 86 130 1129 1129 94 130 1130 1130 94 130 1131 1131 102 130 1132 1132 110 130 1133 1133 110 130 1134 1134 118 130 1135 1135 126 130 1136 1136 126 130 1137 1137 78 130 1138 1138 110 130 1139 1139

+
+
+
+
+ + + + + 1 0 0 0 0 -1.62921e-7 -1 4.222882 0 1 -1.62921e-7 0 0 0 0 1 + + + + + + + + + + 1 0 0 0 0 -1.62921e-7 -1 6.639344 0 1 -1.62921e-7 0 0 0 0 1 + + + + + + + + + + 1 0 0 0.8746815 0 1 0 5.259002 0 0 1 3.169687 0 0 0 1 + + + + + + + +
\ No newline at end of file diff --git a/examples/qt3d/multiviewport/QuadViewportFrameGraph.qml b/examples/qt3d/multiviewport/QuadViewportFrameGraph.qml index 814629a23..a33631880 100644 --- a/examples/qt3d/multiviewport/QuadViewportFrameGraph.qml +++ b/examples/qt3d/multiviewport/QuadViewportFrameGraph.qml @@ -69,6 +69,7 @@ RenderSettings { ClearBuffers { buffers: ClearBuffers.ColorDepthBuffer + clearColor: Qt.rgba(0.6, 0.6, 0.6, 1.0) } Viewport { diff --git a/examples/qt3d/multiviewport/main.qml b/examples/qt3d/multiviewport/main.qml index df01bacec..169b694ed 100644 --- a/examples/qt3d/multiviewport/main.qml +++ b/examples/qt3d/multiviewport/main.qml @@ -73,53 +73,57 @@ Entity { id: cameraSet property var cameras: [camera1, camera2, camera3, camera4] - Timer { - running: true - interval: 10000 - repeat: true - property int count: 0 - onTriggered: { - quadViewportFrameGraph.topLeftCamera = cameraSet.cameras[count++ % 4]; - quadViewportFrameGraph.topRightCamera = cameraSet.cameras[count % 4]; - quadViewportFrameGraph.bottomLeftCamera = cameraSet.cameras[(count + 1) % 4]; - quadViewportFrameGraph.bottomRightCamera = cameraSet.cameras[(count + 2) % 4]; - } - } - CameraLens { - id : cameraLens + id: cameraLens projectionType: CameraLens.PerspectiveProjection fieldOfView: 45 aspectRatio: 16/9 - nearPlane : 0.01 - farPlane : 1000.0 + nearPlane: 0.01 + farPlane: 1000.0 + } + CameraLens { + id: cameraLens2 + projectionType: CameraLens.PerspectiveProjection + fieldOfView: 15 + aspectRatio: 16/9 + nearPlane: 0.01 + farPlane: 1000.0 + } + CameraLens { + id: cameraLens3 + projectionType: CameraLens.PerspectiveProjection + fieldOfView: 5 + aspectRatio: 16/9 + nearPlane: 0.01 + farPlane: 1000.0 } SimpleCamera { id: camera1 - lens: cameraLens - position: Qt.vector3d( 0.0, 0.0, -20.0 ) + lens: cameraLens2 + position: Qt.vector3d(10.0, 1.0, 10.0) + viewCenter: Qt.vector3d(0.0, 1.0, 0.0) } SimpleCamera { id: camera2 lens: cameraLens - position: Qt.vector3d( 0.0, 0.0, 20.0 ) - viewCenter: Qt.vector3d( -3.0, 0.0, 10.0 ) + position: Qt.vector3d(0.0, 0.0, 5.0) + viewCenter: Qt.vector3d(0.0, 0.0, 0.0) } SimpleCamera { id: camera3 - lens: cameraLens - position: Qt.vector3d( 0.0, 30.0, 30.0 ) - viewCenter: Qt.vector3d( -5.0, -20.0, -10.0 ) + lens: cameraLens2 + position: Qt.vector3d(30.0, 30.0, 20.0) + viewCenter: Qt.vector3d(0.0, 0.0, -8.0) } SimpleCamera { id: camera4 - lens: cameraLens - position: Qt.vector3d( 0.0, 15.0, 20.0 ) - viewCenter: Qt.vector3d( 0.0, -15.0, -20.0 ) + lens: cameraLens3 + position: Qt.vector3d(100.0, 0.0, -6.0) + viewCenter: Qt.vector3d(0.0, 0.0, -6.0) } } @@ -130,7 +134,7 @@ Entity { SequentialAnimation { running: true loops: Animation.Infinite - NumberAnimation { target: sceneRoot; property: "rotationAngle"; to: 360; duration: 2000; } + NumberAnimation { target: sceneRoot; property: "rotationAngle"; to: 360; duration: 4000; } } Entity { @@ -139,7 +143,7 @@ Entity { rotation: fromAxisAndAngle(Qt.vector3d(0, 0, 1), -sceneRoot.rotationAngle) }, SceneLoader { - source: "qrc:/assets/test_scene.dae" + source: "qrc:/Gear_scene.dae" } ] } diff --git a/examples/qt3d/multiviewport/multiviewport.qrc b/examples/qt3d/multiviewport/multiviewport.qrc index bd06fb169..1a3f1977b 100644 --- a/examples/qt3d/multiviewport/multiviewport.qrc +++ b/examples/qt3d/multiviewport/multiviewport.qrc @@ -1,7 +1,8 @@ main.qml - SimpleCamera.qml QuadViewportFrameGraph.qml + SimpleCamera.qml + Gear_scene.dae -- cgit v1.2.3 From 63d417d4ee7611d6453289db62b82da9ac0a39a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Mon, 6 Feb 2017 13:41:56 +0200 Subject: Add advanced custom material example Change-Id: I6c5ae0e29960aaab2d0babfe325a9f6483729600 Reviewed-by: Sean Harmer --- examples/qt3d/advancedcustommaterial/SceneRoot.qml | 114 + examples/qt3d/advancedcustommaterial/Water.qml | 175 + .../qt3d/advancedcustommaterial/WaterMaterial.qml | 264 + .../advancedcustommaterial.pro | 16 + examples/qt3d/advancedcustommaterial/main.cpp | 66 + examples/qt3d/advancedcustommaterial/main.qml | 313 + examples/qt3d/advancedcustommaterial/models.qrc | 5 + .../advancedcustommaterial/models/waterPlane.obj | 52263 +++++++++++++++++++ examples/qt3d/advancedcustommaterial/qml.qrc | 8 + examples/qt3d/advancedcustommaterial/shaders.qrc | 8 + .../advancedcustommaterial/shaders/es2/water.frag | 72 + .../advancedcustommaterial/shaders/es2/water.vert | 88 + .../advancedcustommaterial/shaders/gl3/water.frag | 74 + .../advancedcustommaterial/shaders/gl3/water.vert | 88 + examples/qt3d/advancedcustommaterial/textures.qrc | 10 + .../textures/WaterDiffuse.jpg | Bin 0 -> 330492 bytes .../textures/WaterNormal.jpg | Bin 0 -> 277208 bytes .../textures/WaterSpecular.jpg | Bin 0 -> 239707 bytes .../advancedcustommaterial/textures/Waterwave.jpg | Bin 0 -> 55133 bytes .../qt3d/advancedcustommaterial/textures/foam.jpg | Bin 0 -> 665944 bytes .../qt3d/advancedcustommaterial/textures/sky.jpg | Bin 0 -> 176616 bytes examples/qt3d/qt3d.pro | 3 +- 22 files changed, 53566 insertions(+), 1 deletion(-) create mode 100644 examples/qt3d/advancedcustommaterial/SceneRoot.qml create mode 100644 examples/qt3d/advancedcustommaterial/Water.qml create mode 100644 examples/qt3d/advancedcustommaterial/WaterMaterial.qml create mode 100644 examples/qt3d/advancedcustommaterial/advancedcustommaterial.pro create mode 100644 examples/qt3d/advancedcustommaterial/main.cpp create mode 100644 examples/qt3d/advancedcustommaterial/main.qml create mode 100644 examples/qt3d/advancedcustommaterial/models.qrc create mode 100644 examples/qt3d/advancedcustommaterial/models/waterPlane.obj create mode 100644 examples/qt3d/advancedcustommaterial/qml.qrc create mode 100644 examples/qt3d/advancedcustommaterial/shaders.qrc create mode 100644 examples/qt3d/advancedcustommaterial/shaders/es2/water.frag create mode 100644 examples/qt3d/advancedcustommaterial/shaders/es2/water.vert create mode 100644 examples/qt3d/advancedcustommaterial/shaders/gl3/water.frag create mode 100644 examples/qt3d/advancedcustommaterial/shaders/gl3/water.vert create mode 100644 examples/qt3d/advancedcustommaterial/textures.qrc create mode 100644 examples/qt3d/advancedcustommaterial/textures/WaterDiffuse.jpg create mode 100644 examples/qt3d/advancedcustommaterial/textures/WaterNormal.jpg create mode 100644 examples/qt3d/advancedcustommaterial/textures/WaterSpecular.jpg create mode 100644 examples/qt3d/advancedcustommaterial/textures/Waterwave.jpg create mode 100644 examples/qt3d/advancedcustommaterial/textures/foam.jpg create mode 100644 examples/qt3d/advancedcustommaterial/textures/sky.jpg diff --git a/examples/qt3d/advancedcustommaterial/SceneRoot.qml b/examples/qt3d/advancedcustommaterial/SceneRoot.qml new file mode 100644 index 000000000..a15fb0235 --- /dev/null +++ b/examples/qt3d/advancedcustommaterial/SceneRoot.qml @@ -0,0 +1,114 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import Qt3D.Core 2.0 +import Qt3D.Render 2.0 +import Qt3D.Extras 2.0 +import Qt3D.Input 2.0 +import QtQuick 2.0 as QQ2 + + +Entity { + id: sceneRoot + + Camera { + id: camera + projectionType: CameraLens.PerspectiveProjection + fieldOfView: 45 + nearPlane: 0.1 + farPlane: 1000.0 + position: Qt.vector3d(0.0, 4.0, 15.0) + upVector: Qt.vector3d(0.0, 1.0, 0.0) + viewCenter: Qt.vector3d(0.0, -2.0, 0.0) + } + + FirstPersonCameraController { + camera: camera + } + + Entity { + DirectionalLight { + id: directional + worldDirection: Qt.vector3d(0.3, -1.0, 5.0).normalized(); + color: "#fff2a3" + intensity: 0.01 + } + Transform { + id: lightpostransform + translation: Qt.vector3d(0.0, 50.0, 60.0) + } + components: [lightpostransform, directional] + } + + Entity { + PointLight { + id: pointL + color: "#fff2a3" + } + Transform{ + id: plightpostransform + translation: Qt.vector3d(0.0, 4.0, 15.0) + } + components: [plightpostransform, pointL] + } + + components: [ + RenderSettings { + activeFrameGraph: ForwardRenderer { + id: renderer + clearColor: "black" + camera: camera + } + }, + InputSettings { } + ] + + Water { } +} diff --git a/examples/qt3d/advancedcustommaterial/Water.qml b/examples/qt3d/advancedcustommaterial/Water.qml new file mode 100644 index 000000000..1e7f119a5 --- /dev/null +++ b/examples/qt3d/advancedcustommaterial/Water.qml @@ -0,0 +1,175 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import Qt3D.Core 2.0 +import Qt3D.Render 2.0 +import Qt3D.Input 2.0 +import Qt3D.Extras 2.0 +import QtQuick 2.0 as QQ2 + + + Entity { + id: water + + WaterMaterial { + id: watermaterial + + property real tox: 0.0 + property real toy: 0.0 + property real vertY: 1.0 + property real waveRandomAnim: 0.0 + + diffuse: "qrc:/textures/WaterDiffuse.jpg" + normal: "qrc:/textures/WaterNormal.jpg" + specular: "qrc:/textures/WaterSpecular.jpg" + wave: "qrc:/textures/Waterwave.jpg" + sky: "qrc:/textures/sky.jpg" + foam: "qrc:/textures/foam.jpg" + + textureScale: slider1.value + wavescale: vertY * slider2.value + specularity: slider3.value + offsetx: tox * slider5.value + offsety: toy * slider5.value + normalAmount: slider8.value + waveheight: slider6.value + waveStrenght: slider7.value + shininess: 100 + waveRandom: waveRandomAnim + } + + Mesh { + id: watermesh + source: "qrc:/models/waterPlane.obj" + } + + Transform { + id: waterTransform + property real scale: 1.0 + property real rotx: 0.0 + scale3D: Qt.vector3d(scale, scale, scale) + rotationY: slider4.value + } + + Entity { + id: waterEntity + components: [watermesh, watermaterial, waterTransform] + } + + QQ2.SequentialAnimation { + QQ2.NumberAnimation { + target: watermaterial + property: "waveRandomAnim" + to: 3.0 + duration: 4000 + easing.type: Easing.Linear + } + QQ2.NumberAnimation { + target: watermaterial + property: "waveRandomAnim" + to: 1.0 + duration: 4000 + easing.type: Easing.Linear + } + } + + QQ2.SequentialAnimation { + running: true + loops: QQ2.Animation.Infinite + QQ2.ParallelAnimation { + QQ2.NumberAnimation { + target: watermaterial + property: "toy" + to: 10.0 + duration: 100000 + } + QQ2.NumberAnimation { + target: watermaterial + property: "tox" + to: 10.0 + duration: 100000 + } + } + QQ2.ParallelAnimation { + QQ2.NumberAnimation { + target: watermaterial + property: "toy" + to: 0.0 + duration: 0 + } + QQ2.NumberAnimation { + target: watermaterial + property: "tox" + to: 0.0 + duration: 0 + } + } + } + + QQ2.SequentialAnimation { + running: true + loops: QQ2.Animation.Infinite + QQ2.NumberAnimation { + target: watermaterial + property: "vertY" + to: 200 + duration: 200000 + easing.type: Easing.Linear + } + QQ2.NumberAnimation { + target: watermaterial + property: "vertY" + to: 2 + duration: 200000 + easing.type: Easing.Linear + } + } +} + diff --git a/examples/qt3d/advancedcustommaterial/WaterMaterial.qml b/examples/qt3d/advancedcustommaterial/WaterMaterial.qml new file mode 100644 index 000000000..5278d8752 --- /dev/null +++ b/examples/qt3d/advancedcustommaterial/WaterMaterial.qml @@ -0,0 +1,264 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import Qt3D.Core 2.0 +import Qt3D.Render 2.0 + +Material { + id: root + + property color ambient: Qt.rgba(0.15, 0.35, 0.50, 1.0) + property alias diffuse: diffuseTextureImage.source + property alias normal: normalTextureImage.source + property alias wave: waveTextureImage.source + property alias specular: specularTextureImage.source + property alias sky: skyTextureImage.source + property alias foam: foamTextureImage.source + + property color specularColor: Qt.rgba(0.2, 0.2, 0.2, 1.0) + property real shininess: 150.0 + property real textureScale: 1.0 + property real offsetx: 0.0 + property real offsety: 0.0 + property real wavescale: 0.0 + property real specularity: 1.0 + property real waveheight: 0.1 + property real waveStrenght: 0.1 + property real normalAmount: 2.0 + property real waveRandom: 1.0 + + parameters: [ + Parameter { name: "ka"; value: Qt.vector3d(root.ambient.r, root.ambient.g, root.ambient.b) }, + Parameter { + name: "foamTexture" + value: Texture2D { + id: foamTexture + minificationFilter: Texture.LinearMipMapLinear + magnificationFilter: Texture.Linear + wrapMode { + x: WrapMode.Repeat + y: WrapMode.Repeat + } + generateMipMaps: true + maximumAnisotropy: 16.0 + TextureImage { id: foamTextureImage } + } + }, + Parameter { + name: "skyTexture" + value: Texture2D { + id: skyTexture + minificationFilter: Texture.LinearMipMapLinear + magnificationFilter: Texture.Linear + wrapMode { + x: WrapMode.Repeat + y: WrapMode.Repeat + } + generateMipMaps: true + maximumAnisotropy: 16.0 + TextureImage { id: skyTextureImage } + } + }, + Parameter { + name: "waveTexture" + value: Texture2D { + id: waveTexture + minificationFilter: Texture.LinearMipMapLinear + magnificationFilter: Texture.Linear + wrapMode { + x: WrapMode.Repeat + y: WrapMode.Repeat + } + generateMipMaps: true + maximumAnisotropy: 16.0 + TextureImage { id: waveTextureImage } + } + }, + Parameter { + name: "specularTexture" + value: Texture2D { + id: specularTexture + minificationFilter: Texture.LinearMipMapLinear + magnificationFilter: Texture.Linear + wrapMode { + x: WrapMode.Repeat + y: WrapMode.Repeat + } + generateMipMaps: true + maximumAnisotropy: 16.0 + TextureImage { id: specularTextureImage } + } + }, + Parameter { + name: "diffuseTexture" + value: Texture2D { + id: diffuseTexture + minificationFilter: Texture.LinearMipMapLinear + magnificationFilter: Texture.Linear + wrapMode { + x: WrapMode.Repeat + y: WrapMode.Repeat + } + generateMipMaps: true + maximumAnisotropy: 16.0 + TextureImage { id: diffuseTextureImage } + } + }, + Parameter { + name: "normalTexture" + value: Texture2D { + id: normalTexture + minificationFilter: Texture.LinearMipMapLinear + magnificationFilter: Texture.Linear + wrapMode { + x: WrapMode.Repeat + y: WrapMode.Repeat + } + generateMipMaps: true + + maximumAnisotropy: 16.0 + TextureImage { id: normalTextureImage } + } + }, + Parameter { + name: "specularColor" + value: Qt.vector3d(root.specularColor.r, root.specularColor.g, root.specularColor.b) + }, + Parameter { name: "shininess"; value: root.shininess }, + Parameter { name: "texCoordScale"; value: textureScale }, + Parameter { name: "offsetx"; value: root.offsetx }, + Parameter { name: "offsety"; value: root.offsety }, + Parameter { name: "vertYpos"; value: root.wavescale }, + Parameter { name: "specularity"; value: root.specularity }, + Parameter { name: "waveheight"; value: root.waveheight }, + Parameter { name: "waveStrenght"; value: root.waveStrenght }, + Parameter { name: "waveRandom"; value: root.waveRandom }, + Parameter { name: "normalAmount"; value: root.normalAmount } + ] + + + effect: Effect { + property string vertex: "qrc:/shaders/gl3/water.vert" + property string fragment: "qrc:/shaders/gl3/water.frag" + property string vertexES: "qrc:/shaders/es2/water.vert" + property string fragmentES: "qrc:/shaders/es2/water.frag" + + FilterKey { + id: forward + name: "renderingStyle" + value: "forward" + } + ShaderProgram { + id: gl3Shader + vertexShaderCode: loadSource(parent.vertex) + fragmentShaderCode: loadSource(parent.fragment) + } + ShaderProgram { + id: esShader + vertexShaderCode: loadSource(parent.vertexES) + fragmentShaderCode: loadSource(parent.fragmentES) + } + + AlphaCoverage { id: alphaCoverage } + + DepthTest { + id: depth + depthFunction: DepthTest.Less } + + techniques: [ + // OpenGL 3.1 + Technique { + filterKeys: [ forward ] + graphicsApiFilter { + api: GraphicsApiFilter.OpenGL + profile: GraphicsApiFilter.CoreProfile + majorVersion: 3 + minorVersion: 1 + } + renderPasses: RenderPass { + shaderProgram: gl3Shader + renderStates: [alphaCoverage ] + } + }, + + // OpenGL 2.1 + Technique { + filterKeys: [ forward ] + graphicsApiFilter { + api: GraphicsApiFilter.OpenGL + profile: GraphicsApiFilter.NoProfile + majorVersion: 2 + minorVersion: 0 + } + renderPasses: RenderPass { + shaderProgram: gl3Shader + renderStates: [ alphaCoverage ] + } + }, + + // OpenGL ES 2 + Technique { + filterKeys: [ forward ] + graphicsApiFilter { + api: GraphicsApiFilter.OpenGLES + profile: GraphicsApiFilter.NoProfile + majorVersion: 2 + minorVersion: 0 + } + renderPasses: RenderPass { + shaderProgram: esShader + renderStates: [ alphaCoverage ] + } + } + ] + } +} + + diff --git a/examples/qt3d/advancedcustommaterial/advancedcustommaterial.pro b/examples/qt3d/advancedcustommaterial/advancedcustommaterial.pro new file mode 100644 index 000000000..90a6c4a03 --- /dev/null +++ b/examples/qt3d/advancedcustommaterial/advancedcustommaterial.pro @@ -0,0 +1,16 @@ +TEMPLATE = app + +!include( ../examples.pri ) { + error( "Couldn't find the examples.pri file!" ) +} + +QT += qml quick +CONFIG += c++11 + +SOURCES += main.cpp + +RESOURCES += qml.qrc \ + models.qrc \ + textures.qrc \ + shaders.qrc + diff --git a/examples/qt3d/advancedcustommaterial/main.cpp b/examples/qt3d/advancedcustommaterial/main.cpp new file mode 100644 index 000000000..8b76e100c --- /dev/null +++ b/examples/qt3d/advancedcustommaterial/main.cpp @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include + +int main(int argc, char **argv) +{ + QGuiApplication app(argc, argv); + + QQuickView view; + + view.resize(1920, 1080); + view.setResizeMode(QQuickView::SizeRootObjectToView); + view.setSource(QUrl("qrc:/main.qml")); + view.show(); + + return app.exec(); +} diff --git a/examples/qt3d/advancedcustommaterial/main.qml b/examples/qt3d/advancedcustommaterial/main.qml new file mode 100644 index 000000000..7087dd1f2 --- /dev/null +++ b/examples/qt3d/advancedcustommaterial/main.qml @@ -0,0 +1,313 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import QtQuick.Scene3D 2.0 +import Qt3D.Render 2.0 +import QtQuick.Controls 1.4 + + +Item { + + Rectangle { + id: scene + property bool colorChange: true + anchors.fill: parent + color: "#2d2d2d" + + transform: Rotation { + id: sceneRotation + axis.x: 1 + axis.y: 0 + axis.z: 0 + origin.x: scene.width / 2 + origin.y: scene.height / 2 + } + Rectangle { + id: controlsbg + anchors.fill: parent + anchors.leftMargin: 10 + anchors.topMargin: 10 + anchors.rightMargin: 1720 + anchors.bottomMargin: 10 + color: "grey" + Column { + anchors.fill: parent + anchors.leftMargin: 5 + anchors.topMargin: 5 + spacing: 10 + Rectangle { + id: slidertexscale + width: 180 + height: 60 + color: "#2d2d2d" + Text { + id: scaletext + anchors.horizontalCenter: parent.horizontalCenter + anchors.top: parent.top + anchors.topMargin: 10 + text: "TEXTURE SCALE" + color: "white" + font.bold: true + font.pointSize: 12 + } + Slider { + id: slider1 + anchors.fill: parent + anchors.topMargin: 30 + anchors.rightMargin: 10 + anchors.leftMargin: 10 + value: 1.0 + minimumValue: 0.3 + } + } + Rectangle { + id: slidertexturespeed + width: 180 + height: 60 + color: "#2d2d2d" + Text { + id: texturespeedtext + anchors.horizontalCenter: parent.horizontalCenter + anchors.top: parent.top + anchors.topMargin: 10 + text: "TEXTURE SPEED" + color: "white" + font.bold: true + font.pointSize: 12 + } + Slider { + id: slider5 + anchors.fill: parent + anchors.topMargin: 30 + anchors.rightMargin: 10 + anchors.leftMargin: 10 + value: 1.1 + maximumValue: 4.0 + minimumValue: 0.0 + } + } + Rectangle { + id: sliderspecularity + width: 180 + height: 60 + color: "#2d2d2d" + Text { + id: specularitytext + anchors.horizontalCenter: parent.horizontalCenter + anchors.top: parent.top + anchors.topMargin: 10 + text: "SPECULARITY" + color: "white" + font.bold: true + font.pointSize: 12 + } + Slider { + id: slider3 + anchors.fill: parent + anchors.topMargin: 30 + anchors.rightMargin: 10 + anchors.leftMargin: 10 + value: 1.0 + maximumValue: 3.0 + minimumValue: 0.0 + } + } + Rectangle { + id: sliderdistortion + width: 180 + height: 60 + color: "#2d2d2d" + Text { + id: distortiontext + anchors.horizontalCenter: parent.horizontalCenter + anchors.top: parent.top + anchors.topMargin: 10 + text: "DISTORTION" + color: "white" + font.bold: true + font.pointSize: 12 + } + Slider { + id: slider7 + anchors.fill: parent + anchors.topMargin: 30 + anchors.rightMargin: 10 + anchors.leftMargin: 10 + value: 0.015 + maximumValue: 0.1 + minimumValue: 0.0 + } + } + Rectangle { + id: slidernormal + width: 180 + height: 60 + color: "#2d2d2d" + Text { + id: normaltext + anchors.horizontalCenter: parent.horizontalCenter + anchors.top: parent.top + anchors.topMargin: 10 + text: "NORMAL AMOUNT" + color: "white" + font.bold: true + font.pointSize: 12 + } + Slider { + id: slider8 + anchors.fill: parent + anchors.topMargin: 30 + anchors.rightMargin: 10 + anchors.leftMargin: 10 + value: 2.2 + maximumValue: 4.0 + minimumValue: 0.0 + } + } + Rectangle { + id: sliderwavespeed + width: 180 + height: 60 + color: "#2d2d2d" + Text { + id: wawespeedtext + anchors.horizontalCenter: parent.horizontalCenter + anchors.top: parent.top + anchors.topMargin: 10 + text: "WAVE SPEED" + color: "white" + font.bold: true + font.pointSize: 12 + } + Slider { + id: slider2 + updateValueWhileDragging: false + anchors.fill: parent + anchors.topMargin: 30 + anchors.rightMargin: 10 + anchors.leftMargin: 10 + value: 0.75 + maximumValue: 4.0 + minimumValue: 0.1 + } + } + Rectangle { + id: sliderwaveheight + width: 180 + height: 60 + color: "#2d2d2d" + Text { + id: waweheighttext + anchors.horizontalCenter: parent.horizontalCenter + anchors.top: parent.top + anchors.topMargin: 10 + text: "WAVE HEIGHT" + color: "white" + font.bold: true + font.pointSize: 12 + } + Slider { + id: slider6 + anchors.fill: parent + anchors.topMargin: 30 + anchors.rightMargin: 10 + anchors.leftMargin: 10 + value: 0.2 + maximumValue: 0.5 + minimumValue: 0.02 + } + } + Rectangle { + id: slidermeshrotation + width: 180 + height: 60 + color: "#2d2d2d" + Text { + id: meshrotationtext + anchors.horizontalCenter: parent.horizontalCenter + anchors.top: parent.top + anchors.topMargin: 10 + text: "MESH ROTATION" + color: "white" + font.bold: true + font.pointSize: 12 + } + Slider { + id: slider4 + anchors.fill: parent + anchors.topMargin: 30 + anchors.rightMargin: 10 + anchors.leftMargin: 10 + value: 35.0 + maximumValue: 360.0 + minimumValue: 0.0 + } + } + } + } + + Scene3D { + id: scene3d + anchors.fill: parent + anchors.leftMargin: 200 + anchors.topMargin: 10 + anchors.rightMargin: 10 + anchors.bottomMargin: 10 + focus: true + aspects: ["input", "logic"] + cameraAspectRatioMode: Scene3D.AutomaticAspectRatio + + SceneRoot { + id: root + } + } + } +} diff --git a/examples/qt3d/advancedcustommaterial/models.qrc b/examples/qt3d/advancedcustommaterial/models.qrc new file mode 100644 index 000000000..0cd5c4961 --- /dev/null +++ b/examples/qt3d/advancedcustommaterial/models.qrc @@ -0,0 +1,5 @@ + + + models/waterPlane.obj + + diff --git a/examples/qt3d/advancedcustommaterial/models/waterPlane.obj b/examples/qt3d/advancedcustommaterial/models/waterPlane.obj new file mode 100644 index 000000000..5d27eba3f --- /dev/null +++ b/examples/qt3d/advancedcustommaterial/models/waterPlane.obj @@ -0,0 +1,52263 @@ +# Blender v2.77 (sub 0) OBJ File: 'CustomShaderExampleModels.blend' +# www.blender.org +mtllib waterPlane2.mtl +o Plane +v -5.906582 -2.000000 5.906582 +v 5.906582 -2.000000 5.906582 +v -5.906582 -2.000000 -5.906582 +v 5.906582 -2.000000 -5.906582 +v 5.906583 -1.989998 -5.814293 +v 5.906583 -1.989998 -5.906583 +v 5.814293 -1.989998 -5.906583 +v 0.000000 -1.989998 -5.906583 +v -0.092290 -1.989998 -5.906583 +v 5.906583 -1.990000 0.092290 +v 5.906583 -1.990000 -0.000000 +v 5.906583 -1.990001 3.045582 +v 5.906583 -1.990001 2.953292 +v -2.953291 -1.989998 -5.906583 +v -3.045582 -1.989998 -5.906583 +v 2.953291 -1.989998 -5.906583 +v 2.861001 -1.989998 -5.906583 +v 5.906583 -1.989999 -2.861001 +v 5.906583 -1.989999 -2.953291 +v 5.906583 -1.989999 -1.384355 +v 5.906583 -1.989999 -1.476646 +v 1.476646 -1.989998 -5.906583 +v 1.384355 -1.989998 -5.906583 +v -4.429937 -1.989998 -5.906583 +v -4.522227 -1.989998 -5.906583 +v 5.906583 -1.990002 4.522227 +v 5.906583 -1.990002 4.429936 +v 5.906583 -1.990001 1.568936 +v 5.906583 -1.990001 1.476646 +v -1.476646 -1.989998 -5.906583 +v -1.568936 -1.989998 -5.906583 +v 4.429937 -1.989998 -5.906583 +v 4.337647 -1.989998 -5.906583 +v 5.906583 -1.989998 -4.337647 +v 5.906583 -1.989998 -4.429937 +v 5.906583 -1.989998 -3.599324 +v 5.906583 -1.989998 -3.691614 +v 3.691614 -1.989998 -5.906583 +v 3.599324 -1.989998 -5.906583 +v -2.214968 -1.989998 -5.906583 +v -2.307259 -1.989998 -5.906583 +v 5.906583 -1.990001 2.307259 +v 5.906583 -1.990001 2.214968 +v 5.906583 -1.990002 5.260550 +v 5.906583 -1.990002 5.168260 +v -5.168260 -1.989998 -5.906583 +v -5.260550 -1.989998 -5.906583 +v 0.738323 -1.989998 -5.906583 +v 0.646033 -1.989998 -5.906583 +v 5.906583 -1.990000 -0.646033 +v 5.906583 -1.990000 -0.738323 +v 5.906583 -1.989999 -2.122678 +v 5.906583 -1.989999 -2.214968 +v 2.214968 -1.989998 -5.906583 +v 2.122678 -1.989998 -5.906583 +v -3.691614 -1.989998 -5.906583 +v -3.783905 -1.989998 -5.906583 +v 5.906583 -1.990002 3.783905 +v 5.906583 -1.990002 3.691614 +v 5.906583 -1.990000 0.830613 +v 5.906583 -1.990000 0.738323 +v -0.738323 -1.989998 -5.906583 +v -0.830613 -1.989998 -5.906583 +v 5.168260 -1.989998 -5.906583 +v 5.075970 -1.989998 -5.906583 +v 5.906583 -1.989998 -5.075970 +v 5.906583 -1.989998 -5.168261 +v 5.906583 -1.989998 -4.706809 +v 5.906583 -1.989998 -4.799099 +v 4.799098 -1.989998 -5.906583 +v 4.706808 -1.989998 -5.906583 +v -1.107484 -1.989998 -5.906583 +v -1.199775 -1.989998 -5.906583 +v 5.906583 -1.990001 1.199775 +v 5.906583 -1.990000 1.107484 +v 5.906583 -1.990002 4.153066 +v 5.906583 -1.990002 4.060775 +v -4.060776 -1.989998 -5.906583 +v -4.153066 -1.989998 -5.906583 +v 1.845807 -1.989998 -5.906583 +v 1.753517 -1.989998 -5.906583 +v 5.906583 -1.989999 -1.753517 +v 5.906583 -1.989999 -1.845807 +v 5.906583 -1.990000 -0.276871 +v 5.906583 -1.990000 -0.369161 +v 0.369161 -1.989998 -5.906583 +v 0.276871 -1.989998 -5.906583 +v -5.537421 -1.989998 -5.906583 +v -5.629711 -1.989998 -5.906583 +v 5.906583 -1.990002 5.629711 +v 5.906583 -1.990002 5.537421 +v 5.906583 -1.990001 2.676420 +v 5.906583 -1.990001 2.584130 +v -2.584130 -1.989998 -5.906583 +v -2.676420 -1.989998 -5.906583 +v 3.322453 -1.989998 -5.906583 +v 3.230163 -1.989998 -5.906583 +v 5.906583 -1.989999 -3.230162 +v 5.906583 -1.989999 -3.322453 +v 5.906583 -1.989998 -3.968485 +v 5.906583 -1.989998 -4.060776 +v 4.060776 -1.989998 -5.906583 +v 3.968485 -1.989998 -5.906583 +v -1.845807 -1.989998 -5.906583 +v -1.938097 -1.989998 -5.906583 +v 5.906583 -1.990001 1.938097 +v 5.906583 -1.990001 1.845807 +v 5.906583 -1.990002 4.891388 +v 5.906583 -1.990002 4.799098 +v -4.799098 -1.989998 -5.906583 +v -4.891389 -1.989998 -5.906583 +v 1.107484 -1.989998 -5.906583 +v 1.015194 -1.989998 -5.906583 +v 5.906583 -1.990000 -1.015194 +v 5.906583 -1.990000 -1.107484 +v 5.906583 -1.989999 -2.491840 +v 5.906583 -1.989999 -2.584130 +v 2.584130 -1.989998 -5.906583 +v 2.491840 -1.989998 -5.906583 +v -3.322453 -1.989998 -5.906583 +v -3.414743 -1.989998 -5.906583 +v 5.906583 -1.990001 3.414743 +v 5.906583 -1.990001 3.322453 +v 5.906583 -1.990000 0.461452 +v 5.906583 -1.990000 0.369161 +v -0.369161 -1.989998 -5.906583 +v -0.461452 -1.989998 -5.906583 +v 5.537421 -1.989998 -5.906583 +v 5.445131 -1.989998 -5.906583 +v 5.906583 -1.989998 -5.445132 +v 5.906583 -1.989998 -5.537422 +v 5.906583 -1.989998 -5.260551 +v 5.906583 -1.989998 -5.352841 +v 5.352840 -1.989998 -5.906583 +v 5.260550 -1.989998 -5.906583 +v -0.553742 -1.989998 -5.906583 +v -0.646033 -1.989998 -5.906583 +v 5.906583 -1.990000 0.646032 +v 5.906583 -1.990000 0.553742 +v 5.906583 -1.990002 3.599324 +v 5.906583 -1.990001 3.507034 +v -3.507033 -1.989998 -5.906583 +v -3.599324 -1.989998 -5.906583 +v 2.399549 -1.989998 -5.906583 +v 2.307259 -1.989998 -5.906583 +v 5.906583 -1.989999 -2.307259 +v 5.906583 -1.989999 -2.399549 +v 5.906583 -1.990000 -0.830613 +v 5.906583 -1.990000 -0.922903 +v 0.922904 -1.989998 -5.906583 +v 0.830613 -1.989998 -5.906583 +v -4.983679 -1.989998 -5.906583 +v -5.075970 -1.989998 -5.906583 +v 5.906583 -1.990002 5.075969 +v 5.906583 -1.990002 4.983679 +v 5.906583 -1.990001 2.122678 +v 5.906583 -1.990001 2.030388 +v -2.030388 -1.989998 -5.906583 +v -2.122678 -1.989998 -5.906583 +v 3.876195 -1.989998 -5.906583 +v 3.783905 -1.989998 -5.906583 +v 5.906583 -1.989998 -3.783904 +v 5.906583 -1.989998 -3.876195 +v 5.906583 -1.989999 -3.045582 +v 5.906583 -1.989999 -3.137872 +v 3.137872 -1.989998 -5.906583 +v 3.045582 -1.989998 -5.906583 +v -2.768711 -1.989998 -5.906583 +v -2.861001 -1.989998 -5.906583 +v 5.906583 -1.990001 2.861001 +v 5.906583 -1.990001 2.768711 +v 5.906583 -1.990002 5.814292 +v 5.906583 -1.990002 5.722002 +v -5.722002 -1.989998 -5.906583 +v -5.814293 -1.989998 -5.906583 +v 0.184581 -1.989998 -5.906583 +v 0.092290 -1.989998 -5.906583 +v 5.906583 -1.990000 -0.092290 +v 5.906583 -1.990000 -0.184581 +v 5.906583 -1.989999 -1.568936 +v 5.906583 -1.989999 -1.661227 +v 1.661226 -1.989998 -5.906583 +v 1.568936 -1.989998 -5.906583 +v -4.245357 -1.989998 -5.906583 +v -4.337647 -1.989998 -5.906583 +v 5.906583 -1.990002 4.337646 +v 5.906583 -1.990002 4.245356 +v 5.906583 -1.990001 1.384355 +v 5.906583 -1.990001 1.292065 +v -1.292065 -1.989998 -5.906583 +v -1.384355 -1.989998 -5.906583 +v 4.614518 -1.989998 -5.906583 +v 4.522227 -1.989998 -5.906583 +v 5.906583 -1.989998 -4.522228 +v 5.906583 -1.989998 -4.614518 +v 5.906583 -1.989998 -4.891389 +v 5.906583 -1.989998 -4.983680 +v 4.983679 -1.989998 -5.906583 +v 4.891389 -1.989998 -5.906583 +v -0.922904 -1.989998 -5.906583 +v -1.015194 -1.989998 -5.906583 +v 5.906583 -1.990000 1.015194 +v 5.906583 -1.990000 0.922904 +v 5.906583 -1.990002 3.968486 +v 5.906583 -1.990002 3.876195 +v -3.876195 -1.989998 -5.906583 +v -3.968485 -1.989998 -5.906583 +v 2.030388 -1.989998 -5.906583 +v 1.938097 -1.989998 -5.906583 +v 5.906583 -1.989999 -1.938098 +v 5.906583 -1.989999 -2.030388 +v 5.906583 -1.990000 -0.461452 +v 5.906583 -1.990000 -0.553742 +v 0.553742 -1.989998 -5.906583 +v 0.461452 -1.989998 -5.906583 +v -5.352840 -1.989998 -5.906583 +v -5.445131 -1.989998 -5.906583 +v 5.906583 -1.990002 5.445131 +v 5.906583 -1.990002 5.352840 +v 5.906583 -1.990001 2.491840 +v 5.906583 -1.990001 2.399549 +v -2.399549 -1.989998 -5.906583 +v -2.491840 -1.989998 -5.906583 +v 3.507033 -1.989998 -5.906583 +v 3.414743 -1.989998 -5.906583 +v 5.906583 -1.989999 -3.414743 +v 5.906583 -1.989999 -3.507034 +v 5.906583 -1.989998 -4.153067 +v 5.906583 -1.989998 -4.245357 +v 4.245357 -1.989998 -5.906583 +v 4.153066 -1.989998 -5.906583 +v -1.661226 -1.989998 -5.906583 +v -1.753517 -1.989998 -5.906583 +v 5.906583 -1.990001 1.753517 +v 5.906583 -1.990001 1.661226 +v 5.906583 -1.990002 4.706808 +v 5.906583 -1.990002 4.614517 +v -4.614518 -1.989998 -5.906583 +v -4.706808 -1.989998 -5.906583 +v 1.292065 -1.989998 -5.906583 +v 1.199775 -1.989998 -5.906583 +v 5.906583 -1.989999 -1.199775 +v 5.906583 -1.989999 -1.292065 +v 5.906583 -1.989999 -2.676420 +v 5.906583 -1.989999 -2.768710 +v 2.768711 -1.989998 -5.906583 +v 2.676420 -1.989998 -5.906583 +v -3.137872 -1.989998 -5.906583 +v -3.230163 -1.989998 -5.906583 +v 5.906583 -1.990001 3.230162 +v 5.906583 -1.990001 3.137872 +v 5.906583 -1.990000 0.276871 +v 5.906583 -1.990000 0.184581 +v -0.184581 -1.989998 -5.906583 +v -0.276871 -1.989998 -5.906583 +v 5.722002 -1.989998 -5.906583 +v 5.629711 -1.989998 -5.906583 +v 5.906583 -1.989998 -5.629712 +v 5.906583 -1.989998 -5.722003 +v -5.906583 -1.989999 -1.938098 +v -5.906583 -1.989999 -2.030388 +v -5.906583 -1.989999 -1.845807 +v -5.906583 -1.989999 -2.122678 +v -5.906583 -1.989999 -2.214968 +v -5.906583 -1.989999 -1.568936 +v -5.906583 -1.989999 -1.661227 +v -5.906583 -1.989999 -1.476646 +v -5.906583 -1.989999 -1.753517 +v -5.906583 -1.989999 -2.676420 +v -5.906583 -1.989999 -2.768710 +v -5.906583 -1.989999 -2.584130 +v -5.906583 -1.989999 -2.861001 +v -5.906583 -1.989999 -2.953291 +v -5.906583 -1.989999 -2.307259 +v -5.906583 -1.989999 -2.399549 +v -5.906583 -1.989999 -2.491840 +v -5.906583 -1.990000 -0.461452 +v -5.906583 -1.990000 -0.553742 +v -5.906583 -1.990000 -0.369161 +v -5.906583 -1.990000 -0.646033 +v -5.906583 -1.990000 -0.738323 +v -5.906583 -1.990000 -0.092290 +v -5.906583 -1.990000 -0.184581 +v -5.906583 -1.990000 -0.000000 +v -5.906583 -1.990000 -0.276871 +v -5.906583 -1.989999 -1.199775 +v -5.906583 -1.989999 -1.292065 +v -5.906583 -1.990000 -1.107484 +v -5.906583 -1.989999 -1.384355 +v -5.906583 -1.990000 -0.830613 +v -5.906583 -1.990000 -0.922903 +v -5.906583 -1.990000 -1.015194 +v -5.906583 -1.989998 -4.891389 +v -5.906583 -1.989998 -4.983680 +v -5.906583 -1.989998 -4.799099 +v -5.906583 -1.989998 -5.075970 +v -5.906583 -1.989998 -5.168261 +v -5.906583 -1.989998 -4.522228 +v -5.906583 -1.989998 -4.614518 +v -5.906583 -1.989998 -4.429937 +v -5.906583 -1.989998 -4.706809 +v -5.906583 -1.989998 -5.629712 +v -5.906583 -1.989998 -5.722003 +v -5.906583 -1.989998 -5.537422 +v -5.906583 -1.989998 -5.814293 +v -5.906583 -1.989998 -5.906583 +v -5.906583 -1.989998 -5.260551 +v -5.906583 -1.989998 -5.352841 +v -5.906583 -1.989998 -5.445132 +v -5.906583 -1.989999 -3.414743 +v -5.906583 -1.989999 -3.507034 +v -5.906583 -1.989999 -3.322453 +v -5.906583 -1.989998 -3.599324 +v -5.906583 -1.989998 -3.691614 +v -5.906583 -1.989999 -3.045582 +v -5.906583 -1.989999 -3.137872 +v -5.906583 -1.989999 -3.230162 +v -5.906583 -1.989998 -4.153067 +v -5.906583 -1.989998 -4.245357 +v -5.906583 -1.989998 -4.060776 +v -5.906583 -1.989998 -4.337647 +v -5.906583 -1.989998 -3.783904 +v -5.906583 -1.989998 -3.876195 +v -5.906583 -1.989998 -3.968485 +v -2.030388 -1.990002 5.906582 +v -1.938097 -1.990002 5.906582 +v -1.845807 -1.990002 5.906582 +v -2.214968 -1.990002 5.906582 +v -2.122678 -1.990002 5.906582 +v -1.661226 -1.990002 5.906582 +v -1.568936 -1.990002 5.906582 +v -1.476646 -1.990002 5.906582 +v -1.753517 -1.990002 5.906582 +v -2.768711 -1.990002 5.906582 +v -2.676420 -1.990002 5.906582 +v -2.584130 -1.990002 5.906582 +v -2.953291 -1.990002 5.906582 +v -2.861001 -1.990002 5.906582 +v -2.399549 -1.990002 5.906582 +v -2.307259 -1.990002 5.906582 +v -2.491840 -1.990002 5.906582 +v -0.553742 -1.990002 5.906582 +v -0.461452 -1.990002 5.906582 +v -0.369161 -1.990002 5.906582 +v -0.738323 -1.990002 5.906582 +v -0.646033 -1.990002 5.906582 +v -0.184581 -1.990002 5.906582 +v -0.092290 -1.990002 5.906582 +v 0.000000 -1.990002 5.906582 +v -0.276871 -1.990002 5.906582 +v -1.292065 -1.990002 5.906582 +v -1.199775 -1.990002 5.906582 +v -1.107484 -1.990002 5.906582 +v -1.384355 -1.990002 5.906582 +v -0.922904 -1.990002 5.906582 +v -0.830613 -1.990002 5.906582 +v -1.015194 -1.990002 5.906582 +v -5.906583 -1.990002 3.968486 +v -5.906583 -1.990002 3.876195 +v -5.906583 -1.990002 4.060775 +v -5.906583 -1.990002 3.783905 +v -5.906583 -1.990002 3.691614 +v -5.906583 -1.990002 4.337646 +v -5.906583 -1.990002 4.245356 +v -5.906583 -1.990002 4.429936 +v -5.906583 -1.990002 4.153066 +v -5.906583 -1.990001 3.230162 +v -5.906583 -1.990001 3.137872 +v -5.906583 -1.990001 3.322453 +v -5.906583 -1.990001 3.045582 +v -5.906583 -1.990001 2.953292 +v -5.906583 -1.990002 3.599324 +v -5.906583 -1.990001 3.507034 +v -5.906583 -1.990001 3.414743 +v -4.983679 -1.990002 5.906582 +v -4.891389 -1.990002 5.906582 +v -4.799098 -1.990002 5.906582 +v -5.168260 -1.990002 5.906582 +v -5.075970 -1.990002 5.906582 +v -4.614518 -1.990002 5.906582 +v -4.522227 -1.990002 5.906582 +v -4.429937 -1.990002 5.906582 +v -4.706808 -1.990002 5.906582 +v -5.906583 -1.990002 5.445131 +v -5.906583 -1.990002 5.352840 +v -5.906583 -1.990002 5.537421 +v -5.906583 -1.990002 5.260550 +v -5.906583 -1.990002 5.168260 +v -5.722002 -1.990002 5.906582 +v -5.629711 -1.990002 5.906582 +v -5.537421 -1.990002 5.906582 +v -5.906583 -1.990002 5.814292 +v -5.906583 -1.990002 5.722002 +v -5.906583 -1.990002 5.906582 +v -5.814293 -1.990002 5.906582 +v -5.906583 -1.990002 5.629711 +v -5.352840 -1.990002 5.906582 +v -5.260550 -1.990002 5.906582 +v -5.445131 -1.990002 5.906582 +v -5.906583 -1.990002 4.706808 +v -5.906583 -1.990002 4.614517 +v -5.906583 -1.990002 4.799098 +v -5.906583 -1.990002 4.522227 +v -5.906583 -1.990002 5.075969 +v -5.906583 -1.990002 4.983679 +v -5.906583 -1.990002 4.891388 +v -3.507033 -1.990002 5.906582 +v -3.414743 -1.990002 5.906582 +v -3.322453 -1.990002 5.906582 +v -3.691614 -1.990002 5.906582 +v -3.599324 -1.990002 5.906582 +v -3.137872 -1.990002 5.906582 +v -3.045582 -1.990002 5.906582 +v -3.230163 -1.990002 5.906582 +v -4.245357 -1.990002 5.906582 +v -4.153066 -1.990002 5.906582 +v -4.060776 -1.990002 5.906582 +v -4.337647 -1.990002 5.906582 +v -3.876195 -1.990002 5.906582 +v -3.783905 -1.990002 5.906582 +v -3.968485 -1.990002 5.906582 +v -5.906583 -1.990000 1.015194 +v -5.906583 -1.990000 0.922904 +v -5.906583 -1.990000 1.107484 +v -5.906583 -1.990000 0.830613 +v -5.906583 -1.990000 0.738323 +v -5.906583 -1.990001 1.384355 +v -5.906583 -1.990001 1.292065 +v -5.906583 -1.990001 1.476646 +v -5.906583 -1.990001 1.199775 +v -5.906583 -1.990000 0.276871 +v -5.906583 -1.990000 0.184581 +v -5.906583 -1.990000 0.369161 +v -5.906583 -1.990000 0.092290 +v -5.906583 -1.990000 0.646032 +v -5.906583 -1.990000 0.553742 +v -5.906583 -1.990000 0.461452 +v -5.906583 -1.990001 2.491840 +v -5.906583 -1.990001 2.399549 +v -5.906583 -1.990001 2.584130 +v -5.906583 -1.990001 2.307259 +v -5.906583 -1.990001 2.214968 +v -5.906583 -1.990001 2.861001 +v -5.906583 -1.990001 2.768711 +v -5.906583 -1.990001 2.676420 +v -5.906583 -1.990001 1.753517 +v -5.906583 -1.990001 1.661226 +v -5.906583 -1.990001 1.845807 +v -5.906583 -1.990001 1.568936 +v -5.906583 -1.990001 2.122678 +v -5.906583 -1.990001 2.030388 +v -5.906583 -1.990001 1.938097 +v 3.876195 -1.990002 5.906582 +v 3.968485 -1.990002 5.906582 +v 4.060776 -1.990002 5.906582 +v 3.691614 -1.990002 5.906582 +v 3.783905 -1.990002 5.906582 +v 4.245357 -1.990002 5.906582 +v 4.337647 -1.990002 5.906582 +v 4.429937 -1.990002 5.906582 +v 4.153066 -1.990002 5.906582 +v 3.137872 -1.990002 5.906582 +v 3.230163 -1.990002 5.906582 +v 3.322453 -1.990002 5.906582 +v 2.953291 -1.990002 5.906582 +v 3.045582 -1.990002 5.906582 +v 3.507033 -1.990002 5.906582 +v 3.599324 -1.990002 5.906582 +v 3.414743 -1.990002 5.906582 +v 5.352840 -1.990002 5.906582 +v 5.445131 -1.990002 5.906582 +v 5.537421 -1.990002 5.906582 +v 5.168260 -1.990002 5.906582 +v 5.260550 -1.990002 5.906582 +v 5.722002 -1.990002 5.906582 +v 5.814293 -1.990002 5.906582 +v 5.906583 -1.990002 5.906582 +v 5.629711 -1.990002 5.906582 +v 4.614518 -1.990002 5.906582 +v 4.706808 -1.990002 5.906582 +v 4.799098 -1.990002 5.906582 +v 4.522227 -1.990002 5.906582 +v 4.983679 -1.990002 5.906582 +v 5.075970 -1.990002 5.906582 +v 4.891389 -1.990002 5.906582 +v 0.922904 -1.990002 5.906582 +v 1.015194 -1.990002 5.906582 +v 1.107484 -1.990002 5.906582 +v 0.738323 -1.990002 5.906582 +v 0.830613 -1.990002 5.906582 +v 1.292065 -1.990002 5.906582 +v 1.384355 -1.990002 5.906582 +v 1.476646 -1.990002 5.906582 +v 1.199775 -1.990002 5.906582 +v 0.184581 -1.990002 5.906582 +v 0.276871 -1.990002 5.906582 +v 0.369161 -1.990002 5.906582 +v 0.092290 -1.990002 5.906582 +v 0.553742 -1.990002 5.906582 +v 0.646033 -1.990002 5.906582 +v 0.461452 -1.990002 5.906582 +v 2.399549 -1.990002 5.906582 +v 2.491840 -1.990002 5.906582 +v 2.584130 -1.990002 5.906582 +v 2.214968 -1.990002 5.906582 +v 2.307259 -1.990002 5.906582 +v 2.768711 -1.990002 5.906582 +v 2.861001 -1.990002 5.906582 +v 2.676420 -1.990002 5.906582 +v 1.661226 -1.990002 5.906582 +v 1.753517 -1.990002 5.906582 +v 1.845807 -1.990002 5.906582 +v 1.568936 -1.990002 5.906582 +v 2.030388 -1.990002 5.906582 +v 2.122678 -1.990002 5.906582 +v 1.938097 -1.990002 5.906582 +v 5.906583 0.010002 -5.814293 +v 5.906583 0.010002 -5.906583 +v 5.814293 0.010002 -5.906583 +v 0.000000 0.010002 -5.906583 +v -0.092290 0.010002 -5.906583 +v 5.906583 0.010000 0.092290 +v 5.906583 0.010000 -0.000000 +v 5.906583 0.009999 3.045582 +v 5.906583 0.009999 2.953291 +v -2.953291 0.010002 -5.906583 +v -3.045582 0.010002 -5.906583 +v 2.953291 0.010002 -5.906583 +v 2.861001 0.010002 -5.906583 +v 5.906583 0.010001 -2.861001 +v 5.906583 0.010001 -2.953291 +v 5.906583 0.010001 -1.384355 +v 5.906583 0.010001 -1.476646 +v 1.476646 0.010002 -5.906583 +v 1.384355 0.010002 -5.906583 +v -4.429937 0.010002 -5.906583 +v -4.522227 0.010002 -5.906583 +v 5.906583 0.009998 4.522227 +v 5.906583 0.009998 4.429937 +v 5.906583 0.009999 1.568936 +v 5.906583 0.009999 1.476646 +v -1.476646 0.010002 -5.906583 +v -1.568936 0.010002 -5.906583 +v 4.429937 0.010002 -5.906583 +v 4.337647 0.010002 -5.906583 +v 5.906583 0.010002 -4.337647 +v 5.906583 0.010002 -4.429937 +v 5.906583 0.010001 -3.599324 +v 5.906583 0.010002 -3.691614 +v 3.691614 0.010002 -5.906583 +v 3.599324 0.010002 -5.906583 +v -2.214968 0.010002 -5.906583 +v -2.307259 0.010002 -5.906583 +v 5.906583 0.009999 2.307259 +v 5.906583 0.009999 2.214968 +v 5.906583 0.009998 5.260550 +v 5.906583 0.009998 5.168260 +v -5.168260 0.010002 -5.906583 +v -5.260550 0.010002 -5.906583 +v 0.738323 0.010002 -5.906583 +v 0.646033 0.010002 -5.906583 +v 5.906583 0.010000 -0.646033 +v 5.906583 0.010000 -0.738323 +v 5.906583 0.010001 -2.122678 +v 5.906583 0.010001 -2.214968 +v 2.214968 0.010002 -5.906583 +v 2.122678 0.010002 -5.906583 +v -3.691614 0.010002 -5.906583 +v -3.783905 0.010002 -5.906583 +v 5.906583 0.009998 3.783905 +v 5.906583 0.009998 3.691614 +v 5.906583 0.010000 0.830613 +v 5.906583 0.010000 0.738323 +v -0.738323 0.010002 -5.906583 +v -0.830613 0.010002 -5.906583 +v 5.168260 0.010002 -5.906583 +v 5.075970 0.010002 -5.906583 +v 5.906583 0.010002 -5.075970 +v 5.906583 0.010002 -5.168260 +v 5.906583 0.010002 -4.706808 +v 5.906583 0.010002 -4.799098 +v 4.799098 0.010002 -5.906583 +v 4.706808 0.010002 -5.906583 +v -1.107484 0.010002 -5.906583 +v -1.199775 0.010002 -5.906583 +v 5.906583 0.010000 1.199775 +v 5.906583 0.010000 1.107484 +v 5.906583 0.009998 4.153066 +v 5.906583 0.009998 4.060776 +v -4.060776 0.010002 -5.906583 +v -4.153066 0.010002 -5.906583 +v 1.845807 0.010002 -5.906583 +v 1.753517 0.010002 -5.906583 +v 5.906583 0.010001 -1.753517 +v 5.906583 0.010001 -1.845807 +v 5.906583 0.010000 -0.276871 +v 5.906583 0.010000 -0.369161 +v 0.369161 0.010002 -5.906583 +v 0.276871 0.010002 -5.906583 +v -5.537421 0.010002 -5.906583 +v -5.629711 0.010002 -5.906583 +v 5.906583 0.009998 5.629711 +v 5.906583 0.009998 5.537421 +v 5.906583 0.009999 2.676420 +v 5.906583 0.009999 2.584130 +v -2.584130 0.010002 -5.906583 +v -2.676420 0.010002 -5.906583 +v 3.322453 0.010002 -5.906583 +v 3.230163 0.010002 -5.906583 +v 5.906583 0.010001 -3.230163 +v 5.906583 0.010001 -3.322453 +v 5.906583 0.010002 -3.968485 +v 5.906583 0.010002 -4.060776 +v 4.060776 0.010002 -5.906583 +v 3.968485 0.010002 -5.906583 +v -1.845807 0.010002 -5.906583 +v -1.938097 0.010002 -5.906583 +v 5.906583 0.009999 1.938097 +v 5.906583 0.009999 1.845807 +v 5.906583 0.009998 4.891389 +v 5.906583 0.009998 4.799098 +v -4.799098 0.010002 -5.906583 +v -4.891389 0.010002 -5.906583 +v 1.107484 0.010002 -5.906583 +v 1.015194 0.010002 -5.906583 +v 5.906583 0.010000 -1.015194 +v 5.906583 0.010000 -1.107484 +v 5.906583 0.010001 -2.491840 +v 5.906583 0.010001 -2.584130 +v 2.584130 0.010002 -5.906583 +v 2.491840 0.010002 -5.906583 +v -3.322453 0.010002 -5.906583 +v -3.414743 0.010002 -5.906583 +v 5.906583 0.009999 3.414743 +v 5.906583 0.009999 3.322453 +v 5.906583 0.010000 0.461452 +v 5.906583 0.010000 0.369161 +v -0.369161 0.010002 -5.906583 +v -0.461452 0.010002 -5.906583 +v 5.537421 0.010002 -5.906583 +v 5.445131 0.010002 -5.906583 +v 5.906583 0.010002 -5.445131 +v 5.906583 0.010002 -5.537421 +v 5.906583 0.010002 -5.260550 +v 5.906583 0.010002 -5.352840 +v 5.352840 0.010002 -5.906583 +v 5.260550 0.010002 -5.906583 +v -0.553742 0.010002 -5.906583 +v -0.646033 0.010002 -5.906583 +v 5.906583 0.010000 0.646033 +v 5.906583 0.010000 0.553742 +v 5.906583 0.009999 3.599324 +v 5.906583 0.009999 3.507033 +v -3.507033 0.010002 -5.906583 +v -3.599324 0.010002 -5.906583 +v 2.399549 0.010002 -5.906583 +v 2.307259 0.010002 -5.906583 +v 5.906583 0.010001 -2.307259 +v 5.906583 0.010001 -2.399549 +v 5.906583 0.010000 -0.830613 +v 5.906583 0.010000 -0.922904 +v 0.922904 0.010002 -5.906583 +v 0.830613 0.010002 -5.906583 +v -4.983679 0.010002 -5.906583 +v -5.075970 0.010002 -5.906583 +v 5.906583 0.009998 5.075970 +v 5.906583 0.009998 4.983679 +v 5.906583 0.009999 2.122678 +v 5.906583 0.009999 2.030388 +v -2.030388 0.010002 -5.906583 +v -2.122678 0.010002 -5.906583 +v 3.876195 0.010002 -5.906583 +v 3.783905 0.010002 -5.906583 +v 5.906583 0.010002 -3.783905 +v 5.906583 0.010002 -3.876195 +v 5.906583 0.010001 -3.045582 +v 5.906583 0.010001 -3.137872 +v 3.137872 0.010002 -5.906583 +v 3.045582 0.010002 -5.906583 +v -2.768711 0.010002 -5.906583 +v -2.861001 0.010002 -5.906583 +v 5.906583 0.009999 2.861001 +v 5.906583 0.009999 2.768711 +v 5.906583 0.009998 5.814293 +v 5.906583 0.009998 5.722002 +v -5.722002 0.010002 -5.906583 +v -5.814293 0.010002 -5.906583 +v 0.184581 0.010002 -5.906583 +v 0.092290 0.010002 -5.906583 +v 5.906583 0.010000 -0.092290 +v 5.906583 0.010000 -0.184581 +v 5.906583 0.010001 -1.568936 +v 5.906583 0.010001 -1.661226 +v 1.661226 0.010002 -5.906583 +v 1.568936 0.010002 -5.906583 +v -4.245357 0.010002 -5.906583 +v -4.337647 0.010002 -5.906583 +v 5.906583 0.009998 4.337647 +v 5.906583 0.009998 4.245357 +v 5.906583 0.009999 1.384355 +v 5.906583 0.009999 1.292065 +v -1.292065 0.010002 -5.906583 +v -1.384355 0.010002 -5.906583 +v 4.614518 0.010002 -5.906583 +v 4.522227 0.010002 -5.906583 +v 5.906583 0.010002 -4.522227 +v 5.906583 0.010002 -4.614518 +v 5.906583 0.010002 -4.891389 +v 5.906583 0.010002 -4.983679 +v 4.983679 0.010002 -5.906583 +v 4.891389 0.010002 -5.906583 +v -0.922904 0.010002 -5.906583 +v -1.015194 0.010002 -5.906583 +v 5.906583 0.010000 1.015194 +v 5.906583 0.010000 0.922904 +v 5.906583 0.009998 3.968485 +v 5.906583 0.009998 3.876195 +v -3.876195 0.010002 -5.906583 +v -3.968485 0.010002 -5.906583 +v 2.030388 0.010002 -5.906583 +v 1.938097 0.010002 -5.906583 +v 5.906583 0.010001 -1.938097 +v 5.906583 0.010001 -2.030388 +v 5.906583 0.010000 -0.461452 +v 5.906583 0.010000 -0.553742 +v 0.553742 0.010002 -5.906583 +v 0.461452 0.010002 -5.906583 +v -5.352840 0.010002 -5.906583 +v -5.445131 0.010002 -5.906583 +v 5.906583 0.009998 5.445131 +v 5.906583 0.009998 5.352840 +v 5.906583 0.009999 2.491840 +v 5.906583 0.009999 2.399549 +v -2.399549 0.010002 -5.906583 +v -2.491840 0.010002 -5.906583 +v 3.507033 0.010002 -5.906583 +v 3.414743 0.010002 -5.906583 +v 5.906583 0.010001 -3.414743 +v 5.906583 0.010001 -3.507033 +v 5.906583 0.010002 -4.153066 +v 5.906583 0.010002 -4.245357 +v 4.245357 0.010002 -5.906583 +v 4.153066 0.010002 -5.906583 +v -1.661226 0.010002 -5.906583 +v -1.753517 0.010002 -5.906583 +v 5.906583 0.009999 1.753517 +v 5.906583 0.009999 1.661226 +v 5.906583 0.009998 4.706808 +v 5.906583 0.009998 4.614518 +v -4.614518 0.010002 -5.906583 +v -4.706808 0.010002 -5.906583 +v 1.292065 0.010002 -5.906583 +v 1.199775 0.010002 -5.906583 +v 5.906583 0.010000 -1.199775 +v 5.906583 0.010001 -1.292065 +v 5.906583 0.010001 -2.676420 +v 5.906583 0.010001 -2.768711 +v 2.768711 0.010002 -5.906583 +v 2.676420 0.010002 -5.906583 +v -3.137872 0.010002 -5.906583 +v -3.230163 0.010002 -5.906583 +v 5.906583 0.009999 3.230163 +v 5.906583 0.009999 3.137872 +v 5.906583 0.010000 0.276871 +v 5.906583 0.010000 0.184581 +v -0.184581 0.010002 -5.906583 +v -0.276871 0.010002 -5.906583 +v 5.722002 0.010002 -5.906583 +v 5.629711 0.010002 -5.906583 +v 5.906583 0.010002 -5.629711 +v 5.906583 0.010002 -5.722002 +v -5.906583 0.010001 -1.938097 +v -5.906583 0.010001 -2.030388 +v -5.906583 0.010001 -1.845807 +v -5.906583 0.010001 -2.122678 +v -5.906583 0.010001 -2.214968 +v -5.906583 0.010001 -1.568936 +v -5.906583 0.010001 -1.661226 +v -5.906583 0.010001 -1.476646 +v -5.906583 0.010001 -1.753517 +v -5.906583 0.010001 -2.676420 +v -5.906583 0.010001 -2.768711 +v -5.906583 0.010001 -2.584130 +v -5.906583 0.010001 -2.861001 +v -5.906583 0.010001 -2.953291 +v -5.906583 0.010001 -2.307259 +v -5.906583 0.010001 -2.399549 +v -5.906583 0.010001 -2.491840 +v -5.906583 0.010000 -0.461452 +v -5.906583 0.010000 -0.553742 +v -5.906583 0.010000 -0.369161 +v -5.906583 0.010000 -0.646033 +v -5.906583 0.010000 -0.738323 +v -5.906583 0.010000 -0.092290 +v -5.906583 0.010000 -0.184581 +v -5.906583 0.010000 -0.000000 +v -5.906583 0.010000 -0.276871 +v -5.906583 0.010000 -1.199775 +v -5.906583 0.010001 -1.292065 +v -5.906583 0.010000 -1.107484 +v -5.906583 0.010001 -1.384355 +v -5.906583 0.010000 -0.830613 +v -5.906583 0.010000 -0.922904 +v -5.906583 0.010000 -1.015194 +v -5.906583 0.010002 -4.891389 +v -5.906583 0.010002 -4.983679 +v -5.906583 0.010002 -4.799098 +v -5.906583 0.010002 -5.075970 +v -5.906583 0.010002 -5.168260 +v -5.906583 0.010002 -4.522227 +v -5.906583 0.010002 -4.614518 +v -5.906583 0.010002 -4.429937 +v -5.906583 0.010002 -4.706808 +v -5.906583 0.010002 -5.629711 +v -5.906583 0.010002 -5.722002 +v -5.906583 0.010002 -5.537421 +v -5.906583 0.010002 -5.814293 +v -5.906583 0.010002 -5.906583 +v -5.906583 0.010002 -5.260550 +v -5.906583 0.010002 -5.352840 +v -5.906583 0.010002 -5.445131 +v -5.906583 0.010001 -3.414743 +v -5.906583 0.010001 -3.507033 +v -5.906583 0.010001 -3.322453 +v -5.906583 0.010001 -3.599324 +v -5.906583 0.010002 -3.691614 +v -5.906583 0.010001 -3.045582 +v -5.906583 0.010001 -3.137872 +v -5.906583 0.010001 -3.230163 +v -5.906583 0.010002 -4.153066 +v -5.906583 0.010002 -4.245357 +v -5.906583 0.010002 -4.060776 +v -5.906583 0.010002 -4.337647 +v -5.906583 0.010002 -3.783905 +v -5.906583 0.010002 -3.876195 +v -5.906583 0.010002 -3.968485 +v -2.030388 0.009998 5.906583 +v -1.938097 0.009998 5.906583 +v -1.845807 0.009998 5.906583 +v -2.214968 0.009998 5.906583 +v -2.122678 0.009998 5.906583 +v -1.661226 0.009998 5.906583 +v -1.568936 0.009998 5.906583 +v -1.476646 0.009998 5.906583 +v -1.753517 0.009998 5.906583 +v -2.768711 0.009998 5.906583 +v -2.676420 0.009998 5.906583 +v -2.584130 0.009998 5.906583 +v -2.953291 0.009998 5.906583 +v -2.861001 0.009998 5.906583 +v -2.399549 0.009998 5.906583 +v -2.307259 0.009998 5.906583 +v -2.491840 0.009998 5.906583 +v -0.553742 0.009998 5.906583 +v -0.461452 0.009998 5.906583 +v -0.369161 0.009998 5.906583 +v -0.738323 0.009998 5.906583 +v -0.646033 0.009998 5.906583 +v -0.184581 0.009998 5.906583 +v -0.092290 0.009998 5.906583 +v 0.000000 0.009998 5.906583 +v -0.276871 0.009998 5.906583 +v -1.292065 0.009998 5.906583 +v -1.199775 0.009998 5.906583 +v -1.107484 0.009998 5.906583 +v -1.384355 0.009998 5.906583 +v -0.922904 0.009998 5.906583 +v -0.830613 0.009998 5.906583 +v -1.015194 0.009998 5.906583 +v -5.906583 0.009998 3.968485 +v -5.906583 0.009998 3.876195 +v -5.906583 0.009998 4.060776 +v -5.906583 0.009998 3.783905 +v -5.906583 0.009998 3.691614 +v -5.906583 0.009998 4.337647 +v -5.906583 0.009998 4.245357 +v -5.906583 0.009998 4.429937 +v -5.906583 0.009998 4.153066 +v -5.906583 0.009999 3.230163 +v -5.906583 0.009999 3.137872 +v -5.906583 0.009999 3.322453 +v -5.906583 0.009999 3.045582 +v -5.906583 0.009999 2.953291 +v -5.906583 0.009999 3.599324 +v -5.906583 0.009999 3.507033 +v -5.906583 0.009999 3.414743 +v -4.983679 0.009998 5.906583 +v -4.891389 0.009998 5.906583 +v -4.799098 0.009998 5.906583 +v -5.168260 0.009998 5.906583 +v -5.075970 0.009998 5.906583 +v -4.614518 0.009998 5.906583 +v -4.522227 0.009998 5.906583 +v -4.429937 0.009998 5.906583 +v -4.706808 0.009998 5.906583 +v -5.906583 0.009998 5.445131 +v -5.906583 0.009998 5.352840 +v -5.906583 0.009998 5.537421 +v -5.906583 0.009998 5.260550 +v -5.906583 0.009998 5.168260 +v -5.722002 0.009998 5.906583 +v -5.629711 0.009998 5.906583 +v -5.537421 0.009998 5.906583 +v -5.906583 0.009998 5.814293 +v -5.906583 0.009998 5.722002 +v -5.906583 0.009998 5.906583 +v -5.814293 0.009998 5.906583 +v -5.906583 0.009998 5.629711 +v -5.352840 0.009998 5.906583 +v -5.260550 0.009998 5.906583 +v -5.445131 0.009998 5.906583 +v -5.906583 0.009998 4.706808 +v -5.906583 0.009998 4.614518 +v -5.906583 0.009998 4.799098 +v -5.906583 0.009998 4.522227 +v -5.906583 0.009998 5.075970 +v -5.906583 0.009998 4.983679 +v -5.906583 0.009998 4.891389 +v -3.507033 0.009998 5.906583 +v -3.414743 0.009998 5.906583 +v -3.322453 0.009998 5.906583 +v -3.691614 0.009998 5.906583 +v -3.599324 0.009998 5.906583 +v -3.137872 0.009998 5.906583 +v -3.045582 0.009998 5.906583 +v -3.230163 0.009998 5.906583 +v -4.245357 0.009998 5.906583 +v -4.153066 0.009998 5.906583 +v -4.060776 0.009998 5.906583 +v -4.337647 0.009998 5.906583 +v -3.876195 0.009998 5.906583 +v -3.783905 0.009998 5.906583 +v -3.968485 0.009998 5.906583 +v -5.906583 0.010000 1.015194 +v -5.906583 0.010000 0.922904 +v -5.906583 0.010000 1.107484 +v -5.906583 0.010000 0.830613 +v -5.906583 0.010000 0.738323 +v -5.906583 0.009999 1.384355 +v -5.906583 0.009999 1.292065 +v -5.906583 0.009999 1.476646 +v -5.906583 0.010000 1.199775 +v -5.906583 0.010000 0.276871 +v -5.906583 0.010000 0.184581 +v -5.906583 0.010000 0.369161 +v -5.906583 0.010000 0.092290 +v -5.906583 0.010000 0.646033 +v -5.906583 0.010000 0.553742 +v -5.906583 0.010000 0.461452 +v -5.906583 0.009999 2.491840 +v -5.906583 0.009999 2.399549 +v -5.906583 0.009999 2.584130 +v -5.906583 0.009999 2.307259 +v -5.906583 0.009999 2.214968 +v -5.906583 0.009999 2.861001 +v -5.906583 0.009999 2.768711 +v -5.906583 0.009999 2.676420 +v -5.906583 0.009999 1.753517 +v -5.906583 0.009999 1.661226 +v -5.906583 0.009999 1.845807 +v -5.906583 0.009999 1.568936 +v -5.906583 0.009999 2.122678 +v -5.906583 0.009999 2.030388 +v -5.906583 0.009999 1.938097 +v 3.876195 0.009998 5.906583 +v 3.968485 0.009998 5.906583 +v 4.060776 0.009998 5.906583 +v 3.691614 0.009998 5.906583 +v 3.783905 0.009998 5.906583 +v 4.245357 0.009998 5.906583 +v 4.337647 0.009998 5.906583 +v 4.429937 0.009998 5.906583 +v 4.153066 0.009998 5.906583 +v 3.137872 0.009998 5.906583 +v 3.230163 0.009998 5.906583 +v 3.322453 0.009998 5.906583 +v 2.953291 0.009998 5.906583 +v 3.045582 0.009998 5.906583 +v 3.507033 0.009998 5.906583 +v 3.599324 0.009998 5.906583 +v 3.414743 0.009998 5.906583 +v 5.352840 0.009998 5.906583 +v 5.445131 0.009998 5.906583 +v 5.537421 0.009998 5.906583 +v 5.168260 0.009998 5.906583 +v 5.260550 0.009998 5.906583 +v 5.722002 0.009998 5.906583 +v 5.814293 0.009998 5.906583 +v 5.906583 0.009998 5.906583 +v 5.629711 0.009998 5.906583 +v 4.614518 0.009998 5.906583 +v 4.706808 0.009998 5.906583 +v 4.799098 0.009998 5.906583 +v 4.522227 0.009998 5.906583 +v 4.983679 0.009998 5.906583 +v 5.075970 0.009998 5.906583 +v 4.891389 0.009998 5.906583 +v 0.922904 0.009998 5.906583 +v 1.015194 0.009998 5.906583 +v 1.107484 0.009998 5.906583 +v 0.738323 0.009998 5.906583 +v 0.830613 0.009998 5.906583 +v 1.292065 0.009998 5.906583 +v 1.384355 0.009998 5.906583 +v 1.476646 0.009998 5.906583 +v 1.199775 0.009998 5.906583 +v 0.184581 0.009998 5.906583 +v 0.276871 0.009998 5.906583 +v 0.369161 0.009998 5.906583 +v 0.092290 0.009998 5.906583 +v 0.553742 0.009998 5.906583 +v 0.646033 0.009998 5.906583 +v 0.461452 0.009998 5.906583 +v 2.399549 0.009998 5.906583 +v 2.491840 0.009998 5.906583 +v 2.584130 0.009998 5.906583 +v 2.214968 0.009998 5.906583 +v 2.307259 0.009998 5.906583 +v 2.768711 0.009998 5.906583 +v 2.861001 0.009998 5.906583 +v 2.676420 0.009998 5.906583 +v 1.661226 0.009998 5.906583 +v 1.753517 0.009998 5.906583 +v 1.845807 0.009998 5.906583 +v 1.568936 0.009998 5.906583 +v 2.030388 0.009998 5.906583 +v 2.122678 0.009998 5.906583 +v 1.938097 0.009998 5.906583 +v 5.814293 0.010002 -5.814293 +v 5.906583 0.010002 -5.814293 +v 5.906583 0.010002 -5.906583 +v 5.814293 0.010002 -5.906583 +v -0.092290 0.010002 -5.814293 +v 0.000000 0.010002 -5.814293 +v 0.000000 0.010002 -5.906583 +v -0.092290 0.010002 -5.906583 +v -0.092290 0.010000 0.092290 +v 0.000000 0.010000 0.092290 +v 0.000000 0.010000 -0.000000 +v -0.092290 0.010000 -0.000000 +v 5.814293 0.010000 0.092290 +v 5.906583 0.010000 0.092290 +v 5.906583 0.010000 -0.000000 +v 5.814293 0.010000 -0.000000 +v 2.861001 0.010000 0.092290 +v 2.953291 0.010000 0.092290 +v 2.953291 0.010000 -0.000000 +v 2.861001 0.010000 -0.000000 +v 2.861001 0.009999 3.045582 +v 2.953291 0.009999 3.045582 +v 2.953291 0.009999 2.953291 +v 2.861001 0.009999 2.953291 +v 5.814293 0.009999 3.045582 +v 5.906583 0.009999 3.045582 +v 5.906583 0.009999 2.953291 +v 5.814293 0.009999 2.953291 +v -3.045582 0.010000 0.092290 +v -2.953291 0.010000 0.092290 +v -2.953291 0.010000 -0.000000 +v -3.045582 0.010000 -0.000000 +v -3.045582 0.009999 3.045582 +v -2.953291 0.009999 3.045582 +v -2.953291 0.009999 2.953291 +v -3.045582 0.009999 2.953291 +v -0.092290 0.009999 3.045582 +v 0.000000 0.009999 3.045582 +v 0.000000 0.009999 2.953291 +v -0.092290 0.009999 2.953291 +v -3.045582 0.010002 -5.814293 +v -2.953291 0.010002 -5.814293 +v -2.953291 0.010002 -5.906583 +v -3.045582 0.010002 -5.906583 +v -3.045582 0.010001 -2.861001 +v -2.953291 0.010001 -2.861001 +v -2.953291 0.010001 -2.953291 +v -3.045582 0.010001 -2.953291 +v -0.092290 0.010001 -2.861001 +v 0.000000 0.010001 -2.861001 +v 0.000000 0.010001 -2.953291 +v -0.092290 0.010001 -2.953291 +v 2.861001 0.010002 -5.814293 +v 2.953291 0.010002 -5.814293 +v 2.953291 0.010002 -5.906583 +v 2.861001 0.010002 -5.906583 +v 2.861001 0.010001 -2.861001 +v 2.953291 0.010001 -2.861001 +v 2.953291 0.010001 -2.953291 +v 2.861001 0.010001 -2.953291 +v 5.814293 0.010001 -2.861001 +v 5.906583 0.010001 -2.861001 +v 5.906583 0.010001 -2.953291 +v 5.814293 0.010001 -2.953291 +v 4.337647 0.010001 -2.861001 +v 4.429937 0.010001 -2.861001 +v 4.429937 0.010001 -2.953291 +v 4.337647 0.010001 -2.953291 +v 4.337647 0.010001 -1.384355 +v 4.429937 0.010001 -1.384355 +v 4.429937 0.010001 -1.476646 +v 4.337647 0.010001 -1.476646 +v 5.814293 0.010001 -1.384355 +v 5.906583 0.010001 -1.384355 +v 5.906583 0.010001 -1.476646 +v 5.814293 0.010001 -1.476646 +v 1.384355 0.010001 -2.861001 +v 1.476646 0.010001 -2.861001 +v 1.476646 0.010001 -2.953291 +v 1.384355 0.010001 -2.953291 +v 1.384355 0.010001 -1.384355 +v 1.476646 0.010001 -1.384355 +v 1.476646 0.010001 -1.476646 +v 1.384355 0.010001 -1.476646 +v 2.861001 0.010001 -1.384355 +v 2.953291 0.010001 -1.384355 +v 2.953291 0.010001 -1.476646 +v 2.861001 0.010001 -1.476646 +v 1.384355 0.010002 -5.814293 +v 1.476646 0.010002 -5.814293 +v 1.476646 0.010002 -5.906583 +v 1.384355 0.010002 -5.906583 +v 1.384355 0.010002 -4.337647 +v 1.476646 0.010002 -4.337647 +v 1.476646 0.010002 -4.429937 +v 1.384355 0.010002 -4.429937 +v 2.861001 0.010002 -4.337647 +v 2.953291 0.010002 -4.337647 +v 2.953291 0.010002 -4.429937 +v 2.861001 0.010002 -4.429937 +v -1.568936 0.010001 -2.861001 +v -1.476646 0.010001 -2.861001 +v -1.476646 0.010001 -2.953291 +v -1.568936 0.010001 -2.953291 +v -1.568936 0.010001 -1.384355 +v -1.476646 0.010001 -1.384355 +v -1.476646 0.010001 -1.476646 +v -1.568936 0.010001 -1.476646 +v -0.092290 0.010001 -1.384355 +v 0.000000 0.010001 -1.384355 +v 0.000000 0.010001 -1.476646 +v -0.092290 0.010001 -1.476646 +v -4.522227 0.010001 -2.861001 +v -4.429937 0.010001 -2.861001 +v -4.429937 0.010001 -2.953291 +v -4.522227 0.010001 -2.953291 +v -4.522227 0.010001 -1.384355 +v -4.429937 0.010001 -1.384355 +v -4.429937 0.010001 -1.476646 +v -4.522227 0.010001 -1.476646 +v -3.045582 0.010001 -1.384355 +v -2.953291 0.010001 -1.384355 +v -2.953291 0.010001 -1.476646 +v -3.045582 0.010001 -1.476646 +v -4.522227 0.010002 -5.814293 +v -4.429937 0.010002 -5.814293 +v -4.429937 0.010002 -5.906583 +v -4.522227 0.010002 -5.906583 +v -4.522227 0.010002 -4.337647 +v -4.429937 0.010002 -4.337647 +v -4.429937 0.010002 -4.429937 +v -4.522227 0.010002 -4.429937 +v -3.045582 0.010002 -4.337647 +v -2.953291 0.010002 -4.337647 +v -2.953291 0.010002 -4.429937 +v -3.045582 0.010002 -4.429937 +v -1.568936 0.009999 3.045582 +v -1.476646 0.009999 3.045582 +v -1.476646 0.009999 2.953291 +v -1.568936 0.009999 2.953291 +v -1.568936 0.009998 4.522227 +v -1.476646 0.009998 4.522227 +v -1.476646 0.009998 4.429937 +v -1.568936 0.009998 4.429937 +v -0.092290 0.009998 4.522227 +v 0.000000 0.009998 4.522227 +v 0.000000 0.009998 4.429937 +v -0.092290 0.009998 4.429937 +v -4.522227 0.009999 3.045582 +v -4.429937 0.009999 3.045582 +v -4.429937 0.009999 2.953291 +v -4.522227 0.009999 2.953291 +v -4.522227 0.009998 4.522227 +v -4.429937 0.009998 4.522227 +v -4.429937 0.009998 4.429937 +v -4.522227 0.009998 4.429937 +v -3.045582 0.009998 4.522227 +v -2.953291 0.009998 4.522227 +v -2.953291 0.009998 4.429937 +v -3.045582 0.009998 4.429937 +v -4.522227 0.010000 0.092290 +v -4.429937 0.010000 0.092290 +v -4.429937 0.010000 -0.000000 +v -4.522227 0.010000 -0.000000 +v -4.522227 0.009999 1.568936 +v -4.429937 0.009999 1.568936 +v -4.429937 0.009999 1.476646 +v -4.522227 0.009999 1.476646 +v -3.045582 0.009999 1.568936 +v -2.953291 0.009999 1.568936 +v -2.953291 0.009999 1.476646 +v -3.045582 0.009999 1.476646 +v 4.337647 0.009999 3.045582 +v 4.429937 0.009999 3.045582 +v 4.429937 0.009999 2.953291 +v 4.337647 0.009999 2.953291 +v 4.337647 0.009998 4.522227 +v 4.429937 0.009998 4.522227 +v 4.429937 0.009998 4.429937 +v 4.337647 0.009998 4.429937 +v 5.814293 0.009998 4.522227 +v 5.906583 0.009998 4.522227 +v 5.906583 0.009998 4.429937 +v 5.814293 0.009998 4.429937 +v 1.384355 0.009999 3.045582 +v 1.476646 0.009999 3.045582 +v 1.476646 0.009999 2.953291 +v 1.384355 0.009999 2.953291 +v 1.384355 0.009998 4.522227 +v 1.476646 0.009998 4.522227 +v 1.476646 0.009998 4.429937 +v 1.384355 0.009998 4.429937 +v 2.861001 0.009998 4.522227 +v 2.953291 0.009998 4.522227 +v 2.953291 0.009998 4.429937 +v 2.861001 0.009998 4.429937 +v 1.384355 0.010000 0.092290 +v 1.476646 0.010000 0.092290 +v 1.476646 0.010000 -0.000000 +v 1.384355 0.010000 -0.000000 +v 1.384355 0.009999 1.568936 +v 1.476646 0.009999 1.568936 +v 1.476646 0.009999 1.476646 +v 1.384355 0.009999 1.476646 +v 2.861001 0.009999 1.568936 +v 2.953291 0.009999 1.568936 +v 2.953291 0.009999 1.476646 +v 2.861001 0.009999 1.476646 +v 4.337647 0.010000 0.092290 +v 4.429937 0.010000 0.092290 +v 4.429937 0.010000 -0.000000 +v 4.337647 0.010000 -0.000000 +v 4.337647 0.009999 1.568936 +v 4.429937 0.009999 1.568936 +v 4.429937 0.009999 1.476646 +v 4.337647 0.009999 1.476646 +v 5.814293 0.009999 1.568936 +v 5.906583 0.009999 1.568936 +v 5.906583 0.009999 1.476646 +v 5.814293 0.009999 1.476646 +v -1.568936 0.010000 0.092290 +v -1.476646 0.010000 0.092290 +v -1.476646 0.010000 -0.000000 +v -1.568936 0.010000 -0.000000 +v -1.568936 0.009999 1.568936 +v -1.476646 0.009999 1.568936 +v -1.476646 0.009999 1.476646 +v -1.568936 0.009999 1.476646 +v -0.092290 0.009999 1.568936 +v 0.000000 0.009999 1.568936 +v 0.000000 0.009999 1.476646 +v -0.092290 0.009999 1.476646 +v -1.568936 0.010002 -5.814293 +v -1.476646 0.010002 -5.814293 +v -1.476646 0.010002 -5.906583 +v -1.568936 0.010002 -5.906583 +v -1.568936 0.010002 -4.337647 +v -1.476646 0.010002 -4.337647 +v -1.476646 0.010002 -4.429937 +v -1.568936 0.010002 -4.429937 +v -0.092290 0.010002 -4.337647 +v 0.000000 0.010002 -4.337647 +v 0.000000 0.010002 -4.429937 +v -0.092290 0.010002 -4.429937 +v 4.337647 0.010002 -5.814293 +v 4.429937 0.010002 -5.814293 +v 4.429937 0.010002 -5.906583 +v 4.337647 0.010002 -5.906583 +v 4.337647 0.010002 -4.337647 +v 4.429937 0.010002 -4.337647 +v 4.429937 0.010002 -4.429937 +v 4.337647 0.010002 -4.429937 +v 5.814293 0.010002 -4.337647 +v 5.906583 0.010002 -4.337647 +v 5.906583 0.010002 -4.429937 +v 5.814293 0.010002 -4.429937 +v 5.075970 0.010002 -4.337647 +v 5.168260 0.010002 -4.337647 +v 5.168260 0.010002 -4.429937 +v 5.075970 0.010002 -4.429937 +v 5.075970 0.010001 -3.599324 +v 5.168260 0.010001 -3.599324 +v 5.168260 0.010002 -3.691614 +v 5.075970 0.010002 -3.691614 +v 5.814293 0.010001 -3.599324 +v 5.906583 0.010001 -3.599324 +v 5.906583 0.010002 -3.691614 +v 5.814293 0.010002 -3.691614 +v 3.599324 0.010002 -4.337647 +v 3.691614 0.010002 -4.337647 +v 3.691614 0.010002 -4.429937 +v 3.599324 0.010002 -4.429937 +v 3.599324 0.010001 -3.599324 +v 3.691614 0.010001 -3.599324 +v 3.691614 0.010002 -3.691614 +v 3.599324 0.010002 -3.691614 +v 4.337647 0.010001 -3.599324 +v 4.429937 0.010001 -3.599324 +v 4.429937 0.010002 -3.691614 +v 4.337647 0.010002 -3.691614 +v 3.599324 0.010002 -5.814293 +v 3.691614 0.010002 -5.814293 +v 3.691614 0.010002 -5.906583 +v 3.599324 0.010002 -5.906583 +v 3.599324 0.010002 -5.075970 +v 3.691614 0.010002 -5.075970 +v 3.691614 0.010002 -5.168260 +v 3.599324 0.010002 -5.168260 +v 4.337647 0.010002 -5.075970 +v 4.429937 0.010002 -5.075970 +v 4.429937 0.010002 -5.168260 +v 4.337647 0.010002 -5.168260 +v -0.830613 0.010002 -4.337647 +v -0.738323 0.010002 -4.337647 +v -0.738323 0.010002 -4.429937 +v -0.830613 0.010002 -4.429937 +v -0.830613 0.010001 -3.599324 +v -0.738323 0.010001 -3.599324 +v -0.738323 0.010002 -3.691614 +v -0.830613 0.010002 -3.691614 +v -0.092290 0.010001 -3.599324 +v 0.000000 0.010001 -3.599324 +v 0.000000 0.010002 -3.691614 +v -0.092290 0.010002 -3.691614 +v -2.307259 0.010002 -4.337647 +v -2.214968 0.010002 -4.337647 +v -2.214968 0.010002 -4.429937 +v -2.307259 0.010002 -4.429937 +v -2.307259 0.010001 -3.599324 +v -2.214968 0.010001 -3.599324 +v -2.214968 0.010002 -3.691614 +v -2.307259 0.010002 -3.691614 +v -1.568936 0.010001 -3.599324 +v -1.476646 0.010001 -3.599324 +v -1.476646 0.010002 -3.691614 +v -1.568936 0.010002 -3.691614 +v -2.307259 0.010002 -5.814293 +v -2.214968 0.010002 -5.814293 +v -2.214968 0.010002 -5.906583 +v -2.307259 0.010002 -5.906583 +v -2.307259 0.010002 -5.075970 +v -2.214968 0.010002 -5.075970 +v -2.214968 0.010002 -5.168260 +v -2.307259 0.010002 -5.168260 +v -1.568936 0.010002 -5.075970 +v -1.476646 0.010002 -5.075970 +v -1.476646 0.010002 -5.168260 +v -1.568936 0.010002 -5.168260 +v -0.830613 0.009999 1.568936 +v -0.738323 0.009999 1.568936 +v -0.738323 0.009999 1.476646 +v -0.830613 0.009999 1.476646 +v -0.830613 0.009999 2.307259 +v -0.738323 0.009999 2.307259 +v -0.738323 0.009999 2.214968 +v -0.830613 0.009999 2.214968 +v -0.092290 0.009999 2.307259 +v 0.000000 0.009999 2.307259 +v 0.000000 0.009999 2.214968 +v -0.092290 0.009999 2.214968 +v -2.307259 0.009999 1.568936 +v -2.214968 0.009999 1.568936 +v -2.214968 0.009999 1.476646 +v -2.307259 0.009999 1.476646 +v -2.307259 0.009999 2.307259 +v -2.214968 0.009999 2.307259 +v -2.214968 0.009999 2.214968 +v -2.307259 0.009999 2.214968 +v -1.568936 0.009999 2.307259 +v -1.476646 0.009999 2.307259 +v -1.476646 0.009999 2.214968 +v -1.568936 0.009999 2.214968 +v -2.307259 0.010000 0.092290 +v -2.214968 0.010000 0.092290 +v -2.214968 0.010000 -0.000000 +v -2.307259 0.010000 -0.000000 +v -2.307259 0.010000 0.830613 +v -2.214968 0.010000 0.830613 +v -2.214968 0.010000 0.738323 +v -2.307259 0.010000 0.738323 +v -1.568936 0.010000 0.830613 +v -1.476646 0.010000 0.830613 +v -1.476646 0.010000 0.738323 +v -1.568936 0.010000 0.738323 +v 5.075970 0.009999 1.568936 +v 5.168260 0.009999 1.568936 +v 5.168260 0.009999 1.476646 +v 5.075970 0.009999 1.476646 +v 5.075970 0.009999 2.307259 +v 5.168260 0.009999 2.307259 +v 5.168260 0.009999 2.214968 +v 5.075970 0.009999 2.214968 +v 5.814293 0.009999 2.307259 +v 5.906583 0.009999 2.307259 +v 5.906583 0.009999 2.214968 +v 5.814293 0.009999 2.214968 +v 3.599324 0.009999 1.568936 +v 3.691614 0.009999 1.568936 +v 3.691614 0.009999 1.476646 +v 3.599324 0.009999 1.476646 +v 3.599324 0.009999 2.307259 +v 3.691614 0.009999 2.307259 +v 3.691614 0.009999 2.214968 +v 3.599324 0.009999 2.214968 +v 4.337647 0.009999 2.307259 +v 4.429937 0.009999 2.307259 +v 4.429937 0.009999 2.214968 +v 4.337647 0.009999 2.214968 +v 3.599324 0.010000 0.092290 +v 3.691614 0.010000 0.092290 +v 3.691614 0.010000 -0.000000 +v 3.599324 0.010000 -0.000000 +v 3.599324 0.010000 0.830613 +v 3.691614 0.010000 0.830613 +v 3.691614 0.010000 0.738323 +v 3.599324 0.010000 0.738323 +v 4.337647 0.010000 0.830613 +v 4.429937 0.010000 0.830613 +v 4.429937 0.010000 0.738323 +v 4.337647 0.010000 0.738323 +v 2.122678 0.009999 1.568936 +v 2.214968 0.009999 1.568936 +v 2.214968 0.009999 1.476646 +v 2.122678 0.009999 1.476646 +v 2.122678 0.009999 2.307259 +v 2.214968 0.009999 2.307259 +v 2.214968 0.009999 2.214968 +v 2.122678 0.009999 2.214968 +v 2.861001 0.009999 2.307259 +v 2.953291 0.009999 2.307259 +v 2.953291 0.009999 2.214968 +v 2.861001 0.009999 2.214968 +v 0.646033 0.009999 1.568936 +v 0.738323 0.009999 1.568936 +v 0.738323 0.009999 1.476646 +v 0.646033 0.009999 1.476646 +v 0.646033 0.009999 2.307259 +v 0.738323 0.009999 2.307259 +v 0.738323 0.009999 2.214968 +v 0.646033 0.009999 2.214968 +v 1.384355 0.009999 2.307259 +v 1.476646 0.009999 2.307259 +v 1.476646 0.009999 2.214968 +v 1.384355 0.009999 2.214968 +v 0.646033 0.010000 0.092290 +v 0.738323 0.010000 0.092290 +v 0.738323 0.010000 -0.000000 +v 0.646033 0.010000 -0.000000 +v 0.646033 0.010000 0.830613 +v 0.738323 0.010000 0.830613 +v 0.738323 0.010000 0.738323 +v 0.646033 0.010000 0.738323 +v 1.384355 0.010000 0.830613 +v 1.476646 0.010000 0.830613 +v 1.476646 0.010000 0.738323 +v 1.384355 0.010000 0.738323 +v 2.122678 0.009998 4.522227 +v 2.214968 0.009998 4.522227 +v 2.214968 0.009998 4.429937 +v 2.122678 0.009998 4.429937 +v 2.122678 0.009998 5.260550 +v 2.214968 0.009998 5.260550 +v 2.214968 0.009998 5.168260 +v 2.122678 0.009998 5.168260 +v 2.861001 0.009998 5.260550 +v 2.953291 0.009998 5.260550 +v 2.953291 0.009998 5.168260 +v 2.861001 0.009998 5.168260 +v 0.646033 0.009998 4.522227 +v 0.738323 0.009998 4.522227 +v 0.738323 0.009998 4.429937 +v 0.646033 0.009998 4.429937 +v 0.646033 0.009998 5.260550 +v 0.738323 0.009998 5.260550 +v 0.738323 0.009998 5.168260 +v 0.646033 0.009998 5.168260 +v 1.384355 0.009998 5.260550 +v 1.476646 0.009998 5.260550 +v 1.476646 0.009998 5.168260 +v 1.384355 0.009998 5.168260 +v 0.646033 0.009999 3.045582 +v 0.738323 0.009999 3.045582 +v 0.738323 0.009999 2.953291 +v 0.646033 0.009999 2.953291 +v 0.646033 0.009998 3.783905 +v 0.738323 0.009998 3.783905 +v 0.738323 0.009998 3.691614 +v 0.646033 0.009998 3.691614 +v 1.384355 0.009998 3.783905 +v 1.476646 0.009998 3.783905 +v 1.476646 0.009998 3.691614 +v 1.384355 0.009998 3.691614 +v 5.075970 0.009998 4.522227 +v 5.168260 0.009998 4.522227 +v 5.168260 0.009998 4.429937 +v 5.075970 0.009998 4.429937 +v 5.075970 0.009998 5.260550 +v 5.168260 0.009998 5.260550 +v 5.168260 0.009998 5.168260 +v 5.075970 0.009998 5.168260 +v 5.814293 0.009998 5.260550 +v 5.906583 0.009998 5.260550 +v 5.906583 0.009998 5.168260 +v 5.814293 0.009998 5.168260 +v 3.599324 0.009998 4.522227 +v 3.691614 0.009998 4.522227 +v 3.691614 0.009998 4.429937 +v 3.599324 0.009998 4.429937 +v 3.599324 0.009998 5.260550 +v 3.691614 0.009998 5.260550 +v 3.691614 0.009998 5.168260 +v 3.599324 0.009998 5.168260 +v 4.337647 0.009998 5.260550 +v 4.429937 0.009998 5.260550 +v 4.429937 0.009998 5.168260 +v 4.337647 0.009998 5.168260 +v 3.599324 0.009999 3.045582 +v 3.691614 0.009999 3.045582 +v 3.691614 0.009999 2.953291 +v 3.599324 0.009999 2.953291 +v 3.599324 0.009998 3.783905 +v 3.691614 0.009998 3.783905 +v 3.691614 0.009998 3.691614 +v 3.599324 0.009998 3.691614 +v 4.337647 0.009998 3.783905 +v 4.429937 0.009998 3.783905 +v 4.429937 0.009998 3.691614 +v 4.337647 0.009998 3.691614 +v -3.783905 0.009999 1.568936 +v -3.691614 0.009999 1.568936 +v -3.691614 0.009999 1.476646 +v -3.783905 0.009999 1.476646 +v -3.783905 0.009999 2.307259 +v -3.691614 0.009999 2.307259 +v -3.691614 0.009999 2.214968 +v -3.783905 0.009999 2.214968 +v -3.045582 0.009999 2.307259 +v -2.953291 0.009999 2.307259 +v -2.953291 0.009999 2.214968 +v -3.045582 0.009999 2.214968 +v -5.260550 0.009999 1.568936 +v -5.168260 0.009999 1.568936 +v -5.168260 0.009999 1.476646 +v -5.260550 0.009999 1.476646 +v -5.260550 0.009999 2.307259 +v -5.168260 0.009999 2.307259 +v -5.168260 0.009999 2.214968 +v -5.260550 0.009999 2.214968 +v -4.522227 0.009999 2.307259 +v -4.429937 0.009999 2.307259 +v -4.429937 0.009999 2.214968 +v -4.522227 0.009999 2.214968 +v -5.260550 0.010000 0.092290 +v -5.168260 0.010000 0.092290 +v -5.168260 0.010000 -0.000000 +v -5.260550 0.010000 -0.000000 +v -5.260550 0.010000 0.830613 +v -5.168260 0.010000 0.830613 +v -5.168260 0.010000 0.738323 +v -5.260550 0.010000 0.738323 +v -4.522227 0.010000 0.830613 +v -4.429937 0.010000 0.830613 +v -4.429937 0.010000 0.738323 +v -4.522227 0.010000 0.738323 +v -3.783905 0.009998 4.522227 +v -3.691614 0.009998 4.522227 +v -3.691614 0.009998 4.429937 +v -3.783905 0.009998 4.429937 +v -3.783905 0.009998 5.260550 +v -3.691614 0.009998 5.260550 +v -3.691614 0.009998 5.168260 +v -3.783905 0.009998 5.168260 +v -3.045582 0.009998 5.260550 +v -2.953291 0.009998 5.260550 +v -2.953291 0.009998 5.168260 +v -3.045582 0.009998 5.168260 +v -5.260550 0.009998 4.522227 +v -5.168260 0.009998 4.522227 +v -5.168260 0.009998 4.429937 +v -5.260550 0.009998 4.429937 +v -5.260550 0.009998 5.260550 +v -5.168260 0.009998 5.260550 +v -5.168260 0.009998 5.168260 +v -5.260550 0.009998 5.168260 +v -4.522227 0.009998 5.260550 +v -4.429937 0.009998 5.260550 +v -4.429937 0.009998 5.168260 +v -4.522227 0.009998 5.168260 +v -5.260550 0.009999 3.045582 +v -5.168260 0.009999 3.045582 +v -5.168260 0.009999 2.953291 +v -5.260550 0.009999 2.953291 +v -5.260550 0.009998 3.783905 +v -5.168260 0.009998 3.783905 +v -5.168260 0.009998 3.691614 +v -5.260550 0.009998 3.691614 +v -4.522227 0.009998 3.783905 +v -4.429937 0.009998 3.783905 +v -4.429937 0.009998 3.691614 +v -4.522227 0.009998 3.691614 +v -0.830613 0.009998 4.522227 +v -0.738323 0.009998 4.522227 +v -0.738323 0.009998 4.429937 +v -0.830613 0.009998 4.429937 +v -0.830613 0.009998 5.260550 +v -0.738323 0.009998 5.260550 +v -0.738323 0.009998 5.168260 +v -0.830613 0.009998 5.168260 +v -0.092290 0.009998 5.260550 +v 0.000000 0.009998 5.260550 +v 0.000000 0.009998 5.168260 +v -0.092290 0.009998 5.168260 +v -2.307259 0.009998 4.522227 +v -2.214968 0.009998 4.522227 +v -2.214968 0.009998 4.429937 +v -2.307259 0.009998 4.429937 +v -2.307259 0.009998 5.260550 +v -2.214968 0.009998 5.260550 +v -2.214968 0.009998 5.168260 +v -2.307259 0.009998 5.168260 +v -1.568936 0.009998 5.260550 +v -1.476646 0.009998 5.260550 +v -1.476646 0.009998 5.168260 +v -1.568936 0.009998 5.168260 +v -2.307259 0.009999 3.045582 +v -2.214968 0.009999 3.045582 +v -2.214968 0.009999 2.953291 +v -2.307259 0.009999 2.953291 +v -2.307259 0.009998 3.783905 +v -2.214968 0.009998 3.783905 +v -2.214968 0.009998 3.691614 +v -2.307259 0.009998 3.691614 +v -1.568936 0.009998 3.783905 +v -1.476646 0.009998 3.783905 +v -1.476646 0.009998 3.691614 +v -1.568936 0.009998 3.691614 +v -3.783905 0.010002 -4.337647 +v -3.691614 0.010002 -4.337647 +v -3.691614 0.010002 -4.429937 +v -3.783905 0.010002 -4.429937 +v -3.783905 0.010001 -3.599324 +v -3.691614 0.010001 -3.599324 +v -3.691614 0.010002 -3.691614 +v -3.783905 0.010002 -3.691614 +v -3.045582 0.010001 -3.599324 +v -2.953291 0.010001 -3.599324 +v -2.953291 0.010002 -3.691614 +v -3.045582 0.010002 -3.691614 +v -5.260550 0.010002 -4.337647 +v -5.168260 0.010002 -4.337647 +v -5.168260 0.010002 -4.429937 +v -5.260550 0.010002 -4.429937 +v -5.260550 0.010001 -3.599324 +v -5.168260 0.010001 -3.599324 +v -5.168260 0.010002 -3.691614 +v -5.260550 0.010002 -3.691614 +v -4.522227 0.010001 -3.599324 +v -4.429937 0.010001 -3.599324 +v -4.429937 0.010002 -3.691614 +v -4.522227 0.010002 -3.691614 +v -5.260550 0.010002 -5.814293 +v -5.168260 0.010002 -5.814293 +v -5.168260 0.010002 -5.906583 +v -5.260550 0.010002 -5.906583 +v -5.260550 0.010002 -5.075970 +v -5.168260 0.010002 -5.075970 +v -5.168260 0.010002 -5.168260 +v -5.260550 0.010002 -5.168260 +v -4.522227 0.010002 -5.075970 +v -4.429937 0.010002 -5.075970 +v -4.429937 0.010002 -5.168260 +v -4.522227 0.010002 -5.168260 +v -3.783905 0.010001 -1.384355 +v -3.691614 0.010001 -1.384355 +v -3.691614 0.010001 -1.476646 +v -3.783905 0.010001 -1.476646 +v -3.783905 0.010000 -0.646033 +v -3.691614 0.010000 -0.646033 +v -3.691614 0.010000 -0.738323 +v -3.783905 0.010000 -0.738323 +v -3.045582 0.010000 -0.646033 +v -2.953291 0.010000 -0.646033 +v -2.953291 0.010000 -0.738323 +v -3.045582 0.010000 -0.738323 +v -5.260550 0.010001 -1.384355 +v -5.168260 0.010001 -1.384355 +v -5.168260 0.010001 -1.476646 +v -5.260550 0.010001 -1.476646 +v -5.260550 0.010000 -0.646033 +v -5.168260 0.010000 -0.646033 +v -5.168260 0.010000 -0.738323 +v -5.260550 0.010000 -0.738323 +v -4.522227 0.010000 -0.646033 +v -4.429937 0.010000 -0.646033 +v -4.429937 0.010000 -0.738323 +v -4.522227 0.010000 -0.738323 +v -5.260550 0.010001 -2.861001 +v -5.168260 0.010001 -2.861001 +v -5.168260 0.010001 -2.953291 +v -5.260550 0.010001 -2.953291 +v -5.260550 0.010001 -2.122678 +v -5.168260 0.010001 -2.122678 +v -5.168260 0.010001 -2.214968 +v -5.260550 0.010001 -2.214968 +v -4.522227 0.010001 -2.122678 +v -4.429937 0.010001 -2.122678 +v -4.429937 0.010001 -2.214968 +v -4.522227 0.010001 -2.214968 +v -0.830613 0.010001 -1.384355 +v -0.738323 0.010001 -1.384355 +v -0.738323 0.010001 -1.476646 +v -0.830613 0.010001 -1.476646 +v -0.830613 0.010000 -0.646033 +v -0.738323 0.010000 -0.646033 +v -0.738323 0.010000 -0.738323 +v -0.830613 0.010000 -0.738323 +v -0.092290 0.010000 -0.646033 +v 0.000000 0.010000 -0.646033 +v 0.000000 0.010000 -0.738323 +v -0.092290 0.010000 -0.738323 +v -2.307259 0.010001 -1.384355 +v -2.214968 0.010001 -1.384355 +v -2.214968 0.010001 -1.476646 +v -2.307259 0.010001 -1.476646 +v -2.307259 0.010000 -0.646033 +v -2.214968 0.010000 -0.646033 +v -2.214968 0.010000 -0.738323 +v -2.307259 0.010000 -0.738323 +v -1.568936 0.010000 -0.646033 +v -1.476646 0.010000 -0.646033 +v -1.476646 0.010000 -0.738323 +v -1.568936 0.010000 -0.738323 +v -2.307259 0.010001 -2.861001 +v -2.214968 0.010001 -2.861001 +v -2.214968 0.010001 -2.953291 +v -2.307259 0.010001 -2.953291 +v -2.307259 0.010001 -2.122678 +v -2.214968 0.010001 -2.122678 +v -2.214968 0.010001 -2.214968 +v -2.307259 0.010001 -2.214968 +v -1.568936 0.010001 -2.122678 +v -1.476646 0.010001 -2.122678 +v -1.476646 0.010001 -2.214968 +v -1.568936 0.010001 -2.214968 +v 2.122678 0.010002 -4.337647 +v 2.214968 0.010002 -4.337647 +v 2.214968 0.010002 -4.429937 +v 2.122678 0.010002 -4.429937 +v 2.122678 0.010001 -3.599324 +v 2.214968 0.010001 -3.599324 +v 2.214968 0.010002 -3.691614 +v 2.122678 0.010002 -3.691614 +v 2.861001 0.010001 -3.599324 +v 2.953291 0.010001 -3.599324 +v 2.953291 0.010002 -3.691614 +v 2.861001 0.010002 -3.691614 +v 0.646033 0.010002 -4.337647 +v 0.738323 0.010002 -4.337647 +v 0.738323 0.010002 -4.429937 +v 0.646033 0.010002 -4.429937 +v 0.646033 0.010001 -3.599324 +v 0.738323 0.010001 -3.599324 +v 0.738323 0.010002 -3.691614 +v 0.646033 0.010002 -3.691614 +v 1.384355 0.010001 -3.599324 +v 1.476646 0.010001 -3.599324 +v 1.476646 0.010002 -3.691614 +v 1.384355 0.010002 -3.691614 +v 0.646033 0.010002 -5.814293 +v 0.738323 0.010002 -5.814293 +v 0.738323 0.010002 -5.906583 +v 0.646033 0.010002 -5.906583 +v 0.646033 0.010002 -5.075970 +v 0.738323 0.010002 -5.075970 +v 0.738323 0.010002 -5.168260 +v 0.646033 0.010002 -5.168260 +v 1.384355 0.010002 -5.075970 +v 1.476646 0.010002 -5.075970 +v 1.476646 0.010002 -5.168260 +v 1.384355 0.010002 -5.168260 +v 2.122678 0.010001 -1.384355 +v 2.214968 0.010001 -1.384355 +v 2.214968 0.010001 -1.476646 +v 2.122678 0.010001 -1.476646 +v 2.122678 0.010000 -0.646033 +v 2.214968 0.010000 -0.646033 +v 2.214968 0.010000 -0.738323 +v 2.122678 0.010000 -0.738323 +v 2.861001 0.010000 -0.646033 +v 2.953291 0.010000 -0.646033 +v 2.953291 0.010000 -0.738323 +v 2.861001 0.010000 -0.738323 +v 0.646033 0.010001 -1.384355 +v 0.738323 0.010001 -1.384355 +v 0.738323 0.010001 -1.476646 +v 0.646033 0.010001 -1.476646 +v 0.646033 0.010000 -0.646033 +v 0.738323 0.010000 -0.646033 +v 0.738323 0.010000 -0.738323 +v 0.646033 0.010000 -0.738323 +v 1.384355 0.010000 -0.646033 +v 1.476646 0.010000 -0.646033 +v 1.476646 0.010000 -0.738323 +v 1.384355 0.010000 -0.738323 +v 0.646033 0.010001 -2.861001 +v 0.738323 0.010001 -2.861001 +v 0.738323 0.010001 -2.953291 +v 0.646033 0.010001 -2.953291 +v 0.646033 0.010001 -2.122678 +v 0.738323 0.010001 -2.122678 +v 0.738323 0.010001 -2.214968 +v 0.646033 0.010001 -2.214968 +v 1.384355 0.010001 -2.122678 +v 1.476646 0.010001 -2.122678 +v 1.476646 0.010001 -2.214968 +v 1.384355 0.010001 -2.214968 +v 5.075970 0.010001 -1.384355 +v 5.168260 0.010001 -1.384355 +v 5.168260 0.010001 -1.476646 +v 5.075970 0.010001 -1.476646 +v 5.075970 0.010000 -0.646033 +v 5.168260 0.010000 -0.646033 +v 5.168260 0.010000 -0.738323 +v 5.075970 0.010000 -0.738323 +v 5.814293 0.010000 -0.646033 +v 5.906583 0.010000 -0.646033 +v 5.906583 0.010000 -0.738323 +v 5.814293 0.010000 -0.738323 +v 3.599324 0.010001 -1.384355 +v 3.691614 0.010001 -1.384355 +v 3.691614 0.010001 -1.476646 +v 3.599324 0.010001 -1.476646 +v 3.599324 0.010000 -0.646033 +v 3.691614 0.010000 -0.646033 +v 3.691614 0.010000 -0.738323 +v 3.599324 0.010000 -0.738323 +v 4.337647 0.010000 -0.646033 +v 4.429937 0.010000 -0.646033 +v 4.429937 0.010000 -0.738323 +v 4.337647 0.010000 -0.738323 +v 3.599324 0.010001 -2.861001 +v 3.691614 0.010001 -2.861001 +v 3.691614 0.010001 -2.953291 +v 3.599324 0.010001 -2.953291 +v 3.599324 0.010001 -2.122678 +v 3.691614 0.010001 -2.122678 +v 3.691614 0.010001 -2.214968 +v 3.599324 0.010001 -2.214968 +v 4.337647 0.010001 -2.122678 +v 4.429937 0.010001 -2.122678 +v 4.429937 0.010001 -2.214968 +v 4.337647 0.010001 -2.214968 +v 5.075970 0.010001 -2.861001 +v 5.168260 0.010001 -2.861001 +v 5.168260 0.010001 -2.953291 +v 5.075970 0.010001 -2.953291 +v 5.075970 0.010001 -2.122678 +v 5.168260 0.010001 -2.122678 +v 5.168260 0.010001 -2.214968 +v 5.075970 0.010001 -2.214968 +v 5.814293 0.010001 -2.122678 +v 5.906583 0.010001 -2.122678 +v 5.906583 0.010001 -2.214968 +v 5.814293 0.010001 -2.214968 +v 2.122678 0.010001 -2.861001 +v 2.214968 0.010001 -2.861001 +v 2.214968 0.010001 -2.953291 +v 2.122678 0.010001 -2.953291 +v 2.122678 0.010001 -2.122678 +v 2.214968 0.010001 -2.122678 +v 2.214968 0.010001 -2.214968 +v 2.122678 0.010001 -2.214968 +v 2.861001 0.010001 -2.122678 +v 2.953291 0.010001 -2.122678 +v 2.953291 0.010001 -2.214968 +v 2.861001 0.010001 -2.214968 +v 2.122678 0.010002 -5.814293 +v 2.214968 0.010002 -5.814293 +v 2.214968 0.010002 -5.906583 +v 2.122678 0.010002 -5.906583 +v 2.122678 0.010002 -5.075970 +v 2.214968 0.010002 -5.075970 +v 2.214968 0.010002 -5.168260 +v 2.122678 0.010002 -5.168260 +v 2.861001 0.010002 -5.075970 +v 2.953291 0.010002 -5.075970 +v 2.953291 0.010002 -5.168260 +v 2.861001 0.010002 -5.168260 +v -0.830613 0.010001 -2.861001 +v -0.738323 0.010001 -2.861001 +v -0.738323 0.010001 -2.953291 +v -0.830613 0.010001 -2.953291 +v -0.830613 0.010001 -2.122678 +v -0.738323 0.010001 -2.122678 +v -0.738323 0.010001 -2.214968 +v -0.830613 0.010001 -2.214968 +v -0.092290 0.010001 -2.122678 +v 0.000000 0.010001 -2.122678 +v 0.000000 0.010001 -2.214968 +v -0.092290 0.010001 -2.214968 +v -3.783905 0.010001 -2.861001 +v -3.691614 0.010001 -2.861001 +v -3.691614 0.010001 -2.953291 +v -3.783905 0.010001 -2.953291 +v -3.783905 0.010001 -2.122678 +v -3.691614 0.010001 -2.122678 +v -3.691614 0.010001 -2.214968 +v -3.783905 0.010001 -2.214968 +v -3.045582 0.010001 -2.122678 +v -2.953291 0.010001 -2.122678 +v -2.953291 0.010001 -2.214968 +v -3.045582 0.010001 -2.214968 +v -3.783905 0.010002 -5.814293 +v -3.691614 0.010002 -5.814293 +v -3.691614 0.010002 -5.906583 +v -3.783905 0.010002 -5.906583 +v -3.783905 0.010002 -5.075970 +v -3.691614 0.010002 -5.075970 +v -3.691614 0.010002 -5.168260 +v -3.783905 0.010002 -5.168260 +v -3.045582 0.010002 -5.075970 +v -2.953291 0.010002 -5.075970 +v -2.953291 0.010002 -5.168260 +v -3.045582 0.010002 -5.168260 +v -0.830613 0.009999 3.045582 +v -0.738323 0.009999 3.045582 +v -0.738323 0.009999 2.953291 +v -0.830613 0.009999 2.953291 +v -0.830613 0.009998 3.783905 +v -0.738323 0.009998 3.783905 +v -0.738323 0.009998 3.691614 +v -0.830613 0.009998 3.691614 +v -0.092290 0.009998 3.783905 +v 0.000000 0.009998 3.783905 +v 0.000000 0.009998 3.691614 +v -0.092290 0.009998 3.691614 +v -3.783905 0.009999 3.045582 +v -3.691614 0.009999 3.045582 +v -3.691614 0.009999 2.953291 +v -3.783905 0.009999 2.953291 +v -3.783905 0.009998 3.783905 +v -3.691614 0.009998 3.783905 +v -3.691614 0.009998 3.691614 +v -3.783905 0.009998 3.691614 +v -3.045582 0.009998 3.783905 +v -2.953291 0.009998 3.783905 +v -2.953291 0.009998 3.691614 +v -3.045582 0.009998 3.691614 +v -3.783905 0.010000 0.092290 +v -3.691614 0.010000 0.092290 +v -3.691614 0.010000 -0.000000 +v -3.783905 0.010000 -0.000000 +v -3.783905 0.010000 0.830613 +v -3.691614 0.010000 0.830613 +v -3.691614 0.010000 0.738323 +v -3.783905 0.010000 0.738323 +v -3.045582 0.010000 0.830613 +v -2.953291 0.010000 0.830613 +v -2.953291 0.010000 0.738323 +v -3.045582 0.010000 0.738323 +v 5.075970 0.009999 3.045582 +v 5.168260 0.009999 3.045582 +v 5.168260 0.009999 2.953291 +v 5.075970 0.009999 2.953291 +v 5.075970 0.009998 3.783905 +v 5.168260 0.009998 3.783905 +v 5.168260 0.009998 3.691614 +v 5.075970 0.009998 3.691614 +v 5.814293 0.009998 3.783905 +v 5.906583 0.009998 3.783905 +v 5.906583 0.009998 3.691614 +v 5.814293 0.009998 3.691614 +v 2.122678 0.009999 3.045582 +v 2.214968 0.009999 3.045582 +v 2.214968 0.009999 2.953291 +v 2.122678 0.009999 2.953291 +v 2.122678 0.009998 3.783905 +v 2.214968 0.009998 3.783905 +v 2.214968 0.009998 3.691614 +v 2.122678 0.009998 3.691614 +v 2.861001 0.009998 3.783905 +v 2.953291 0.009998 3.783905 +v 2.953291 0.009998 3.691614 +v 2.861001 0.009998 3.691614 +v 2.122678 0.010000 0.092290 +v 2.214968 0.010000 0.092290 +v 2.214968 0.010000 -0.000000 +v 2.122678 0.010000 -0.000000 +v 2.122678 0.010000 0.830613 +v 2.214968 0.010000 0.830613 +v 2.214968 0.010000 0.738323 +v 2.122678 0.010000 0.738323 +v 2.861001 0.010000 0.830613 +v 2.953291 0.010000 0.830613 +v 2.953291 0.010000 0.738323 +v 2.861001 0.010000 0.738323 +v 5.075970 0.010000 0.092290 +v 5.168260 0.010000 0.092290 +v 5.168260 0.010000 -0.000000 +v 5.075970 0.010000 -0.000000 +v 5.075970 0.010000 0.830613 +v 5.168260 0.010000 0.830613 +v 5.168260 0.010000 0.738323 +v 5.075970 0.010000 0.738323 +v 5.814293 0.010000 0.830613 +v 5.906583 0.010000 0.830613 +v 5.906583 0.010000 0.738323 +v 5.814293 0.010000 0.738323 +v -0.830613 0.010000 0.092290 +v -0.738323 0.010000 0.092290 +v -0.738323 0.010000 -0.000000 +v -0.830613 0.010000 -0.000000 +v -0.830613 0.010000 0.830613 +v -0.738323 0.010000 0.830613 +v -0.738323 0.010000 0.738323 +v -0.830613 0.010000 0.738323 +v -0.092290 0.010000 0.830613 +v 0.000000 0.010000 0.830613 +v 0.000000 0.010000 0.738323 +v -0.092290 0.010000 0.738323 +v -0.830613 0.010002 -5.814293 +v -0.738323 0.010002 -5.814293 +v -0.738323 0.010002 -5.906583 +v -0.830613 0.010002 -5.906583 +v -0.830613 0.010002 -5.075970 +v -0.738323 0.010002 -5.075970 +v -0.738323 0.010002 -5.168260 +v -0.830613 0.010002 -5.168260 +v -0.092290 0.010002 -5.075970 +v 0.000000 0.010002 -5.075970 +v 0.000000 0.010002 -5.168260 +v -0.092290 0.010002 -5.168260 +v 5.075970 0.010002 -5.814293 +v 5.168260 0.010002 -5.814293 +v 5.168260 0.010002 -5.906583 +v 5.075970 0.010002 -5.906583 +v 5.075970 0.010002 -5.075970 +v 5.168260 0.010002 -5.075970 +v 5.168260 0.010002 -5.168260 +v 5.075970 0.010002 -5.168260 +v 5.814293 0.010002 -5.075970 +v 5.906583 0.010002 -5.075970 +v 5.906583 0.010002 -5.168260 +v 5.814293 0.010002 -5.168260 +v 5.445131 0.010002 -5.075970 +v 5.537421 0.010002 -5.075970 +v 5.537421 0.010002 -5.168260 +v 5.445131 0.010002 -5.168260 +v 5.445131 0.010002 -4.706808 +v 5.537421 0.010002 -4.706808 +v 5.537421 0.010002 -4.799098 +v 5.445131 0.010002 -4.799098 +v 5.814293 0.010002 -4.706808 +v 5.906583 0.010002 -4.706808 +v 5.906583 0.010002 -4.799098 +v 5.814293 0.010002 -4.799098 +v 4.706808 0.010002 -5.075970 +v 4.799098 0.010002 -5.075970 +v 4.799098 0.010002 -5.168260 +v 4.706808 0.010002 -5.168260 +v 4.706808 0.010002 -4.706808 +v 4.799098 0.010002 -4.706808 +v 4.799098 0.010002 -4.799098 +v 4.706808 0.010002 -4.799098 +v 5.075970 0.010002 -4.706808 +v 5.168260 0.010002 -4.706808 +v 5.168260 0.010002 -4.799098 +v 5.075970 0.010002 -4.799098 +v 4.706808 0.010002 -5.814293 +v 4.799098 0.010002 -5.814293 +v 4.799098 0.010002 -5.906583 +v 4.706808 0.010002 -5.906583 +v 4.706808 0.010002 -5.445131 +v 4.799098 0.010002 -5.445131 +v 4.799098 0.010002 -5.537421 +v 4.706808 0.010002 -5.537421 +v 5.075970 0.010002 -5.445131 +v 5.168260 0.010002 -5.445131 +v 5.168260 0.010002 -5.537421 +v 5.075970 0.010002 -5.537421 +v -0.461452 0.010002 -5.075970 +v -0.369161 0.010002 -5.075970 +v -0.369161 0.010002 -5.168260 +v -0.461452 0.010002 -5.168260 +v -0.461452 0.010002 -4.706808 +v -0.369161 0.010002 -4.706808 +v -0.369161 0.010002 -4.799098 +v -0.461452 0.010002 -4.799098 +v -0.092290 0.010002 -4.706808 +v 0.000000 0.010002 -4.706808 +v 0.000000 0.010002 -4.799098 +v -0.092290 0.010002 -4.799098 +v -1.199775 0.010002 -5.075970 +v -1.107484 0.010002 -5.075970 +v -1.107484 0.010002 -5.168260 +v -1.199775 0.010002 -5.168260 +v -1.199775 0.010002 -4.706808 +v -1.107484 0.010002 -4.706808 +v -1.107484 0.010002 -4.799098 +v -1.199775 0.010002 -4.799098 +v -0.830613 0.010002 -4.706808 +v -0.738323 0.010002 -4.706808 +v -0.738323 0.010002 -4.799098 +v -0.830613 0.010002 -4.799098 +v -1.199775 0.010002 -5.814293 +v -1.107484 0.010002 -5.814293 +v -1.107484 0.010002 -5.906583 +v -1.199775 0.010002 -5.906583 +v -1.199775 0.010002 -5.445131 +v -1.107484 0.010002 -5.445131 +v -1.107484 0.010002 -5.537421 +v -1.199775 0.010002 -5.537421 +v -0.830613 0.010002 -5.445131 +v -0.738323 0.010002 -5.445131 +v -0.738323 0.010002 -5.537421 +v -0.830613 0.010002 -5.537421 +v -0.461452 0.010000 0.830613 +v -0.369161 0.010000 0.830613 +v -0.369161 0.010000 0.738323 +v -0.461452 0.010000 0.738323 +v -0.461452 0.010000 1.199775 +v -0.369161 0.010000 1.199775 +v -0.369161 0.010000 1.107484 +v -0.461452 0.010000 1.107484 +v -0.092290 0.010000 1.199775 +v 0.000000 0.010000 1.199775 +v 0.000000 0.010000 1.107484 +v -0.092290 0.010000 1.107484 +v -1.199775 0.010000 0.830613 +v -1.107484 0.010000 0.830613 +v -1.107484 0.010000 0.738323 +v -1.199775 0.010000 0.738323 +v -1.199775 0.010000 1.199775 +v -1.107484 0.010000 1.199775 +v -1.107484 0.010000 1.107484 +v -1.199775 0.010000 1.107484 +v -0.830613 0.010000 1.199775 +v -0.738323 0.010000 1.199775 +v -0.738323 0.010000 1.107484 +v -0.830613 0.010000 1.107484 +v -1.199775 0.010000 0.092290 +v -1.107484 0.010000 0.092290 +v -1.107484 0.010000 -0.000000 +v -1.199775 0.010000 -0.000000 +v -1.199775 0.010000 0.461452 +v -1.107484 0.010000 0.461452 +v -1.107484 0.010000 0.369161 +v -1.199775 0.010000 0.369161 +v -0.830613 0.010000 0.461452 +v -0.738323 0.010000 0.461452 +v -0.738323 0.010000 0.369161 +v -0.830613 0.010000 0.369161 +v 5.445131 0.010000 0.830613 +v 5.537421 0.010000 0.830613 +v 5.537421 0.010000 0.738323 +v 5.445131 0.010000 0.738323 +v 5.445131 0.010000 1.199775 +v 5.537421 0.010000 1.199775 +v 5.537421 0.010000 1.107484 +v 5.445131 0.010000 1.107484 +v 5.814293 0.010000 1.199775 +v 5.906583 0.010000 1.199775 +v 5.906583 0.010000 1.107484 +v 5.814293 0.010000 1.107484 +v 4.706808 0.010000 0.830613 +v 4.799098 0.010000 0.830613 +v 4.799098 0.010000 0.738323 +v 4.706808 0.010000 0.738323 +v 4.706808 0.010000 1.199775 +v 4.799098 0.010000 1.199775 +v 4.799098 0.010000 1.107484 +v 4.706808 0.010000 1.107484 +v 5.075970 0.010000 1.199775 +v 5.168260 0.010000 1.199775 +v 5.168260 0.010000 1.107484 +v 5.075970 0.010000 1.107484 +v 4.706808 0.010000 0.092290 +v 4.799098 0.010000 0.092290 +v 4.799098 0.010000 -0.000000 +v 4.706808 0.010000 -0.000000 +v 4.706808 0.010000 0.461452 +v 4.799098 0.010000 0.461452 +v 4.799098 0.010000 0.369161 +v 4.706808 0.010000 0.369161 +v 5.075970 0.010000 0.461452 +v 5.168260 0.010000 0.461452 +v 5.168260 0.010000 0.369161 +v 5.075970 0.010000 0.369161 +v 2.491840 0.010000 0.830613 +v 2.584130 0.010000 0.830613 +v 2.584130 0.010000 0.738323 +v 2.491840 0.010000 0.738323 +v 2.491840 0.010000 1.199775 +v 2.584130 0.010000 1.199775 +v 2.584130 0.010000 1.107484 +v 2.491840 0.010000 1.107484 +v 2.861001 0.010000 1.199775 +v 2.953291 0.010000 1.199775 +v 2.953291 0.010000 1.107484 +v 2.861001 0.010000 1.107484 +v 1.753517 0.010000 0.830613 +v 1.845807 0.010000 0.830613 +v 1.845807 0.010000 0.738323 +v 1.753517 0.010000 0.738323 +v 1.753517 0.010000 1.199775 +v 1.845807 0.010000 1.199775 +v 1.845807 0.010000 1.107484 +v 1.753517 0.010000 1.107484 +v 2.122678 0.010000 1.199775 +v 2.214968 0.010000 1.199775 +v 2.214968 0.010000 1.107484 +v 2.122678 0.010000 1.107484 +v 1.753517 0.010000 0.092290 +v 1.845807 0.010000 0.092290 +v 1.845807 0.010000 -0.000000 +v 1.753517 0.010000 -0.000000 +v 1.753517 0.010000 0.461452 +v 1.845807 0.010000 0.461452 +v 1.845807 0.010000 0.369161 +v 1.753517 0.010000 0.369161 +v 2.122678 0.010000 0.461452 +v 2.214968 0.010000 0.461452 +v 2.214968 0.010000 0.369161 +v 2.122678 0.010000 0.369161 +v 2.491840 0.009998 3.783905 +v 2.584130 0.009998 3.783905 +v 2.584130 0.009998 3.691614 +v 2.491840 0.009998 3.691614 +v 2.491840 0.009998 4.153066 +v 2.584130 0.009998 4.153066 +v 2.584130 0.009998 4.060776 +v 2.491840 0.009998 4.060776 +v 2.861001 0.009998 4.153066 +v 2.953291 0.009998 4.153066 +v 2.953291 0.009998 4.060776 +v 2.861001 0.009998 4.060776 +v 1.753517 0.009998 3.783905 +v 1.845807 0.009998 3.783905 +v 1.845807 0.009998 3.691614 +v 1.753517 0.009998 3.691614 +v 1.753517 0.009998 4.153066 +v 1.845807 0.009998 4.153066 +v 1.845807 0.009998 4.060776 +v 1.753517 0.009998 4.060776 +v 2.122678 0.009998 4.153066 +v 2.214968 0.009998 4.153066 +v 2.214968 0.009998 4.060776 +v 2.122678 0.009998 4.060776 +v 1.753517 0.009999 3.045582 +v 1.845807 0.009999 3.045582 +v 1.845807 0.009999 2.953291 +v 1.753517 0.009999 2.953291 +v 1.753517 0.009999 3.414743 +v 1.845807 0.009999 3.414743 +v 1.845807 0.009999 3.322453 +v 1.753517 0.009999 3.322453 +v 2.122678 0.009999 3.414743 +v 2.214968 0.009999 3.414743 +v 2.214968 0.009999 3.322453 +v 2.122678 0.009999 3.322453 +v 5.445131 0.009998 3.783905 +v 5.537421 0.009998 3.783905 +v 5.537421 0.009998 3.691614 +v 5.445131 0.009998 3.691614 +v 5.445131 0.009998 4.153066 +v 5.537421 0.009998 4.153066 +v 5.537421 0.009998 4.060776 +v 5.445131 0.009998 4.060776 +v 5.814293 0.009998 4.153066 +v 5.906583 0.009998 4.153066 +v 5.906583 0.009998 4.060776 +v 5.814293 0.009998 4.060776 +v 4.706808 0.009998 3.783905 +v 4.799098 0.009998 3.783905 +v 4.799098 0.009998 3.691614 +v 4.706808 0.009998 3.691614 +v 4.706808 0.009998 4.153066 +v 4.799098 0.009998 4.153066 +v 4.799098 0.009998 4.060776 +v 4.706808 0.009998 4.060776 +v 5.075970 0.009998 4.153066 +v 5.168260 0.009998 4.153066 +v 5.168260 0.009998 4.060776 +v 5.075970 0.009998 4.060776 +v 4.706808 0.009999 3.045582 +v 4.799098 0.009999 3.045582 +v 4.799098 0.009999 2.953291 +v 4.706808 0.009999 2.953291 +v 4.706808 0.009999 3.414743 +v 4.799098 0.009999 3.414743 +v 4.799098 0.009999 3.322453 +v 4.706808 0.009999 3.322453 +v 5.075970 0.009999 3.414743 +v 5.168260 0.009999 3.414743 +v 5.168260 0.009999 3.322453 +v 5.075970 0.009999 3.322453 +v -3.414743 0.010000 0.830613 +v -3.322453 0.010000 0.830613 +v -3.322453 0.010000 0.738323 +v -3.414743 0.010000 0.738323 +v -3.414743 0.010000 1.199775 +v -3.322453 0.010000 1.199775 +v -3.322453 0.010000 1.107484 +v -3.414743 0.010000 1.107484 +v -3.045582 0.010000 1.199775 +v -2.953291 0.010000 1.199775 +v -2.953291 0.010000 1.107484 +v -3.045582 0.010000 1.107484 +v -4.153066 0.010000 0.830613 +v -4.060776 0.010000 0.830613 +v -4.060776 0.010000 0.738323 +v -4.153066 0.010000 0.738323 +v -4.153066 0.010000 1.199775 +v -4.060776 0.010000 1.199775 +v -4.060776 0.010000 1.107484 +v -4.153066 0.010000 1.107484 +v -3.783905 0.010000 1.199775 +v -3.691614 0.010000 1.199775 +v -3.691614 0.010000 1.107484 +v -3.783905 0.010000 1.107484 +v -4.153066 0.010000 0.092290 +v -4.060776 0.010000 0.092290 +v -4.060776 0.010000 -0.000000 +v -4.153066 0.010000 -0.000000 +v -4.153066 0.010000 0.461452 +v -4.060776 0.010000 0.461452 +v -4.060776 0.010000 0.369161 +v -4.153066 0.010000 0.369161 +v -3.783905 0.010000 0.461452 +v -3.691614 0.010000 0.461452 +v -3.691614 0.010000 0.369161 +v -3.783905 0.010000 0.369161 +v -3.414743 0.009998 3.783905 +v -3.322453 0.009998 3.783905 +v -3.322453 0.009998 3.691614 +v -3.414743 0.009998 3.691614 +v -3.414743 0.009998 4.153066 +v -3.322453 0.009998 4.153066 +v -3.322453 0.009998 4.060776 +v -3.414743 0.009998 4.060776 +v -3.045582 0.009998 4.153066 +v -2.953291 0.009998 4.153066 +v -2.953291 0.009998 4.060776 +v -3.045582 0.009998 4.060776 +v -4.153066 0.009998 3.783905 +v -4.060776 0.009998 3.783905 +v -4.060776 0.009998 3.691614 +v -4.153066 0.009998 3.691614 +v -4.153066 0.009998 4.153066 +v -4.060776 0.009998 4.153066 +v -4.060776 0.009998 4.060776 +v -4.153066 0.009998 4.060776 +v -3.783905 0.009998 4.153066 +v -3.691614 0.009998 4.153066 +v -3.691614 0.009998 4.060776 +v -3.783905 0.009998 4.060776 +v -4.153066 0.009999 3.045582 +v -4.060776 0.009999 3.045582 +v -4.060776 0.009999 2.953291 +v -4.153066 0.009999 2.953291 +v -4.153066 0.009999 3.414743 +v -4.060776 0.009999 3.414743 +v -4.060776 0.009999 3.322453 +v -4.153066 0.009999 3.322453 +v -3.783905 0.009999 3.414743 +v -3.691614 0.009999 3.414743 +v -3.691614 0.009999 3.322453 +v -3.783905 0.009999 3.322453 +v -0.461452 0.009998 3.783905 +v -0.369161 0.009998 3.783905 +v -0.369161 0.009998 3.691614 +v -0.461452 0.009998 3.691614 +v -0.461452 0.009998 4.153066 +v -0.369161 0.009998 4.153066 +v -0.369161 0.009998 4.060776 +v -0.461452 0.009998 4.060776 +v -0.092290 0.009998 4.153066 +v 0.000000 0.009998 4.153066 +v 0.000000 0.009998 4.060776 +v -0.092290 0.009998 4.060776 +v -1.199775 0.009998 3.783905 +v -1.107484 0.009998 3.783905 +v -1.107484 0.009998 3.691614 +v -1.199775 0.009998 3.691614 +v -1.199775 0.009998 4.153066 +v -1.107484 0.009998 4.153066 +v -1.107484 0.009998 4.060776 +v -1.199775 0.009998 4.060776 +v -0.830613 0.009998 4.153066 +v -0.738323 0.009998 4.153066 +v -0.738323 0.009998 4.060776 +v -0.830613 0.009998 4.060776 +v -1.199775 0.009999 3.045582 +v -1.107484 0.009999 3.045582 +v -1.107484 0.009999 2.953291 +v -1.199775 0.009999 2.953291 +v -1.199775 0.009999 3.414743 +v -1.107484 0.009999 3.414743 +v -1.107484 0.009999 3.322453 +v -1.199775 0.009999 3.322453 +v -0.830613 0.009999 3.414743 +v -0.738323 0.009999 3.414743 +v -0.738323 0.009999 3.322453 +v -0.830613 0.009999 3.322453 +v -3.414743 0.010002 -5.075970 +v -3.322453 0.010002 -5.075970 +v -3.322453 0.010002 -5.168260 +v -3.414743 0.010002 -5.168260 +v -3.414743 0.010002 -4.706808 +v -3.322453 0.010002 -4.706808 +v -3.322453 0.010002 -4.799098 +v -3.414743 0.010002 -4.799098 +v -3.045582 0.010002 -4.706808 +v -2.953291 0.010002 -4.706808 +v -2.953291 0.010002 -4.799098 +v -3.045582 0.010002 -4.799098 +v -4.153066 0.010002 -5.075970 +v -4.060776 0.010002 -5.075970 +v -4.060776 0.010002 -5.168260 +v -4.153066 0.010002 -5.168260 +v -4.153066 0.010002 -4.706808 +v -4.060776 0.010002 -4.706808 +v -4.060776 0.010002 -4.799098 +v -4.153066 0.010002 -4.799098 +v -3.783905 0.010002 -4.706808 +v -3.691614 0.010002 -4.706808 +v -3.691614 0.010002 -4.799098 +v -3.783905 0.010002 -4.799098 +v -4.153066 0.010002 -5.814293 +v -4.060776 0.010002 -5.814293 +v -4.060776 0.010002 -5.906583 +v -4.153066 0.010002 -5.906583 +v -4.153066 0.010002 -5.445131 +v -4.060776 0.010002 -5.445131 +v -4.060776 0.010002 -5.537421 +v -4.153066 0.010002 -5.537421 +v -3.783905 0.010002 -5.445131 +v -3.691614 0.010002 -5.445131 +v -3.691614 0.010002 -5.537421 +v -3.783905 0.010002 -5.537421 +v -3.414743 0.010001 -2.122678 +v -3.322453 0.010001 -2.122678 +v -3.322453 0.010001 -2.214968 +v -3.414743 0.010001 -2.214968 +v -3.414743 0.010001 -1.753517 +v -3.322453 0.010001 -1.753517 +v -3.322453 0.010001 -1.845807 +v -3.414743 0.010001 -1.845807 +v -3.045582 0.010001 -1.753517 +v -2.953291 0.010001 -1.753517 +v -2.953291 0.010001 -1.845807 +v -3.045582 0.010001 -1.845807 +v -4.153066 0.010001 -2.122678 +v -4.060776 0.010001 -2.122678 +v -4.060776 0.010001 -2.214968 +v -4.153066 0.010001 -2.214968 +v -4.153066 0.010001 -1.753517 +v -4.060776 0.010001 -1.753517 +v -4.060776 0.010001 -1.845807 +v -4.153066 0.010001 -1.845807 +v -3.783905 0.010001 -1.753517 +v -3.691614 0.010001 -1.753517 +v -3.691614 0.010001 -1.845807 +v -3.783905 0.010001 -1.845807 +v -4.153066 0.010001 -2.861001 +v -4.060776 0.010001 -2.861001 +v -4.060776 0.010001 -2.953291 +v -4.153066 0.010001 -2.953291 +v -4.153066 0.010001 -2.491840 +v -4.060776 0.010001 -2.491840 +v -4.060776 0.010001 -2.584130 +v -4.153066 0.010001 -2.584130 +v -3.783905 0.010001 -2.491840 +v -3.691614 0.010001 -2.491840 +v -3.691614 0.010001 -2.584130 +v -3.783905 0.010001 -2.584130 +v -0.461452 0.010001 -2.122678 +v -0.369161 0.010001 -2.122678 +v -0.369161 0.010001 -2.214968 +v -0.461452 0.010001 -2.214968 +v -0.461452 0.010001 -1.753517 +v -0.369161 0.010001 -1.753517 +v -0.369161 0.010001 -1.845807 +v -0.461452 0.010001 -1.845807 +v -0.092290 0.010001 -1.753517 +v 0.000000 0.010001 -1.753517 +v 0.000000 0.010001 -1.845807 +v -0.092290 0.010001 -1.845807 +v -1.199775 0.010001 -2.122678 +v -1.107484 0.010001 -2.122678 +v -1.107484 0.010001 -2.214968 +v -1.199775 0.010001 -2.214968 +v -1.199775 0.010001 -1.753517 +v -1.107484 0.010001 -1.753517 +v -1.107484 0.010001 -1.845807 +v -1.199775 0.010001 -1.845807 +v -0.830613 0.010001 -1.753517 +v -0.738323 0.010001 -1.753517 +v -0.738323 0.010001 -1.845807 +v -0.830613 0.010001 -1.845807 +v -1.199775 0.010001 -2.861001 +v -1.107484 0.010001 -2.861001 +v -1.107484 0.010001 -2.953291 +v -1.199775 0.010001 -2.953291 +v -1.199775 0.010001 -2.491840 +v -1.107484 0.010001 -2.491840 +v -1.107484 0.010001 -2.584130 +v -1.199775 0.010001 -2.584130 +v -0.830613 0.010001 -2.491840 +v -0.738323 0.010001 -2.491840 +v -0.738323 0.010001 -2.584130 +v -0.830613 0.010001 -2.584130 +v 2.491840 0.010002 -5.075970 +v 2.584130 0.010002 -5.075970 +v 2.584130 0.010002 -5.168260 +v 2.491840 0.010002 -5.168260 +v 2.491840 0.010002 -4.706808 +v 2.584130 0.010002 -4.706808 +v 2.584130 0.010002 -4.799098 +v 2.491840 0.010002 -4.799098 +v 2.861001 0.010002 -4.706808 +v 2.953291 0.010002 -4.706808 +v 2.953291 0.010002 -4.799098 +v 2.861001 0.010002 -4.799098 +v 1.753517 0.010002 -5.075970 +v 1.845807 0.010002 -5.075970 +v 1.845807 0.010002 -5.168260 +v 1.753517 0.010002 -5.168260 +v 1.753517 0.010002 -4.706808 +v 1.845807 0.010002 -4.706808 +v 1.845807 0.010002 -4.799098 +v 1.753517 0.010002 -4.799098 +v 2.122678 0.010002 -4.706808 +v 2.214968 0.010002 -4.706808 +v 2.214968 0.010002 -4.799098 +v 2.122678 0.010002 -4.799098 +v 1.753517 0.010002 -5.814293 +v 1.845807 0.010002 -5.814293 +v 1.845807 0.010002 -5.906583 +v 1.753517 0.010002 -5.906583 +v 1.753517 0.010002 -5.445131 +v 1.845807 0.010002 -5.445131 +v 1.845807 0.010002 -5.537421 +v 1.753517 0.010002 -5.537421 +v 2.122678 0.010002 -5.445131 +v 2.214968 0.010002 -5.445131 +v 2.214968 0.010002 -5.537421 +v 2.122678 0.010002 -5.537421 +v 2.491840 0.010001 -2.122678 +v 2.584130 0.010001 -2.122678 +v 2.584130 0.010001 -2.214968 +v 2.491840 0.010001 -2.214968 +v 2.491840 0.010001 -1.753517 +v 2.584130 0.010001 -1.753517 +v 2.584130 0.010001 -1.845807 +v 2.491840 0.010001 -1.845807 +v 2.861001 0.010001 -1.753517 +v 2.953291 0.010001 -1.753517 +v 2.953291 0.010001 -1.845807 +v 2.861001 0.010001 -1.845807 +v 1.753517 0.010001 -2.122678 +v 1.845807 0.010001 -2.122678 +v 1.845807 0.010001 -2.214968 +v 1.753517 0.010001 -2.214968 +v 1.753517 0.010001 -1.753517 +v 1.845807 0.010001 -1.753517 +v 1.845807 0.010001 -1.845807 +v 1.753517 0.010001 -1.845807 +v 2.122678 0.010001 -1.753517 +v 2.214968 0.010001 -1.753517 +v 2.214968 0.010001 -1.845807 +v 2.122678 0.010001 -1.845807 +v 1.753517 0.010001 -2.861001 +v 1.845807 0.010001 -2.861001 +v 1.845807 0.010001 -2.953291 +v 1.753517 0.010001 -2.953291 +v 1.753517 0.010001 -2.491840 +v 1.845807 0.010001 -2.491840 +v 1.845807 0.010001 -2.584130 +v 1.753517 0.010001 -2.584130 +v 2.122678 0.010001 -2.491840 +v 2.214968 0.010001 -2.491840 +v 2.214968 0.010001 -2.584130 +v 2.122678 0.010001 -2.584130 +v 5.445131 0.010001 -2.122678 +v 5.537421 0.010001 -2.122678 +v 5.537421 0.010001 -2.214968 +v 5.445131 0.010001 -2.214968 +v 5.445131 0.010001 -1.753517 +v 5.537421 0.010001 -1.753517 +v 5.537421 0.010001 -1.845807 +v 5.445131 0.010001 -1.845807 +v 5.814293 0.010001 -1.753517 +v 5.906583 0.010001 -1.753517 +v 5.906583 0.010001 -1.845807 +v 5.814293 0.010001 -1.845807 +v 4.706808 0.010001 -2.122678 +v 4.799098 0.010001 -2.122678 +v 4.799098 0.010001 -2.214968 +v 4.706808 0.010001 -2.214968 +v 4.706808 0.010001 -1.753517 +v 4.799098 0.010001 -1.753517 +v 4.799098 0.010001 -1.845807 +v 4.706808 0.010001 -1.845807 +v 5.075970 0.010001 -1.753517 +v 5.168260 0.010001 -1.753517 +v 5.168260 0.010001 -1.845807 +v 5.075970 0.010001 -1.845807 +v 4.706808 0.010001 -2.861001 +v 4.799098 0.010001 -2.861001 +v 4.799098 0.010001 -2.953291 +v 4.706808 0.010001 -2.953291 +v 4.706808 0.010001 -2.491840 +v 4.799098 0.010001 -2.491840 +v 4.799098 0.010001 -2.584130 +v 4.706808 0.010001 -2.584130 +v 5.075970 0.010001 -2.491840 +v 5.168260 0.010001 -2.491840 +v 5.168260 0.010001 -2.584130 +v 5.075970 0.010001 -2.584130 +v 3.968485 0.010001 -2.122678 +v 4.060776 0.010001 -2.122678 +v 4.060776 0.010001 -2.214968 +v 3.968485 0.010001 -2.214968 +v 3.968485 0.010001 -1.753517 +v 4.060776 0.010001 -1.753517 +v 4.060776 0.010001 -1.845807 +v 3.968485 0.010001 -1.845807 +v 4.337647 0.010001 -1.753517 +v 4.429937 0.010001 -1.753517 +v 4.429937 0.010001 -1.845807 +v 4.337647 0.010001 -1.845807 +v 3.230163 0.010001 -2.122678 +v 3.322453 0.010001 -2.122678 +v 3.322453 0.010001 -2.214968 +v 3.230163 0.010001 -2.214968 +v 3.230163 0.010001 -1.753517 +v 3.322453 0.010001 -1.753517 +v 3.322453 0.010001 -1.845807 +v 3.230163 0.010001 -1.845807 +v 3.599324 0.010001 -1.753517 +v 3.691614 0.010001 -1.753517 +v 3.691614 0.010001 -1.845807 +v 3.599324 0.010001 -1.845807 +v 3.230163 0.010001 -2.861001 +v 3.322453 0.010001 -2.861001 +v 3.322453 0.010001 -2.953291 +v 3.230163 0.010001 -2.953291 +v 3.230163 0.010001 -2.491840 +v 3.322453 0.010001 -2.491840 +v 3.322453 0.010001 -2.584130 +v 3.230163 0.010001 -2.584130 +v 3.599324 0.010001 -2.491840 +v 3.691614 0.010001 -2.491840 +v 3.691614 0.010001 -2.584130 +v 3.599324 0.010001 -2.584130 +v 3.968485 0.010000 -0.646033 +v 4.060776 0.010000 -0.646033 +v 4.060776 0.010000 -0.738323 +v 3.968485 0.010000 -0.738323 +v 3.968485 0.010000 -0.276871 +v 4.060776 0.010000 -0.276871 +v 4.060776 0.010000 -0.369161 +v 3.968485 0.010000 -0.369161 +v 4.337647 0.010000 -0.276871 +v 4.429937 0.010000 -0.276871 +v 4.429937 0.010000 -0.369161 +v 4.337647 0.010000 -0.369161 +v 3.230163 0.010000 -0.646033 +v 3.322453 0.010000 -0.646033 +v 3.322453 0.010000 -0.738323 +v 3.230163 0.010000 -0.738323 +v 3.230163 0.010000 -0.276871 +v 3.322453 0.010000 -0.276871 +v 3.322453 0.010000 -0.369161 +v 3.230163 0.010000 -0.369161 +v 3.599324 0.010000 -0.276871 +v 3.691614 0.010000 -0.276871 +v 3.691614 0.010000 -0.369161 +v 3.599324 0.010000 -0.369161 +v 3.230163 0.010001 -1.384355 +v 3.322453 0.010001 -1.384355 +v 3.322453 0.010001 -1.476646 +v 3.230163 0.010001 -1.476646 +v 3.230163 0.010000 -1.015194 +v 3.322453 0.010000 -1.015194 +v 3.322453 0.010000 -1.107484 +v 3.230163 0.010000 -1.107484 +v 3.599324 0.010000 -1.015194 +v 3.691614 0.010000 -1.015194 +v 3.691614 0.010000 -1.107484 +v 3.599324 0.010000 -1.107484 +v 5.445131 0.010000 -0.646033 +v 5.537421 0.010000 -0.646033 +v 5.537421 0.010000 -0.738323 +v 5.445131 0.010000 -0.738323 +v 5.445131 0.010000 -0.276871 +v 5.537421 0.010000 -0.276871 +v 5.537421 0.010000 -0.369161 +v 5.445131 0.010000 -0.369161 +v 5.814293 0.010000 -0.276871 +v 5.906583 0.010000 -0.276871 +v 5.906583 0.010000 -0.369161 +v 5.814293 0.010000 -0.369161 +v 4.706808 0.010000 -0.646033 +v 4.799098 0.010000 -0.646033 +v 4.799098 0.010000 -0.738323 +v 4.706808 0.010000 -0.738323 +v 4.706808 0.010000 -0.276871 +v 4.799098 0.010000 -0.276871 +v 4.799098 0.010000 -0.369161 +v 4.706808 0.010000 -0.369161 +v 5.075970 0.010000 -0.276871 +v 5.168260 0.010000 -0.276871 +v 5.168260 0.010000 -0.369161 +v 5.075970 0.010000 -0.369161 +v 4.706808 0.010001 -1.384355 +v 4.799098 0.010001 -1.384355 +v 4.799098 0.010001 -1.476646 +v 4.706808 0.010001 -1.476646 +v 4.706808 0.010000 -1.015194 +v 4.799098 0.010000 -1.015194 +v 4.799098 0.010000 -1.107484 +v 4.706808 0.010000 -1.107484 +v 5.075970 0.010000 -1.015194 +v 5.168260 0.010000 -1.015194 +v 5.168260 0.010000 -1.107484 +v 5.075970 0.010000 -1.107484 +v 1.015194 0.010001 -2.122678 +v 1.107484 0.010001 -2.122678 +v 1.107484 0.010001 -2.214968 +v 1.015194 0.010001 -2.214968 +v 1.015194 0.010001 -1.753517 +v 1.107484 0.010001 -1.753517 +v 1.107484 0.010001 -1.845807 +v 1.015194 0.010001 -1.845807 +v 1.384355 0.010001 -1.753517 +v 1.476646 0.010001 -1.753517 +v 1.476646 0.010001 -1.845807 +v 1.384355 0.010001 -1.845807 +v 0.276871 0.010001 -2.122678 +v 0.369161 0.010001 -2.122678 +v 0.369161 0.010001 -2.214968 +v 0.276871 0.010001 -2.214968 +v 0.276871 0.010001 -1.753517 +v 0.369161 0.010001 -1.753517 +v 0.369161 0.010001 -1.845807 +v 0.276871 0.010001 -1.845807 +v 0.646033 0.010001 -1.753517 +v 0.738323 0.010001 -1.753517 +v 0.738323 0.010001 -1.845807 +v 0.646033 0.010001 -1.845807 +v 0.276871 0.010001 -2.861001 +v 0.369161 0.010001 -2.861001 +v 0.369161 0.010001 -2.953291 +v 0.276871 0.010001 -2.953291 +v 0.276871 0.010001 -2.491840 +v 0.369161 0.010001 -2.491840 +v 0.369161 0.010001 -2.584130 +v 0.276871 0.010001 -2.584130 +v 0.646033 0.010001 -2.491840 +v 0.738323 0.010001 -2.491840 +v 0.738323 0.010001 -2.584130 +v 0.646033 0.010001 -2.584130 +v 1.015194 0.010000 -0.646033 +v 1.107484 0.010000 -0.646033 +v 1.107484 0.010000 -0.738323 +v 1.015194 0.010000 -0.738323 +v 1.015194 0.010000 -0.276871 +v 1.107484 0.010000 -0.276871 +v 1.107484 0.010000 -0.369161 +v 1.015194 0.010000 -0.369161 +v 1.384355 0.010000 -0.276871 +v 1.476646 0.010000 -0.276871 +v 1.476646 0.010000 -0.369161 +v 1.384355 0.010000 -0.369161 +v 0.276871 0.010000 -0.646033 +v 0.369161 0.010000 -0.646033 +v 0.369161 0.010000 -0.738323 +v 0.276871 0.010000 -0.738323 +v 0.276871 0.010000 -0.276871 +v 0.369161 0.010000 -0.276871 +v 0.369161 0.010000 -0.369161 +v 0.276871 0.010000 -0.369161 +v 0.646033 0.010000 -0.276871 +v 0.738323 0.010000 -0.276871 +v 0.738323 0.010000 -0.369161 +v 0.646033 0.010000 -0.369161 +v 0.276871 0.010001 -1.384355 +v 0.369161 0.010001 -1.384355 +v 0.369161 0.010001 -1.476646 +v 0.276871 0.010001 -1.476646 +v 0.276871 0.010000 -1.015194 +v 0.369161 0.010000 -1.015194 +v 0.369161 0.010000 -1.107484 +v 0.276871 0.010000 -1.107484 +v 0.646033 0.010000 -1.015194 +v 0.738323 0.010000 -1.015194 +v 0.738323 0.010000 -1.107484 +v 0.646033 0.010000 -1.107484 +v 2.491840 0.010000 -0.646033 +v 2.584130 0.010000 -0.646033 +v 2.584130 0.010000 -0.738323 +v 2.491840 0.010000 -0.738323 +v 2.491840 0.010000 -0.276871 +v 2.584130 0.010000 -0.276871 +v 2.584130 0.010000 -0.369161 +v 2.491840 0.010000 -0.369161 +v 2.861001 0.010000 -0.276871 +v 2.953291 0.010000 -0.276871 +v 2.953291 0.010000 -0.369161 +v 2.861001 0.010000 -0.369161 +v 1.753517 0.010000 -0.646033 +v 1.845807 0.010000 -0.646033 +v 1.845807 0.010000 -0.738323 +v 1.753517 0.010000 -0.738323 +v 1.753517 0.010000 -0.276871 +v 1.845807 0.010000 -0.276871 +v 1.845807 0.010000 -0.369161 +v 1.753517 0.010000 -0.369161 +v 2.122678 0.010000 -0.276871 +v 2.214968 0.010000 -0.276871 +v 2.214968 0.010000 -0.369161 +v 2.122678 0.010000 -0.369161 +v 1.753517 0.010001 -1.384355 +v 1.845807 0.010001 -1.384355 +v 1.845807 0.010001 -1.476646 +v 1.753517 0.010001 -1.476646 +v 1.753517 0.010000 -1.015194 +v 1.845807 0.010000 -1.015194 +v 1.845807 0.010000 -1.107484 +v 1.753517 0.010000 -1.107484 +v 2.122678 0.010000 -1.015194 +v 2.214968 0.010000 -1.015194 +v 2.214968 0.010000 -1.107484 +v 2.122678 0.010000 -1.107484 +v 1.015194 0.010002 -5.075970 +v 1.107484 0.010002 -5.075970 +v 1.107484 0.010002 -5.168260 +v 1.015194 0.010002 -5.168260 +v 1.015194 0.010002 -4.706808 +v 1.107484 0.010002 -4.706808 +v 1.107484 0.010002 -4.799098 +v 1.015194 0.010002 -4.799098 +v 1.384355 0.010002 -4.706808 +v 1.476646 0.010002 -4.706808 +v 1.476646 0.010002 -4.799098 +v 1.384355 0.010002 -4.799098 +v 0.276871 0.010002 -5.075970 +v 0.369161 0.010002 -5.075970 +v 0.369161 0.010002 -5.168260 +v 0.276871 0.010002 -5.168260 +v 0.276871 0.010002 -4.706808 +v 0.369161 0.010002 -4.706808 +v 0.369161 0.010002 -4.799098 +v 0.276871 0.010002 -4.799098 +v 0.646033 0.010002 -4.706808 +v 0.738323 0.010002 -4.706808 +v 0.738323 0.010002 -4.799098 +v 0.646033 0.010002 -4.799098 +v 0.276871 0.010002 -5.814293 +v 0.369161 0.010002 -5.814293 +v 0.369161 0.010002 -5.906583 +v 0.276871 0.010002 -5.906583 +v 0.276871 0.010002 -5.445131 +v 0.369161 0.010002 -5.445131 +v 0.369161 0.010002 -5.537421 +v 0.276871 0.010002 -5.537421 +v 0.646033 0.010002 -5.445131 +v 0.738323 0.010002 -5.445131 +v 0.738323 0.010002 -5.537421 +v 0.646033 0.010002 -5.537421 +v 1.015194 0.010001 -3.599324 +v 1.107484 0.010001 -3.599324 +v 1.107484 0.010002 -3.691614 +v 1.015194 0.010002 -3.691614 +v 1.015194 0.010001 -3.230163 +v 1.107484 0.010001 -3.230163 +v 1.107484 0.010001 -3.322453 +v 1.015194 0.010001 -3.322453 +v 1.384355 0.010001 -3.230163 +v 1.476646 0.010001 -3.230163 +v 1.476646 0.010001 -3.322453 +v 1.384355 0.010001 -3.322453 +v 0.276871 0.010001 -3.599324 +v 0.369161 0.010001 -3.599324 +v 0.369161 0.010002 -3.691614 +v 0.276871 0.010002 -3.691614 +v 0.276871 0.010001 -3.230163 +v 0.369161 0.010001 -3.230163 +v 0.369161 0.010001 -3.322453 +v 0.276871 0.010001 -3.322453 +v 0.646033 0.010001 -3.230163 +v 0.738323 0.010001 -3.230163 +v 0.738323 0.010001 -3.322453 +v 0.646033 0.010001 -3.322453 +v 0.276871 0.010002 -4.337647 +v 0.369161 0.010002 -4.337647 +v 0.369161 0.010002 -4.429937 +v 0.276871 0.010002 -4.429937 +v 0.276871 0.010002 -3.968485 +v 0.369161 0.010002 -3.968485 +v 0.369161 0.010002 -4.060776 +v 0.276871 0.010002 -4.060776 +v 0.646033 0.010002 -3.968485 +v 0.738323 0.010002 -3.968485 +v 0.738323 0.010002 -4.060776 +v 0.646033 0.010002 -4.060776 +v 2.491840 0.010001 -3.599324 +v 2.584130 0.010001 -3.599324 +v 2.584130 0.010002 -3.691614 +v 2.491840 0.010002 -3.691614 +v 2.491840 0.010001 -3.230163 +v 2.584130 0.010001 -3.230163 +v 2.584130 0.010001 -3.322453 +v 2.491840 0.010001 -3.322453 +v 2.861001 0.010001 -3.230163 +v 2.953291 0.010001 -3.230163 +v 2.953291 0.010001 -3.322453 +v 2.861001 0.010001 -3.322453 +v 1.753517 0.010001 -3.599324 +v 1.845807 0.010001 -3.599324 +v 1.845807 0.010002 -3.691614 +v 1.753517 0.010002 -3.691614 +v 1.753517 0.010001 -3.230163 +v 1.845807 0.010001 -3.230163 +v 1.845807 0.010001 -3.322453 +v 1.753517 0.010001 -3.322453 +v 2.122678 0.010001 -3.230163 +v 2.214968 0.010001 -3.230163 +v 2.214968 0.010001 -3.322453 +v 2.122678 0.010001 -3.322453 +v 1.753517 0.010002 -4.337647 +v 1.845807 0.010002 -4.337647 +v 1.845807 0.010002 -4.429937 +v 1.753517 0.010002 -4.429937 +v 1.753517 0.010002 -3.968485 +v 1.845807 0.010002 -3.968485 +v 1.845807 0.010002 -4.060776 +v 1.753517 0.010002 -4.060776 +v 2.122678 0.010002 -3.968485 +v 2.214968 0.010002 -3.968485 +v 2.214968 0.010002 -4.060776 +v 2.122678 0.010002 -4.060776 +v -1.938097 0.010001 -2.122678 +v -1.845807 0.010001 -2.122678 +v -1.845807 0.010001 -2.214968 +v -1.938097 0.010001 -2.214968 +v -1.938097 0.010001 -1.753517 +v -1.845807 0.010001 -1.753517 +v -1.845807 0.010001 -1.845807 +v -1.938097 0.010001 -1.845807 +v -1.568936 0.010001 -1.753517 +v -1.476646 0.010001 -1.753517 +v -1.476646 0.010001 -1.845807 +v -1.568936 0.010001 -1.845807 +v -2.676420 0.010001 -2.122678 +v -2.584130 0.010001 -2.122678 +v -2.584130 0.010001 -2.214968 +v -2.676420 0.010001 -2.214968 +v -2.676420 0.010001 -1.753517 +v -2.584130 0.010001 -1.753517 +v -2.584130 0.010001 -1.845807 +v -2.676420 0.010001 -1.845807 +v -2.307259 0.010001 -1.753517 +v -2.214968 0.010001 -1.753517 +v -2.214968 0.010001 -1.845807 +v -2.307259 0.010001 -1.845807 +v -2.676420 0.010001 -2.861001 +v -2.584130 0.010001 -2.861001 +v -2.584130 0.010001 -2.953291 +v -2.676420 0.010001 -2.953291 +v -2.676420 0.010001 -2.491840 +v -2.584130 0.010001 -2.491840 +v -2.584130 0.010001 -2.584130 +v -2.676420 0.010001 -2.584130 +v -2.307259 0.010001 -2.491840 +v -2.214968 0.010001 -2.491840 +v -2.214968 0.010001 -2.584130 +v -2.307259 0.010001 -2.584130 +v -1.938097 0.010000 -0.646033 +v -1.845807 0.010000 -0.646033 +v -1.845807 0.010000 -0.738323 +v -1.938097 0.010000 -0.738323 +v -1.938097 0.010000 -0.276871 +v -1.845807 0.010000 -0.276871 +v -1.845807 0.010000 -0.369161 +v -1.938097 0.010000 -0.369161 +v -1.568936 0.010000 -0.276871 +v -1.476646 0.010000 -0.276871 +v -1.476646 0.010000 -0.369161 +v -1.568936 0.010000 -0.369161 +v -2.676420 0.010000 -0.646033 +v -2.584130 0.010000 -0.646033 +v -2.584130 0.010000 -0.738323 +v -2.676420 0.010000 -0.738323 +v -2.676420 0.010000 -0.276871 +v -2.584130 0.010000 -0.276871 +v -2.584130 0.010000 -0.369161 +v -2.676420 0.010000 -0.369161 +v -2.307259 0.010000 -0.276871 +v -2.214968 0.010000 -0.276871 +v -2.214968 0.010000 -0.369161 +v -2.307259 0.010000 -0.369161 +v -2.676420 0.010001 -1.384355 +v -2.584130 0.010001 -1.384355 +v -2.584130 0.010001 -1.476646 +v -2.676420 0.010001 -1.476646 +v -2.676420 0.010000 -1.015194 +v -2.584130 0.010000 -1.015194 +v -2.584130 0.010000 -1.107484 +v -2.676420 0.010000 -1.107484 +v -2.307259 0.010000 -1.015194 +v -2.214968 0.010000 -1.015194 +v -2.214968 0.010000 -1.107484 +v -2.307259 0.010000 -1.107484 +v -0.461452 0.010000 -0.646033 +v -0.369161 0.010000 -0.646033 +v -0.369161 0.010000 -0.738323 +v -0.461452 0.010000 -0.738323 +v -0.461452 0.010000 -0.276871 +v -0.369161 0.010000 -0.276871 +v -0.369161 0.010000 -0.369161 +v -0.461452 0.010000 -0.369161 +v -0.092290 0.010000 -0.276871 +v 0.000000 0.010000 -0.276871 +v 0.000000 0.010000 -0.369161 +v -0.092290 0.010000 -0.369161 +v -1.199775 0.010000 -0.646033 +v -1.107484 0.010000 -0.646033 +v -1.107484 0.010000 -0.738323 +v -1.199775 0.010000 -0.738323 +v -1.199775 0.010000 -0.276871 +v -1.107484 0.010000 -0.276871 +v -1.107484 0.010000 -0.369161 +v -1.199775 0.010000 -0.369161 +v -0.830613 0.010000 -0.276871 +v -0.738323 0.010000 -0.276871 +v -0.738323 0.010000 -0.369161 +v -0.830613 0.010000 -0.369161 +v -1.199775 0.010001 -1.384355 +v -1.107484 0.010001 -1.384355 +v -1.107484 0.010001 -1.476646 +v -1.199775 0.010001 -1.476646 +v -1.199775 0.010000 -1.015194 +v -1.107484 0.010000 -1.015194 +v -1.107484 0.010000 -1.107484 +v -1.199775 0.010000 -1.107484 +v -0.830613 0.010000 -1.015194 +v -0.738323 0.010000 -1.015194 +v -0.738323 0.010000 -1.107484 +v -0.830613 0.010000 -1.107484 +v -4.891389 0.010001 -2.122678 +v -4.799098 0.010001 -2.122678 +v -4.799098 0.010001 -2.214968 +v -4.891389 0.010001 -2.214968 +v -4.891389 0.010001 -1.753517 +v -4.799098 0.010001 -1.753517 +v -4.799098 0.010001 -1.845807 +v -4.891389 0.010001 -1.845807 +v -4.522227 0.010001 -1.753517 +v -4.429937 0.010001 -1.753517 +v -4.429937 0.010001 -1.845807 +v -4.522227 0.010001 -1.845807 +v -5.629711 0.010001 -2.122678 +v -5.537421 0.010001 -2.122678 +v -5.537421 0.010001 -2.214968 +v -5.629711 0.010001 -2.214968 +v -5.629711 0.010001 -1.753517 +v -5.537421 0.010001 -1.753517 +v -5.537421 0.010001 -1.845807 +v -5.629711 0.010001 -1.845807 +v -5.260550 0.010001 -1.753517 +v -5.168260 0.010001 -1.753517 +v -5.168260 0.010001 -1.845807 +v -5.260550 0.010001 -1.845807 +v -5.629711 0.010001 -2.861001 +v -5.537421 0.010001 -2.861001 +v -5.537421 0.010001 -2.953291 +v -5.629711 0.010001 -2.953291 +v -5.629711 0.010001 -2.491840 +v -5.537421 0.010001 -2.491840 +v -5.537421 0.010001 -2.584130 +v -5.629711 0.010001 -2.584130 +v -5.260550 0.010001 -2.491840 +v -5.168260 0.010001 -2.491840 +v -5.168260 0.010001 -2.584130 +v -5.260550 0.010001 -2.584130 +v -4.891389 0.010000 -0.646033 +v -4.799098 0.010000 -0.646033 +v -4.799098 0.010000 -0.738323 +v -4.891389 0.010000 -0.738323 +v -4.891389 0.010000 -0.276871 +v -4.799098 0.010000 -0.276871 +v -4.799098 0.010000 -0.369161 +v -4.891389 0.010000 -0.369161 +v -4.522227 0.010000 -0.276871 +v -4.429937 0.010000 -0.276871 +v -4.429937 0.010000 -0.369161 +v -4.522227 0.010000 -0.369161 +v -5.629711 0.010000 -0.646033 +v -5.537421 0.010000 -0.646033 +v -5.537421 0.010000 -0.738323 +v -5.629711 0.010000 -0.738323 +v -5.629711 0.010000 -0.276871 +v -5.537421 0.010000 -0.276871 +v -5.537421 0.010000 -0.369161 +v -5.629711 0.010000 -0.369161 +v -5.260550 0.010000 -0.276871 +v -5.168260 0.010000 -0.276871 +v -5.168260 0.010000 -0.369161 +v -5.260550 0.010000 -0.369161 +v -5.629711 0.010001 -1.384355 +v -5.537421 0.010001 -1.384355 +v -5.537421 0.010001 -1.476646 +v -5.629711 0.010001 -1.476646 +v -5.629711 0.010000 -1.015194 +v -5.537421 0.010000 -1.015194 +v -5.537421 0.010000 -1.107484 +v -5.629711 0.010000 -1.107484 +v -5.260550 0.010000 -1.015194 +v -5.168260 0.010000 -1.015194 +v -5.168260 0.010000 -1.107484 +v -5.260550 0.010000 -1.107484 +v -3.414743 0.010000 -0.646033 +v -3.322453 0.010000 -0.646033 +v -3.322453 0.010000 -0.738323 +v -3.414743 0.010000 -0.738323 +v -3.414743 0.010000 -0.276871 +v -3.322453 0.010000 -0.276871 +v -3.322453 0.010000 -0.369161 +v -3.414743 0.010000 -0.369161 +v -3.045582 0.010000 -0.276871 +v -2.953291 0.010000 -0.276871 +v -2.953291 0.010000 -0.369161 +v -3.045582 0.010000 -0.369161 +v -4.153066 0.010000 -0.646033 +v -4.060776 0.010000 -0.646033 +v -4.060776 0.010000 -0.738323 +v -4.153066 0.010000 -0.738323 +v -4.153066 0.010000 -0.276871 +v -4.060776 0.010000 -0.276871 +v -4.060776 0.010000 -0.369161 +v -4.153066 0.010000 -0.369161 +v -3.783905 0.010000 -0.276871 +v -3.691614 0.010000 -0.276871 +v -3.691614 0.010000 -0.369161 +v -3.783905 0.010000 -0.369161 +v -4.153066 0.010001 -1.384355 +v -4.060776 0.010001 -1.384355 +v -4.060776 0.010001 -1.476646 +v -4.153066 0.010001 -1.476646 +v -4.153066 0.010000 -1.015194 +v -4.060776 0.010000 -1.015194 +v -4.060776 0.010000 -1.107484 +v -4.153066 0.010000 -1.107484 +v -3.783905 0.010000 -1.015194 +v -3.691614 0.010000 -1.015194 +v -3.691614 0.010000 -1.107484 +v -3.783905 0.010000 -1.107484 +v -4.891389 0.010002 -5.075970 +v -4.799098 0.010002 -5.075970 +v -4.799098 0.010002 -5.168260 +v -4.891389 0.010002 -5.168260 +v -4.891389 0.010002 -4.706808 +v -4.799098 0.010002 -4.706808 +v -4.799098 0.010002 -4.799098 +v -4.891389 0.010002 -4.799098 +v -4.522227 0.010002 -4.706808 +v -4.429937 0.010002 -4.706808 +v -4.429937 0.010002 -4.799098 +v -4.522227 0.010002 -4.799098 +v -5.629711 0.010002 -5.075970 +v -5.537421 0.010002 -5.075970 +v -5.537421 0.010002 -5.168260 +v -5.629711 0.010002 -5.168260 +v -5.629711 0.010002 -4.706808 +v -5.537421 0.010002 -4.706808 +v -5.537421 0.010002 -4.799098 +v -5.629711 0.010002 -4.799098 +v -5.260550 0.010002 -4.706808 +v -5.168260 0.010002 -4.706808 +v -5.168260 0.010002 -4.799098 +v -5.260550 0.010002 -4.799098 +v -5.629711 0.010002 -5.814293 +v -5.537421 0.010002 -5.814293 +v -5.537421 0.010002 -5.906583 +v -5.629711 0.010002 -5.906583 +v -5.629711 0.010002 -5.445131 +v -5.537421 0.010002 -5.445131 +v -5.537421 0.010002 -5.537421 +v -5.629711 0.010002 -5.537421 +v -5.260550 0.010002 -5.445131 +v -5.168260 0.010002 -5.445131 +v -5.168260 0.010002 -5.537421 +v -5.260550 0.010002 -5.537421 +v -4.891389 0.010001 -3.599324 +v -4.799098 0.010001 -3.599324 +v -4.799098 0.010002 -3.691614 +v -4.891389 0.010002 -3.691614 +v -4.891389 0.010001 -3.230163 +v -4.799098 0.010001 -3.230163 +v -4.799098 0.010001 -3.322453 +v -4.891389 0.010001 -3.322453 +v -4.522227 0.010001 -3.230163 +v -4.429937 0.010001 -3.230163 +v -4.429937 0.010001 -3.322453 +v -4.522227 0.010001 -3.322453 +v -5.629711 0.010001 -3.599324 +v -5.537421 0.010001 -3.599324 +v -5.537421 0.010002 -3.691614 +v -5.629711 0.010002 -3.691614 +v -5.629711 0.010001 -3.230163 +v -5.537421 0.010001 -3.230163 +v -5.537421 0.010001 -3.322453 +v -5.629711 0.010001 -3.322453 +v -5.260550 0.010001 -3.230163 +v -5.168260 0.010001 -3.230163 +v -5.168260 0.010001 -3.322453 +v -5.260550 0.010001 -3.322453 +v -5.629711 0.010002 -4.337647 +v -5.537421 0.010002 -4.337647 +v -5.537421 0.010002 -4.429937 +v -5.629711 0.010002 -4.429937 +v -5.629711 0.010002 -3.968485 +v -5.537421 0.010002 -3.968485 +v -5.537421 0.010002 -4.060776 +v -5.629711 0.010002 -4.060776 +v -5.260550 0.010002 -3.968485 +v -5.168260 0.010002 -3.968485 +v -5.168260 0.010002 -4.060776 +v -5.260550 0.010002 -4.060776 +v -3.414743 0.010001 -3.599324 +v -3.322453 0.010001 -3.599324 +v -3.322453 0.010002 -3.691614 +v -3.414743 0.010002 -3.691614 +v -3.414743 0.010001 -3.230163 +v -3.322453 0.010001 -3.230163 +v -3.322453 0.010001 -3.322453 +v -3.414743 0.010001 -3.322453 +v -3.045582 0.010001 -3.230163 +v -2.953291 0.010001 -3.230163 +v -2.953291 0.010001 -3.322453 +v -3.045582 0.010001 -3.322453 +v -4.153066 0.010001 -3.599324 +v -4.060776 0.010001 -3.599324 +v -4.060776 0.010002 -3.691614 +v -4.153066 0.010002 -3.691614 +v -4.153066 0.010001 -3.230163 +v -4.060776 0.010001 -3.230163 +v -4.060776 0.010001 -3.322453 +v -4.153066 0.010001 -3.322453 +v -3.783905 0.010001 -3.230163 +v -3.691614 0.010001 -3.230163 +v -3.691614 0.010001 -3.322453 +v -3.783905 0.010001 -3.322453 +v -4.153066 0.010002 -4.337647 +v -4.060776 0.010002 -4.337647 +v -4.060776 0.010002 -4.429937 +v -4.153066 0.010002 -4.429937 +v -4.153066 0.010002 -3.968485 +v -4.060776 0.010002 -3.968485 +v -4.060776 0.010002 -4.060776 +v -4.153066 0.010002 -4.060776 +v -3.783905 0.010002 -3.968485 +v -3.691614 0.010002 -3.968485 +v -3.691614 0.010002 -4.060776 +v -3.783905 0.010002 -4.060776 +v -1.938097 0.009998 3.783905 +v -1.845807 0.009998 3.783905 +v -1.845807 0.009998 3.691614 +v -1.938097 0.009998 3.691614 +v -1.938097 0.009998 4.153066 +v -1.845807 0.009998 4.153066 +v -1.845807 0.009998 4.060776 +v -1.938097 0.009998 4.060776 +v -1.568936 0.009998 4.153066 +v -1.476646 0.009998 4.153066 +v -1.476646 0.009998 4.060776 +v -1.568936 0.009998 4.060776 +v -2.676420 0.009998 3.783905 +v -2.584130 0.009998 3.783905 +v -2.584130 0.009998 3.691614 +v -2.676420 0.009998 3.691614 +v -2.676420 0.009998 4.153066 +v -2.584130 0.009998 4.153066 +v -2.584130 0.009998 4.060776 +v -2.676420 0.009998 4.060776 +v -2.307259 0.009998 4.153066 +v -2.214968 0.009998 4.153066 +v -2.214968 0.009998 4.060776 +v -2.307259 0.009998 4.060776 +v -2.676420 0.009999 3.045582 +v -2.584130 0.009999 3.045582 +v -2.584130 0.009999 2.953291 +v -2.676420 0.009999 2.953291 +v -2.676420 0.009999 3.414743 +v -2.584130 0.009999 3.414743 +v -2.584130 0.009999 3.322453 +v -2.676420 0.009999 3.322453 +v -2.307259 0.009999 3.414743 +v -2.214968 0.009999 3.414743 +v -2.214968 0.009999 3.322453 +v -2.307259 0.009999 3.322453 +v -1.938097 0.009998 5.260550 +v -1.845807 0.009998 5.260550 +v -1.845807 0.009998 5.168260 +v -1.938097 0.009998 5.168260 +v -1.938097 0.009998 5.629711 +v -1.845807 0.009998 5.629711 +v -1.845807 0.009998 5.537421 +v -1.938097 0.009998 5.537421 +v -1.568936 0.009998 5.629711 +v -1.476646 0.009998 5.629711 +v -1.476646 0.009998 5.537421 +v -1.568936 0.009998 5.537421 +v -2.676420 0.009998 5.260550 +v -2.584130 0.009998 5.260550 +v -2.584130 0.009998 5.168260 +v -2.676420 0.009998 5.168260 +v -2.676420 0.009998 5.629711 +v -2.584130 0.009998 5.629711 +v -2.584130 0.009998 5.537421 +v -2.676420 0.009998 5.537421 +v -2.307259 0.009998 5.629711 +v -2.214968 0.009998 5.629711 +v -2.214968 0.009998 5.537421 +v -2.307259 0.009998 5.537421 +v -2.676420 0.009998 4.522227 +v -2.584130 0.009998 4.522227 +v -2.584130 0.009998 4.429937 +v -2.676420 0.009998 4.429937 +v -2.676420 0.009998 4.891389 +v -2.584130 0.009998 4.891389 +v -2.584130 0.009998 4.799098 +v -2.676420 0.009998 4.799098 +v -2.307259 0.009998 4.891389 +v -2.214968 0.009998 4.891389 +v -2.214968 0.009998 4.799098 +v -2.307259 0.009998 4.799098 +v -0.461452 0.009998 5.260550 +v -0.369161 0.009998 5.260550 +v -0.369161 0.009998 5.168260 +v -0.461452 0.009998 5.168260 +v -0.461452 0.009998 5.629711 +v -0.369161 0.009998 5.629711 +v -0.369161 0.009998 5.537421 +v -0.461452 0.009998 5.537421 +v -0.092290 0.009998 5.629711 +v 0.000000 0.009998 5.629711 +v 0.000000 0.009998 5.537421 +v -0.092290 0.009998 5.537421 +v -1.199775 0.009998 5.260550 +v -1.107484 0.009998 5.260550 +v -1.107484 0.009998 5.168260 +v -1.199775 0.009998 5.168260 +v -1.199775 0.009998 5.629711 +v -1.107484 0.009998 5.629711 +v -1.107484 0.009998 5.537421 +v -1.199775 0.009998 5.537421 +v -0.830613 0.009998 5.629711 +v -0.738323 0.009998 5.629711 +v -0.738323 0.009998 5.537421 +v -0.830613 0.009998 5.537421 +v -1.199775 0.009998 4.522227 +v -1.107484 0.009998 4.522227 +v -1.107484 0.009998 4.429937 +v -1.199775 0.009998 4.429937 +v -1.199775 0.009998 4.891389 +v -1.107484 0.009998 4.891389 +v -1.107484 0.009998 4.799098 +v -1.199775 0.009998 4.799098 +v -0.830613 0.009998 4.891389 +v -0.738323 0.009998 4.891389 +v -0.738323 0.009998 4.799098 +v -0.830613 0.009998 4.799098 +v -4.891389 0.009998 3.783905 +v -4.799098 0.009998 3.783905 +v -4.799098 0.009998 3.691614 +v -4.891389 0.009998 3.691614 +v -4.891389 0.009998 4.153066 +v -4.799098 0.009998 4.153066 +v -4.799098 0.009998 4.060776 +v -4.891389 0.009998 4.060776 +v -4.522227 0.009998 4.153066 +v -4.429937 0.009998 4.153066 +v -4.429937 0.009998 4.060776 +v -4.522227 0.009998 4.060776 +v -5.629711 0.009998 3.783905 +v -5.537421 0.009998 3.783905 +v -5.537421 0.009998 3.691614 +v -5.629711 0.009998 3.691614 +v -5.629711 0.009998 4.153066 +v -5.537421 0.009998 4.153066 +v -5.537421 0.009998 4.060776 +v -5.629711 0.009998 4.060776 +v -5.260550 0.009998 4.153066 +v -5.168260 0.009998 4.153066 +v -5.168260 0.009998 4.060776 +v -5.260550 0.009998 4.060776 +v -5.629711 0.009999 3.045582 +v -5.537421 0.009999 3.045582 +v -5.537421 0.009999 2.953291 +v -5.629711 0.009999 2.953291 +v -5.629711 0.009999 3.414743 +v -5.537421 0.009999 3.414743 +v -5.537421 0.009999 3.322453 +v -5.629711 0.009999 3.322453 +v -5.260550 0.009999 3.414743 +v -5.168260 0.009999 3.414743 +v -5.168260 0.009999 3.322453 +v -5.260550 0.009999 3.322453 +v -4.891389 0.009998 5.260550 +v -4.799098 0.009998 5.260550 +v -4.799098 0.009998 5.168260 +v -4.891389 0.009998 5.168260 +v -4.891389 0.009998 5.629711 +v -4.799098 0.009998 5.629711 +v -4.799098 0.009998 5.537421 +v -4.891389 0.009998 5.537421 +v -4.522227 0.009998 5.629711 +v -4.429937 0.009998 5.629711 +v -4.429937 0.009998 5.537421 +v -4.522227 0.009998 5.537421 +v -5.629711 0.009998 5.260550 +v -5.537421 0.009998 5.260550 +v -5.537421 0.009998 5.168260 +v -5.629711 0.009998 5.168260 +v -5.629711 0.009998 5.629711 +v -5.537421 0.009998 5.629711 +v -5.537421 0.009998 5.537421 +v -5.629711 0.009998 5.537421 +v -5.260550 0.009998 5.629711 +v -5.168260 0.009998 5.629711 +v -5.168260 0.009998 5.537421 +v -5.260550 0.009998 5.537421 +v -5.629711 0.009998 4.522227 +v -5.537421 0.009998 4.522227 +v -5.537421 0.009998 4.429937 +v -5.629711 0.009998 4.429937 +v -5.629711 0.009998 4.891389 +v -5.537421 0.009998 4.891389 +v -5.537421 0.009998 4.799098 +v -5.629711 0.009998 4.799098 +v -5.260550 0.009998 4.891389 +v -5.168260 0.009998 4.891389 +v -5.168260 0.009998 4.799098 +v -5.260550 0.009998 4.799098 +v -3.414743 0.009998 5.260550 +v -3.322453 0.009998 5.260550 +v -3.322453 0.009998 5.168260 +v -3.414743 0.009998 5.168260 +v -3.414743 0.009998 5.629711 +v -3.322453 0.009998 5.629711 +v -3.322453 0.009998 5.537421 +v -3.414743 0.009998 5.537421 +v -3.045582 0.009998 5.629711 +v -2.953291 0.009998 5.629711 +v -2.953291 0.009998 5.537421 +v -3.045582 0.009998 5.537421 +v -4.153066 0.009998 5.260550 +v -4.060776 0.009998 5.260550 +v -4.060776 0.009998 5.168260 +v -4.153066 0.009998 5.168260 +v -4.153066 0.009998 5.629711 +v -4.060776 0.009998 5.629711 +v -4.060776 0.009998 5.537421 +v -4.153066 0.009998 5.537421 +v -3.783905 0.009998 5.629711 +v -3.691614 0.009998 5.629711 +v -3.691614 0.009998 5.537421 +v -3.783905 0.009998 5.537421 +v -4.153066 0.009998 4.522227 +v -4.060776 0.009998 4.522227 +v -4.060776 0.009998 4.429937 +v -4.153066 0.009998 4.429937 +v -4.153066 0.009998 4.891389 +v -4.060776 0.009998 4.891389 +v -4.060776 0.009998 4.799098 +v -4.153066 0.009998 4.799098 +v -3.783905 0.009998 4.891389 +v -3.691614 0.009998 4.891389 +v -3.691614 0.009998 4.799098 +v -3.783905 0.009998 4.799098 +v -4.891389 0.010000 0.830613 +v -4.799098 0.010000 0.830613 +v -4.799098 0.010000 0.738323 +v -4.891389 0.010000 0.738323 +v -4.891389 0.010000 1.199775 +v -4.799098 0.010000 1.199775 +v -4.799098 0.010000 1.107484 +v -4.891389 0.010000 1.107484 +v -4.522227 0.010000 1.199775 +v -4.429937 0.010000 1.199775 +v -4.429937 0.010000 1.107484 +v -4.522227 0.010000 1.107484 +v -5.629711 0.010000 0.830613 +v -5.537421 0.010000 0.830613 +v -5.537421 0.010000 0.738323 +v -5.629711 0.010000 0.738323 +v -5.629711 0.010000 1.199775 +v -5.537421 0.010000 1.199775 +v -5.537421 0.010000 1.107484 +v -5.629711 0.010000 1.107484 +v -5.260550 0.010000 1.199775 +v -5.168260 0.010000 1.199775 +v -5.168260 0.010000 1.107484 +v -5.260550 0.010000 1.107484 +v -5.629711 0.010000 0.092290 +v -5.537421 0.010000 0.092290 +v -5.537421 0.010000 -0.000000 +v -5.629711 0.010000 -0.000000 +v -5.629711 0.010000 0.461452 +v -5.537421 0.010000 0.461452 +v -5.537421 0.010000 0.369161 +v -5.629711 0.010000 0.369161 +v -5.260550 0.010000 0.461452 +v -5.168260 0.010000 0.461452 +v -5.168260 0.010000 0.369161 +v -5.260550 0.010000 0.369161 +v -4.891389 0.009999 2.307259 +v -4.799098 0.009999 2.307259 +v -4.799098 0.009999 2.214968 +v -4.891389 0.009999 2.214968 +v -4.891389 0.009999 2.676420 +v -4.799098 0.009999 2.676420 +v -4.799098 0.009999 2.584130 +v -4.891389 0.009999 2.584130 +v -4.522227 0.009999 2.676420 +v -4.429937 0.009999 2.676420 +v -4.429937 0.009999 2.584130 +v -4.522227 0.009999 2.584130 +v -5.629711 0.009999 2.307259 +v -5.537421 0.009999 2.307259 +v -5.537421 0.009999 2.214968 +v -5.629711 0.009999 2.214968 +v -5.629711 0.009999 2.676420 +v -5.537421 0.009999 2.676420 +v -5.537421 0.009999 2.584130 +v -5.629711 0.009999 2.584130 +v -5.260550 0.009999 2.676420 +v -5.168260 0.009999 2.676420 +v -5.168260 0.009999 2.584130 +v -5.260550 0.009999 2.584130 +v -5.629711 0.009999 1.568936 +v -5.537421 0.009999 1.568936 +v -5.537421 0.009999 1.476646 +v -5.629711 0.009999 1.476646 +v -5.629711 0.009999 1.938097 +v -5.537421 0.009999 1.938097 +v -5.537421 0.009999 1.845807 +v -5.629711 0.009999 1.845807 +v -5.260550 0.009999 1.938097 +v -5.168260 0.009999 1.938097 +v -5.168260 0.009999 1.845807 +v -5.260550 0.009999 1.845807 +v -3.414743 0.009999 2.307259 +v -3.322453 0.009999 2.307259 +v -3.322453 0.009999 2.214968 +v -3.414743 0.009999 2.214968 +v -3.414743 0.009999 2.676420 +v -3.322453 0.009999 2.676420 +v -3.322453 0.009999 2.584130 +v -3.414743 0.009999 2.584130 +v -3.045582 0.009999 2.676420 +v -2.953291 0.009999 2.676420 +v -2.953291 0.009999 2.584130 +v -3.045582 0.009999 2.584130 +v -4.153066 0.009999 2.307259 +v -4.060776 0.009999 2.307259 +v -4.060776 0.009999 2.214968 +v -4.153066 0.009999 2.214968 +v -4.153066 0.009999 2.676420 +v -4.060776 0.009999 2.676420 +v -4.060776 0.009999 2.584130 +v -4.153066 0.009999 2.584130 +v -3.783905 0.009999 2.676420 +v -3.691614 0.009999 2.676420 +v -3.691614 0.009999 2.584130 +v -3.783905 0.009999 2.584130 +v -4.153066 0.009999 1.568936 +v -4.060776 0.009999 1.568936 +v -4.060776 0.009999 1.476646 +v -4.153066 0.009999 1.476646 +v -4.153066 0.009999 1.938097 +v -4.060776 0.009999 1.938097 +v -4.060776 0.009999 1.845807 +v -4.153066 0.009999 1.845807 +v -3.783905 0.009999 1.938097 +v -3.691614 0.009999 1.938097 +v -3.691614 0.009999 1.845807 +v -3.783905 0.009999 1.845807 +v 3.968485 0.009998 3.783905 +v 4.060776 0.009998 3.783905 +v 4.060776 0.009998 3.691614 +v 3.968485 0.009998 3.691614 +v 3.968485 0.009998 4.153066 +v 4.060776 0.009998 4.153066 +v 4.060776 0.009998 4.060776 +v 3.968485 0.009998 4.060776 +v 4.337647 0.009998 4.153066 +v 4.429937 0.009998 4.153066 +v 4.429937 0.009998 4.060776 +v 4.337647 0.009998 4.060776 +v 3.230163 0.009998 3.783905 +v 3.322453 0.009998 3.783905 +v 3.322453 0.009998 3.691614 +v 3.230163 0.009998 3.691614 +v 3.230163 0.009998 4.153066 +v 3.322453 0.009998 4.153066 +v 3.322453 0.009998 4.060776 +v 3.230163 0.009998 4.060776 +v 3.599324 0.009998 4.153066 +v 3.691614 0.009998 4.153066 +v 3.691614 0.009998 4.060776 +v 3.599324 0.009998 4.060776 +v 3.230163 0.009999 3.045582 +v 3.322453 0.009999 3.045582 +v 3.322453 0.009999 2.953291 +v 3.230163 0.009999 2.953291 +v 3.230163 0.009999 3.414743 +v 3.322453 0.009999 3.414743 +v 3.322453 0.009999 3.322453 +v 3.230163 0.009999 3.322453 +v 3.599324 0.009999 3.414743 +v 3.691614 0.009999 3.414743 +v 3.691614 0.009999 3.322453 +v 3.599324 0.009999 3.322453 +v 3.968485 0.009998 5.260550 +v 4.060776 0.009998 5.260550 +v 4.060776 0.009998 5.168260 +v 3.968485 0.009998 5.168260 +v 3.968485 0.009998 5.629711 +v 4.060776 0.009998 5.629711 +v 4.060776 0.009998 5.537421 +v 3.968485 0.009998 5.537421 +v 4.337647 0.009998 5.629711 +v 4.429937 0.009998 5.629711 +v 4.429937 0.009998 5.537421 +v 4.337647 0.009998 5.537421 +v 3.230163 0.009998 5.260550 +v 3.322453 0.009998 5.260550 +v 3.322453 0.009998 5.168260 +v 3.230163 0.009998 5.168260 +v 3.230163 0.009998 5.629711 +v 3.322453 0.009998 5.629711 +v 3.322453 0.009998 5.537421 +v 3.230163 0.009998 5.537421 +v 3.599324 0.009998 5.629711 +v 3.691614 0.009998 5.629711 +v 3.691614 0.009998 5.537421 +v 3.599324 0.009998 5.537421 +v 3.230163 0.009998 4.522227 +v 3.322453 0.009998 4.522227 +v 3.322453 0.009998 4.429937 +v 3.230163 0.009998 4.429937 +v 3.230163 0.009998 4.891389 +v 3.322453 0.009998 4.891389 +v 3.322453 0.009998 4.799098 +v 3.230163 0.009998 4.799098 +v 3.599324 0.009998 4.891389 +v 3.691614 0.009998 4.891389 +v 3.691614 0.009998 4.799098 +v 3.599324 0.009998 4.799098 +v 5.445131 0.009998 5.260550 +v 5.537421 0.009998 5.260550 +v 5.537421 0.009998 5.168260 +v 5.445131 0.009998 5.168260 +v 5.445131 0.009998 5.629711 +v 5.537421 0.009998 5.629711 +v 5.537421 0.009998 5.537421 +v 5.445131 0.009998 5.537421 +v 5.814293 0.009998 5.629711 +v 5.906583 0.009998 5.629711 +v 5.906583 0.009998 5.537421 +v 5.814293 0.009998 5.537421 +v 4.706808 0.009998 5.260550 +v 4.799098 0.009998 5.260550 +v 4.799098 0.009998 5.168260 +v 4.706808 0.009998 5.168260 +v 4.706808 0.009998 5.629711 +v 4.799098 0.009998 5.629711 +v 4.799098 0.009998 5.537421 +v 4.706808 0.009998 5.537421 +v 5.075970 0.009998 5.629711 +v 5.168260 0.009998 5.629711 +v 5.168260 0.009998 5.537421 +v 5.075970 0.009998 5.537421 +v 4.706808 0.009998 4.522227 +v 4.799098 0.009998 4.522227 +v 4.799098 0.009998 4.429937 +v 4.706808 0.009998 4.429937 +v 4.706808 0.009998 4.891389 +v 4.799098 0.009998 4.891389 +v 4.799098 0.009998 4.799098 +v 4.706808 0.009998 4.799098 +v 5.075970 0.009998 4.891389 +v 5.168260 0.009998 4.891389 +v 5.168260 0.009998 4.799098 +v 5.075970 0.009998 4.799098 +v 1.015194 0.009998 3.783905 +v 1.107484 0.009998 3.783905 +v 1.107484 0.009998 3.691614 +v 1.015194 0.009998 3.691614 +v 1.015194 0.009998 4.153066 +v 1.107484 0.009998 4.153066 +v 1.107484 0.009998 4.060776 +v 1.015194 0.009998 4.060776 +v 1.384355 0.009998 4.153066 +v 1.476646 0.009998 4.153066 +v 1.476646 0.009998 4.060776 +v 1.384355 0.009998 4.060776 +v 0.276871 0.009998 3.783905 +v 0.369161 0.009998 3.783905 +v 0.369161 0.009998 3.691614 +v 0.276871 0.009998 3.691614 +v 0.276871 0.009998 4.153066 +v 0.369161 0.009998 4.153066 +v 0.369161 0.009998 4.060776 +v 0.276871 0.009998 4.060776 +v 0.646033 0.009998 4.153066 +v 0.738323 0.009998 4.153066 +v 0.738323 0.009998 4.060776 +v 0.646033 0.009998 4.060776 +v 0.276871 0.009999 3.045582 +v 0.369161 0.009999 3.045582 +v 0.369161 0.009999 2.953291 +v 0.276871 0.009999 2.953291 +v 0.276871 0.009999 3.414743 +v 0.369161 0.009999 3.414743 +v 0.369161 0.009999 3.322453 +v 0.276871 0.009999 3.322453 +v 0.646033 0.009999 3.414743 +v 0.738323 0.009999 3.414743 +v 0.738323 0.009999 3.322453 +v 0.646033 0.009999 3.322453 +v 1.015194 0.009998 5.260550 +v 1.107484 0.009998 5.260550 +v 1.107484 0.009998 5.168260 +v 1.015194 0.009998 5.168260 +v 1.015194 0.009998 5.629711 +v 1.107484 0.009998 5.629711 +v 1.107484 0.009998 5.537421 +v 1.015194 0.009998 5.537421 +v 1.384355 0.009998 5.629711 +v 1.476646 0.009998 5.629711 +v 1.476646 0.009998 5.537421 +v 1.384355 0.009998 5.537421 +v 0.276871 0.009998 5.260550 +v 0.369161 0.009998 5.260550 +v 0.369161 0.009998 5.168260 +v 0.276871 0.009998 5.168260 +v 0.276871 0.009998 5.629711 +v 0.369161 0.009998 5.629711 +v 0.369161 0.009998 5.537421 +v 0.276871 0.009998 5.537421 +v 0.646033 0.009998 5.629711 +v 0.738323 0.009998 5.629711 +v 0.738323 0.009998 5.537421 +v 0.646033 0.009998 5.537421 +v 0.276871 0.009998 4.522227 +v 0.369161 0.009998 4.522227 +v 0.369161 0.009998 4.429937 +v 0.276871 0.009998 4.429937 +v 0.276871 0.009998 4.891389 +v 0.369161 0.009998 4.891389 +v 0.369161 0.009998 4.799098 +v 0.276871 0.009998 4.799098 +v 0.646033 0.009998 4.891389 +v 0.738323 0.009998 4.891389 +v 0.738323 0.009998 4.799098 +v 0.646033 0.009998 4.799098 +v 2.491840 0.009998 5.260550 +v 2.584130 0.009998 5.260550 +v 2.584130 0.009998 5.168260 +v 2.491840 0.009998 5.168260 +v 2.491840 0.009998 5.629711 +v 2.584130 0.009998 5.629711 +v 2.584130 0.009998 5.537421 +v 2.491840 0.009998 5.537421 +v 2.861001 0.009998 5.629711 +v 2.953291 0.009998 5.629711 +v 2.953291 0.009998 5.537421 +v 2.861001 0.009998 5.537421 +v 1.753517 0.009998 5.260550 +v 1.845807 0.009998 5.260550 +v 1.845807 0.009998 5.168260 +v 1.753517 0.009998 5.168260 +v 1.753517 0.009998 5.629711 +v 1.845807 0.009998 5.629711 +v 1.845807 0.009998 5.537421 +v 1.753517 0.009998 5.537421 +v 2.122678 0.009998 5.629711 +v 2.214968 0.009998 5.629711 +v 2.214968 0.009998 5.537421 +v 2.122678 0.009998 5.537421 +v 1.753517 0.009998 4.522227 +v 1.845807 0.009998 4.522227 +v 1.845807 0.009998 4.429937 +v 1.753517 0.009998 4.429937 +v 1.753517 0.009998 4.891389 +v 1.845807 0.009998 4.891389 +v 1.845807 0.009998 4.799098 +v 1.753517 0.009998 4.799098 +v 2.122678 0.009998 4.891389 +v 2.214968 0.009998 4.891389 +v 2.214968 0.009998 4.799098 +v 2.122678 0.009998 4.799098 +v 1.015194 0.010000 0.830613 +v 1.107484 0.010000 0.830613 +v 1.107484 0.010000 0.738323 +v 1.015194 0.010000 0.738323 +v 1.015194 0.010000 1.199775 +v 1.107484 0.010000 1.199775 +v 1.107484 0.010000 1.107484 +v 1.015194 0.010000 1.107484 +v 1.384355 0.010000 1.199775 +v 1.476646 0.010000 1.199775 +v 1.476646 0.010000 1.107484 +v 1.384355 0.010000 1.107484 +v 0.276871 0.010000 0.830613 +v 0.369161 0.010000 0.830613 +v 0.369161 0.010000 0.738323 +v 0.276871 0.010000 0.738323 +v 0.276871 0.010000 1.199775 +v 0.369161 0.010000 1.199775 +v 0.369161 0.010000 1.107484 +v 0.276871 0.010000 1.107484 +v 0.646033 0.010000 1.199775 +v 0.738323 0.010000 1.199775 +v 0.738323 0.010000 1.107484 +v 0.646033 0.010000 1.107484 +v 0.276871 0.010000 0.092290 +v 0.369161 0.010000 0.092290 +v 0.369161 0.010000 -0.000000 +v 0.276871 0.010000 -0.000000 +v 0.276871 0.010000 0.461452 +v 0.369161 0.010000 0.461452 +v 0.369161 0.010000 0.369161 +v 0.276871 0.010000 0.369161 +v 0.646033 0.010000 0.461452 +v 0.738323 0.010000 0.461452 +v 0.738323 0.010000 0.369161 +v 0.646033 0.010000 0.369161 +v 1.015194 0.009999 2.307259 +v 1.107484 0.009999 2.307259 +v 1.107484 0.009999 2.214968 +v 1.015194 0.009999 2.214968 +v 1.015194 0.009999 2.676420 +v 1.107484 0.009999 2.676420 +v 1.107484 0.009999 2.584130 +v 1.015194 0.009999 2.584130 +v 1.384355 0.009999 2.676420 +v 1.476646 0.009999 2.676420 +v 1.476646 0.009999 2.584130 +v 1.384355 0.009999 2.584130 +v 0.276871 0.009999 2.307259 +v 0.369161 0.009999 2.307259 +v 0.369161 0.009999 2.214968 +v 0.276871 0.009999 2.214968 +v 0.276871 0.009999 2.676420 +v 0.369161 0.009999 2.676420 +v 0.369161 0.009999 2.584130 +v 0.276871 0.009999 2.584130 +v 0.646033 0.009999 2.676420 +v 0.738323 0.009999 2.676420 +v 0.738323 0.009999 2.584130 +v 0.646033 0.009999 2.584130 +v 0.276871 0.009999 1.568936 +v 0.369161 0.009999 1.568936 +v 0.369161 0.009999 1.476646 +v 0.276871 0.009999 1.476646 +v 0.276871 0.009999 1.938097 +v 0.369161 0.009999 1.938097 +v 0.369161 0.009999 1.845807 +v 0.276871 0.009999 1.845807 +v 0.646033 0.009999 1.938097 +v 0.738323 0.009999 1.938097 +v 0.738323 0.009999 1.845807 +v 0.646033 0.009999 1.845807 +v 2.491840 0.009999 2.307259 +v 2.584130 0.009999 2.307259 +v 2.584130 0.009999 2.214968 +v 2.491840 0.009999 2.214968 +v 2.491840 0.009999 2.676420 +v 2.584130 0.009999 2.676420 +v 2.584130 0.009999 2.584130 +v 2.491840 0.009999 2.584130 +v 2.861001 0.009999 2.676420 +v 2.953291 0.009999 2.676420 +v 2.953291 0.009999 2.584130 +v 2.861001 0.009999 2.584130 +v 1.753517 0.009999 2.307259 +v 1.845807 0.009999 2.307259 +v 1.845807 0.009999 2.214968 +v 1.753517 0.009999 2.214968 +v 1.753517 0.009999 2.676420 +v 1.845807 0.009999 2.676420 +v 1.845807 0.009999 2.584130 +v 1.753517 0.009999 2.584130 +v 2.122678 0.009999 2.676420 +v 2.214968 0.009999 2.676420 +v 2.214968 0.009999 2.584130 +v 2.122678 0.009999 2.584130 +v 1.753517 0.009999 1.568936 +v 1.845807 0.009999 1.568936 +v 1.845807 0.009999 1.476646 +v 1.753517 0.009999 1.476646 +v 1.753517 0.009999 1.938097 +v 1.845807 0.009999 1.938097 +v 1.845807 0.009999 1.845807 +v 1.753517 0.009999 1.845807 +v 2.122678 0.009999 1.938097 +v 2.214968 0.009999 1.938097 +v 2.214968 0.009999 1.845807 +v 2.122678 0.009999 1.845807 +v 3.968485 0.010000 0.830613 +v 4.060776 0.010000 0.830613 +v 4.060776 0.010000 0.738323 +v 3.968485 0.010000 0.738323 +v 3.968485 0.010000 1.199775 +v 4.060776 0.010000 1.199775 +v 4.060776 0.010000 1.107484 +v 3.968485 0.010000 1.107484 +v 4.337647 0.010000 1.199775 +v 4.429937 0.010000 1.199775 +v 4.429937 0.010000 1.107484 +v 4.337647 0.010000 1.107484 +v 3.230163 0.010000 0.830613 +v 3.322453 0.010000 0.830613 +v 3.322453 0.010000 0.738323 +v 3.230163 0.010000 0.738323 +v 3.230163 0.010000 1.199775 +v 3.322453 0.010000 1.199775 +v 3.322453 0.010000 1.107484 +v 3.230163 0.010000 1.107484 +v 3.599324 0.010000 1.199775 +v 3.691614 0.010000 1.199775 +v 3.691614 0.010000 1.107484 +v 3.599324 0.010000 1.107484 +v 3.230163 0.010000 0.092290 +v 3.322453 0.010000 0.092290 +v 3.322453 0.010000 -0.000000 +v 3.230163 0.010000 -0.000000 +v 3.230163 0.010000 0.461452 +v 3.322453 0.010000 0.461452 +v 3.322453 0.010000 0.369161 +v 3.230163 0.010000 0.369161 +v 3.599324 0.010000 0.461452 +v 3.691614 0.010000 0.461452 +v 3.691614 0.010000 0.369161 +v 3.599324 0.010000 0.369161 +v 3.968485 0.009999 2.307259 +v 4.060776 0.009999 2.307259 +v 4.060776 0.009999 2.214968 +v 3.968485 0.009999 2.214968 +v 3.968485 0.009999 2.676420 +v 4.060776 0.009999 2.676420 +v 4.060776 0.009999 2.584130 +v 3.968485 0.009999 2.584130 +v 4.337647 0.009999 2.676420 +v 4.429937 0.009999 2.676420 +v 4.429937 0.009999 2.584130 +v 4.337647 0.009999 2.584130 +v 3.230163 0.009999 2.307259 +v 3.322453 0.009999 2.307259 +v 3.322453 0.009999 2.214968 +v 3.230163 0.009999 2.214968 +v 3.230163 0.009999 2.676420 +v 3.322453 0.009999 2.676420 +v 3.322453 0.009999 2.584130 +v 3.230163 0.009999 2.584130 +v 3.599324 0.009999 2.676420 +v 3.691614 0.009999 2.676420 +v 3.691614 0.009999 2.584130 +v 3.599324 0.009999 2.584130 +v 3.230163 0.009999 1.568936 +v 3.322453 0.009999 1.568936 +v 3.322453 0.009999 1.476646 +v 3.230163 0.009999 1.476646 +v 3.230163 0.009999 1.938097 +v 3.322453 0.009999 1.938097 +v 3.322453 0.009999 1.845807 +v 3.230163 0.009999 1.845807 +v 3.599324 0.009999 1.938097 +v 3.691614 0.009999 1.938097 +v 3.691614 0.009999 1.845807 +v 3.599324 0.009999 1.845807 +v 5.445131 0.009999 2.307259 +v 5.537421 0.009999 2.307259 +v 5.537421 0.009999 2.214968 +v 5.445131 0.009999 2.214968 +v 5.445131 0.009999 2.676420 +v 5.537421 0.009999 2.676420 +v 5.537421 0.009999 2.584130 +v 5.445131 0.009999 2.584130 +v 5.814293 0.009999 2.676420 +v 5.906583 0.009999 2.676420 +v 5.906583 0.009999 2.584130 +v 5.814293 0.009999 2.584130 +v 4.706808 0.009999 2.307259 +v 4.799098 0.009999 2.307259 +v 4.799098 0.009999 2.214968 +v 4.706808 0.009999 2.214968 +v 4.706808 0.009999 2.676420 +v 4.799098 0.009999 2.676420 +v 4.799098 0.009999 2.584130 +v 4.706808 0.009999 2.584130 +v 5.075970 0.009999 2.676420 +v 5.168260 0.009999 2.676420 +v 5.168260 0.009999 2.584130 +v 5.075970 0.009999 2.584130 +v 4.706808 0.009999 1.568936 +v 4.799098 0.009999 1.568936 +v 4.799098 0.009999 1.476646 +v 4.706808 0.009999 1.476646 +v 4.706808 0.009999 1.938097 +v 4.799098 0.009999 1.938097 +v 4.799098 0.009999 1.845807 +v 4.706808 0.009999 1.845807 +v 5.075970 0.009999 1.938097 +v 5.168260 0.009999 1.938097 +v 5.168260 0.009999 1.845807 +v 5.075970 0.009999 1.845807 +v -1.938097 0.010000 0.830613 +v -1.845807 0.010000 0.830613 +v -1.845807 0.010000 0.738323 +v -1.938097 0.010000 0.738323 +v -1.938097 0.010000 1.199775 +v -1.845807 0.010000 1.199775 +v -1.845807 0.010000 1.107484 +v -1.938097 0.010000 1.107484 +v -1.568936 0.010000 1.199775 +v -1.476646 0.010000 1.199775 +v -1.476646 0.010000 1.107484 +v -1.568936 0.010000 1.107484 +v -2.676420 0.010000 0.830613 +v -2.584130 0.010000 0.830613 +v -2.584130 0.010000 0.738323 +v -2.676420 0.010000 0.738323 +v -2.676420 0.010000 1.199775 +v -2.584130 0.010000 1.199775 +v -2.584130 0.010000 1.107484 +v -2.676420 0.010000 1.107484 +v -2.307259 0.010000 1.199775 +v -2.214968 0.010000 1.199775 +v -2.214968 0.010000 1.107484 +v -2.307259 0.010000 1.107484 +v -2.676420 0.010000 0.092290 +v -2.584130 0.010000 0.092290 +v -2.584130 0.010000 -0.000000 +v -2.676420 0.010000 -0.000000 +v -2.676420 0.010000 0.461452 +v -2.584130 0.010000 0.461452 +v -2.584130 0.010000 0.369161 +v -2.676420 0.010000 0.369161 +v -2.307259 0.010000 0.461452 +v -2.214968 0.010000 0.461452 +v -2.214968 0.010000 0.369161 +v -2.307259 0.010000 0.369161 +v -1.938097 0.009999 2.307259 +v -1.845807 0.009999 2.307259 +v -1.845807 0.009999 2.214968 +v -1.938097 0.009999 2.214968 +v -1.938097 0.009999 2.676420 +v -1.845807 0.009999 2.676420 +v -1.845807 0.009999 2.584130 +v -1.938097 0.009999 2.584130 +v -1.568936 0.009999 2.676420 +v -1.476646 0.009999 2.676420 +v -1.476646 0.009999 2.584130 +v -1.568936 0.009999 2.584130 +v -2.676420 0.009999 2.307259 +v -2.584130 0.009999 2.307259 +v -2.584130 0.009999 2.214968 +v -2.676420 0.009999 2.214968 +v -2.676420 0.009999 2.676420 +v -2.584130 0.009999 2.676420 +v -2.584130 0.009999 2.584130 +v -2.676420 0.009999 2.584130 +v -2.307259 0.009999 2.676420 +v -2.214968 0.009999 2.676420 +v -2.214968 0.009999 2.584130 +v -2.307259 0.009999 2.584130 +v -2.676420 0.009999 1.568936 +v -2.584130 0.009999 1.568936 +v -2.584130 0.009999 1.476646 +v -2.676420 0.009999 1.476646 +v -2.676420 0.009999 1.938097 +v -2.584130 0.009999 1.938097 +v -2.584130 0.009999 1.845807 +v -2.676420 0.009999 1.845807 +v -2.307259 0.009999 1.938097 +v -2.214968 0.009999 1.938097 +v -2.214968 0.009999 1.845807 +v -2.307259 0.009999 1.845807 +v -0.461452 0.009999 2.307259 +v -0.369161 0.009999 2.307259 +v -0.369161 0.009999 2.214968 +v -0.461452 0.009999 2.214968 +v -0.461452 0.009999 2.676420 +v -0.369161 0.009999 2.676420 +v -0.369161 0.009999 2.584130 +v -0.461452 0.009999 2.584130 +v -0.092290 0.009999 2.676420 +v 0.000000 0.009999 2.676420 +v 0.000000 0.009999 2.584130 +v -0.092290 0.009999 2.584130 +v -1.199775 0.009999 2.307259 +v -1.107484 0.009999 2.307259 +v -1.107484 0.009999 2.214968 +v -1.199775 0.009999 2.214968 +v -1.199775 0.009999 2.676420 +v -1.107484 0.009999 2.676420 +v -1.107484 0.009999 2.584130 +v -1.199775 0.009999 2.584130 +v -0.830613 0.009999 2.676420 +v -0.738323 0.009999 2.676420 +v -0.738323 0.009999 2.584130 +v -0.830613 0.009999 2.584130 +v -1.199775 0.009999 1.568936 +v -1.107484 0.009999 1.568936 +v -1.107484 0.009999 1.476646 +v -1.199775 0.009999 1.476646 +v -1.199775 0.009999 1.938097 +v -1.107484 0.009999 1.938097 +v -1.107484 0.009999 1.845807 +v -1.199775 0.009999 1.845807 +v -0.830613 0.009999 1.938097 +v -0.738323 0.009999 1.938097 +v -0.738323 0.009999 1.845807 +v -0.830613 0.009999 1.845807 +v -1.938097 0.010002 -5.075970 +v -1.845807 0.010002 -5.075970 +v -1.845807 0.010002 -5.168260 +v -1.938097 0.010002 -5.168260 +v -1.938097 0.010002 -4.706808 +v -1.845807 0.010002 -4.706808 +v -1.845807 0.010002 -4.799098 +v -1.938097 0.010002 -4.799098 +v -1.568936 0.010002 -4.706808 +v -1.476646 0.010002 -4.706808 +v -1.476646 0.010002 -4.799098 +v -1.568936 0.010002 -4.799098 +v -2.676420 0.010002 -5.075970 +v -2.584130 0.010002 -5.075970 +v -2.584130 0.010002 -5.168260 +v -2.676420 0.010002 -5.168260 +v -2.676420 0.010002 -4.706808 +v -2.584130 0.010002 -4.706808 +v -2.584130 0.010002 -4.799098 +v -2.676420 0.010002 -4.799098 +v -2.307259 0.010002 -4.706808 +v -2.214968 0.010002 -4.706808 +v -2.214968 0.010002 -4.799098 +v -2.307259 0.010002 -4.799098 +v -2.676420 0.010002 -5.814293 +v -2.584130 0.010002 -5.814293 +v -2.584130 0.010002 -5.906583 +v -2.676420 0.010002 -5.906583 +v -2.676420 0.010002 -5.445131 +v -2.584130 0.010002 -5.445131 +v -2.584130 0.010002 -5.537421 +v -2.676420 0.010002 -5.537421 +v -2.307259 0.010002 -5.445131 +v -2.214968 0.010002 -5.445131 +v -2.214968 0.010002 -5.537421 +v -2.307259 0.010002 -5.537421 +v -1.938097 0.010001 -3.599324 +v -1.845807 0.010001 -3.599324 +v -1.845807 0.010002 -3.691614 +v -1.938097 0.010002 -3.691614 +v -1.938097 0.010001 -3.230163 +v -1.845807 0.010001 -3.230163 +v -1.845807 0.010001 -3.322453 +v -1.938097 0.010001 -3.322453 +v -1.568936 0.010001 -3.230163 +v -1.476646 0.010001 -3.230163 +v -1.476646 0.010001 -3.322453 +v -1.568936 0.010001 -3.322453 +v -2.676420 0.010001 -3.599324 +v -2.584130 0.010001 -3.599324 +v -2.584130 0.010002 -3.691614 +v -2.676420 0.010002 -3.691614 +v -2.676420 0.010001 -3.230163 +v -2.584130 0.010001 -3.230163 +v -2.584130 0.010001 -3.322453 +v -2.676420 0.010001 -3.322453 +v -2.307259 0.010001 -3.230163 +v -2.214968 0.010001 -3.230163 +v -2.214968 0.010001 -3.322453 +v -2.307259 0.010001 -3.322453 +v -2.676420 0.010002 -4.337647 +v -2.584130 0.010002 -4.337647 +v -2.584130 0.010002 -4.429937 +v -2.676420 0.010002 -4.429937 +v -2.676420 0.010002 -3.968485 +v -2.584130 0.010002 -3.968485 +v -2.584130 0.010002 -4.060776 +v -2.676420 0.010002 -4.060776 +v -2.307259 0.010002 -3.968485 +v -2.214968 0.010002 -3.968485 +v -2.214968 0.010002 -4.060776 +v -2.307259 0.010002 -4.060776 +v -0.461452 0.010001 -3.599324 +v -0.369161 0.010001 -3.599324 +v -0.369161 0.010002 -3.691614 +v -0.461452 0.010002 -3.691614 +v -0.461452 0.010001 -3.230163 +v -0.369161 0.010001 -3.230163 +v -0.369161 0.010001 -3.322453 +v -0.461452 0.010001 -3.322453 +v -0.092290 0.010001 -3.230163 +v 0.000000 0.010001 -3.230163 +v 0.000000 0.010001 -3.322453 +v -0.092290 0.010001 -3.322453 +v -1.199775 0.010001 -3.599324 +v -1.107484 0.010001 -3.599324 +v -1.107484 0.010002 -3.691614 +v -1.199775 0.010002 -3.691614 +v -1.199775 0.010001 -3.230163 +v -1.107484 0.010001 -3.230163 +v -1.107484 0.010001 -3.322453 +v -1.199775 0.010001 -3.322453 +v -0.830613 0.010001 -3.230163 +v -0.738323 0.010001 -3.230163 +v -0.738323 0.010001 -3.322453 +v -0.830613 0.010001 -3.322453 +v -1.199775 0.010002 -4.337647 +v -1.107484 0.010002 -4.337647 +v -1.107484 0.010002 -4.429937 +v -1.199775 0.010002 -4.429937 +v -1.199775 0.010002 -3.968485 +v -1.107484 0.010002 -3.968485 +v -1.107484 0.010002 -4.060776 +v -1.199775 0.010002 -4.060776 +v -0.830613 0.010002 -3.968485 +v -0.738323 0.010002 -3.968485 +v -0.738323 0.010002 -4.060776 +v -0.830613 0.010002 -4.060776 +v 3.968485 0.010002 -5.075970 +v 4.060776 0.010002 -5.075970 +v 4.060776 0.010002 -5.168260 +v 3.968485 0.010002 -5.168260 +v 3.968485 0.010002 -4.706808 +v 4.060776 0.010002 -4.706808 +v 4.060776 0.010002 -4.799098 +v 3.968485 0.010002 -4.799098 +v 4.337647 0.010002 -4.706808 +v 4.429937 0.010002 -4.706808 +v 4.429937 0.010002 -4.799098 +v 4.337647 0.010002 -4.799098 +v 3.230163 0.010002 -5.075970 +v 3.322453 0.010002 -5.075970 +v 3.322453 0.010002 -5.168260 +v 3.230163 0.010002 -5.168260 +v 3.230163 0.010002 -4.706808 +v 3.322453 0.010002 -4.706808 +v 3.322453 0.010002 -4.799098 +v 3.230163 0.010002 -4.799098 +v 3.599324 0.010002 -4.706808 +v 3.691614 0.010002 -4.706808 +v 3.691614 0.010002 -4.799098 +v 3.599324 0.010002 -4.799098 +v 3.230163 0.010002 -5.814293 +v 3.322453 0.010002 -5.814293 +v 3.322453 0.010002 -5.906583 +v 3.230163 0.010002 -5.906583 +v 3.230163 0.010002 -5.445131 +v 3.322453 0.010002 -5.445131 +v 3.322453 0.010002 -5.537421 +v 3.230163 0.010002 -5.537421 +v 3.599324 0.010002 -5.445131 +v 3.691614 0.010002 -5.445131 +v 3.691614 0.010002 -5.537421 +v 3.599324 0.010002 -5.537421 +v 3.968485 0.010001 -3.599324 +v 4.060776 0.010001 -3.599324 +v 4.060776 0.010002 -3.691614 +v 3.968485 0.010002 -3.691614 +v 3.968485 0.010001 -3.230163 +v 4.060776 0.010001 -3.230163 +v 4.060776 0.010001 -3.322453 +v 3.968485 0.010001 -3.322453 +v 4.337647 0.010001 -3.230163 +v 4.429937 0.010001 -3.230163 +v 4.429937 0.010001 -3.322453 +v 4.337647 0.010001 -3.322453 +v 3.230163 0.010001 -3.599324 +v 3.322453 0.010001 -3.599324 +v 3.322453 0.010002 -3.691614 +v 3.230163 0.010002 -3.691614 +v 3.230163 0.010001 -3.230163 +v 3.322453 0.010001 -3.230163 +v 3.322453 0.010001 -3.322453 +v 3.230163 0.010001 -3.322453 +v 3.599324 0.010001 -3.230163 +v 3.691614 0.010001 -3.230163 +v 3.691614 0.010001 -3.322453 +v 3.599324 0.010001 -3.322453 +v 3.230163 0.010002 -4.337647 +v 3.322453 0.010002 -4.337647 +v 3.322453 0.010002 -4.429937 +v 3.230163 0.010002 -4.429937 +v 3.230163 0.010002 -3.968485 +v 3.322453 0.010002 -3.968485 +v 3.322453 0.010002 -4.060776 +v 3.230163 0.010002 -4.060776 +v 3.599324 0.010002 -3.968485 +v 3.691614 0.010002 -3.968485 +v 3.691614 0.010002 -4.060776 +v 3.599324 0.010002 -4.060776 +v 5.445131 0.010001 -3.599324 +v 5.537421 0.010001 -3.599324 +v 5.537421 0.010002 -3.691614 +v 5.445131 0.010002 -3.691614 +v 5.445131 0.010001 -3.230163 +v 5.537421 0.010001 -3.230163 +v 5.537421 0.010001 -3.322453 +v 5.445131 0.010001 -3.322453 +v 5.814293 0.010001 -3.230163 +v 5.906583 0.010001 -3.230163 +v 5.906583 0.010001 -3.322453 +v 5.814293 0.010001 -3.322453 +v 4.706808 0.010001 -3.599324 +v 4.799098 0.010001 -3.599324 +v 4.799098 0.010002 -3.691614 +v 4.706808 0.010002 -3.691614 +v 4.706808 0.010001 -3.230163 +v 4.799098 0.010001 -3.230163 +v 4.799098 0.010001 -3.322453 +v 4.706808 0.010001 -3.322453 +v 5.075970 0.010001 -3.230163 +v 5.168260 0.010001 -3.230163 +v 5.168260 0.010001 -3.322453 +v 5.075970 0.010001 -3.322453 +v 4.706808 0.010002 -4.337647 +v 4.799098 0.010002 -4.337647 +v 4.799098 0.010002 -4.429937 +v 4.706808 0.010002 -4.429937 +v 4.706808 0.010002 -3.968485 +v 4.799098 0.010002 -3.968485 +v 4.799098 0.010002 -4.060776 +v 4.706808 0.010002 -4.060776 +v 5.075970 0.010002 -3.968485 +v 5.168260 0.010002 -3.968485 +v 5.168260 0.010002 -4.060776 +v 5.075970 0.010002 -4.060776 +v 5.445131 0.010002 -4.337647 +v 5.537421 0.010002 -4.337647 +v 5.537421 0.010002 -4.429937 +v 5.445131 0.010002 -4.429937 +v 5.445131 0.010002 -3.968485 +v 5.537421 0.010002 -3.968485 +v 5.537421 0.010002 -4.060776 +v 5.445131 0.010002 -4.060776 +v 5.814293 0.010002 -3.968485 +v 5.906583 0.010002 -3.968485 +v 5.906583 0.010002 -4.060776 +v 5.814293 0.010002 -4.060776 +v 3.968485 0.010002 -4.337647 +v 4.060776 0.010002 -4.337647 +v 4.060776 0.010002 -4.429937 +v 3.968485 0.010002 -4.429937 +v 3.968485 0.010002 -3.968485 +v 4.060776 0.010002 -3.968485 +v 4.060776 0.010002 -4.060776 +v 3.968485 0.010002 -4.060776 +v 4.337647 0.010002 -3.968485 +v 4.429937 0.010002 -3.968485 +v 4.429937 0.010002 -4.060776 +v 4.337647 0.010002 -4.060776 +v 3.968485 0.010002 -5.814293 +v 4.060776 0.010002 -5.814293 +v 4.060776 0.010002 -5.906583 +v 3.968485 0.010002 -5.906583 +v 3.968485 0.010002 -5.445131 +v 4.060776 0.010002 -5.445131 +v 4.060776 0.010002 -5.537421 +v 3.968485 0.010002 -5.537421 +v 4.337647 0.010002 -5.445131 +v 4.429937 0.010002 -5.445131 +v 4.429937 0.010002 -5.537421 +v 4.337647 0.010002 -5.537421 +v -0.461452 0.010002 -4.337647 +v -0.369161 0.010002 -4.337647 +v -0.369161 0.010002 -4.429937 +v -0.461452 0.010002 -4.429937 +v -0.461452 0.010002 -3.968485 +v -0.369161 0.010002 -3.968485 +v -0.369161 0.010002 -4.060776 +v -0.461452 0.010002 -4.060776 +v -0.092290 0.010002 -3.968485 +v 0.000000 0.010002 -3.968485 +v 0.000000 0.010002 -4.060776 +v -0.092290 0.010002 -4.060776 +v -1.938097 0.010002 -4.337647 +v -1.845807 0.010002 -4.337647 +v -1.845807 0.010002 -4.429937 +v -1.938097 0.010002 -4.429937 +v -1.938097 0.010002 -3.968485 +v -1.845807 0.010002 -3.968485 +v -1.845807 0.010002 -4.060776 +v -1.938097 0.010002 -4.060776 +v -1.568936 0.010002 -3.968485 +v -1.476646 0.010002 -3.968485 +v -1.476646 0.010002 -4.060776 +v -1.568936 0.010002 -4.060776 +v -1.938097 0.010002 -5.814293 +v -1.845807 0.010002 -5.814293 +v -1.845807 0.010002 -5.906583 +v -1.938097 0.010002 -5.906583 +v -1.938097 0.010002 -5.445131 +v -1.845807 0.010002 -5.445131 +v -1.845807 0.010002 -5.537421 +v -1.938097 0.010002 -5.537421 +v -1.568936 0.010002 -5.445131 +v -1.476646 0.010002 -5.445131 +v -1.476646 0.010002 -5.537421 +v -1.568936 0.010002 -5.537421 +v -0.461452 0.009999 1.568936 +v -0.369161 0.009999 1.568936 +v -0.369161 0.009999 1.476646 +v -0.461452 0.009999 1.476646 +v -0.461452 0.009999 1.938097 +v -0.369161 0.009999 1.938097 +v -0.369161 0.009999 1.845807 +v -0.461452 0.009999 1.845807 +v -0.092290 0.009999 1.938097 +v 0.000000 0.009999 1.938097 +v 0.000000 0.009999 1.845807 +v -0.092290 0.009999 1.845807 +v -1.938097 0.009999 1.568936 +v -1.845807 0.009999 1.568936 +v -1.845807 0.009999 1.476646 +v -1.938097 0.009999 1.476646 +v -1.938097 0.009999 1.938097 +v -1.845807 0.009999 1.938097 +v -1.845807 0.009999 1.845807 +v -1.938097 0.009999 1.845807 +v -1.568936 0.009999 1.938097 +v -1.476646 0.009999 1.938097 +v -1.476646 0.009999 1.845807 +v -1.568936 0.009999 1.845807 +v -1.938097 0.010000 0.092290 +v -1.845807 0.010000 0.092290 +v -1.845807 0.010000 -0.000000 +v -1.938097 0.010000 -0.000000 +v -1.938097 0.010000 0.461452 +v -1.845807 0.010000 0.461452 +v -1.845807 0.010000 0.369161 +v -1.938097 0.010000 0.369161 +v -1.568936 0.010000 0.461452 +v -1.476646 0.010000 0.461452 +v -1.476646 0.010000 0.369161 +v -1.568936 0.010000 0.369161 +v 5.445131 0.009999 1.568936 +v 5.537421 0.009999 1.568936 +v 5.537421 0.009999 1.476646 +v 5.445131 0.009999 1.476646 +v 5.445131 0.009999 1.938097 +v 5.537421 0.009999 1.938097 +v 5.537421 0.009999 1.845807 +v 5.445131 0.009999 1.845807 +v 5.814293 0.009999 1.938097 +v 5.906583 0.009999 1.938097 +v 5.906583 0.009999 1.845807 +v 5.814293 0.009999 1.845807 +v 3.968485 0.009999 1.568936 +v 4.060776 0.009999 1.568936 +v 4.060776 0.009999 1.476646 +v 3.968485 0.009999 1.476646 +v 3.968485 0.009999 1.938097 +v 4.060776 0.009999 1.938097 +v 4.060776 0.009999 1.845807 +v 3.968485 0.009999 1.845807 +v 4.337647 0.009999 1.938097 +v 4.429937 0.009999 1.938097 +v 4.429937 0.009999 1.845807 +v 4.337647 0.009999 1.845807 +v 3.968485 0.010000 0.092290 +v 4.060776 0.010000 0.092290 +v 4.060776 0.010000 -0.000000 +v 3.968485 0.010000 -0.000000 +v 3.968485 0.010000 0.461452 +v 4.060776 0.010000 0.461452 +v 4.060776 0.010000 0.369161 +v 3.968485 0.010000 0.369161 +v 4.337647 0.010000 0.461452 +v 4.429937 0.010000 0.461452 +v 4.429937 0.010000 0.369161 +v 4.337647 0.010000 0.369161 +v 2.491840 0.009999 1.568936 +v 2.584130 0.009999 1.568936 +v 2.584130 0.009999 1.476646 +v 2.491840 0.009999 1.476646 +v 2.491840 0.009999 1.938097 +v 2.584130 0.009999 1.938097 +v 2.584130 0.009999 1.845807 +v 2.491840 0.009999 1.845807 +v 2.861001 0.009999 1.938097 +v 2.953291 0.009999 1.938097 +v 2.953291 0.009999 1.845807 +v 2.861001 0.009999 1.845807 +v 1.015194 0.009999 1.568936 +v 1.107484 0.009999 1.568936 +v 1.107484 0.009999 1.476646 +v 1.015194 0.009999 1.476646 +v 1.015194 0.009999 1.938097 +v 1.107484 0.009999 1.938097 +v 1.107484 0.009999 1.845807 +v 1.015194 0.009999 1.845807 +v 1.384355 0.009999 1.938097 +v 1.476646 0.009999 1.938097 +v 1.476646 0.009999 1.845807 +v 1.384355 0.009999 1.845807 +v 1.015194 0.010000 0.092290 +v 1.107484 0.010000 0.092290 +v 1.107484 0.010000 -0.000000 +v 1.015194 0.010000 -0.000000 +v 1.015194 0.010000 0.461452 +v 1.107484 0.010000 0.461452 +v 1.107484 0.010000 0.369161 +v 1.015194 0.010000 0.369161 +v 1.384355 0.010000 0.461452 +v 1.476646 0.010000 0.461452 +v 1.476646 0.010000 0.369161 +v 1.384355 0.010000 0.369161 +v 2.491840 0.009998 4.522227 +v 2.584130 0.009998 4.522227 +v 2.584130 0.009998 4.429937 +v 2.491840 0.009998 4.429937 +v 2.491840 0.009998 4.891389 +v 2.584130 0.009998 4.891389 +v 2.584130 0.009998 4.799098 +v 2.491840 0.009998 4.799098 +v 2.861001 0.009998 4.891389 +v 2.953291 0.009998 4.891389 +v 2.953291 0.009998 4.799098 +v 2.861001 0.009998 4.799098 +v 1.015194 0.009998 4.522227 +v 1.107484 0.009998 4.522227 +v 1.107484 0.009998 4.429937 +v 1.015194 0.009998 4.429937 +v 1.015194 0.009998 4.891389 +v 1.107484 0.009998 4.891389 +v 1.107484 0.009998 4.799098 +v 1.015194 0.009998 4.799098 +v 1.384355 0.009998 4.891389 +v 1.476646 0.009998 4.891389 +v 1.476646 0.009998 4.799098 +v 1.384355 0.009998 4.799098 +v 1.015194 0.009999 3.045582 +v 1.107484 0.009999 3.045582 +v 1.107484 0.009999 2.953291 +v 1.015194 0.009999 2.953291 +v 1.015194 0.009999 3.414743 +v 1.107484 0.009999 3.414743 +v 1.107484 0.009999 3.322453 +v 1.015194 0.009999 3.322453 +v 1.384355 0.009999 3.414743 +v 1.476646 0.009999 3.414743 +v 1.476646 0.009999 3.322453 +v 1.384355 0.009999 3.322453 +v 5.445131 0.009998 4.522227 +v 5.537421 0.009998 4.522227 +v 5.537421 0.009998 4.429937 +v 5.445131 0.009998 4.429937 +v 5.445131 0.009998 4.891389 +v 5.537421 0.009998 4.891389 +v 5.537421 0.009998 4.799098 +v 5.445131 0.009998 4.799098 +v 5.814293 0.009998 4.891389 +v 5.906583 0.009998 4.891389 +v 5.906583 0.009998 4.799098 +v 5.814293 0.009998 4.799098 +v 3.968485 0.009998 4.522227 +v 4.060776 0.009998 4.522227 +v 4.060776 0.009998 4.429937 +v 3.968485 0.009998 4.429937 +v 3.968485 0.009998 4.891389 +v 4.060776 0.009998 4.891389 +v 4.060776 0.009998 4.799098 +v 3.968485 0.009998 4.799098 +v 4.337647 0.009998 4.891389 +v 4.429937 0.009998 4.891389 +v 4.429937 0.009998 4.799098 +v 4.337647 0.009998 4.799098 +v 3.968485 0.009999 3.045582 +v 4.060776 0.009999 3.045582 +v 4.060776 0.009999 2.953291 +v 3.968485 0.009999 2.953291 +v 3.968485 0.009999 3.414743 +v 4.060776 0.009999 3.414743 +v 4.060776 0.009999 3.322453 +v 3.968485 0.009999 3.322453 +v 4.337647 0.009999 3.414743 +v 4.429937 0.009999 3.414743 +v 4.429937 0.009999 3.322453 +v 4.337647 0.009999 3.322453 +v -3.414743 0.009999 1.568936 +v -3.322453 0.009999 1.568936 +v -3.322453 0.009999 1.476646 +v -3.414743 0.009999 1.476646 +v -3.414743 0.009999 1.938097 +v -3.322453 0.009999 1.938097 +v -3.322453 0.009999 1.845807 +v -3.414743 0.009999 1.845807 +v -3.045582 0.009999 1.938097 +v -2.953291 0.009999 1.938097 +v -2.953291 0.009999 1.845807 +v -3.045582 0.009999 1.845807 +v -4.891389 0.009999 1.568936 +v -4.799098 0.009999 1.568936 +v -4.799098 0.009999 1.476646 +v -4.891389 0.009999 1.476646 +v -4.891389 0.009999 1.938097 +v -4.799098 0.009999 1.938097 +v -4.799098 0.009999 1.845807 +v -4.891389 0.009999 1.845807 +v -4.522227 0.009999 1.938097 +v -4.429937 0.009999 1.938097 +v -4.429937 0.009999 1.845807 +v -4.522227 0.009999 1.845807 +v -4.891389 0.010000 0.092290 +v -4.799098 0.010000 0.092290 +v -4.799098 0.010000 -0.000000 +v -4.891389 0.010000 -0.000000 +v -4.891389 0.010000 0.461452 +v -4.799098 0.010000 0.461452 +v -4.799098 0.010000 0.369161 +v -4.891389 0.010000 0.369161 +v -4.522227 0.010000 0.461452 +v -4.429937 0.010000 0.461452 +v -4.429937 0.010000 0.369161 +v -4.522227 0.010000 0.369161 +v -3.414743 0.009998 4.522227 +v -3.322453 0.009998 4.522227 +v -3.322453 0.009998 4.429937 +v -3.414743 0.009998 4.429937 +v -3.414743 0.009998 4.891389 +v -3.322453 0.009998 4.891389 +v -3.322453 0.009998 4.799098 +v -3.414743 0.009998 4.799098 +v -3.045582 0.009998 4.891389 +v -2.953291 0.009998 4.891389 +v -2.953291 0.009998 4.799098 +v -3.045582 0.009998 4.799098 +v -4.891389 0.009998 4.522227 +v -4.799098 0.009998 4.522227 +v -4.799098 0.009998 4.429937 +v -4.891389 0.009998 4.429937 +v -4.891389 0.009998 4.891389 +v -4.799098 0.009998 4.891389 +v -4.799098 0.009998 4.799098 +v -4.891389 0.009998 4.799098 +v -4.522227 0.009998 4.891389 +v -4.429937 0.009998 4.891389 +v -4.429937 0.009998 4.799098 +v -4.522227 0.009998 4.799098 +v -4.891389 0.009999 3.045582 +v -4.799098 0.009999 3.045582 +v -4.799098 0.009999 2.953291 +v -4.891389 0.009999 2.953291 +v -4.891389 0.009999 3.414743 +v -4.799098 0.009999 3.414743 +v -4.799098 0.009999 3.322453 +v -4.891389 0.009999 3.322453 +v -4.522227 0.009999 3.414743 +v -4.429937 0.009999 3.414743 +v -4.429937 0.009999 3.322453 +v -4.522227 0.009999 3.322453 +v -0.461452 0.009998 4.522227 +v -0.369161 0.009998 4.522227 +v -0.369161 0.009998 4.429937 +v -0.461452 0.009998 4.429937 +v -0.461452 0.009998 4.891389 +v -0.369161 0.009998 4.891389 +v -0.369161 0.009998 4.799098 +v -0.461452 0.009998 4.799098 +v -0.092290 0.009998 4.891389 +v 0.000000 0.009998 4.891389 +v 0.000000 0.009998 4.799098 +v -0.092290 0.009998 4.799098 +v -1.938097 0.009998 4.522227 +v -1.845807 0.009998 4.522227 +v -1.845807 0.009998 4.429937 +v -1.938097 0.009998 4.429937 +v -1.938097 0.009998 4.891389 +v -1.845807 0.009998 4.891389 +v -1.845807 0.009998 4.799098 +v -1.938097 0.009998 4.799098 +v -1.568936 0.009998 4.891389 +v -1.476646 0.009998 4.891389 +v -1.476646 0.009998 4.799098 +v -1.568936 0.009998 4.799098 +v -1.938097 0.009999 3.045582 +v -1.845807 0.009999 3.045582 +v -1.845807 0.009999 2.953291 +v -1.938097 0.009999 2.953291 +v -1.938097 0.009999 3.414743 +v -1.845807 0.009999 3.414743 +v -1.845807 0.009999 3.322453 +v -1.938097 0.009999 3.322453 +v -1.568936 0.009999 3.414743 +v -1.476646 0.009999 3.414743 +v -1.476646 0.009999 3.322453 +v -1.568936 0.009999 3.322453 +v -3.414743 0.010002 -4.337647 +v -3.322453 0.010002 -4.337647 +v -3.322453 0.010002 -4.429937 +v -3.414743 0.010002 -4.429937 +v -3.414743 0.010002 -3.968485 +v -3.322453 0.010002 -3.968485 +v -3.322453 0.010002 -4.060776 +v -3.414743 0.010002 -4.060776 +v -3.045582 0.010002 -3.968485 +v -2.953291 0.010002 -3.968485 +v -2.953291 0.010002 -4.060776 +v -3.045582 0.010002 -4.060776 +v -4.891389 0.010002 -4.337647 +v -4.799098 0.010002 -4.337647 +v -4.799098 0.010002 -4.429937 +v -4.891389 0.010002 -4.429937 +v -4.891389 0.010002 -3.968485 +v -4.799098 0.010002 -3.968485 +v -4.799098 0.010002 -4.060776 +v -4.891389 0.010002 -4.060776 +v -4.522227 0.010002 -3.968485 +v -4.429937 0.010002 -3.968485 +v -4.429937 0.010002 -4.060776 +v -4.522227 0.010002 -4.060776 +v -4.891389 0.010002 -5.814293 +v -4.799098 0.010002 -5.814293 +v -4.799098 0.010002 -5.906583 +v -4.891389 0.010002 -5.906583 +v -4.891389 0.010002 -5.445131 +v -4.799098 0.010002 -5.445131 +v -4.799098 0.010002 -5.537421 +v -4.891389 0.010002 -5.537421 +v -4.522227 0.010002 -5.445131 +v -4.429937 0.010002 -5.445131 +v -4.429937 0.010002 -5.537421 +v -4.522227 0.010002 -5.537421 +v -3.414743 0.010001 -1.384355 +v -3.322453 0.010001 -1.384355 +v -3.322453 0.010001 -1.476646 +v -3.414743 0.010001 -1.476646 +v -3.414743 0.010000 -1.015194 +v -3.322453 0.010000 -1.015194 +v -3.322453 0.010000 -1.107484 +v -3.414743 0.010000 -1.107484 +v -3.045582 0.010000 -1.015194 +v -2.953291 0.010000 -1.015194 +v -2.953291 0.010000 -1.107484 +v -3.045582 0.010000 -1.107484 +v -4.891389 0.010001 -1.384355 +v -4.799098 0.010001 -1.384355 +v -4.799098 0.010001 -1.476646 +v -4.891389 0.010001 -1.476646 +v -4.891389 0.010000 -1.015194 +v -4.799098 0.010000 -1.015194 +v -4.799098 0.010000 -1.107484 +v -4.891389 0.010000 -1.107484 +v -4.522227 0.010000 -1.015194 +v -4.429937 0.010000 -1.015194 +v -4.429937 0.010000 -1.107484 +v -4.522227 0.010000 -1.107484 +v -4.891389 0.010001 -2.861001 +v -4.799098 0.010001 -2.861001 +v -4.799098 0.010001 -2.953291 +v -4.891389 0.010001 -2.953291 +v -4.891389 0.010001 -2.491840 +v -4.799098 0.010001 -2.491840 +v -4.799098 0.010001 -2.584130 +v -4.891389 0.010001 -2.584130 +v -4.522227 0.010001 -2.491840 +v -4.429937 0.010001 -2.491840 +v -4.429937 0.010001 -2.584130 +v -4.522227 0.010001 -2.584130 +v -0.461452 0.010001 -1.384355 +v -0.369161 0.010001 -1.384355 +v -0.369161 0.010001 -1.476646 +v -0.461452 0.010001 -1.476646 +v -0.461452 0.010000 -1.015194 +v -0.369161 0.010000 -1.015194 +v -0.369161 0.010000 -1.107484 +v -0.461452 0.010000 -1.107484 +v -0.092290 0.010000 -1.015194 +v 0.000000 0.010000 -1.015194 +v 0.000000 0.010000 -1.107484 +v -0.092290 0.010000 -1.107484 +v -1.938097 0.010001 -1.384355 +v -1.845807 0.010001 -1.384355 +v -1.845807 0.010001 -1.476646 +v -1.938097 0.010001 -1.476646 +v -1.938097 0.010000 -1.015194 +v -1.845807 0.010000 -1.015194 +v -1.845807 0.010000 -1.107484 +v -1.938097 0.010000 -1.107484 +v -1.568936 0.010000 -1.015194 +v -1.476646 0.010000 -1.015194 +v -1.476646 0.010000 -1.107484 +v -1.568936 0.010000 -1.107484 +v -1.938097 0.010001 -2.861001 +v -1.845807 0.010001 -2.861001 +v -1.845807 0.010001 -2.953291 +v -1.938097 0.010001 -2.953291 +v -1.938097 0.010001 -2.491840 +v -1.845807 0.010001 -2.491840 +v -1.845807 0.010001 -2.584130 +v -1.938097 0.010001 -2.584130 +v -1.568936 0.010001 -2.491840 +v -1.476646 0.010001 -2.491840 +v -1.476646 0.010001 -2.584130 +v -1.568936 0.010001 -2.584130 +v 2.491840 0.010002 -4.337647 +v 2.584130 0.010002 -4.337647 +v 2.584130 0.010002 -4.429937 +v 2.491840 0.010002 -4.429937 +v 2.491840 0.010002 -3.968485 +v 2.584130 0.010002 -3.968485 +v 2.584130 0.010002 -4.060776 +v 2.491840 0.010002 -4.060776 +v 2.861001 0.010002 -3.968485 +v 2.953291 0.010002 -3.968485 +v 2.953291 0.010002 -4.060776 +v 2.861001 0.010002 -4.060776 +v 1.015194 0.010002 -4.337647 +v 1.107484 0.010002 -4.337647 +v 1.107484 0.010002 -4.429937 +v 1.015194 0.010002 -4.429937 +v 1.015194 0.010002 -3.968485 +v 1.107484 0.010002 -3.968485 +v 1.107484 0.010002 -4.060776 +v 1.015194 0.010002 -4.060776 +v 1.384355 0.010002 -3.968485 +v 1.476646 0.010002 -3.968485 +v 1.476646 0.010002 -4.060776 +v 1.384355 0.010002 -4.060776 +v 1.015194 0.010002 -5.814293 +v 1.107484 0.010002 -5.814293 +v 1.107484 0.010002 -5.906583 +v 1.015194 0.010002 -5.906583 +v 1.015194 0.010002 -5.445131 +v 1.107484 0.010002 -5.445131 +v 1.107484 0.010002 -5.537421 +v 1.015194 0.010002 -5.537421 +v 1.384355 0.010002 -5.445131 +v 1.476646 0.010002 -5.445131 +v 1.476646 0.010002 -5.537421 +v 1.384355 0.010002 -5.537421 +v 2.491840 0.010001 -1.384355 +v 2.584130 0.010001 -1.384355 +v 2.584130 0.010001 -1.476646 +v 2.491840 0.010001 -1.476646 +v 2.491840 0.010000 -1.015194 +v 2.584130 0.010000 -1.015194 +v 2.584130 0.010000 -1.107484 +v 2.491840 0.010000 -1.107484 +v 2.861001 0.010000 -1.015194 +v 2.953291 0.010000 -1.015194 +v 2.953291 0.010000 -1.107484 +v 2.861001 0.010000 -1.107484 +v 1.015194 0.010001 -1.384355 +v 1.107484 0.010001 -1.384355 +v 1.107484 0.010001 -1.476646 +v 1.015194 0.010001 -1.476646 +v 1.015194 0.010000 -1.015194 +v 1.107484 0.010000 -1.015194 +v 1.107484 0.010000 -1.107484 +v 1.015194 0.010000 -1.107484 +v 1.384355 0.010000 -1.015194 +v 1.476646 0.010000 -1.015194 +v 1.476646 0.010000 -1.107484 +v 1.384355 0.010000 -1.107484 +v 1.015194 0.010001 -2.861001 +v 1.107484 0.010001 -2.861001 +v 1.107484 0.010001 -2.953291 +v 1.015194 0.010001 -2.953291 +v 1.015194 0.010001 -2.491840 +v 1.107484 0.010001 -2.491840 +v 1.107484 0.010001 -2.584130 +v 1.015194 0.010001 -2.584130 +v 1.384355 0.010001 -2.491840 +v 1.476646 0.010001 -2.491840 +v 1.476646 0.010001 -2.584130 +v 1.384355 0.010001 -2.584130 +v 5.445131 0.010001 -1.384355 +v 5.537421 0.010001 -1.384355 +v 5.537421 0.010001 -1.476646 +v 5.445131 0.010001 -1.476646 +v 5.445131 0.010000 -1.015194 +v 5.537421 0.010000 -1.015194 +v 5.537421 0.010000 -1.107484 +v 5.445131 0.010000 -1.107484 +v 5.814293 0.010000 -1.015194 +v 5.906583 0.010000 -1.015194 +v 5.906583 0.010000 -1.107484 +v 5.814293 0.010000 -1.107484 +v 3.968485 0.010001 -1.384355 +v 4.060776 0.010001 -1.384355 +v 4.060776 0.010001 -1.476646 +v 3.968485 0.010001 -1.476646 +v 3.968485 0.010000 -1.015194 +v 4.060776 0.010000 -1.015194 +v 4.060776 0.010000 -1.107484 +v 3.968485 0.010000 -1.107484 +v 4.337647 0.010000 -1.015194 +v 4.429937 0.010000 -1.015194 +v 4.429937 0.010000 -1.107484 +v 4.337647 0.010000 -1.107484 +v 3.968485 0.010001 -2.861001 +v 4.060776 0.010001 -2.861001 +v 4.060776 0.010001 -2.953291 +v 3.968485 0.010001 -2.953291 +v 3.968485 0.010001 -2.491840 +v 4.060776 0.010001 -2.491840 +v 4.060776 0.010001 -2.584130 +v 3.968485 0.010001 -2.584130 +v 4.337647 0.010001 -2.491840 +v 4.429937 0.010001 -2.491840 +v 4.429937 0.010001 -2.584130 +v 4.337647 0.010001 -2.584130 +v 5.445131 0.010001 -2.861001 +v 5.537421 0.010001 -2.861001 +v 5.537421 0.010001 -2.953291 +v 5.445131 0.010001 -2.953291 +v 5.445131 0.010001 -2.491840 +v 5.537421 0.010001 -2.491840 +v 5.537421 0.010001 -2.584130 +v 5.445131 0.010001 -2.584130 +v 5.814293 0.010001 -2.491840 +v 5.906583 0.010001 -2.491840 +v 5.906583 0.010001 -2.584130 +v 5.814293 0.010001 -2.584130 +v 2.491840 0.010001 -2.861001 +v 2.584130 0.010001 -2.861001 +v 2.584130 0.010001 -2.953291 +v 2.491840 0.010001 -2.953291 +v 2.491840 0.010001 -2.491840 +v 2.584130 0.010001 -2.491840 +v 2.584130 0.010001 -2.584130 +v 2.491840 0.010001 -2.584130 +v 2.861001 0.010001 -2.491840 +v 2.953291 0.010001 -2.491840 +v 2.953291 0.010001 -2.584130 +v 2.861001 0.010001 -2.584130 +v 2.491840 0.010002 -5.814293 +v 2.584130 0.010002 -5.814293 +v 2.584130 0.010002 -5.906583 +v 2.491840 0.010002 -5.906583 +v 2.491840 0.010002 -5.445131 +v 2.584130 0.010002 -5.445131 +v 2.584130 0.010002 -5.537421 +v 2.491840 0.010002 -5.537421 +v 2.861001 0.010002 -5.445131 +v 2.953291 0.010002 -5.445131 +v 2.953291 0.010002 -5.537421 +v 2.861001 0.010002 -5.537421 +v -0.461452 0.010001 -2.861001 +v -0.369161 0.010001 -2.861001 +v -0.369161 0.010001 -2.953291 +v -0.461452 0.010001 -2.953291 +v -0.461452 0.010001 -2.491840 +v -0.369161 0.010001 -2.491840 +v -0.369161 0.010001 -2.584130 +v -0.461452 0.010001 -2.584130 +v -0.092290 0.010001 -2.491840 +v 0.000000 0.010001 -2.491840 +v 0.000000 0.010001 -2.584130 +v -0.092290 0.010001 -2.584130 +v -3.414743 0.010001 -2.861001 +v -3.322453 0.010001 -2.861001 +v -3.322453 0.010001 -2.953291 +v -3.414743 0.010001 -2.953291 +v -3.414743 0.010001 -2.491840 +v -3.322453 0.010001 -2.491840 +v -3.322453 0.010001 -2.584130 +v -3.414743 0.010001 -2.584130 +v -3.045582 0.010001 -2.491840 +v -2.953291 0.010001 -2.491840 +v -2.953291 0.010001 -2.584130 +v -3.045582 0.010001 -2.584130 +v -3.414743 0.010002 -5.814293 +v -3.322453 0.010002 -5.814293 +v -3.322453 0.010002 -5.906583 +v -3.414743 0.010002 -5.906583 +v -3.414743 0.010002 -5.445131 +v -3.322453 0.010002 -5.445131 +v -3.322453 0.010002 -5.537421 +v -3.414743 0.010002 -5.537421 +v -3.045582 0.010002 -5.445131 +v -2.953291 0.010002 -5.445131 +v -2.953291 0.010002 -5.537421 +v -3.045582 0.010002 -5.537421 +v -0.461452 0.009999 3.045582 +v -0.369161 0.009999 3.045582 +v -0.369161 0.009999 2.953291 +v -0.461452 0.009999 2.953291 +v -0.461452 0.009999 3.414743 +v -0.369161 0.009999 3.414743 +v -0.369161 0.009999 3.322453 +v -0.461452 0.009999 3.322453 +v -0.092290 0.009999 3.414743 +v 0.000000 0.009999 3.414743 +v 0.000000 0.009999 3.322453 +v -0.092290 0.009999 3.322453 +v -3.414743 0.009999 3.045582 +v -3.322453 0.009999 3.045582 +v -3.322453 0.009999 2.953291 +v -3.414743 0.009999 2.953291 +v -3.414743 0.009999 3.414743 +v -3.322453 0.009999 3.414743 +v -3.322453 0.009999 3.322453 +v -3.414743 0.009999 3.322453 +v -3.045582 0.009999 3.414743 +v -2.953291 0.009999 3.414743 +v -2.953291 0.009999 3.322453 +v -3.045582 0.009999 3.322453 +v -3.414743 0.010000 0.092290 +v -3.322453 0.010000 0.092290 +v -3.322453 0.010000 -0.000000 +v -3.414743 0.010000 -0.000000 +v -3.414743 0.010000 0.461452 +v -3.322453 0.010000 0.461452 +v -3.322453 0.010000 0.369161 +v -3.414743 0.010000 0.369161 +v -3.045582 0.010000 0.461452 +v -2.953291 0.010000 0.461452 +v -2.953291 0.010000 0.369161 +v -3.045582 0.010000 0.369161 +v 5.445131 0.009999 3.045582 +v 5.537421 0.009999 3.045582 +v 5.537421 0.009999 2.953291 +v 5.445131 0.009999 2.953291 +v 5.445131 0.009999 3.414743 +v 5.537421 0.009999 3.414743 +v 5.537421 0.009999 3.322453 +v 5.445131 0.009999 3.322453 +v 5.814293 0.009999 3.414743 +v 5.906583 0.009999 3.414743 +v 5.906583 0.009999 3.322453 +v 5.814293 0.009999 3.322453 +v 2.491840 0.009999 3.045582 +v 2.584130 0.009999 3.045582 +v 2.584130 0.009999 2.953291 +v 2.491840 0.009999 2.953291 +v 2.491840 0.009999 3.414743 +v 2.584130 0.009999 3.414743 +v 2.584130 0.009999 3.322453 +v 2.491840 0.009999 3.322453 +v 2.861001 0.009999 3.414743 +v 2.953291 0.009999 3.414743 +v 2.953291 0.009999 3.322453 +v 2.861001 0.009999 3.322453 +v 2.491840 0.010000 0.092290 +v 2.584130 0.010000 0.092290 +v 2.584130 0.010000 -0.000000 +v 2.491840 0.010000 -0.000000 +v 2.491840 0.010000 0.461452 +v 2.584130 0.010000 0.461452 +v 2.584130 0.010000 0.369161 +v 2.491840 0.010000 0.369161 +v 2.861001 0.010000 0.461452 +v 2.953291 0.010000 0.461452 +v 2.953291 0.010000 0.369161 +v 2.861001 0.010000 0.369161 +v 5.445131 0.010000 0.092290 +v 5.537421 0.010000 0.092290 +v 5.537421 0.010000 -0.000000 +v 5.445131 0.010000 -0.000000 +v 5.445131 0.010000 0.461452 +v 5.537421 0.010000 0.461452 +v 5.537421 0.010000 0.369161 +v 5.445131 0.010000 0.369161 +v 5.814293 0.010000 0.461452 +v 5.906583 0.010000 0.461452 +v 5.906583 0.010000 0.369161 +v 5.814293 0.010000 0.369161 +v -0.461452 0.010000 0.092290 +v -0.369161 0.010000 0.092290 +v -0.369161 0.010000 -0.000000 +v -0.461452 0.010000 -0.000000 +v -0.461452 0.010000 0.461452 +v -0.369161 0.010000 0.461452 +v -0.369161 0.010000 0.369161 +v -0.461452 0.010000 0.369161 +v -0.092290 0.010000 0.461452 +v 0.000000 0.010000 0.461452 +v 0.000000 0.010000 0.369161 +v -0.092290 0.010000 0.369161 +v -0.461452 0.010002 -5.814293 +v -0.369161 0.010002 -5.814293 +v -0.369161 0.010002 -5.906583 +v -0.461452 0.010002 -5.906583 +v -0.461452 0.010002 -5.445131 +v -0.369161 0.010002 -5.445131 +v -0.369161 0.010002 -5.537421 +v -0.461452 0.010002 -5.537421 +v -0.092290 0.010002 -5.445131 +v 0.000000 0.010002 -5.445131 +v 0.000000 0.010002 -5.537421 +v -0.092290 0.010002 -5.537421 +v 5.445131 0.010002 -5.814293 +v 5.537421 0.010002 -5.814293 +v 5.537421 0.010002 -5.906583 +v 5.445131 0.010002 -5.906583 +v 5.445131 0.010002 -5.445131 +v 5.537421 0.010002 -5.445131 +v 5.537421 0.010002 -5.537421 +v 5.445131 0.010002 -5.537421 +v 5.814293 0.010002 -5.445131 +v 5.906583 0.010002 -5.445131 +v 5.906583 0.010002 -5.537421 +v 5.814293 0.010002 -5.537421 +v 5.629711 0.010002 -5.445131 +v 5.722002 0.010002 -5.445131 +v 5.722002 0.010002 -5.537421 +v 5.629711 0.010002 -5.537421 +v 5.629711 0.010002 -5.260550 +v 5.722002 0.010002 -5.260550 +v 5.722002 0.010002 -5.352840 +v 5.629711 0.010002 -5.352840 +v 5.814293 0.010002 -5.260550 +v 5.906583 0.010002 -5.260550 +v 5.906583 0.010002 -5.352840 +v 5.814293 0.010002 -5.352840 +v 5.260550 0.010002 -5.445131 +v 5.352840 0.010002 -5.445131 +v 5.352840 0.010002 -5.537421 +v 5.260550 0.010002 -5.537421 +v 5.260550 0.010002 -5.260550 +v 5.352840 0.010002 -5.260550 +v 5.352840 0.010002 -5.352840 +v 5.260550 0.010002 -5.352840 +v 5.445131 0.010002 -5.260550 +v 5.537421 0.010002 -5.260550 +v 5.537421 0.010002 -5.352840 +v 5.445131 0.010002 -5.352840 +v 5.260550 0.010002 -5.814293 +v 5.352840 0.010002 -5.814293 +v 5.352840 0.010002 -5.906583 +v 5.260550 0.010002 -5.906583 +v 5.260550 0.010002 -5.629711 +v 5.352840 0.010002 -5.629711 +v 5.352840 0.010002 -5.722002 +v 5.260550 0.010002 -5.722002 +v 5.445131 0.010002 -5.629711 +v 5.537421 0.010002 -5.629711 +v 5.537421 0.010002 -5.722002 +v 5.445131 0.010002 -5.722002 +v -0.276871 0.010002 -5.445131 +v -0.184581 0.010002 -5.445131 +v -0.184581 0.010002 -5.537421 +v -0.276871 0.010002 -5.537421 +v -0.276871 0.010002 -5.260550 +v -0.184581 0.010002 -5.260550 +v -0.184581 0.010002 -5.352840 +v -0.276871 0.010002 -5.352840 +v -0.092290 0.010002 -5.260550 +v 0.000000 0.010002 -5.260550 +v 0.000000 0.010002 -5.352840 +v -0.092290 0.010002 -5.352840 +v -0.646033 0.010002 -5.445131 +v -0.553742 0.010002 -5.445131 +v -0.553742 0.010002 -5.537421 +v -0.646033 0.010002 -5.537421 +v -0.646033 0.010002 -5.260550 +v -0.553742 0.010002 -5.260550 +v -0.553742 0.010002 -5.352840 +v -0.646033 0.010002 -5.352840 +v -0.461452 0.010002 -5.260550 +v -0.369161 0.010002 -5.260550 +v -0.369161 0.010002 -5.352840 +v -0.461452 0.010002 -5.352840 +v -0.646033 0.010002 -5.814293 +v -0.553742 0.010002 -5.814293 +v -0.553742 0.010002 -5.906583 +v -0.646033 0.010002 -5.906583 +v -0.646033 0.010002 -5.629711 +v -0.553742 0.010002 -5.629711 +v -0.553742 0.010002 -5.722002 +v -0.646033 0.010002 -5.722002 +v -0.461452 0.010002 -5.629711 +v -0.369161 0.010002 -5.629711 +v -0.369161 0.010002 -5.722002 +v -0.461452 0.010002 -5.722002 +v -0.276871 0.010000 0.461452 +v -0.184581 0.010000 0.461452 +v -0.184581 0.010000 0.369161 +v -0.276871 0.010000 0.369161 +v -0.276871 0.010000 0.646033 +v -0.184581 0.010000 0.646033 +v -0.184581 0.010000 0.553742 +v -0.276871 0.010000 0.553742 +v -0.092290 0.010000 0.646033 +v 0.000000 0.010000 0.646033 +v 0.000000 0.010000 0.553742 +v -0.092290 0.010000 0.553742 +v -0.646033 0.010000 0.461452 +v -0.553742 0.010000 0.461452 +v -0.553742 0.010000 0.369161 +v -0.646033 0.010000 0.369161 +v -0.646033 0.010000 0.646033 +v -0.553742 0.010000 0.646033 +v -0.553742 0.010000 0.553742 +v -0.646033 0.010000 0.553742 +v -0.461452 0.010000 0.646033 +v -0.369161 0.010000 0.646033 +v -0.369161 0.010000 0.553742 +v -0.461452 0.010000 0.553742 +v -0.646033 0.010000 0.092290 +v -0.553742 0.010000 0.092290 +v -0.553742 0.010000 -0.000000 +v -0.646033 0.010000 -0.000000 +v -0.646033 0.010000 0.276871 +v -0.553742 0.010000 0.276871 +v -0.553742 0.010000 0.184581 +v -0.646033 0.010000 0.184581 +v -0.461452 0.010000 0.276871 +v -0.369161 0.010000 0.276871 +v -0.369161 0.010000 0.184581 +v -0.461452 0.010000 0.184581 +v 5.629711 0.010000 0.461452 +v 5.722002 0.010000 0.461452 +v 5.722002 0.010000 0.369161 +v 5.629711 0.010000 0.369161 +v 5.629711 0.010000 0.646033 +v 5.722002 0.010000 0.646033 +v 5.722002 0.010000 0.553742 +v 5.629711 0.010000 0.553742 +v 5.814293 0.010000 0.646033 +v 5.906583 0.010000 0.646033 +v 5.906583 0.010000 0.553742 +v 5.814293 0.010000 0.553742 +v 5.260550 0.010000 0.461452 +v 5.352840 0.010000 0.461452 +v 5.352840 0.010000 0.369161 +v 5.260550 0.010000 0.369161 +v 5.260550 0.010000 0.646033 +v 5.352840 0.010000 0.646033 +v 5.352840 0.010000 0.553742 +v 5.260550 0.010000 0.553742 +v 5.445131 0.010000 0.646033 +v 5.537421 0.010000 0.646033 +v 5.537421 0.010000 0.553742 +v 5.445131 0.010000 0.553742 +v 5.260550 0.010000 0.092290 +v 5.352840 0.010000 0.092290 +v 5.352840 0.010000 -0.000000 +v 5.260550 0.010000 -0.000000 +v 5.260550 0.010000 0.276871 +v 5.352840 0.010000 0.276871 +v 5.352840 0.010000 0.184581 +v 5.260550 0.010000 0.184581 +v 5.445131 0.010000 0.276871 +v 5.537421 0.010000 0.276871 +v 5.537421 0.010000 0.184581 +v 5.445131 0.010000 0.184581 +v 2.676420 0.010000 0.461452 +v 2.768711 0.010000 0.461452 +v 2.768711 0.010000 0.369161 +v 2.676420 0.010000 0.369161 +v 2.676420 0.010000 0.646033 +v 2.768711 0.010000 0.646033 +v 2.768711 0.010000 0.553742 +v 2.676420 0.010000 0.553742 +v 2.861001 0.010000 0.646033 +v 2.953291 0.010000 0.646033 +v 2.953291 0.010000 0.553742 +v 2.861001 0.010000 0.553742 +v 2.307259 0.010000 0.461452 +v 2.399549 0.010000 0.461452 +v 2.399549 0.010000 0.369161 +v 2.307259 0.010000 0.369161 +v 2.307259 0.010000 0.646033 +v 2.399549 0.010000 0.646033 +v 2.399549 0.010000 0.553742 +v 2.307259 0.010000 0.553742 +v 2.491840 0.010000 0.646033 +v 2.584130 0.010000 0.646033 +v 2.584130 0.010000 0.553742 +v 2.491840 0.010000 0.553742 +v 2.307259 0.010000 0.092290 +v 2.399549 0.010000 0.092290 +v 2.399549 0.010000 -0.000000 +v 2.307259 0.010000 -0.000000 +v 2.307259 0.010000 0.276871 +v 2.399549 0.010000 0.276871 +v 2.399549 0.010000 0.184581 +v 2.307259 0.010000 0.184581 +v 2.491840 0.010000 0.276871 +v 2.584130 0.010000 0.276871 +v 2.584130 0.010000 0.184581 +v 2.491840 0.010000 0.184581 +v 2.676420 0.009999 3.414743 +v 2.768711 0.009999 3.414743 +v 2.768711 0.009999 3.322453 +v 2.676420 0.009999 3.322453 +v 2.676420 0.009999 3.599324 +v 2.768711 0.009999 3.599324 +v 2.768711 0.009999 3.507033 +v 2.676420 0.009999 3.507033 +v 2.861001 0.009999 3.599324 +v 2.953291 0.009999 3.599324 +v 2.953291 0.009999 3.507033 +v 2.861001 0.009999 3.507033 +v 2.307259 0.009999 3.414743 +v 2.399549 0.009999 3.414743 +v 2.399549 0.009999 3.322453 +v 2.307259 0.009999 3.322453 +v 2.307259 0.009999 3.599324 +v 2.399549 0.009999 3.599324 +v 2.399549 0.009999 3.507033 +v 2.307259 0.009999 3.507033 +v 2.491840 0.009999 3.599324 +v 2.584130 0.009999 3.599324 +v 2.584130 0.009999 3.507033 +v 2.491840 0.009999 3.507033 +v 2.307259 0.009999 3.045582 +v 2.399549 0.009999 3.045582 +v 2.399549 0.009999 2.953291 +v 2.307259 0.009999 2.953291 +v 2.307259 0.009999 3.230163 +v 2.399549 0.009999 3.230163 +v 2.399549 0.009999 3.137872 +v 2.307259 0.009999 3.137872 +v 2.491840 0.009999 3.230163 +v 2.584130 0.009999 3.230163 +v 2.584130 0.009999 3.137872 +v 2.491840 0.009999 3.137872 +v 5.629711 0.009999 3.414743 +v 5.722002 0.009999 3.414743 +v 5.722002 0.009999 3.322453 +v 5.629711 0.009999 3.322453 +v 5.629711 0.009999 3.599324 +v 5.722002 0.009999 3.599324 +v 5.722002 0.009999 3.507033 +v 5.629711 0.009999 3.507033 +v 5.814293 0.009999 3.599324 +v 5.906583 0.009999 3.599324 +v 5.906583 0.009999 3.507033 +v 5.814293 0.009999 3.507033 +v 5.260550 0.009999 3.414743 +v 5.352840 0.009999 3.414743 +v 5.352840 0.009999 3.322453 +v 5.260550 0.009999 3.322453 +v 5.260550 0.009999 3.599324 +v 5.352840 0.009999 3.599324 +v 5.352840 0.009999 3.507033 +v 5.260550 0.009999 3.507033 +v 5.445131 0.009999 3.599324 +v 5.537421 0.009999 3.599324 +v 5.537421 0.009999 3.507033 +v 5.445131 0.009999 3.507033 +v 5.260550 0.009999 3.045582 +v 5.352840 0.009999 3.045582 +v 5.352840 0.009999 2.953291 +v 5.260550 0.009999 2.953291 +v 5.260550 0.009999 3.230163 +v 5.352840 0.009999 3.230163 +v 5.352840 0.009999 3.137872 +v 5.260550 0.009999 3.137872 +v 5.445131 0.009999 3.230163 +v 5.537421 0.009999 3.230163 +v 5.537421 0.009999 3.137872 +v 5.445131 0.009999 3.137872 +v -3.230163 0.010000 0.461452 +v -3.137872 0.010000 0.461452 +v -3.137872 0.010000 0.369161 +v -3.230163 0.010000 0.369161 +v -3.230163 0.010000 0.646033 +v -3.137872 0.010000 0.646033 +v -3.137872 0.010000 0.553742 +v -3.230163 0.010000 0.553742 +v -3.045582 0.010000 0.646033 +v -2.953291 0.010000 0.646033 +v -2.953291 0.010000 0.553742 +v -3.045582 0.010000 0.553742 +v -3.599324 0.010000 0.461452 +v -3.507033 0.010000 0.461452 +v -3.507033 0.010000 0.369161 +v -3.599324 0.010000 0.369161 +v -3.599324 0.010000 0.646033 +v -3.507033 0.010000 0.646033 +v -3.507033 0.010000 0.553742 +v -3.599324 0.010000 0.553742 +v -3.414743 0.010000 0.646033 +v -3.322453 0.010000 0.646033 +v -3.322453 0.010000 0.553742 +v -3.414743 0.010000 0.553742 +v -3.599324 0.010000 0.092290 +v -3.507033 0.010000 0.092290 +v -3.507033 0.010000 -0.000000 +v -3.599324 0.010000 -0.000000 +v -3.599324 0.010000 0.276871 +v -3.507033 0.010000 0.276871 +v -3.507033 0.010000 0.184581 +v -3.599324 0.010000 0.184581 +v -3.414743 0.010000 0.276871 +v -3.322453 0.010000 0.276871 +v -3.322453 0.010000 0.184581 +v -3.414743 0.010000 0.184581 +v -3.230163 0.009999 3.414743 +v -3.137872 0.009999 3.414743 +v -3.137872 0.009999 3.322453 +v -3.230163 0.009999 3.322453 +v -3.230163 0.009999 3.599324 +v -3.137872 0.009999 3.599324 +v -3.137872 0.009999 3.507033 +v -3.230163 0.009999 3.507033 +v -3.045582 0.009999 3.599324 +v -2.953291 0.009999 3.599324 +v -2.953291 0.009999 3.507033 +v -3.045582 0.009999 3.507033 +v -3.599324 0.009999 3.414743 +v -3.507033 0.009999 3.414743 +v -3.507033 0.009999 3.322453 +v -3.599324 0.009999 3.322453 +v -3.599324 0.009999 3.599324 +v -3.507033 0.009999 3.599324 +v -3.507033 0.009999 3.507033 +v -3.599324 0.009999 3.507033 +v -3.414743 0.009999 3.599324 +v -3.322453 0.009999 3.599324 +v -3.322453 0.009999 3.507033 +v -3.414743 0.009999 3.507033 +v -3.599324 0.009999 3.045582 +v -3.507033 0.009999 3.045582 +v -3.507033 0.009999 2.953291 +v -3.599324 0.009999 2.953291 +v -3.599324 0.009999 3.230163 +v -3.507033 0.009999 3.230163 +v -3.507033 0.009999 3.137872 +v -3.599324 0.009999 3.137872 +v -3.414743 0.009999 3.230163 +v -3.322453 0.009999 3.230163 +v -3.322453 0.009999 3.137872 +v -3.414743 0.009999 3.137872 +v -0.276871 0.009999 3.414743 +v -0.184581 0.009999 3.414743 +v -0.184581 0.009999 3.322453 +v -0.276871 0.009999 3.322453 +v -0.276871 0.009999 3.599324 +v -0.184581 0.009999 3.599324 +v -0.184581 0.009999 3.507033 +v -0.276871 0.009999 3.507033 +v -0.092290 0.009999 3.599324 +v 0.000000 0.009999 3.599324 +v 0.000000 0.009999 3.507033 +v -0.092290 0.009999 3.507033 +v -0.646033 0.009999 3.414743 +v -0.553742 0.009999 3.414743 +v -0.553742 0.009999 3.322453 +v -0.646033 0.009999 3.322453 +v -0.646033 0.009999 3.599324 +v -0.553742 0.009999 3.599324 +v -0.553742 0.009999 3.507033 +v -0.646033 0.009999 3.507033 +v -0.461452 0.009999 3.599324 +v -0.369161 0.009999 3.599324 +v -0.369161 0.009999 3.507033 +v -0.461452 0.009999 3.507033 +v -0.646033 0.009999 3.045582 +v -0.553742 0.009999 3.045582 +v -0.553742 0.009999 2.953291 +v -0.646033 0.009999 2.953291 +v -0.646033 0.009999 3.230163 +v -0.553742 0.009999 3.230163 +v -0.553742 0.009999 3.137872 +v -0.646033 0.009999 3.137872 +v -0.461452 0.009999 3.230163 +v -0.369161 0.009999 3.230163 +v -0.369161 0.009999 3.137872 +v -0.461452 0.009999 3.137872 +v -3.230163 0.010002 -5.445131 +v -3.137872 0.010002 -5.445131 +v -3.137872 0.010002 -5.537421 +v -3.230163 0.010002 -5.537421 +v -3.230163 0.010002 -5.260550 +v -3.137872 0.010002 -5.260550 +v -3.137872 0.010002 -5.352840 +v -3.230163 0.010002 -5.352840 +v -3.045582 0.010002 -5.260550 +v -2.953291 0.010002 -5.260550 +v -2.953291 0.010002 -5.352840 +v -3.045582 0.010002 -5.352840 +v -3.599324 0.010002 -5.445131 +v -3.507033 0.010002 -5.445131 +v -3.507033 0.010002 -5.537421 +v -3.599324 0.010002 -5.537421 +v -3.599324 0.010002 -5.260550 +v -3.507033 0.010002 -5.260550 +v -3.507033 0.010002 -5.352840 +v -3.599324 0.010002 -5.352840 +v -3.414743 0.010002 -5.260550 +v -3.322453 0.010002 -5.260550 +v -3.322453 0.010002 -5.352840 +v -3.414743 0.010002 -5.352840 +v -3.599324 0.010002 -5.814293 +v -3.507033 0.010002 -5.814293 +v -3.507033 0.010002 -5.906583 +v -3.599324 0.010002 -5.906583 +v -3.599324 0.010002 -5.629711 +v -3.507033 0.010002 -5.629711 +v -3.507033 0.010002 -5.722002 +v -3.599324 0.010002 -5.722002 +v -3.414743 0.010002 -5.629711 +v -3.322453 0.010002 -5.629711 +v -3.322453 0.010002 -5.722002 +v -3.414743 0.010002 -5.722002 +v -3.230163 0.010001 -2.491840 +v -3.137872 0.010001 -2.491840 +v -3.137872 0.010001 -2.584130 +v -3.230163 0.010001 -2.584130 +v -3.230163 0.010001 -2.307259 +v -3.137872 0.010001 -2.307259 +v -3.137872 0.010001 -2.399549 +v -3.230163 0.010001 -2.399549 +v -3.045582 0.010001 -2.307259 +v -2.953291 0.010001 -2.307259 +v -2.953291 0.010001 -2.399549 +v -3.045582 0.010001 -2.399549 +v -3.599324 0.010001 -2.491840 +v -3.507033 0.010001 -2.491840 +v -3.507033 0.010001 -2.584130 +v -3.599324 0.010001 -2.584130 +v -3.599324 0.010001 -2.307259 +v -3.507033 0.010001 -2.307259 +v -3.507033 0.010001 -2.399549 +v -3.599324 0.010001 -2.399549 +v -3.414743 0.010001 -2.307259 +v -3.322453 0.010001 -2.307259 +v -3.322453 0.010001 -2.399549 +v -3.414743 0.010001 -2.399549 +v -3.599324 0.010001 -2.861001 +v -3.507033 0.010001 -2.861001 +v -3.507033 0.010001 -2.953291 +v -3.599324 0.010001 -2.953291 +v -3.599324 0.010001 -2.676420 +v -3.507033 0.010001 -2.676420 +v -3.507033 0.010001 -2.768711 +v -3.599324 0.010001 -2.768711 +v -3.414743 0.010001 -2.676420 +v -3.322453 0.010001 -2.676420 +v -3.322453 0.010001 -2.768711 +v -3.414743 0.010001 -2.768711 +v -0.276871 0.010001 -2.491840 +v -0.184581 0.010001 -2.491840 +v -0.184581 0.010001 -2.584130 +v -0.276871 0.010001 -2.584130 +v -0.276871 0.010001 -2.307259 +v -0.184581 0.010001 -2.307259 +v -0.184581 0.010001 -2.399549 +v -0.276871 0.010001 -2.399549 +v -0.092290 0.010001 -2.307259 +v 0.000000 0.010001 -2.307259 +v 0.000000 0.010001 -2.399549 +v -0.092290 0.010001 -2.399549 +v -0.646033 0.010001 -2.491840 +v -0.553742 0.010001 -2.491840 +v -0.553742 0.010001 -2.584130 +v -0.646033 0.010001 -2.584130 +v -0.646033 0.010001 -2.307259 +v -0.553742 0.010001 -2.307259 +v -0.553742 0.010001 -2.399549 +v -0.646033 0.010001 -2.399549 +v -0.461452 0.010001 -2.307259 +v -0.369161 0.010001 -2.307259 +v -0.369161 0.010001 -2.399549 +v -0.461452 0.010001 -2.399549 +v -0.646033 0.010001 -2.861001 +v -0.553742 0.010001 -2.861001 +v -0.553742 0.010001 -2.953291 +v -0.646033 0.010001 -2.953291 +v -0.646033 0.010001 -2.676420 +v -0.553742 0.010001 -2.676420 +v -0.553742 0.010001 -2.768711 +v -0.646033 0.010001 -2.768711 +v -0.461452 0.010001 -2.676420 +v -0.369161 0.010001 -2.676420 +v -0.369161 0.010001 -2.768711 +v -0.461452 0.010001 -2.768711 +v 2.676420 0.010002 -5.445131 +v 2.768711 0.010002 -5.445131 +v 2.768711 0.010002 -5.537421 +v 2.676420 0.010002 -5.537421 +v 2.676420 0.010002 -5.260550 +v 2.768711 0.010002 -5.260550 +v 2.768711 0.010002 -5.352840 +v 2.676420 0.010002 -5.352840 +v 2.861001 0.010002 -5.260550 +v 2.953291 0.010002 -5.260550 +v 2.953291 0.010002 -5.352840 +v 2.861001 0.010002 -5.352840 +v 2.307259 0.010002 -5.445131 +v 2.399549 0.010002 -5.445131 +v 2.399549 0.010002 -5.537421 +v 2.307259 0.010002 -5.537421 +v 2.307259 0.010002 -5.260550 +v 2.399549 0.010002 -5.260550 +v 2.399549 0.010002 -5.352840 +v 2.307259 0.010002 -5.352840 +v 2.491840 0.010002 -5.260550 +v 2.584130 0.010002 -5.260550 +v 2.584130 0.010002 -5.352840 +v 2.491840 0.010002 -5.352840 +v 2.307259 0.010002 -5.814293 +v 2.399549 0.010002 -5.814293 +v 2.399549 0.010002 -5.906583 +v 2.307259 0.010002 -5.906583 +v 2.307259 0.010002 -5.629711 +v 2.399549 0.010002 -5.629711 +v 2.399549 0.010002 -5.722002 +v 2.307259 0.010002 -5.722002 +v 2.491840 0.010002 -5.629711 +v 2.584130 0.010002 -5.629711 +v 2.584130 0.010002 -5.722002 +v 2.491840 0.010002 -5.722002 +v 2.676420 0.010001 -2.491840 +v 2.768711 0.010001 -2.491840 +v 2.768711 0.010001 -2.584130 +v 2.676420 0.010001 -2.584130 +v 2.676420 0.010001 -2.307259 +v 2.768711 0.010001 -2.307259 +v 2.768711 0.010001 -2.399549 +v 2.676420 0.010001 -2.399549 +v 2.861001 0.010001 -2.307259 +v 2.953291 0.010001 -2.307259 +v 2.953291 0.010001 -2.399549 +v 2.861001 0.010001 -2.399549 +v 2.307259 0.010001 -2.491840 +v 2.399549 0.010001 -2.491840 +v 2.399549 0.010001 -2.584130 +v 2.307259 0.010001 -2.584130 +v 2.307259 0.010001 -2.307259 +v 2.399549 0.010001 -2.307259 +v 2.399549 0.010001 -2.399549 +v 2.307259 0.010001 -2.399549 +v 2.491840 0.010001 -2.307259 +v 2.584130 0.010001 -2.307259 +v 2.584130 0.010001 -2.399549 +v 2.491840 0.010001 -2.399549 +v 2.307259 0.010001 -2.861001 +v 2.399549 0.010001 -2.861001 +v 2.399549 0.010001 -2.953291 +v 2.307259 0.010001 -2.953291 +v 2.307259 0.010001 -2.676420 +v 2.399549 0.010001 -2.676420 +v 2.399549 0.010001 -2.768711 +v 2.307259 0.010001 -2.768711 +v 2.491840 0.010001 -2.676420 +v 2.584130 0.010001 -2.676420 +v 2.584130 0.010001 -2.768711 +v 2.491840 0.010001 -2.768711 +v 5.629711 0.010001 -2.491840 +v 5.722002 0.010001 -2.491840 +v 5.722002 0.010001 -2.584130 +v 5.629711 0.010001 -2.584130 +v 5.629711 0.010001 -2.307259 +v 5.722002 0.010001 -2.307259 +v 5.722002 0.010001 -2.399549 +v 5.629711 0.010001 -2.399549 +v 5.814293 0.010001 -2.307259 +v 5.906583 0.010001 -2.307259 +v 5.906583 0.010001 -2.399549 +v 5.814293 0.010001 -2.399549 +v 5.260550 0.010001 -2.491840 +v 5.352840 0.010001 -2.491840 +v 5.352840 0.010001 -2.584130 +v 5.260550 0.010001 -2.584130 +v 5.260550 0.010001 -2.307259 +v 5.352840 0.010001 -2.307259 +v 5.352840 0.010001 -2.399549 +v 5.260550 0.010001 -2.399549 +v 5.445131 0.010001 -2.307259 +v 5.537421 0.010001 -2.307259 +v 5.537421 0.010001 -2.399549 +v 5.445131 0.010001 -2.399549 +v 5.260550 0.010001 -2.861001 +v 5.352840 0.010001 -2.861001 +v 5.352840 0.010001 -2.953291 +v 5.260550 0.010001 -2.953291 +v 5.260550 0.010001 -2.676420 +v 5.352840 0.010001 -2.676420 +v 5.352840 0.010001 -2.768711 +v 5.260550 0.010001 -2.768711 +v 5.445131 0.010001 -2.676420 +v 5.537421 0.010001 -2.676420 +v 5.537421 0.010001 -2.768711 +v 5.445131 0.010001 -2.768711 +v 4.153066 0.010001 -2.491840 +v 4.245357 0.010001 -2.491840 +v 4.245357 0.010001 -2.584130 +v 4.153066 0.010001 -2.584130 +v 4.153066 0.010001 -2.307259 +v 4.245357 0.010001 -2.307259 +v 4.245357 0.010001 -2.399549 +v 4.153066 0.010001 -2.399549 +v 4.337647 0.010001 -2.307259 +v 4.429937 0.010001 -2.307259 +v 4.429937 0.010001 -2.399549 +v 4.337647 0.010001 -2.399549 +v 3.783905 0.010001 -2.491840 +v 3.876195 0.010001 -2.491840 +v 3.876195 0.010001 -2.584130 +v 3.783905 0.010001 -2.584130 +v 3.783905 0.010001 -2.307259 +v 3.876195 0.010001 -2.307259 +v 3.876195 0.010001 -2.399549 +v 3.783905 0.010001 -2.399549 +v 3.968485 0.010001 -2.307259 +v 4.060776 0.010001 -2.307259 +v 4.060776 0.010001 -2.399549 +v 3.968485 0.010001 -2.399549 +v 3.783905 0.010001 -2.861001 +v 3.876195 0.010001 -2.861001 +v 3.876195 0.010001 -2.953291 +v 3.783905 0.010001 -2.953291 +v 3.783905 0.010001 -2.676420 +v 3.876195 0.010001 -2.676420 +v 3.876195 0.010001 -2.768711 +v 3.783905 0.010001 -2.768711 +v 3.968485 0.010001 -2.676420 +v 4.060776 0.010001 -2.676420 +v 4.060776 0.010001 -2.768711 +v 3.968485 0.010001 -2.768711 +v 4.153066 0.010000 -1.015194 +v 4.245357 0.010000 -1.015194 +v 4.245357 0.010000 -1.107484 +v 4.153066 0.010000 -1.107484 +v 4.153066 0.010000 -0.830613 +v 4.245357 0.010000 -0.830613 +v 4.245357 0.010000 -0.922904 +v 4.153066 0.010000 -0.922904 +v 4.337647 0.010000 -0.830613 +v 4.429937 0.010000 -0.830613 +v 4.429937 0.010000 -0.922904 +v 4.337647 0.010000 -0.922904 +v 3.783905 0.010000 -1.015194 +v 3.876195 0.010000 -1.015194 +v 3.876195 0.010000 -1.107484 +v 3.783905 0.010000 -1.107484 +v 3.783905 0.010000 -0.830613 +v 3.876195 0.010000 -0.830613 +v 3.876195 0.010000 -0.922904 +v 3.783905 0.010000 -0.922904 +v 3.968485 0.010000 -0.830613 +v 4.060776 0.010000 -0.830613 +v 4.060776 0.010000 -0.922904 +v 3.968485 0.010000 -0.922904 +v 3.783905 0.010001 -1.384355 +v 3.876195 0.010001 -1.384355 +v 3.876195 0.010001 -1.476646 +v 3.783905 0.010001 -1.476646 +v 3.783905 0.010000 -1.199775 +v 3.876195 0.010000 -1.199775 +v 3.876195 0.010001 -1.292065 +v 3.783905 0.010001 -1.292065 +v 3.968485 0.010000 -1.199775 +v 4.060776 0.010000 -1.199775 +v 4.060776 0.010001 -1.292065 +v 3.968485 0.010001 -1.292065 +v 5.629711 0.010000 -1.015194 +v 5.722002 0.010000 -1.015194 +v 5.722002 0.010000 -1.107484 +v 5.629711 0.010000 -1.107484 +v 5.629711 0.010000 -0.830613 +v 5.722002 0.010000 -0.830613 +v 5.722002 0.010000 -0.922904 +v 5.629711 0.010000 -0.922904 +v 5.814293 0.010000 -0.830613 +v 5.906583 0.010000 -0.830613 +v 5.906583 0.010000 -0.922904 +v 5.814293 0.010000 -0.922904 +v 5.260550 0.010000 -1.015194 +v 5.352840 0.010000 -1.015194 +v 5.352840 0.010000 -1.107484 +v 5.260550 0.010000 -1.107484 +v 5.260550 0.010000 -0.830613 +v 5.352840 0.010000 -0.830613 +v 5.352840 0.010000 -0.922904 +v 5.260550 0.010000 -0.922904 +v 5.445131 0.010000 -0.830613 +v 5.537421 0.010000 -0.830613 +v 5.537421 0.010000 -0.922904 +v 5.445131 0.010000 -0.922904 +v 5.260550 0.010001 -1.384355 +v 5.352840 0.010001 -1.384355 +v 5.352840 0.010001 -1.476646 +v 5.260550 0.010001 -1.476646 +v 5.260550 0.010000 -1.199775 +v 5.352840 0.010000 -1.199775 +v 5.352840 0.010001 -1.292065 +v 5.260550 0.010001 -1.292065 +v 5.445131 0.010000 -1.199775 +v 5.537421 0.010000 -1.199775 +v 5.537421 0.010001 -1.292065 +v 5.445131 0.010001 -1.292065 +v 1.199775 0.010001 -2.491840 +v 1.292065 0.010001 -2.491840 +v 1.292065 0.010001 -2.584130 +v 1.199775 0.010001 -2.584130 +v 1.199775 0.010001 -2.307259 +v 1.292065 0.010001 -2.307259 +v 1.292065 0.010001 -2.399549 +v 1.199775 0.010001 -2.399549 +v 1.384355 0.010001 -2.307259 +v 1.476646 0.010001 -2.307259 +v 1.476646 0.010001 -2.399549 +v 1.384355 0.010001 -2.399549 +v 0.830613 0.010001 -2.491840 +v 0.922904 0.010001 -2.491840 +v 0.922904 0.010001 -2.584130 +v 0.830613 0.010001 -2.584130 +v 0.830613 0.010001 -2.307259 +v 0.922904 0.010001 -2.307259 +v 0.922904 0.010001 -2.399549 +v 0.830613 0.010001 -2.399549 +v 1.015194 0.010001 -2.307259 +v 1.107484 0.010001 -2.307259 +v 1.107484 0.010001 -2.399549 +v 1.015194 0.010001 -2.399549 +v 0.830613 0.010001 -2.861001 +v 0.922904 0.010001 -2.861001 +v 0.922904 0.010001 -2.953291 +v 0.830613 0.010001 -2.953291 +v 0.830613 0.010001 -2.676420 +v 0.922904 0.010001 -2.676420 +v 0.922904 0.010001 -2.768711 +v 0.830613 0.010001 -2.768711 +v 1.015194 0.010001 -2.676420 +v 1.107484 0.010001 -2.676420 +v 1.107484 0.010001 -2.768711 +v 1.015194 0.010001 -2.768711 +v 1.199775 0.010000 -1.015194 +v 1.292065 0.010000 -1.015194 +v 1.292065 0.010000 -1.107484 +v 1.199775 0.010000 -1.107484 +v 1.199775 0.010000 -0.830613 +v 1.292065 0.010000 -0.830613 +v 1.292065 0.010000 -0.922904 +v 1.199775 0.010000 -0.922904 +v 1.384355 0.010000 -0.830613 +v 1.476646 0.010000 -0.830613 +v 1.476646 0.010000 -0.922904 +v 1.384355 0.010000 -0.922904 +v 0.830613 0.010000 -1.015194 +v 0.922904 0.010000 -1.015194 +v 0.922904 0.010000 -1.107484 +v 0.830613 0.010000 -1.107484 +v 0.830613 0.010000 -0.830613 +v 0.922904 0.010000 -0.830613 +v 0.922904 0.010000 -0.922904 +v 0.830613 0.010000 -0.922904 +v 1.015194 0.010000 -0.830613 +v 1.107484 0.010000 -0.830613 +v 1.107484 0.010000 -0.922904 +v 1.015194 0.010000 -0.922904 +v 0.830613 0.010001 -1.384355 +v 0.922904 0.010001 -1.384355 +v 0.922904 0.010001 -1.476646 +v 0.830613 0.010001 -1.476646 +v 0.830613 0.010000 -1.199775 +v 0.922904 0.010000 -1.199775 +v 0.922904 0.010001 -1.292065 +v 0.830613 0.010001 -1.292065 +v 1.015194 0.010000 -1.199775 +v 1.107484 0.010000 -1.199775 +v 1.107484 0.010001 -1.292065 +v 1.015194 0.010001 -1.292065 +v 2.676420 0.010000 -1.015194 +v 2.768711 0.010000 -1.015194 +v 2.768711 0.010000 -1.107484 +v 2.676420 0.010000 -1.107484 +v 2.676420 0.010000 -0.830613 +v 2.768711 0.010000 -0.830613 +v 2.768711 0.010000 -0.922904 +v 2.676420 0.010000 -0.922904 +v 2.861001 0.010000 -0.830613 +v 2.953291 0.010000 -0.830613 +v 2.953291 0.010000 -0.922904 +v 2.861001 0.010000 -0.922904 +v 2.307259 0.010000 -1.015194 +v 2.399549 0.010000 -1.015194 +v 2.399549 0.010000 -1.107484 +v 2.307259 0.010000 -1.107484 +v 2.307259 0.010000 -0.830613 +v 2.399549 0.010000 -0.830613 +v 2.399549 0.010000 -0.922904 +v 2.307259 0.010000 -0.922904 +v 2.491840 0.010000 -0.830613 +v 2.584130 0.010000 -0.830613 +v 2.584130 0.010000 -0.922904 +v 2.491840 0.010000 -0.922904 +v 2.307259 0.010001 -1.384355 +v 2.399549 0.010001 -1.384355 +v 2.399549 0.010001 -1.476646 +v 2.307259 0.010001 -1.476646 +v 2.307259 0.010000 -1.199775 +v 2.399549 0.010000 -1.199775 +v 2.399549 0.010001 -1.292065 +v 2.307259 0.010001 -1.292065 +v 2.491840 0.010000 -1.199775 +v 2.584130 0.010000 -1.199775 +v 2.584130 0.010001 -1.292065 +v 2.491840 0.010001 -1.292065 +v 1.199775 0.010002 -5.445131 +v 1.292065 0.010002 -5.445131 +v 1.292065 0.010002 -5.537421 +v 1.199775 0.010002 -5.537421 +v 1.199775 0.010002 -5.260550 +v 1.292065 0.010002 -5.260550 +v 1.292065 0.010002 -5.352840 +v 1.199775 0.010002 -5.352840 +v 1.384355 0.010002 -5.260550 +v 1.476646 0.010002 -5.260550 +v 1.476646 0.010002 -5.352840 +v 1.384355 0.010002 -5.352840 +v 0.830613 0.010002 -5.445131 +v 0.922904 0.010002 -5.445131 +v 0.922904 0.010002 -5.537421 +v 0.830613 0.010002 -5.537421 +v 0.830613 0.010002 -5.260550 +v 0.922904 0.010002 -5.260550 +v 0.922904 0.010002 -5.352840 +v 0.830613 0.010002 -5.352840 +v 1.015194 0.010002 -5.260550 +v 1.107484 0.010002 -5.260550 +v 1.107484 0.010002 -5.352840 +v 1.015194 0.010002 -5.352840 +v 0.830613 0.010002 -5.814293 +v 0.922904 0.010002 -5.814293 +v 0.922904 0.010002 -5.906583 +v 0.830613 0.010002 -5.906583 +v 0.830613 0.010002 -5.629711 +v 0.922904 0.010002 -5.629711 +v 0.922904 0.010002 -5.722002 +v 0.830613 0.010002 -5.722002 +v 1.015194 0.010002 -5.629711 +v 1.107484 0.010002 -5.629711 +v 1.107484 0.010002 -5.722002 +v 1.015194 0.010002 -5.722002 +v 1.199775 0.010002 -3.968485 +v 1.292065 0.010002 -3.968485 +v 1.292065 0.010002 -4.060776 +v 1.199775 0.010002 -4.060776 +v 1.199775 0.010002 -3.783905 +v 1.292065 0.010002 -3.783905 +v 1.292065 0.010002 -3.876195 +v 1.199775 0.010002 -3.876195 +v 1.384355 0.010002 -3.783905 +v 1.476646 0.010002 -3.783905 +v 1.476646 0.010002 -3.876195 +v 1.384355 0.010002 -3.876195 +v 0.830613 0.010002 -3.968485 +v 0.922904 0.010002 -3.968485 +v 0.922904 0.010002 -4.060776 +v 0.830613 0.010002 -4.060776 +v 0.830613 0.010002 -3.783905 +v 0.922904 0.010002 -3.783905 +v 0.922904 0.010002 -3.876195 +v 0.830613 0.010002 -3.876195 +v 1.015194 0.010002 -3.783905 +v 1.107484 0.010002 -3.783905 +v 1.107484 0.010002 -3.876195 +v 1.015194 0.010002 -3.876195 +v 0.830613 0.010002 -4.337647 +v 0.922904 0.010002 -4.337647 +v 0.922904 0.010002 -4.429937 +v 0.830613 0.010002 -4.429937 +v 0.830613 0.010002 -4.153066 +v 0.922904 0.010002 -4.153066 +v 0.922904 0.010002 -4.245357 +v 0.830613 0.010002 -4.245357 +v 1.015194 0.010002 -4.153066 +v 1.107484 0.010002 -4.153066 +v 1.107484 0.010002 -4.245357 +v 1.015194 0.010002 -4.245357 +v 2.676420 0.010002 -3.968485 +v 2.768711 0.010002 -3.968485 +v 2.768711 0.010002 -4.060776 +v 2.676420 0.010002 -4.060776 +v 2.676420 0.010002 -3.783905 +v 2.768711 0.010002 -3.783905 +v 2.768711 0.010002 -3.876195 +v 2.676420 0.010002 -3.876195 +v 2.861001 0.010002 -3.783905 +v 2.953291 0.010002 -3.783905 +v 2.953291 0.010002 -3.876195 +v 2.861001 0.010002 -3.876195 +v 2.307259 0.010002 -3.968485 +v 2.399549 0.010002 -3.968485 +v 2.399549 0.010002 -4.060776 +v 2.307259 0.010002 -4.060776 +v 2.307259 0.010002 -3.783905 +v 2.399549 0.010002 -3.783905 +v 2.399549 0.010002 -3.876195 +v 2.307259 0.010002 -3.876195 +v 2.491840 0.010002 -3.783905 +v 2.584130 0.010002 -3.783905 +v 2.584130 0.010002 -3.876195 +v 2.491840 0.010002 -3.876195 +v 2.307259 0.010002 -4.337647 +v 2.399549 0.010002 -4.337647 +v 2.399549 0.010002 -4.429937 +v 2.307259 0.010002 -4.429937 +v 2.307259 0.010002 -4.153066 +v 2.399549 0.010002 -4.153066 +v 2.399549 0.010002 -4.245357 +v 2.307259 0.010002 -4.245357 +v 2.491840 0.010002 -4.153066 +v 2.584130 0.010002 -4.153066 +v 2.584130 0.010002 -4.245357 +v 2.491840 0.010002 -4.245357 +v -1.753517 0.010001 -2.491840 +v -1.661226 0.010001 -2.491840 +v -1.661226 0.010001 -2.584130 +v -1.753517 0.010001 -2.584130 +v -1.753517 0.010001 -2.307259 +v -1.661226 0.010001 -2.307259 +v -1.661226 0.010001 -2.399549 +v -1.753517 0.010001 -2.399549 +v -1.568936 0.010001 -2.307259 +v -1.476646 0.010001 -2.307259 +v -1.476646 0.010001 -2.399549 +v -1.568936 0.010001 -2.399549 +v -2.122678 0.010001 -2.491840 +v -2.030388 0.010001 -2.491840 +v -2.030388 0.010001 -2.584130 +v -2.122678 0.010001 -2.584130 +v -2.122678 0.010001 -2.307259 +v -2.030388 0.010001 -2.307259 +v -2.030388 0.010001 -2.399549 +v -2.122678 0.010001 -2.399549 +v -1.938097 0.010001 -2.307259 +v -1.845807 0.010001 -2.307259 +v -1.845807 0.010001 -2.399549 +v -1.938097 0.010001 -2.399549 +v -2.122678 0.010001 -2.861001 +v -2.030388 0.010001 -2.861001 +v -2.030388 0.010001 -2.953291 +v -2.122678 0.010001 -2.953291 +v -2.122678 0.010001 -2.676420 +v -2.030388 0.010001 -2.676420 +v -2.030388 0.010001 -2.768711 +v -2.122678 0.010001 -2.768711 +v -1.938097 0.010001 -2.676420 +v -1.845807 0.010001 -2.676420 +v -1.845807 0.010001 -2.768711 +v -1.938097 0.010001 -2.768711 +v -1.753517 0.010000 -1.015194 +v -1.661226 0.010000 -1.015194 +v -1.661226 0.010000 -1.107484 +v -1.753517 0.010000 -1.107484 +v -1.753517 0.010000 -0.830613 +v -1.661226 0.010000 -0.830613 +v -1.661226 0.010000 -0.922904 +v -1.753517 0.010000 -0.922904 +v -1.568936 0.010000 -0.830613 +v -1.476646 0.010000 -0.830613 +v -1.476646 0.010000 -0.922904 +v -1.568936 0.010000 -0.922904 +v -2.122678 0.010000 -1.015194 +v -2.030388 0.010000 -1.015194 +v -2.030388 0.010000 -1.107484 +v -2.122678 0.010000 -1.107484 +v -2.122678 0.010000 -0.830613 +v -2.030388 0.010000 -0.830613 +v -2.030388 0.010000 -0.922904 +v -2.122678 0.010000 -0.922904 +v -1.938097 0.010000 -0.830613 +v -1.845807 0.010000 -0.830613 +v -1.845807 0.010000 -0.922904 +v -1.938097 0.010000 -0.922904 +v -2.122678 0.010001 -1.384355 +v -2.030388 0.010001 -1.384355 +v -2.030388 0.010001 -1.476646 +v -2.122678 0.010001 -1.476646 +v -2.122678 0.010000 -1.199775 +v -2.030388 0.010000 -1.199775 +v -2.030388 0.010001 -1.292065 +v -2.122678 0.010001 -1.292065 +v -1.938097 0.010000 -1.199775 +v -1.845807 0.010000 -1.199775 +v -1.845807 0.010001 -1.292065 +v -1.938097 0.010001 -1.292065 +v -0.276871 0.010000 -1.015194 +v -0.184581 0.010000 -1.015194 +v -0.184581 0.010000 -1.107484 +v -0.276871 0.010000 -1.107484 +v -0.276871 0.010000 -0.830613 +v -0.184581 0.010000 -0.830613 +v -0.184581 0.010000 -0.922904 +v -0.276871 0.010000 -0.922904 +v -0.092290 0.010000 -0.830613 +v 0.000000 0.010000 -0.830613 +v 0.000000 0.010000 -0.922904 +v -0.092290 0.010000 -0.922904 +v -0.646033 0.010000 -1.015194 +v -0.553742 0.010000 -1.015194 +v -0.553742 0.010000 -1.107484 +v -0.646033 0.010000 -1.107484 +v -0.646033 0.010000 -0.830613 +v -0.553742 0.010000 -0.830613 +v -0.553742 0.010000 -0.922904 +v -0.646033 0.010000 -0.922904 +v -0.461452 0.010000 -0.830613 +v -0.369161 0.010000 -0.830613 +v -0.369161 0.010000 -0.922904 +v -0.461452 0.010000 -0.922904 +v -0.646033 0.010001 -1.384355 +v -0.553742 0.010001 -1.384355 +v -0.553742 0.010001 -1.476646 +v -0.646033 0.010001 -1.476646 +v -0.646033 0.010000 -1.199775 +v -0.553742 0.010000 -1.199775 +v -0.553742 0.010001 -1.292065 +v -0.646033 0.010001 -1.292065 +v -0.461452 0.010000 -1.199775 +v -0.369161 0.010000 -1.199775 +v -0.369161 0.010001 -1.292065 +v -0.461452 0.010001 -1.292065 +v -4.706808 0.010001 -2.491840 +v -4.614518 0.010001 -2.491840 +v -4.614518 0.010001 -2.584130 +v -4.706808 0.010001 -2.584130 +v -4.706808 0.010001 -2.307259 +v -4.614518 0.010001 -2.307259 +v -4.614518 0.010001 -2.399549 +v -4.706808 0.010001 -2.399549 +v -4.522227 0.010001 -2.307259 +v -4.429937 0.010001 -2.307259 +v -4.429937 0.010001 -2.399549 +v -4.522227 0.010001 -2.399549 +v -5.075970 0.010001 -2.491840 +v -4.983679 0.010001 -2.491840 +v -4.983679 0.010001 -2.584130 +v -5.075970 0.010001 -2.584130 +v -5.075970 0.010001 -2.307259 +v -4.983679 0.010001 -2.307259 +v -4.983679 0.010001 -2.399549 +v -5.075970 0.010001 -2.399549 +v -4.891389 0.010001 -2.307259 +v -4.799098 0.010001 -2.307259 +v -4.799098 0.010001 -2.399549 +v -4.891389 0.010001 -2.399549 +v -5.075970 0.010001 -2.861001 +v -4.983679 0.010001 -2.861001 +v -4.983679 0.010001 -2.953291 +v -5.075970 0.010001 -2.953291 +v -5.075970 0.010001 -2.676420 +v -4.983679 0.010001 -2.676420 +v -4.983679 0.010001 -2.768711 +v -5.075970 0.010001 -2.768711 +v -4.891389 0.010001 -2.676420 +v -4.799098 0.010001 -2.676420 +v -4.799098 0.010001 -2.768711 +v -4.891389 0.010001 -2.768711 +v -4.706808 0.010000 -1.015194 +v -4.614518 0.010000 -1.015194 +v -4.614518 0.010000 -1.107484 +v -4.706808 0.010000 -1.107484 +v -4.706808 0.010000 -0.830613 +v -4.614518 0.010000 -0.830613 +v -4.614518 0.010000 -0.922904 +v -4.706808 0.010000 -0.922904 +v -4.522227 0.010000 -0.830613 +v -4.429937 0.010000 -0.830613 +v -4.429937 0.010000 -0.922904 +v -4.522227 0.010000 -0.922904 +v -5.075970 0.010000 -1.015194 +v -4.983679 0.010000 -1.015194 +v -4.983679 0.010000 -1.107484 +v -5.075970 0.010000 -1.107484 +v -5.075970 0.010000 -0.830613 +v -4.983679 0.010000 -0.830613 +v -4.983679 0.010000 -0.922904 +v -5.075970 0.010000 -0.922904 +v -4.891389 0.010000 -0.830613 +v -4.799098 0.010000 -0.830613 +v -4.799098 0.010000 -0.922904 +v -4.891389 0.010000 -0.922904 +v -5.075970 0.010001 -1.384355 +v -4.983679 0.010001 -1.384355 +v -4.983679 0.010001 -1.476646 +v -5.075970 0.010001 -1.476646 +v -5.075970 0.010000 -1.199775 +v -4.983679 0.010000 -1.199775 +v -4.983679 0.010001 -1.292065 +v -5.075970 0.010001 -1.292065 +v -4.891389 0.010000 -1.199775 +v -4.799098 0.010000 -1.199775 +v -4.799098 0.010001 -1.292065 +v -4.891389 0.010001 -1.292065 +v -3.230163 0.010000 -1.015194 +v -3.137872 0.010000 -1.015194 +v -3.137872 0.010000 -1.107484 +v -3.230163 0.010000 -1.107484 +v -3.230163 0.010000 -0.830613 +v -3.137872 0.010000 -0.830613 +v -3.137872 0.010000 -0.922904 +v -3.230163 0.010000 -0.922904 +v -3.045582 0.010000 -0.830613 +v -2.953291 0.010000 -0.830613 +v -2.953291 0.010000 -0.922904 +v -3.045582 0.010000 -0.922904 +v -3.599324 0.010000 -1.015194 +v -3.507033 0.010000 -1.015194 +v -3.507033 0.010000 -1.107484 +v -3.599324 0.010000 -1.107484 +v -3.599324 0.010000 -0.830613 +v -3.507033 0.010000 -0.830613 +v -3.507033 0.010000 -0.922904 +v -3.599324 0.010000 -0.922904 +v -3.414743 0.010000 -0.830613 +v -3.322453 0.010000 -0.830613 +v -3.322453 0.010000 -0.922904 +v -3.414743 0.010000 -0.922904 +v -3.599324 0.010001 -1.384355 +v -3.507033 0.010001 -1.384355 +v -3.507033 0.010001 -1.476646 +v -3.599324 0.010001 -1.476646 +v -3.599324 0.010000 -1.199775 +v -3.507033 0.010000 -1.199775 +v -3.507033 0.010001 -1.292065 +v -3.599324 0.010001 -1.292065 +v -3.414743 0.010000 -1.199775 +v -3.322453 0.010000 -1.199775 +v -3.322453 0.010001 -1.292065 +v -3.414743 0.010001 -1.292065 +v -4.706808 0.010002 -5.445131 +v -4.614518 0.010002 -5.445131 +v -4.614518 0.010002 -5.537421 +v -4.706808 0.010002 -5.537421 +v -4.706808 0.010002 -5.260550 +v -4.614518 0.010002 -5.260550 +v -4.614518 0.010002 -5.352840 +v -4.706808 0.010002 -5.352840 +v -4.522227 0.010002 -5.260550 +v -4.429937 0.010002 -5.260550 +v -4.429937 0.010002 -5.352840 +v -4.522227 0.010002 -5.352840 +v -5.075970 0.010002 -5.445131 +v -4.983679 0.010002 -5.445131 +v -4.983679 0.010002 -5.537421 +v -5.075970 0.010002 -5.537421 +v -5.075970 0.010002 -5.260550 +v -4.983679 0.010002 -5.260550 +v -4.983679 0.010002 -5.352840 +v -5.075970 0.010002 -5.352840 +v -4.891389 0.010002 -5.260550 +v -4.799098 0.010002 -5.260550 +v -4.799098 0.010002 -5.352840 +v -4.891389 0.010002 -5.352840 +v -5.075970 0.010002 -5.814293 +v -4.983679 0.010002 -5.814293 +v -4.983679 0.010002 -5.906583 +v -5.075970 0.010002 -5.906583 +v -5.075970 0.010002 -5.629711 +v -4.983679 0.010002 -5.629711 +v -4.983679 0.010002 -5.722002 +v -5.075970 0.010002 -5.722002 +v -4.891389 0.010002 -5.629711 +v -4.799098 0.010002 -5.629711 +v -4.799098 0.010002 -5.722002 +v -4.891389 0.010002 -5.722002 +v -4.706808 0.010002 -3.968485 +v -4.614518 0.010002 -3.968485 +v -4.614518 0.010002 -4.060776 +v -4.706808 0.010002 -4.060776 +v -4.706808 0.010002 -3.783905 +v -4.614518 0.010002 -3.783905 +v -4.614518 0.010002 -3.876195 +v -4.706808 0.010002 -3.876195 +v -4.522227 0.010002 -3.783905 +v -4.429937 0.010002 -3.783905 +v -4.429937 0.010002 -3.876195 +v -4.522227 0.010002 -3.876195 +v -5.075970 0.010002 -3.968485 +v -4.983679 0.010002 -3.968485 +v -4.983679 0.010002 -4.060776 +v -5.075970 0.010002 -4.060776 +v -5.075970 0.010002 -3.783905 +v -4.983679 0.010002 -3.783905 +v -4.983679 0.010002 -3.876195 +v -5.075970 0.010002 -3.876195 +v -4.891389 0.010002 -3.783905 +v -4.799098 0.010002 -3.783905 +v -4.799098 0.010002 -3.876195 +v -4.891389 0.010002 -3.876195 +v -5.075970 0.010002 -4.337647 +v -4.983679 0.010002 -4.337647 +v -4.983679 0.010002 -4.429937 +v -5.075970 0.010002 -4.429937 +v -5.075970 0.010002 -4.153066 +v -4.983679 0.010002 -4.153066 +v -4.983679 0.010002 -4.245357 +v -5.075970 0.010002 -4.245357 +v -4.891389 0.010002 -4.153066 +v -4.799098 0.010002 -4.153066 +v -4.799098 0.010002 -4.245357 +v -4.891389 0.010002 -4.245357 +v -3.230163 0.010002 -3.968485 +v -3.137872 0.010002 -3.968485 +v -3.137872 0.010002 -4.060776 +v -3.230163 0.010002 -4.060776 +v -3.230163 0.010002 -3.783905 +v -3.137872 0.010002 -3.783905 +v -3.137872 0.010002 -3.876195 +v -3.230163 0.010002 -3.876195 +v -3.045582 0.010002 -3.783905 +v -2.953291 0.010002 -3.783905 +v -2.953291 0.010002 -3.876195 +v -3.045582 0.010002 -3.876195 +v -3.599324 0.010002 -3.968485 +v -3.507033 0.010002 -3.968485 +v -3.507033 0.010002 -4.060776 +v -3.599324 0.010002 -4.060776 +v -3.599324 0.010002 -3.783905 +v -3.507033 0.010002 -3.783905 +v -3.507033 0.010002 -3.876195 +v -3.599324 0.010002 -3.876195 +v -3.414743 0.010002 -3.783905 +v -3.322453 0.010002 -3.783905 +v -3.322453 0.010002 -3.876195 +v -3.414743 0.010002 -3.876195 +v -3.599324 0.010002 -4.337647 +v -3.507033 0.010002 -4.337647 +v -3.507033 0.010002 -4.429937 +v -3.599324 0.010002 -4.429937 +v -3.599324 0.010002 -4.153066 +v -3.507033 0.010002 -4.153066 +v -3.507033 0.010002 -4.245357 +v -3.599324 0.010002 -4.245357 +v -3.414743 0.010002 -4.153066 +v -3.322453 0.010002 -4.153066 +v -3.322453 0.010002 -4.245357 +v -3.414743 0.010002 -4.245357 +v -1.753517 0.009999 3.414743 +v -1.661226 0.009999 3.414743 +v -1.661226 0.009999 3.322453 +v -1.753517 0.009999 3.322453 +v -1.753517 0.009999 3.599324 +v -1.661226 0.009999 3.599324 +v -1.661226 0.009999 3.507033 +v -1.753517 0.009999 3.507033 +v -1.568936 0.009999 3.599324 +v -1.476646 0.009999 3.599324 +v -1.476646 0.009999 3.507033 +v -1.568936 0.009999 3.507033 +v -2.122678 0.009999 3.414743 +v -2.030388 0.009999 3.414743 +v -2.030388 0.009999 3.322453 +v -2.122678 0.009999 3.322453 +v -2.122678 0.009999 3.599324 +v -2.030388 0.009999 3.599324 +v -2.030388 0.009999 3.507033 +v -2.122678 0.009999 3.507033 +v -1.938097 0.009999 3.599324 +v -1.845807 0.009999 3.599324 +v -1.845807 0.009999 3.507033 +v -1.938097 0.009999 3.507033 +v -2.122678 0.009999 3.045582 +v -2.030388 0.009999 3.045582 +v -2.030388 0.009999 2.953291 +v -2.122678 0.009999 2.953291 +v -2.122678 0.009999 3.230163 +v -2.030388 0.009999 3.230163 +v -2.030388 0.009999 3.137872 +v -2.122678 0.009999 3.137872 +v -1.938097 0.009999 3.230163 +v -1.845807 0.009999 3.230163 +v -1.845807 0.009999 3.137872 +v -1.938097 0.009999 3.137872 +v -1.753517 0.009998 4.891389 +v -1.661226 0.009998 4.891389 +v -1.661226 0.009998 4.799098 +v -1.753517 0.009998 4.799098 +v -1.753517 0.009998 5.075970 +v -1.661226 0.009998 5.075970 +v -1.661226 0.009998 4.983679 +v -1.753517 0.009998 4.983679 +v -1.568936 0.009998 5.075970 +v -1.476646 0.009998 5.075970 +v -1.476646 0.009998 4.983679 +v -1.568936 0.009998 4.983679 +v -2.122678 0.009998 4.891389 +v -2.030388 0.009998 4.891389 +v -2.030388 0.009998 4.799098 +v -2.122678 0.009998 4.799098 +v -2.122678 0.009998 5.075970 +v -2.030388 0.009998 5.075970 +v -2.030388 0.009998 4.983679 +v -2.122678 0.009998 4.983679 +v -1.938097 0.009998 5.075970 +v -1.845807 0.009998 5.075970 +v -1.845807 0.009998 4.983679 +v -1.938097 0.009998 4.983679 +v -2.122678 0.009998 4.522227 +v -2.030388 0.009998 4.522227 +v -2.030388 0.009998 4.429937 +v -2.122678 0.009998 4.429937 +v -2.122678 0.009998 4.706808 +v -2.030388 0.009998 4.706808 +v -2.030388 0.009998 4.614518 +v -2.122678 0.009998 4.614518 +v -1.938097 0.009998 4.706808 +v -1.845807 0.009998 4.706808 +v -1.845807 0.009998 4.614518 +v -1.938097 0.009998 4.614518 +v -0.276871 0.009998 4.891389 +v -0.184581 0.009998 4.891389 +v -0.184581 0.009998 4.799098 +v -0.276871 0.009998 4.799098 +v -0.276871 0.009998 5.075970 +v -0.184581 0.009998 5.075970 +v -0.184581 0.009998 4.983679 +v -0.276871 0.009998 4.983679 +v -0.092290 0.009998 5.075970 +v 0.000000 0.009998 5.075970 +v 0.000000 0.009998 4.983679 +v -0.092290 0.009998 4.983679 +v -0.646033 0.009998 4.891389 +v -0.553742 0.009998 4.891389 +v -0.553742 0.009998 4.799098 +v -0.646033 0.009998 4.799098 +v -0.646033 0.009998 5.075970 +v -0.553742 0.009998 5.075970 +v -0.553742 0.009998 4.983679 +v -0.646033 0.009998 4.983679 +v -0.461452 0.009998 5.075970 +v -0.369161 0.009998 5.075970 +v -0.369161 0.009998 4.983679 +v -0.461452 0.009998 4.983679 +v -0.646033 0.009998 4.522227 +v -0.553742 0.009998 4.522227 +v -0.553742 0.009998 4.429937 +v -0.646033 0.009998 4.429937 +v -0.646033 0.009998 4.706808 +v -0.553742 0.009998 4.706808 +v -0.553742 0.009998 4.614518 +v -0.646033 0.009998 4.614518 +v -0.461452 0.009998 4.706808 +v -0.369161 0.009998 4.706808 +v -0.369161 0.009998 4.614518 +v -0.461452 0.009998 4.614518 +v -4.706808 0.009999 3.414743 +v -4.614518 0.009999 3.414743 +v -4.614518 0.009999 3.322453 +v -4.706808 0.009999 3.322453 +v -4.706808 0.009999 3.599324 +v -4.614518 0.009999 3.599324 +v -4.614518 0.009999 3.507033 +v -4.706808 0.009999 3.507033 +v -4.522227 0.009999 3.599324 +v -4.429937 0.009999 3.599324 +v -4.429937 0.009999 3.507033 +v -4.522227 0.009999 3.507033 +v -5.075970 0.009999 3.414743 +v -4.983679 0.009999 3.414743 +v -4.983679 0.009999 3.322453 +v -5.075970 0.009999 3.322453 +v -5.075970 0.009999 3.599324 +v -4.983679 0.009999 3.599324 +v -4.983679 0.009999 3.507033 +v -5.075970 0.009999 3.507033 +v -4.891389 0.009999 3.599324 +v -4.799098 0.009999 3.599324 +v -4.799098 0.009999 3.507033 +v -4.891389 0.009999 3.507033 +v -5.075970 0.009999 3.045582 +v -4.983679 0.009999 3.045582 +v -4.983679 0.009999 2.953291 +v -5.075970 0.009999 2.953291 +v -5.075970 0.009999 3.230163 +v -4.983679 0.009999 3.230163 +v -4.983679 0.009999 3.137872 +v -5.075970 0.009999 3.137872 +v -4.891389 0.009999 3.230163 +v -4.799098 0.009999 3.230163 +v -4.799098 0.009999 3.137872 +v -4.891389 0.009999 3.137872 +v -4.706808 0.009998 4.891389 +v -4.614518 0.009998 4.891389 +v -4.614518 0.009998 4.799098 +v -4.706808 0.009998 4.799098 +v -4.706808 0.009998 5.075970 +v -4.614518 0.009998 5.075970 +v -4.614518 0.009998 4.983679 +v -4.706808 0.009998 4.983679 +v -4.522227 0.009998 5.075970 +v -4.429937 0.009998 5.075970 +v -4.429937 0.009998 4.983679 +v -4.522227 0.009998 4.983679 +v -5.075970 0.009998 4.891389 +v -4.983679 0.009998 4.891389 +v -4.983679 0.009998 4.799098 +v -5.075970 0.009998 4.799098 +v -5.075970 0.009998 5.075970 +v -4.983679 0.009998 5.075970 +v -4.983679 0.009998 4.983679 +v -5.075970 0.009998 4.983679 +v -4.891389 0.009998 5.075970 +v -4.799098 0.009998 5.075970 +v -4.799098 0.009998 4.983679 +v -4.891389 0.009998 4.983679 +v -5.075970 0.009998 4.522227 +v -4.983679 0.009998 4.522227 +v -4.983679 0.009998 4.429937 +v -5.075970 0.009998 4.429937 +v -5.075970 0.009998 4.706808 +v -4.983679 0.009998 4.706808 +v -4.983679 0.009998 4.614518 +v -5.075970 0.009998 4.614518 +v -4.891389 0.009998 4.706808 +v -4.799098 0.009998 4.706808 +v -4.799098 0.009998 4.614518 +v -4.891389 0.009998 4.614518 +v -3.230163 0.009998 4.891389 +v -3.137872 0.009998 4.891389 +v -3.137872 0.009998 4.799098 +v -3.230163 0.009998 4.799098 +v -3.230163 0.009998 5.075970 +v -3.137872 0.009998 5.075970 +v -3.137872 0.009998 4.983679 +v -3.230163 0.009998 4.983679 +v -3.045582 0.009998 5.075970 +v -2.953291 0.009998 5.075970 +v -2.953291 0.009998 4.983679 +v -3.045582 0.009998 4.983679 +v -3.599324 0.009998 4.891389 +v -3.507033 0.009998 4.891389 +v -3.507033 0.009998 4.799098 +v -3.599324 0.009998 4.799098 +v -3.599324 0.009998 5.075970 +v -3.507033 0.009998 5.075970 +v -3.507033 0.009998 4.983679 +v -3.599324 0.009998 4.983679 +v -3.414743 0.009998 5.075970 +v -3.322453 0.009998 5.075970 +v -3.322453 0.009998 4.983679 +v -3.414743 0.009998 4.983679 +v -3.599324 0.009998 4.522227 +v -3.507033 0.009998 4.522227 +v -3.507033 0.009998 4.429937 +v -3.599324 0.009998 4.429937 +v -3.599324 0.009998 4.706808 +v -3.507033 0.009998 4.706808 +v -3.507033 0.009998 4.614518 +v -3.599324 0.009998 4.614518 +v -3.414743 0.009998 4.706808 +v -3.322453 0.009998 4.706808 +v -3.322453 0.009998 4.614518 +v -3.414743 0.009998 4.614518 +v -4.706808 0.010000 0.461452 +v -4.614518 0.010000 0.461452 +v -4.614518 0.010000 0.369161 +v -4.706808 0.010000 0.369161 +v -4.706808 0.010000 0.646033 +v -4.614518 0.010000 0.646033 +v -4.614518 0.010000 0.553742 +v -4.706808 0.010000 0.553742 +v -4.522227 0.010000 0.646033 +v -4.429937 0.010000 0.646033 +v -4.429937 0.010000 0.553742 +v -4.522227 0.010000 0.553742 +v -5.075970 0.010000 0.461452 +v -4.983679 0.010000 0.461452 +v -4.983679 0.010000 0.369161 +v -5.075970 0.010000 0.369161 +v -5.075970 0.010000 0.646033 +v -4.983679 0.010000 0.646033 +v -4.983679 0.010000 0.553742 +v -5.075970 0.010000 0.553742 +v -4.891389 0.010000 0.646033 +v -4.799098 0.010000 0.646033 +v -4.799098 0.010000 0.553742 +v -4.891389 0.010000 0.553742 +v -5.075970 0.010000 0.092290 +v -4.983679 0.010000 0.092290 +v -4.983679 0.010000 -0.000000 +v -5.075970 0.010000 -0.000000 +v -5.075970 0.010000 0.276871 +v -4.983679 0.010000 0.276871 +v -4.983679 0.010000 0.184581 +v -5.075970 0.010000 0.184581 +v -4.891389 0.010000 0.276871 +v -4.799098 0.010000 0.276871 +v -4.799098 0.010000 0.184581 +v -4.891389 0.010000 0.184581 +v -4.706808 0.009999 1.938097 +v -4.614518 0.009999 1.938097 +v -4.614518 0.009999 1.845807 +v -4.706808 0.009999 1.845807 +v -4.706808 0.009999 2.122678 +v -4.614518 0.009999 2.122678 +v -4.614518 0.009999 2.030388 +v -4.706808 0.009999 2.030388 +v -4.522227 0.009999 2.122678 +v -4.429937 0.009999 2.122678 +v -4.429937 0.009999 2.030388 +v -4.522227 0.009999 2.030388 +v -5.075970 0.009999 1.938097 +v -4.983679 0.009999 1.938097 +v -4.983679 0.009999 1.845807 +v -5.075970 0.009999 1.845807 +v -5.075970 0.009999 2.122678 +v -4.983679 0.009999 2.122678 +v -4.983679 0.009999 2.030388 +v -5.075970 0.009999 2.030388 +v -4.891389 0.009999 2.122678 +v -4.799098 0.009999 2.122678 +v -4.799098 0.009999 2.030388 +v -4.891389 0.009999 2.030388 +v -5.075970 0.009999 1.568936 +v -4.983679 0.009999 1.568936 +v -4.983679 0.009999 1.476646 +v -5.075970 0.009999 1.476646 +v -5.075970 0.009999 1.753517 +v -4.983679 0.009999 1.753517 +v -4.983679 0.009999 1.661226 +v -5.075970 0.009999 1.661226 +v -4.891389 0.009999 1.753517 +v -4.799098 0.009999 1.753517 +v -4.799098 0.009999 1.661226 +v -4.891389 0.009999 1.661226 +v -3.230163 0.009999 1.938097 +v -3.137872 0.009999 1.938097 +v -3.137872 0.009999 1.845807 +v -3.230163 0.009999 1.845807 +v -3.230163 0.009999 2.122678 +v -3.137872 0.009999 2.122678 +v -3.137872 0.009999 2.030388 +v -3.230163 0.009999 2.030388 +v -3.045582 0.009999 2.122678 +v -2.953291 0.009999 2.122678 +v -2.953291 0.009999 2.030388 +v -3.045582 0.009999 2.030388 +v -3.599324 0.009999 1.938097 +v -3.507033 0.009999 1.938097 +v -3.507033 0.009999 1.845807 +v -3.599324 0.009999 1.845807 +v -3.599324 0.009999 2.122678 +v -3.507033 0.009999 2.122678 +v -3.507033 0.009999 2.030388 +v -3.599324 0.009999 2.030388 +v -3.414743 0.009999 2.122678 +v -3.322453 0.009999 2.122678 +v -3.322453 0.009999 2.030388 +v -3.414743 0.009999 2.030388 +v -3.599324 0.009999 1.568936 +v -3.507033 0.009999 1.568936 +v -3.507033 0.009999 1.476646 +v -3.599324 0.009999 1.476646 +v -3.599324 0.009999 1.753517 +v -3.507033 0.009999 1.753517 +v -3.507033 0.009999 1.661226 +v -3.599324 0.009999 1.661226 +v -3.414743 0.009999 1.753517 +v -3.322453 0.009999 1.753517 +v -3.322453 0.009999 1.661226 +v -3.414743 0.009999 1.661226 +v 4.153066 0.009999 3.414743 +v 4.245357 0.009999 3.414743 +v 4.245357 0.009999 3.322453 +v 4.153066 0.009999 3.322453 +v 4.153066 0.009999 3.599324 +v 4.245357 0.009999 3.599324 +v 4.245357 0.009999 3.507033 +v 4.153066 0.009999 3.507033 +v 4.337647 0.009999 3.599324 +v 4.429937 0.009999 3.599324 +v 4.429937 0.009999 3.507033 +v 4.337647 0.009999 3.507033 +v 3.783905 0.009999 3.414743 +v 3.876195 0.009999 3.414743 +v 3.876195 0.009999 3.322453 +v 3.783905 0.009999 3.322453 +v 3.783905 0.009999 3.599324 +v 3.876195 0.009999 3.599324 +v 3.876195 0.009999 3.507033 +v 3.783905 0.009999 3.507033 +v 3.968485 0.009999 3.599324 +v 4.060776 0.009999 3.599324 +v 4.060776 0.009999 3.507033 +v 3.968485 0.009999 3.507033 +v 3.783905 0.009999 3.045582 +v 3.876195 0.009999 3.045582 +v 3.876195 0.009999 2.953291 +v 3.783905 0.009999 2.953291 +v 3.783905 0.009999 3.230163 +v 3.876195 0.009999 3.230163 +v 3.876195 0.009999 3.137872 +v 3.783905 0.009999 3.137872 +v 3.968485 0.009999 3.230163 +v 4.060776 0.009999 3.230163 +v 4.060776 0.009999 3.137872 +v 3.968485 0.009999 3.137872 +v 4.153066 0.009998 4.891389 +v 4.245357 0.009998 4.891389 +v 4.245357 0.009998 4.799098 +v 4.153066 0.009998 4.799098 +v 4.153066 0.009998 5.075970 +v 4.245357 0.009998 5.075970 +v 4.245357 0.009998 4.983679 +v 4.153066 0.009998 4.983679 +v 4.337647 0.009998 5.075970 +v 4.429937 0.009998 5.075970 +v 4.429937 0.009998 4.983679 +v 4.337647 0.009998 4.983679 +v 3.783905 0.009998 4.891389 +v 3.876195 0.009998 4.891389 +v 3.876195 0.009998 4.799098 +v 3.783905 0.009998 4.799098 +v 3.783905 0.009998 5.075970 +v 3.876195 0.009998 5.075970 +v 3.876195 0.009998 4.983679 +v 3.783905 0.009998 4.983679 +v 3.968485 0.009998 5.075970 +v 4.060776 0.009998 5.075970 +v 4.060776 0.009998 4.983679 +v 3.968485 0.009998 4.983679 +v 3.783905 0.009998 4.522227 +v 3.876195 0.009998 4.522227 +v 3.876195 0.009998 4.429937 +v 3.783905 0.009998 4.429937 +v 3.783905 0.009998 4.706808 +v 3.876195 0.009998 4.706808 +v 3.876195 0.009998 4.614518 +v 3.783905 0.009998 4.614518 +v 3.968485 0.009998 4.706808 +v 4.060776 0.009998 4.706808 +v 4.060776 0.009998 4.614518 +v 3.968485 0.009998 4.614518 +v 5.629711 0.009998 4.891389 +v 5.722002 0.009998 4.891389 +v 5.722002 0.009998 4.799098 +v 5.629711 0.009998 4.799098 +v 5.629711 0.009998 5.075970 +v 5.722002 0.009998 5.075970 +v 5.722002 0.009998 4.983679 +v 5.629711 0.009998 4.983679 +v 5.814293 0.009998 5.075970 +v 5.906583 0.009998 5.075970 +v 5.906583 0.009998 4.983679 +v 5.814293 0.009998 4.983679 +v 5.260550 0.009998 4.891389 +v 5.352840 0.009998 4.891389 +v 5.352840 0.009998 4.799098 +v 5.260550 0.009998 4.799098 +v 5.260550 0.009998 5.075970 +v 5.352840 0.009998 5.075970 +v 5.352840 0.009998 4.983679 +v 5.260550 0.009998 4.983679 +v 5.445131 0.009998 5.075970 +v 5.537421 0.009998 5.075970 +v 5.537421 0.009998 4.983679 +v 5.445131 0.009998 4.983679 +v 5.260550 0.009998 4.522227 +v 5.352840 0.009998 4.522227 +v 5.352840 0.009998 4.429937 +v 5.260550 0.009998 4.429937 +v 5.260550 0.009998 4.706808 +v 5.352840 0.009998 4.706808 +v 5.352840 0.009998 4.614518 +v 5.260550 0.009998 4.614518 +v 5.445131 0.009998 4.706808 +v 5.537421 0.009998 4.706808 +v 5.537421 0.009998 4.614518 +v 5.445131 0.009998 4.614518 +v 1.199775 0.009999 3.414743 +v 1.292065 0.009999 3.414743 +v 1.292065 0.009999 3.322453 +v 1.199775 0.009999 3.322453 +v 1.199775 0.009999 3.599324 +v 1.292065 0.009999 3.599324 +v 1.292065 0.009999 3.507033 +v 1.199775 0.009999 3.507033 +v 1.384355 0.009999 3.599324 +v 1.476646 0.009999 3.599324 +v 1.476646 0.009999 3.507033 +v 1.384355 0.009999 3.507033 +v 0.830613 0.009999 3.414743 +v 0.922904 0.009999 3.414743 +v 0.922904 0.009999 3.322453 +v 0.830613 0.009999 3.322453 +v 0.830613 0.009999 3.599324 +v 0.922904 0.009999 3.599324 +v 0.922904 0.009999 3.507033 +v 0.830613 0.009999 3.507033 +v 1.015194 0.009999 3.599324 +v 1.107484 0.009999 3.599324 +v 1.107484 0.009999 3.507033 +v 1.015194 0.009999 3.507033 +v 0.830613 0.009999 3.045582 +v 0.922904 0.009999 3.045582 +v 0.922904 0.009999 2.953291 +v 0.830613 0.009999 2.953291 +v 0.830613 0.009999 3.230163 +v 0.922904 0.009999 3.230163 +v 0.922904 0.009999 3.137872 +v 0.830613 0.009999 3.137872 +v 1.015194 0.009999 3.230163 +v 1.107484 0.009999 3.230163 +v 1.107484 0.009999 3.137872 +v 1.015194 0.009999 3.137872 +v 1.199775 0.009998 4.891389 +v 1.292065 0.009998 4.891389 +v 1.292065 0.009998 4.799098 +v 1.199775 0.009998 4.799098 +v 1.199775 0.009998 5.075970 +v 1.292065 0.009998 5.075970 +v 1.292065 0.009998 4.983679 +v 1.199775 0.009998 4.983679 +v 1.384355 0.009998 5.075970 +v 1.476646 0.009998 5.075970 +v 1.476646 0.009998 4.983679 +v 1.384355 0.009998 4.983679 +v 0.830613 0.009998 4.891389 +v 0.922904 0.009998 4.891389 +v 0.922904 0.009998 4.799098 +v 0.830613 0.009998 4.799098 +v 0.830613 0.009998 5.075970 +v 0.922904 0.009998 5.075970 +v 0.922904 0.009998 4.983679 +v 0.830613 0.009998 4.983679 +v 1.015194 0.009998 5.075970 +v 1.107484 0.009998 5.075970 +v 1.107484 0.009998 4.983679 +v 1.015194 0.009998 4.983679 +v 0.830613 0.009998 4.522227 +v 0.922904 0.009998 4.522227 +v 0.922904 0.009998 4.429937 +v 0.830613 0.009998 4.429937 +v 0.830613 0.009998 4.706808 +v 0.922904 0.009998 4.706808 +v 0.922904 0.009998 4.614518 +v 0.830613 0.009998 4.614518 +v 1.015194 0.009998 4.706808 +v 1.107484 0.009998 4.706808 +v 1.107484 0.009998 4.614518 +v 1.015194 0.009998 4.614518 +v 2.676420 0.009998 4.891389 +v 2.768711 0.009998 4.891389 +v 2.768711 0.009998 4.799098 +v 2.676420 0.009998 4.799098 +v 2.676420 0.009998 5.075970 +v 2.768711 0.009998 5.075970 +v 2.768711 0.009998 4.983679 +v 2.676420 0.009998 4.983679 +v 2.861001 0.009998 5.075970 +v 2.953291 0.009998 5.075970 +v 2.953291 0.009998 4.983679 +v 2.861001 0.009998 4.983679 +v 2.307259 0.009998 4.891389 +v 2.399549 0.009998 4.891389 +v 2.399549 0.009998 4.799098 +v 2.307259 0.009998 4.799098 +v 2.307259 0.009998 5.075970 +v 2.399549 0.009998 5.075970 +v 2.399549 0.009998 4.983679 +v 2.307259 0.009998 4.983679 +v 2.491840 0.009998 5.075970 +v 2.584130 0.009998 5.075970 +v 2.584130 0.009998 4.983679 +v 2.491840 0.009998 4.983679 +v 2.307259 0.009998 4.522227 +v 2.399549 0.009998 4.522227 +v 2.399549 0.009998 4.429937 +v 2.307259 0.009998 4.429937 +v 2.307259 0.009998 4.706808 +v 2.399549 0.009998 4.706808 +v 2.399549 0.009998 4.614518 +v 2.307259 0.009998 4.614518 +v 2.491840 0.009998 4.706808 +v 2.584130 0.009998 4.706808 +v 2.584130 0.009998 4.614518 +v 2.491840 0.009998 4.614518 +v 1.199775 0.010000 0.461452 +v 1.292065 0.010000 0.461452 +v 1.292065 0.010000 0.369161 +v 1.199775 0.010000 0.369161 +v 1.199775 0.010000 0.646033 +v 1.292065 0.010000 0.646033 +v 1.292065 0.010000 0.553742 +v 1.199775 0.010000 0.553742 +v 1.384355 0.010000 0.646033 +v 1.476646 0.010000 0.646033 +v 1.476646 0.010000 0.553742 +v 1.384355 0.010000 0.553742 +v 0.830613 0.010000 0.461452 +v 0.922904 0.010000 0.461452 +v 0.922904 0.010000 0.369161 +v 0.830613 0.010000 0.369161 +v 0.830613 0.010000 0.646033 +v 0.922904 0.010000 0.646033 +v 0.922904 0.010000 0.553742 +v 0.830613 0.010000 0.553742 +v 1.015194 0.010000 0.646033 +v 1.107484 0.010000 0.646033 +v 1.107484 0.010000 0.553742 +v 1.015194 0.010000 0.553742 +v 0.830613 0.010000 0.092290 +v 0.922904 0.010000 0.092290 +v 0.922904 0.010000 -0.000000 +v 0.830613 0.010000 -0.000000 +v 0.830613 0.010000 0.276871 +v 0.922904 0.010000 0.276871 +v 0.922904 0.010000 0.184581 +v 0.830613 0.010000 0.184581 +v 1.015194 0.010000 0.276871 +v 1.107484 0.010000 0.276871 +v 1.107484 0.010000 0.184581 +v 1.015194 0.010000 0.184581 +v 1.199775 0.009999 1.938097 +v 1.292065 0.009999 1.938097 +v 1.292065 0.009999 1.845807 +v 1.199775 0.009999 1.845807 +v 1.199775 0.009999 2.122678 +v 1.292065 0.009999 2.122678 +v 1.292065 0.009999 2.030388 +v 1.199775 0.009999 2.030388 +v 1.384355 0.009999 2.122678 +v 1.476646 0.009999 2.122678 +v 1.476646 0.009999 2.030388 +v 1.384355 0.009999 2.030388 +v 0.830613 0.009999 1.938097 +v 0.922904 0.009999 1.938097 +v 0.922904 0.009999 1.845807 +v 0.830613 0.009999 1.845807 +v 0.830613 0.009999 2.122678 +v 0.922904 0.009999 2.122678 +v 0.922904 0.009999 2.030388 +v 0.830613 0.009999 2.030388 +v 1.015194 0.009999 2.122678 +v 1.107484 0.009999 2.122678 +v 1.107484 0.009999 2.030388 +v 1.015194 0.009999 2.030388 +v 0.830613 0.009999 1.568936 +v 0.922904 0.009999 1.568936 +v 0.922904 0.009999 1.476646 +v 0.830613 0.009999 1.476646 +v 0.830613 0.009999 1.753517 +v 0.922904 0.009999 1.753517 +v 0.922904 0.009999 1.661226 +v 0.830613 0.009999 1.661226 +v 1.015194 0.009999 1.753517 +v 1.107484 0.009999 1.753517 +v 1.107484 0.009999 1.661226 +v 1.015194 0.009999 1.661226 +v 2.676420 0.009999 1.938097 +v 2.768711 0.009999 1.938097 +v 2.768711 0.009999 1.845807 +v 2.676420 0.009999 1.845807 +v 2.676420 0.009999 2.122678 +v 2.768711 0.009999 2.122678 +v 2.768711 0.009999 2.030388 +v 2.676420 0.009999 2.030388 +v 2.861001 0.009999 2.122678 +v 2.953291 0.009999 2.122678 +v 2.953291 0.009999 2.030388 +v 2.861001 0.009999 2.030388 +v 2.307259 0.009999 1.938097 +v 2.399549 0.009999 1.938097 +v 2.399549 0.009999 1.845807 +v 2.307259 0.009999 1.845807 +v 2.307259 0.009999 2.122678 +v 2.399549 0.009999 2.122678 +v 2.399549 0.009999 2.030388 +v 2.307259 0.009999 2.030388 +v 2.491840 0.009999 2.122678 +v 2.584130 0.009999 2.122678 +v 2.584130 0.009999 2.030388 +v 2.491840 0.009999 2.030388 +v 2.307259 0.009999 1.568936 +v 2.399549 0.009999 1.568936 +v 2.399549 0.009999 1.476646 +v 2.307259 0.009999 1.476646 +v 2.307259 0.009999 1.753517 +v 2.399549 0.009999 1.753517 +v 2.399549 0.009999 1.661226 +v 2.307259 0.009999 1.661226 +v 2.491840 0.009999 1.753517 +v 2.584130 0.009999 1.753517 +v 2.584130 0.009999 1.661226 +v 2.491840 0.009999 1.661226 +v 4.153066 0.010000 0.461452 +v 4.245357 0.010000 0.461452 +v 4.245357 0.010000 0.369161 +v 4.153066 0.010000 0.369161 +v 4.153066 0.010000 0.646033 +v 4.245357 0.010000 0.646033 +v 4.245357 0.010000 0.553742 +v 4.153066 0.010000 0.553742 +v 4.337647 0.010000 0.646033 +v 4.429937 0.010000 0.646033 +v 4.429937 0.010000 0.553742 +v 4.337647 0.010000 0.553742 +v 3.783905 0.010000 0.461452 +v 3.876195 0.010000 0.461452 +v 3.876195 0.010000 0.369161 +v 3.783905 0.010000 0.369161 +v 3.783905 0.010000 0.646033 +v 3.876195 0.010000 0.646033 +v 3.876195 0.010000 0.553742 +v 3.783905 0.010000 0.553742 +v 3.968485 0.010000 0.646033 +v 4.060776 0.010000 0.646033 +v 4.060776 0.010000 0.553742 +v 3.968485 0.010000 0.553742 +v 3.783905 0.010000 0.092290 +v 3.876195 0.010000 0.092290 +v 3.876195 0.010000 -0.000000 +v 3.783905 0.010000 -0.000000 +v 3.783905 0.010000 0.276871 +v 3.876195 0.010000 0.276871 +v 3.876195 0.010000 0.184581 +v 3.783905 0.010000 0.184581 +v 3.968485 0.010000 0.276871 +v 4.060776 0.010000 0.276871 +v 4.060776 0.010000 0.184581 +v 3.968485 0.010000 0.184581 +v 4.153066 0.009999 1.938097 +v 4.245357 0.009999 1.938097 +v 4.245357 0.009999 1.845807 +v 4.153066 0.009999 1.845807 +v 4.153066 0.009999 2.122678 +v 4.245357 0.009999 2.122678 +v 4.245357 0.009999 2.030388 +v 4.153066 0.009999 2.030388 +v 4.337647 0.009999 2.122678 +v 4.429937 0.009999 2.122678 +v 4.429937 0.009999 2.030388 +v 4.337647 0.009999 2.030388 +v 3.783905 0.009999 1.938097 +v 3.876195 0.009999 1.938097 +v 3.876195 0.009999 1.845807 +v 3.783905 0.009999 1.845807 +v 3.783905 0.009999 2.122678 +v 3.876195 0.009999 2.122678 +v 3.876195 0.009999 2.030388 +v 3.783905 0.009999 2.030388 +v 3.968485 0.009999 2.122678 +v 4.060776 0.009999 2.122678 +v 4.060776 0.009999 2.030388 +v 3.968485 0.009999 2.030388 +v 3.783905 0.009999 1.568936 +v 3.876195 0.009999 1.568936 +v 3.876195 0.009999 1.476646 +v 3.783905 0.009999 1.476646 +v 3.783905 0.009999 1.753517 +v 3.876195 0.009999 1.753517 +v 3.876195 0.009999 1.661226 +v 3.783905 0.009999 1.661226 +v 3.968485 0.009999 1.753517 +v 4.060776 0.009999 1.753517 +v 4.060776 0.009999 1.661226 +v 3.968485 0.009999 1.661226 +v 5.629711 0.009999 1.938097 +v 5.722002 0.009999 1.938097 +v 5.722002 0.009999 1.845807 +v 5.629711 0.009999 1.845807 +v 5.629711 0.009999 2.122678 +v 5.722002 0.009999 2.122678 +v 5.722002 0.009999 2.030388 +v 5.629711 0.009999 2.030388 +v 5.814293 0.009999 2.122678 +v 5.906583 0.009999 2.122678 +v 5.906583 0.009999 2.030388 +v 5.814293 0.009999 2.030388 +v 5.260550 0.009999 1.938097 +v 5.352840 0.009999 1.938097 +v 5.352840 0.009999 1.845807 +v 5.260550 0.009999 1.845807 +v 5.260550 0.009999 2.122678 +v 5.352840 0.009999 2.122678 +v 5.352840 0.009999 2.030388 +v 5.260550 0.009999 2.030388 +v 5.445131 0.009999 2.122678 +v 5.537421 0.009999 2.122678 +v 5.537421 0.009999 2.030388 +v 5.445131 0.009999 2.030388 +v 5.260550 0.009999 1.568936 +v 5.352840 0.009999 1.568936 +v 5.352840 0.009999 1.476646 +v 5.260550 0.009999 1.476646 +v 5.260550 0.009999 1.753517 +v 5.352840 0.009999 1.753517 +v 5.352840 0.009999 1.661226 +v 5.260550 0.009999 1.661226 +v 5.445131 0.009999 1.753517 +v 5.537421 0.009999 1.753517 +v 5.537421 0.009999 1.661226 +v 5.445131 0.009999 1.661226 +v -1.753517 0.010000 0.461452 +v -1.661226 0.010000 0.461452 +v -1.661226 0.010000 0.369161 +v -1.753517 0.010000 0.369161 +v -1.753517 0.010000 0.646033 +v -1.661226 0.010000 0.646033 +v -1.661226 0.010000 0.553742 +v -1.753517 0.010000 0.553742 +v -1.568936 0.010000 0.646033 +v -1.476646 0.010000 0.646033 +v -1.476646 0.010000 0.553742 +v -1.568936 0.010000 0.553742 +v -2.122678 0.010000 0.461452 +v -2.030388 0.010000 0.461452 +v -2.030388 0.010000 0.369161 +v -2.122678 0.010000 0.369161 +v -2.122678 0.010000 0.646033 +v -2.030388 0.010000 0.646033 +v -2.030388 0.010000 0.553742 +v -2.122678 0.010000 0.553742 +v -1.938097 0.010000 0.646033 +v -1.845807 0.010000 0.646033 +v -1.845807 0.010000 0.553742 +v -1.938097 0.010000 0.553742 +v -2.122678 0.010000 0.092290 +v -2.030388 0.010000 0.092290 +v -2.030388 0.010000 -0.000000 +v -2.122678 0.010000 -0.000000 +v -2.122678 0.010000 0.276871 +v -2.030388 0.010000 0.276871 +v -2.030388 0.010000 0.184581 +v -2.122678 0.010000 0.184581 +v -1.938097 0.010000 0.276871 +v -1.845807 0.010000 0.276871 +v -1.845807 0.010000 0.184581 +v -1.938097 0.010000 0.184581 +v -1.753517 0.009999 1.938097 +v -1.661226 0.009999 1.938097 +v -1.661226 0.009999 1.845807 +v -1.753517 0.009999 1.845807 +v -1.753517 0.009999 2.122678 +v -1.661226 0.009999 2.122678 +v -1.661226 0.009999 2.030388 +v -1.753517 0.009999 2.030388 +v -1.568936 0.009999 2.122678 +v -1.476646 0.009999 2.122678 +v -1.476646 0.009999 2.030388 +v -1.568936 0.009999 2.030388 +v -2.122678 0.009999 1.938097 +v -2.030388 0.009999 1.938097 +v -2.030388 0.009999 1.845807 +v -2.122678 0.009999 1.845807 +v -2.122678 0.009999 2.122678 +v -2.030388 0.009999 2.122678 +v -2.030388 0.009999 2.030388 +v -2.122678 0.009999 2.030388 +v -1.938097 0.009999 2.122678 +v -1.845807 0.009999 2.122678 +v -1.845807 0.009999 2.030388 +v -1.938097 0.009999 2.030388 +v -2.122678 0.009999 1.568936 +v -2.030388 0.009999 1.568936 +v -2.030388 0.009999 1.476646 +v -2.122678 0.009999 1.476646 +v -2.122678 0.009999 1.753517 +v -2.030388 0.009999 1.753517 +v -2.030388 0.009999 1.661226 +v -2.122678 0.009999 1.661226 +v -1.938097 0.009999 1.753517 +v -1.845807 0.009999 1.753517 +v -1.845807 0.009999 1.661226 +v -1.938097 0.009999 1.661226 +v -0.276871 0.009999 1.938097 +v -0.184581 0.009999 1.938097 +v -0.184581 0.009999 1.845807 +v -0.276871 0.009999 1.845807 +v -0.276871 0.009999 2.122678 +v -0.184581 0.009999 2.122678 +v -0.184581 0.009999 2.030388 +v -0.276871 0.009999 2.030388 +v -0.092290 0.009999 2.122678 +v 0.000000 0.009999 2.122678 +v 0.000000 0.009999 2.030388 +v -0.092290 0.009999 2.030388 +v -0.646033 0.009999 1.938097 +v -0.553742 0.009999 1.938097 +v -0.553742 0.009999 1.845807 +v -0.646033 0.009999 1.845807 +v -0.646033 0.009999 2.122678 +v -0.553742 0.009999 2.122678 +v -0.553742 0.009999 2.030388 +v -0.646033 0.009999 2.030388 +v -0.461452 0.009999 2.122678 +v -0.369161 0.009999 2.122678 +v -0.369161 0.009999 2.030388 +v -0.461452 0.009999 2.030388 +v -0.646033 0.009999 1.568936 +v -0.553742 0.009999 1.568936 +v -0.553742 0.009999 1.476646 +v -0.646033 0.009999 1.476646 +v -0.646033 0.009999 1.753517 +v -0.553742 0.009999 1.753517 +v -0.553742 0.009999 1.661226 +v -0.646033 0.009999 1.661226 +v -0.461452 0.009999 1.753517 +v -0.369161 0.009999 1.753517 +v -0.369161 0.009999 1.661226 +v -0.461452 0.009999 1.661226 +v -1.753517 0.010002 -5.445131 +v -1.661226 0.010002 -5.445131 +v -1.661226 0.010002 -5.537421 +v -1.753517 0.010002 -5.537421 +v -1.753517 0.010002 -5.260550 +v -1.661226 0.010002 -5.260550 +v -1.661226 0.010002 -5.352840 +v -1.753517 0.010002 -5.352840 +v -1.568936 0.010002 -5.260550 +v -1.476646 0.010002 -5.260550 +v -1.476646 0.010002 -5.352840 +v -1.568936 0.010002 -5.352840 +v -2.122678 0.010002 -5.445131 +v -2.030388 0.010002 -5.445131 +v -2.030388 0.010002 -5.537421 +v -2.122678 0.010002 -5.537421 +v -2.122678 0.010002 -5.260550 +v -2.030388 0.010002 -5.260550 +v -2.030388 0.010002 -5.352840 +v -2.122678 0.010002 -5.352840 +v -1.938097 0.010002 -5.260550 +v -1.845807 0.010002 -5.260550 +v -1.845807 0.010002 -5.352840 +v -1.938097 0.010002 -5.352840 +v -2.122678 0.010002 -5.814293 +v -2.030388 0.010002 -5.814293 +v -2.030388 0.010002 -5.906583 +v -2.122678 0.010002 -5.906583 +v -2.122678 0.010002 -5.629711 +v -2.030388 0.010002 -5.629711 +v -2.030388 0.010002 -5.722002 +v -2.122678 0.010002 -5.722002 +v -1.938097 0.010002 -5.629711 +v -1.845807 0.010002 -5.629711 +v -1.845807 0.010002 -5.722002 +v -1.938097 0.010002 -5.722002 +v -1.753517 0.010002 -3.968485 +v -1.661226 0.010002 -3.968485 +v -1.661226 0.010002 -4.060776 +v -1.753517 0.010002 -4.060776 +v -1.753517 0.010002 -3.783905 +v -1.661226 0.010002 -3.783905 +v -1.661226 0.010002 -3.876195 +v -1.753517 0.010002 -3.876195 +v -1.568936 0.010002 -3.783905 +v -1.476646 0.010002 -3.783905 +v -1.476646 0.010002 -3.876195 +v -1.568936 0.010002 -3.876195 +v -2.122678 0.010002 -3.968485 +v -2.030388 0.010002 -3.968485 +v -2.030388 0.010002 -4.060776 +v -2.122678 0.010002 -4.060776 +v -2.122678 0.010002 -3.783905 +v -2.030388 0.010002 -3.783905 +v -2.030388 0.010002 -3.876195 +v -2.122678 0.010002 -3.876195 +v -1.938097 0.010002 -3.783905 +v -1.845807 0.010002 -3.783905 +v -1.845807 0.010002 -3.876195 +v -1.938097 0.010002 -3.876195 +v -2.122678 0.010002 -4.337647 +v -2.030388 0.010002 -4.337647 +v -2.030388 0.010002 -4.429937 +v -2.122678 0.010002 -4.429937 +v -2.122678 0.010002 -4.153066 +v -2.030388 0.010002 -4.153066 +v -2.030388 0.010002 -4.245357 +v -2.122678 0.010002 -4.245357 +v -1.938097 0.010002 -4.153066 +v -1.845807 0.010002 -4.153066 +v -1.845807 0.010002 -4.245357 +v -1.938097 0.010002 -4.245357 +v -0.276871 0.010002 -3.968485 +v -0.184581 0.010002 -3.968485 +v -0.184581 0.010002 -4.060776 +v -0.276871 0.010002 -4.060776 +v -0.276871 0.010002 -3.783905 +v -0.184581 0.010002 -3.783905 +v -0.184581 0.010002 -3.876195 +v -0.276871 0.010002 -3.876195 +v -0.092290 0.010002 -3.783905 +v 0.000000 0.010002 -3.783905 +v 0.000000 0.010002 -3.876195 +v -0.092290 0.010002 -3.876195 +v -0.646033 0.010002 -3.968485 +v -0.553742 0.010002 -3.968485 +v -0.553742 0.010002 -4.060776 +v -0.646033 0.010002 -4.060776 +v -0.646033 0.010002 -3.783905 +v -0.553742 0.010002 -3.783905 +v -0.553742 0.010002 -3.876195 +v -0.646033 0.010002 -3.876195 +v -0.461452 0.010002 -3.783905 +v -0.369161 0.010002 -3.783905 +v -0.369161 0.010002 -3.876195 +v -0.461452 0.010002 -3.876195 +v -0.646033 0.010002 -4.337647 +v -0.553742 0.010002 -4.337647 +v -0.553742 0.010002 -4.429937 +v -0.646033 0.010002 -4.429937 +v -0.646033 0.010002 -4.153066 +v -0.553742 0.010002 -4.153066 +v -0.553742 0.010002 -4.245357 +v -0.646033 0.010002 -4.245357 +v -0.461452 0.010002 -4.153066 +v -0.369161 0.010002 -4.153066 +v -0.369161 0.010002 -4.245357 +v -0.461452 0.010002 -4.245357 +v 4.153066 0.010002 -5.445131 +v 4.245357 0.010002 -5.445131 +v 4.245357 0.010002 -5.537421 +v 4.153066 0.010002 -5.537421 +v 4.153066 0.010002 -5.260550 +v 4.245357 0.010002 -5.260550 +v 4.245357 0.010002 -5.352840 +v 4.153066 0.010002 -5.352840 +v 4.337647 0.010002 -5.260550 +v 4.429937 0.010002 -5.260550 +v 4.429937 0.010002 -5.352840 +v 4.337647 0.010002 -5.352840 +v 3.783905 0.010002 -5.445131 +v 3.876195 0.010002 -5.445131 +v 3.876195 0.010002 -5.537421 +v 3.783905 0.010002 -5.537421 +v 3.783905 0.010002 -5.260550 +v 3.876195 0.010002 -5.260550 +v 3.876195 0.010002 -5.352840 +v 3.783905 0.010002 -5.352840 +v 3.968485 0.010002 -5.260550 +v 4.060776 0.010002 -5.260550 +v 4.060776 0.010002 -5.352840 +v 3.968485 0.010002 -5.352840 +v 3.783905 0.010002 -5.814293 +v 3.876195 0.010002 -5.814293 +v 3.876195 0.010002 -5.906583 +v 3.783905 0.010002 -5.906583 +v 3.783905 0.010002 -5.629711 +v 3.876195 0.010002 -5.629711 +v 3.876195 0.010002 -5.722002 +v 3.783905 0.010002 -5.722002 +v 3.968485 0.010002 -5.629711 +v 4.060776 0.010002 -5.629711 +v 4.060776 0.010002 -5.722002 +v 3.968485 0.010002 -5.722002 +v 4.153066 0.010002 -3.968485 +v 4.245357 0.010002 -3.968485 +v 4.245357 0.010002 -4.060776 +v 4.153066 0.010002 -4.060776 +v 4.153066 0.010002 -3.783905 +v 4.245357 0.010002 -3.783905 +v 4.245357 0.010002 -3.876195 +v 4.153066 0.010002 -3.876195 +v 4.337647 0.010002 -3.783905 +v 4.429937 0.010002 -3.783905 +v 4.429937 0.010002 -3.876195 +v 4.337647 0.010002 -3.876195 +v 3.783905 0.010002 -3.968485 +v 3.876195 0.010002 -3.968485 +v 3.876195 0.010002 -4.060776 +v 3.783905 0.010002 -4.060776 +v 3.783905 0.010002 -3.783905 +v 3.876195 0.010002 -3.783905 +v 3.876195 0.010002 -3.876195 +v 3.783905 0.010002 -3.876195 +v 3.968485 0.010002 -3.783905 +v 4.060776 0.010002 -3.783905 +v 4.060776 0.010002 -3.876195 +v 3.968485 0.010002 -3.876195 +v 3.783905 0.010002 -4.337647 +v 3.876195 0.010002 -4.337647 +v 3.876195 0.010002 -4.429937 +v 3.783905 0.010002 -4.429937 +v 3.783905 0.010002 -4.153066 +v 3.876195 0.010002 -4.153066 +v 3.876195 0.010002 -4.245357 +v 3.783905 0.010002 -4.245357 +v 3.968485 0.010002 -4.153066 +v 4.060776 0.010002 -4.153066 +v 4.060776 0.010002 -4.245357 +v 3.968485 0.010002 -4.245357 +v 5.629711 0.010002 -3.968485 +v 5.722002 0.010002 -3.968485 +v 5.722002 0.010002 -4.060776 +v 5.629711 0.010002 -4.060776 +v 5.629711 0.010002 -3.783905 +v 5.722002 0.010002 -3.783905 +v 5.722002 0.010002 -3.876195 +v 5.629711 0.010002 -3.876195 +v 5.814293 0.010002 -3.783905 +v 5.906583 0.010002 -3.783905 +v 5.906583 0.010002 -3.876195 +v 5.814293 0.010002 -3.876195 +v 5.260550 0.010002 -3.968485 +v 5.352840 0.010002 -3.968485 +v 5.352840 0.010002 -4.060776 +v 5.260550 0.010002 -4.060776 +v 5.260550 0.010002 -3.783905 +v 5.352840 0.010002 -3.783905 +v 5.352840 0.010002 -3.876195 +v 5.260550 0.010002 -3.876195 +v 5.445131 0.010002 -3.783905 +v 5.537421 0.010002 -3.783905 +v 5.537421 0.010002 -3.876195 +v 5.445131 0.010002 -3.876195 +v 5.260550 0.010002 -4.337647 +v 5.352840 0.010002 -4.337647 +v 5.352840 0.010002 -4.429937 +v 5.260550 0.010002 -4.429937 +v 5.260550 0.010002 -4.153066 +v 5.352840 0.010002 -4.153066 +v 5.352840 0.010002 -4.245357 +v 5.260550 0.010002 -4.245357 +v 5.445131 0.010002 -4.153066 +v 5.537421 0.010002 -4.153066 +v 5.537421 0.010002 -4.245357 +v 5.445131 0.010002 -4.245357 +v 4.891389 0.010002 -3.968485 +v 4.983679 0.010002 -3.968485 +v 4.983679 0.010002 -4.060776 +v 4.891389 0.010002 -4.060776 +v 4.891389 0.010002 -3.783905 +v 4.983679 0.010002 -3.783905 +v 4.983679 0.010002 -3.876195 +v 4.891389 0.010002 -3.876195 +v 5.075970 0.010002 -3.783905 +v 5.168260 0.010002 -3.783905 +v 5.168260 0.010002 -3.876195 +v 5.075970 0.010002 -3.876195 +v 4.522227 0.010002 -3.968485 +v 4.614518 0.010002 -3.968485 +v 4.614518 0.010002 -4.060776 +v 4.522227 0.010002 -4.060776 +v 4.522227 0.010002 -3.783905 +v 4.614518 0.010002 -3.783905 +v 4.614518 0.010002 -3.876195 +v 4.522227 0.010002 -3.876195 +v 4.706808 0.010002 -3.783905 +v 4.799098 0.010002 -3.783905 +v 4.799098 0.010002 -3.876195 +v 4.706808 0.010002 -3.876195 +v 4.522227 0.010002 -4.337647 +v 4.614518 0.010002 -4.337647 +v 4.614518 0.010002 -4.429937 +v 4.522227 0.010002 -4.429937 +v 4.522227 0.010002 -4.153066 +v 4.614518 0.010002 -4.153066 +v 4.614518 0.010002 -4.245357 +v 4.522227 0.010002 -4.245357 +v 4.706808 0.010002 -4.153066 +v 4.799098 0.010002 -4.153066 +v 4.799098 0.010002 -4.245357 +v 4.706808 0.010002 -4.245357 +v 4.891389 0.010001 -3.230163 +v 4.983679 0.010001 -3.230163 +v 4.983679 0.010001 -3.322453 +v 4.891389 0.010001 -3.322453 +v 4.891389 0.010001 -3.045582 +v 4.983679 0.010001 -3.045582 +v 4.983679 0.010001 -3.137872 +v 4.891389 0.010001 -3.137872 +v 5.075970 0.010001 -3.045582 +v 5.168260 0.010001 -3.045582 +v 5.168260 0.010001 -3.137872 +v 5.075970 0.010001 -3.137872 +v 4.522227 0.010001 -3.230163 +v 4.614518 0.010001 -3.230163 +v 4.614518 0.010001 -3.322453 +v 4.522227 0.010001 -3.322453 +v 4.522227 0.010001 -3.045582 +v 4.614518 0.010001 -3.045582 +v 4.614518 0.010001 -3.137872 +v 4.522227 0.010001 -3.137872 +v 4.706808 0.010001 -3.045582 +v 4.799098 0.010001 -3.045582 +v 4.799098 0.010001 -3.137872 +v 4.706808 0.010001 -3.137872 +v 4.522227 0.010001 -3.599324 +v 4.614518 0.010001 -3.599324 +v 4.614518 0.010002 -3.691614 +v 4.522227 0.010002 -3.691614 +v 4.522227 0.010001 -3.414743 +v 4.614518 0.010001 -3.414743 +v 4.614518 0.010001 -3.507033 +v 4.522227 0.010001 -3.507033 +v 4.706808 0.010001 -3.414743 +v 4.799098 0.010001 -3.414743 +v 4.799098 0.010001 -3.507033 +v 4.706808 0.010001 -3.507033 +v 5.629711 0.010001 -3.230163 +v 5.722002 0.010001 -3.230163 +v 5.722002 0.010001 -3.322453 +v 5.629711 0.010001 -3.322453 +v 5.629711 0.010001 -3.045582 +v 5.722002 0.010001 -3.045582 +v 5.722002 0.010001 -3.137872 +v 5.629711 0.010001 -3.137872 +v 5.814293 0.010001 -3.045582 +v 5.906583 0.010001 -3.045582 +v 5.906583 0.010001 -3.137872 +v 5.814293 0.010001 -3.137872 +v 5.260550 0.010001 -3.230163 +v 5.352840 0.010001 -3.230163 +v 5.352840 0.010001 -3.322453 +v 5.260550 0.010001 -3.322453 +v 5.260550 0.010001 -3.045582 +v 5.352840 0.010001 -3.045582 +v 5.352840 0.010001 -3.137872 +v 5.260550 0.010001 -3.137872 +v 5.445131 0.010001 -3.045582 +v 5.537421 0.010001 -3.045582 +v 5.537421 0.010001 -3.137872 +v 5.445131 0.010001 -3.137872 +v 5.260550 0.010001 -3.599324 +v 5.352840 0.010001 -3.599324 +v 5.352840 0.010002 -3.691614 +v 5.260550 0.010002 -3.691614 +v 5.260550 0.010001 -3.414743 +v 5.352840 0.010001 -3.414743 +v 5.352840 0.010001 -3.507033 +v 5.260550 0.010001 -3.507033 +v 5.445131 0.010001 -3.414743 +v 5.537421 0.010001 -3.414743 +v 5.537421 0.010001 -3.507033 +v 5.445131 0.010001 -3.507033 +v 3.414743 0.010002 -3.968485 +v 3.507033 0.010002 -3.968485 +v 3.507033 0.010002 -4.060776 +v 3.414743 0.010002 -4.060776 +v 3.414743 0.010002 -3.783905 +v 3.507033 0.010002 -3.783905 +v 3.507033 0.010002 -3.876195 +v 3.414743 0.010002 -3.876195 +v 3.599324 0.010002 -3.783905 +v 3.691614 0.010002 -3.783905 +v 3.691614 0.010002 -3.876195 +v 3.599324 0.010002 -3.876195 +v 3.045582 0.010002 -3.968485 +v 3.137872 0.010002 -3.968485 +v 3.137872 0.010002 -4.060776 +v 3.045582 0.010002 -4.060776 +v 3.045582 0.010002 -3.783905 +v 3.137872 0.010002 -3.783905 +v 3.137872 0.010002 -3.876195 +v 3.045582 0.010002 -3.876195 +v 3.230163 0.010002 -3.783905 +v 3.322453 0.010002 -3.783905 +v 3.322453 0.010002 -3.876195 +v 3.230163 0.010002 -3.876195 +v 3.045582 0.010002 -4.337647 +v 3.137872 0.010002 -4.337647 +v 3.137872 0.010002 -4.429937 +v 3.045582 0.010002 -4.429937 +v 3.045582 0.010002 -4.153066 +v 3.137872 0.010002 -4.153066 +v 3.137872 0.010002 -4.245357 +v 3.045582 0.010002 -4.245357 +v 3.230163 0.010002 -4.153066 +v 3.322453 0.010002 -4.153066 +v 3.322453 0.010002 -4.245357 +v 3.230163 0.010002 -4.245357 +v 3.414743 0.010001 -3.230163 +v 3.507033 0.010001 -3.230163 +v 3.507033 0.010001 -3.322453 +v 3.414743 0.010001 -3.322453 +v 3.414743 0.010001 -3.045582 +v 3.507033 0.010001 -3.045582 +v 3.507033 0.010001 -3.137872 +v 3.414743 0.010001 -3.137872 +v 3.599324 0.010001 -3.045582 +v 3.691614 0.010001 -3.045582 +v 3.691614 0.010001 -3.137872 +v 3.599324 0.010001 -3.137872 +v 3.045582 0.010001 -3.230163 +v 3.137872 0.010001 -3.230163 +v 3.137872 0.010001 -3.322453 +v 3.045582 0.010001 -3.322453 +v 3.045582 0.010001 -3.045582 +v 3.137872 0.010001 -3.045582 +v 3.137872 0.010001 -3.137872 +v 3.045582 0.010001 -3.137872 +v 3.230163 0.010001 -3.045582 +v 3.322453 0.010001 -3.045582 +v 3.322453 0.010001 -3.137872 +v 3.230163 0.010001 -3.137872 +v 3.045582 0.010001 -3.599324 +v 3.137872 0.010001 -3.599324 +v 3.137872 0.010002 -3.691614 +v 3.045582 0.010002 -3.691614 +v 3.045582 0.010001 -3.414743 +v 3.137872 0.010001 -3.414743 +v 3.137872 0.010001 -3.507033 +v 3.045582 0.010001 -3.507033 +v 3.230163 0.010001 -3.414743 +v 3.322453 0.010001 -3.414743 +v 3.322453 0.010001 -3.507033 +v 3.230163 0.010001 -3.507033 +v 4.153066 0.010001 -3.230163 +v 4.245357 0.010001 -3.230163 +v 4.245357 0.010001 -3.322453 +v 4.153066 0.010001 -3.322453 +v 4.153066 0.010001 -3.045582 +v 4.245357 0.010001 -3.045582 +v 4.245357 0.010001 -3.137872 +v 4.153066 0.010001 -3.137872 +v 4.337647 0.010001 -3.045582 +v 4.429937 0.010001 -3.045582 +v 4.429937 0.010001 -3.137872 +v 4.337647 0.010001 -3.137872 +v 3.783905 0.010001 -3.230163 +v 3.876195 0.010001 -3.230163 +v 3.876195 0.010001 -3.322453 +v 3.783905 0.010001 -3.322453 +v 3.783905 0.010001 -3.045582 +v 3.876195 0.010001 -3.045582 +v 3.876195 0.010001 -3.137872 +v 3.783905 0.010001 -3.137872 +v 3.968485 0.010001 -3.045582 +v 4.060776 0.010001 -3.045582 +v 4.060776 0.010001 -3.137872 +v 3.968485 0.010001 -3.137872 +v 3.783905 0.010001 -3.599324 +v 3.876195 0.010001 -3.599324 +v 3.876195 0.010002 -3.691614 +v 3.783905 0.010002 -3.691614 +v 3.783905 0.010001 -3.414743 +v 3.876195 0.010001 -3.414743 +v 3.876195 0.010001 -3.507033 +v 3.783905 0.010001 -3.507033 +v 3.968485 0.010001 -3.414743 +v 4.060776 0.010001 -3.414743 +v 4.060776 0.010001 -3.507033 +v 3.968485 0.010001 -3.507033 +v 3.414743 0.010002 -5.445131 +v 3.507033 0.010002 -5.445131 +v 3.507033 0.010002 -5.537421 +v 3.414743 0.010002 -5.537421 +v 3.414743 0.010002 -5.260550 +v 3.507033 0.010002 -5.260550 +v 3.507033 0.010002 -5.352840 +v 3.414743 0.010002 -5.352840 +v 3.599324 0.010002 -5.260550 +v 3.691614 0.010002 -5.260550 +v 3.691614 0.010002 -5.352840 +v 3.599324 0.010002 -5.352840 +v 3.045582 0.010002 -5.445131 +v 3.137872 0.010002 -5.445131 +v 3.137872 0.010002 -5.537421 +v 3.045582 0.010002 -5.537421 +v 3.045582 0.010002 -5.260550 +v 3.137872 0.010002 -5.260550 +v 3.137872 0.010002 -5.352840 +v 3.045582 0.010002 -5.352840 +v 3.230163 0.010002 -5.260550 +v 3.322453 0.010002 -5.260550 +v 3.322453 0.010002 -5.352840 +v 3.230163 0.010002 -5.352840 +v 3.045582 0.010002 -5.814293 +v 3.137872 0.010002 -5.814293 +v 3.137872 0.010002 -5.906583 +v 3.045582 0.010002 -5.906583 +v 3.045582 0.010002 -5.629711 +v 3.137872 0.010002 -5.629711 +v 3.137872 0.010002 -5.722002 +v 3.045582 0.010002 -5.722002 +v 3.230163 0.010002 -5.629711 +v 3.322453 0.010002 -5.629711 +v 3.322453 0.010002 -5.722002 +v 3.230163 0.010002 -5.722002 +v 3.414743 0.010002 -4.706808 +v 3.507033 0.010002 -4.706808 +v 3.507033 0.010002 -4.799098 +v 3.414743 0.010002 -4.799098 +v 3.414743 0.010002 -4.522227 +v 3.507033 0.010002 -4.522227 +v 3.507033 0.010002 -4.614518 +v 3.414743 0.010002 -4.614518 +v 3.599324 0.010002 -4.522227 +v 3.691614 0.010002 -4.522227 +v 3.691614 0.010002 -4.614518 +v 3.599324 0.010002 -4.614518 +v 3.045582 0.010002 -4.706808 +v 3.137872 0.010002 -4.706808 +v 3.137872 0.010002 -4.799098 +v 3.045582 0.010002 -4.799098 +v 3.045582 0.010002 -4.522227 +v 3.137872 0.010002 -4.522227 +v 3.137872 0.010002 -4.614518 +v 3.045582 0.010002 -4.614518 +v 3.230163 0.010002 -4.522227 +v 3.322453 0.010002 -4.522227 +v 3.322453 0.010002 -4.614518 +v 3.230163 0.010002 -4.614518 +v 3.045582 0.010002 -5.075970 +v 3.137872 0.010002 -5.075970 +v 3.137872 0.010002 -5.168260 +v 3.045582 0.010002 -5.168260 +v 3.045582 0.010002 -4.891389 +v 3.137872 0.010002 -4.891389 +v 3.137872 0.010002 -4.983679 +v 3.045582 0.010002 -4.983679 +v 3.230163 0.010002 -4.891389 +v 3.322453 0.010002 -4.891389 +v 3.322453 0.010002 -4.983679 +v 3.230163 0.010002 -4.983679 +v 4.153066 0.010002 -4.706808 +v 4.245357 0.010002 -4.706808 +v 4.245357 0.010002 -4.799098 +v 4.153066 0.010002 -4.799098 +v 4.153066 0.010002 -4.522227 +v 4.245357 0.010002 -4.522227 +v 4.245357 0.010002 -4.614518 +v 4.153066 0.010002 -4.614518 +v 4.337647 0.010002 -4.522227 +v 4.429937 0.010002 -4.522227 +v 4.429937 0.010002 -4.614518 +v 4.337647 0.010002 -4.614518 +v 3.783905 0.010002 -4.706808 +v 3.876195 0.010002 -4.706808 +v 3.876195 0.010002 -4.799098 +v 3.783905 0.010002 -4.799098 +v 3.783905 0.010002 -4.522227 +v 3.876195 0.010002 -4.522227 +v 3.876195 0.010002 -4.614518 +v 3.783905 0.010002 -4.614518 +v 3.968485 0.010002 -4.522227 +v 4.060776 0.010002 -4.522227 +v 4.060776 0.010002 -4.614518 +v 3.968485 0.010002 -4.614518 +v 3.783905 0.010002 -5.075970 +v 3.876195 0.010002 -5.075970 +v 3.876195 0.010002 -5.168260 +v 3.783905 0.010002 -5.168260 +v 3.783905 0.010002 -4.891389 +v 3.876195 0.010002 -4.891389 +v 3.876195 0.010002 -4.983679 +v 3.783905 0.010002 -4.983679 +v 3.968485 0.010002 -4.891389 +v 4.060776 0.010002 -4.891389 +v 4.060776 0.010002 -4.983679 +v 3.968485 0.010002 -4.983679 +v -1.015194 0.010002 -3.968485 +v -0.922904 0.010002 -3.968485 +v -0.922904 0.010002 -4.060776 +v -1.015194 0.010002 -4.060776 +v -1.015194 0.010002 -3.783905 +v -0.922904 0.010002 -3.783905 +v -0.922904 0.010002 -3.876195 +v -1.015194 0.010002 -3.876195 +v -0.830613 0.010002 -3.783905 +v -0.738323 0.010002 -3.783905 +v -0.738323 0.010002 -3.876195 +v -0.830613 0.010002 -3.876195 +v -1.384355 0.010002 -3.968485 +v -1.292065 0.010002 -3.968485 +v -1.292065 0.010002 -4.060776 +v -1.384355 0.010002 -4.060776 +v -1.384355 0.010002 -3.783905 +v -1.292065 0.010002 -3.783905 +v -1.292065 0.010002 -3.876195 +v -1.384355 0.010002 -3.876195 +v -1.199775 0.010002 -3.783905 +v -1.107484 0.010002 -3.783905 +v -1.107484 0.010002 -3.876195 +v -1.199775 0.010002 -3.876195 +v -1.384355 0.010002 -4.337647 +v -1.292065 0.010002 -4.337647 +v -1.292065 0.010002 -4.429937 +v -1.384355 0.010002 -4.429937 +v -1.384355 0.010002 -4.153066 +v -1.292065 0.010002 -4.153066 +v -1.292065 0.010002 -4.245357 +v -1.384355 0.010002 -4.245357 +v -1.199775 0.010002 -4.153066 +v -1.107484 0.010002 -4.153066 +v -1.107484 0.010002 -4.245357 +v -1.199775 0.010002 -4.245357 +v -1.015194 0.010001 -3.230163 +v -0.922904 0.010001 -3.230163 +v -0.922904 0.010001 -3.322453 +v -1.015194 0.010001 -3.322453 +v -1.015194 0.010001 -3.045582 +v -0.922904 0.010001 -3.045582 +v -0.922904 0.010001 -3.137872 +v -1.015194 0.010001 -3.137872 +v -0.830613 0.010001 -3.045582 +v -0.738323 0.010001 -3.045582 +v -0.738323 0.010001 -3.137872 +v -0.830613 0.010001 -3.137872 +v -1.384355 0.010001 -3.230163 +v -1.292065 0.010001 -3.230163 +v -1.292065 0.010001 -3.322453 +v -1.384355 0.010001 -3.322453 +v -1.384355 0.010001 -3.045582 +v -1.292065 0.010001 -3.045582 +v -1.292065 0.010001 -3.137872 +v -1.384355 0.010001 -3.137872 +v -1.199775 0.010001 -3.045582 +v -1.107484 0.010001 -3.045582 +v -1.107484 0.010001 -3.137872 +v -1.199775 0.010001 -3.137872 +v -1.384355 0.010001 -3.599324 +v -1.292065 0.010001 -3.599324 +v -1.292065 0.010002 -3.691614 +v -1.384355 0.010002 -3.691614 +v -1.384355 0.010001 -3.414743 +v -1.292065 0.010001 -3.414743 +v -1.292065 0.010001 -3.507033 +v -1.384355 0.010001 -3.507033 +v -1.199775 0.010001 -3.414743 +v -1.107484 0.010001 -3.414743 +v -1.107484 0.010001 -3.507033 +v -1.199775 0.010001 -3.507033 +v -0.276871 0.010001 -3.230163 +v -0.184581 0.010001 -3.230163 +v -0.184581 0.010001 -3.322453 +v -0.276871 0.010001 -3.322453 +v -0.276871 0.010001 -3.045582 +v -0.184581 0.010001 -3.045582 +v -0.184581 0.010001 -3.137872 +v -0.276871 0.010001 -3.137872 +v -0.092290 0.010001 -3.045582 +v 0.000000 0.010001 -3.045582 +v 0.000000 0.010001 -3.137872 +v -0.092290 0.010001 -3.137872 +v -0.646033 0.010001 -3.230163 +v -0.553742 0.010001 -3.230163 +v -0.553742 0.010001 -3.322453 +v -0.646033 0.010001 -3.322453 +v -0.646033 0.010001 -3.045582 +v -0.553742 0.010001 -3.045582 +v -0.553742 0.010001 -3.137872 +v -0.646033 0.010001 -3.137872 +v -0.461452 0.010001 -3.045582 +v -0.369161 0.010001 -3.045582 +v -0.369161 0.010001 -3.137872 +v -0.461452 0.010001 -3.137872 +v -0.646033 0.010001 -3.599324 +v -0.553742 0.010001 -3.599324 +v -0.553742 0.010002 -3.691614 +v -0.646033 0.010002 -3.691614 +v -0.646033 0.010001 -3.414743 +v -0.553742 0.010001 -3.414743 +v -0.553742 0.010001 -3.507033 +v -0.646033 0.010001 -3.507033 +v -0.461452 0.010001 -3.414743 +v -0.369161 0.010001 -3.414743 +v -0.369161 0.010001 -3.507033 +v -0.461452 0.010001 -3.507033 +v -2.491840 0.010002 -3.968485 +v -2.399549 0.010002 -3.968485 +v -2.399549 0.010002 -4.060776 +v -2.491840 0.010002 -4.060776 +v -2.491840 0.010002 -3.783905 +v -2.399549 0.010002 -3.783905 +v -2.399549 0.010002 -3.876195 +v -2.491840 0.010002 -3.876195 +v -2.307259 0.010002 -3.783905 +v -2.214968 0.010002 -3.783905 +v -2.214968 0.010002 -3.876195 +v -2.307259 0.010002 -3.876195 +v -2.861001 0.010002 -3.968485 +v -2.768711 0.010002 -3.968485 +v -2.768711 0.010002 -4.060776 +v -2.861001 0.010002 -4.060776 +v -2.861001 0.010002 -3.783905 +v -2.768711 0.010002 -3.783905 +v -2.768711 0.010002 -3.876195 +v -2.861001 0.010002 -3.876195 +v -2.676420 0.010002 -3.783905 +v -2.584130 0.010002 -3.783905 +v -2.584130 0.010002 -3.876195 +v -2.676420 0.010002 -3.876195 +v -2.861001 0.010002 -4.337647 +v -2.768711 0.010002 -4.337647 +v -2.768711 0.010002 -4.429937 +v -2.861001 0.010002 -4.429937 +v -2.861001 0.010002 -4.153066 +v -2.768711 0.010002 -4.153066 +v -2.768711 0.010002 -4.245357 +v -2.861001 0.010002 -4.245357 +v -2.676420 0.010002 -4.153066 +v -2.584130 0.010002 -4.153066 +v -2.584130 0.010002 -4.245357 +v -2.676420 0.010002 -4.245357 +v -2.491840 0.010001 -3.230163 +v -2.399549 0.010001 -3.230163 +v -2.399549 0.010001 -3.322453 +v -2.491840 0.010001 -3.322453 +v -2.491840 0.010001 -3.045582 +v -2.399549 0.010001 -3.045582 +v -2.399549 0.010001 -3.137872 +v -2.491840 0.010001 -3.137872 +v -2.307259 0.010001 -3.045582 +v -2.214968 0.010001 -3.045582 +v -2.214968 0.010001 -3.137872 +v -2.307259 0.010001 -3.137872 +v -2.861001 0.010001 -3.230163 +v -2.768711 0.010001 -3.230163 +v -2.768711 0.010001 -3.322453 +v -2.861001 0.010001 -3.322453 +v -2.861001 0.010001 -3.045582 +v -2.768711 0.010001 -3.045582 +v -2.768711 0.010001 -3.137872 +v -2.861001 0.010001 -3.137872 +v -2.676420 0.010001 -3.045582 +v -2.584130 0.010001 -3.045582 +v -2.584130 0.010001 -3.137872 +v -2.676420 0.010001 -3.137872 +v -2.861001 0.010001 -3.599324 +v -2.768711 0.010001 -3.599324 +v -2.768711 0.010002 -3.691614 +v -2.861001 0.010002 -3.691614 +v -2.861001 0.010001 -3.414743 +v -2.768711 0.010001 -3.414743 +v -2.768711 0.010001 -3.507033 +v -2.861001 0.010001 -3.507033 +v -2.676420 0.010001 -3.414743 +v -2.584130 0.010001 -3.414743 +v -2.584130 0.010001 -3.507033 +v -2.676420 0.010001 -3.507033 +v -1.753517 0.010001 -3.230163 +v -1.661226 0.010001 -3.230163 +v -1.661226 0.010001 -3.322453 +v -1.753517 0.010001 -3.322453 +v -1.753517 0.010001 -3.045582 +v -1.661226 0.010001 -3.045582 +v -1.661226 0.010001 -3.137872 +v -1.753517 0.010001 -3.137872 +v -1.568936 0.010001 -3.045582 +v -1.476646 0.010001 -3.045582 +v -1.476646 0.010001 -3.137872 +v -1.568936 0.010001 -3.137872 +v -2.122678 0.010001 -3.230163 +v -2.030388 0.010001 -3.230163 +v -2.030388 0.010001 -3.322453 +v -2.122678 0.010001 -3.322453 +v -2.122678 0.010001 -3.045582 +v -2.030388 0.010001 -3.045582 +v -2.030388 0.010001 -3.137872 +v -2.122678 0.010001 -3.137872 +v -1.938097 0.010001 -3.045582 +v -1.845807 0.010001 -3.045582 +v -1.845807 0.010001 -3.137872 +v -1.938097 0.010001 -3.137872 +v -2.122678 0.010001 -3.599324 +v -2.030388 0.010001 -3.599324 +v -2.030388 0.010002 -3.691614 +v -2.122678 0.010002 -3.691614 +v -2.122678 0.010001 -3.414743 +v -2.030388 0.010001 -3.414743 +v -2.030388 0.010001 -3.507033 +v -2.122678 0.010001 -3.507033 +v -1.938097 0.010001 -3.414743 +v -1.845807 0.010001 -3.414743 +v -1.845807 0.010001 -3.507033 +v -1.938097 0.010001 -3.507033 +v -2.491840 0.010002 -5.445131 +v -2.399549 0.010002 -5.445131 +v -2.399549 0.010002 -5.537421 +v -2.491840 0.010002 -5.537421 +v -2.491840 0.010002 -5.260550 +v -2.399549 0.010002 -5.260550 +v -2.399549 0.010002 -5.352840 +v -2.491840 0.010002 -5.352840 +v -2.307259 0.010002 -5.260550 +v -2.214968 0.010002 -5.260550 +v -2.214968 0.010002 -5.352840 +v -2.307259 0.010002 -5.352840 +v -2.861001 0.010002 -5.445131 +v -2.768711 0.010002 -5.445131 +v -2.768711 0.010002 -5.537421 +v -2.861001 0.010002 -5.537421 +v -2.861001 0.010002 -5.260550 +v -2.768711 0.010002 -5.260550 +v -2.768711 0.010002 -5.352840 +v -2.861001 0.010002 -5.352840 +v -2.676420 0.010002 -5.260550 +v -2.584130 0.010002 -5.260550 +v -2.584130 0.010002 -5.352840 +v -2.676420 0.010002 -5.352840 +v -2.861001 0.010002 -5.814293 +v -2.768711 0.010002 -5.814293 +v -2.768711 0.010002 -5.906583 +v -2.861001 0.010002 -5.906583 +v -2.861001 0.010002 -5.629711 +v -2.768711 0.010002 -5.629711 +v -2.768711 0.010002 -5.722002 +v -2.861001 0.010002 -5.722002 +v -2.676420 0.010002 -5.629711 +v -2.584130 0.010002 -5.629711 +v -2.584130 0.010002 -5.722002 +v -2.676420 0.010002 -5.722002 +v -2.491840 0.010002 -4.706808 +v -2.399549 0.010002 -4.706808 +v -2.399549 0.010002 -4.799098 +v -2.491840 0.010002 -4.799098 +v -2.491840 0.010002 -4.522227 +v -2.399549 0.010002 -4.522227 +v -2.399549 0.010002 -4.614518 +v -2.491840 0.010002 -4.614518 +v -2.307259 0.010002 -4.522227 +v -2.214968 0.010002 -4.522227 +v -2.214968 0.010002 -4.614518 +v -2.307259 0.010002 -4.614518 +v -2.861001 0.010002 -4.706808 +v -2.768711 0.010002 -4.706808 +v -2.768711 0.010002 -4.799098 +v -2.861001 0.010002 -4.799098 +v -2.861001 0.010002 -4.522227 +v -2.768711 0.010002 -4.522227 +v -2.768711 0.010002 -4.614518 +v -2.861001 0.010002 -4.614518 +v -2.676420 0.010002 -4.522227 +v -2.584130 0.010002 -4.522227 +v -2.584130 0.010002 -4.614518 +v -2.676420 0.010002 -4.614518 +v -2.861001 0.010002 -5.075970 +v -2.768711 0.010002 -5.075970 +v -2.768711 0.010002 -5.168260 +v -2.861001 0.010002 -5.168260 +v -2.861001 0.010002 -4.891389 +v -2.768711 0.010002 -4.891389 +v -2.768711 0.010002 -4.983679 +v -2.861001 0.010002 -4.983679 +v -2.676420 0.010002 -4.891389 +v -2.584130 0.010002 -4.891389 +v -2.584130 0.010002 -4.983679 +v -2.676420 0.010002 -4.983679 +v -1.753517 0.010002 -4.706808 +v -1.661226 0.010002 -4.706808 +v -1.661226 0.010002 -4.799098 +v -1.753517 0.010002 -4.799098 +v -1.753517 0.010002 -4.522227 +v -1.661226 0.010002 -4.522227 +v -1.661226 0.010002 -4.614518 +v -1.753517 0.010002 -4.614518 +v -1.568936 0.010002 -4.522227 +v -1.476646 0.010002 -4.522227 +v -1.476646 0.010002 -4.614518 +v -1.568936 0.010002 -4.614518 +v -2.122678 0.010002 -4.706808 +v -2.030388 0.010002 -4.706808 +v -2.030388 0.010002 -4.799098 +v -2.122678 0.010002 -4.799098 +v -2.122678 0.010002 -4.522227 +v -2.030388 0.010002 -4.522227 +v -2.030388 0.010002 -4.614518 +v -2.122678 0.010002 -4.614518 +v -1.938097 0.010002 -4.522227 +v -1.845807 0.010002 -4.522227 +v -1.845807 0.010002 -4.614518 +v -1.938097 0.010002 -4.614518 +v -2.122678 0.010002 -5.075970 +v -2.030388 0.010002 -5.075970 +v -2.030388 0.010002 -5.168260 +v -2.122678 0.010002 -5.168260 +v -2.122678 0.010002 -4.891389 +v -2.030388 0.010002 -4.891389 +v -2.030388 0.010002 -4.983679 +v -2.122678 0.010002 -4.983679 +v -1.938097 0.010002 -4.891389 +v -1.845807 0.010002 -4.891389 +v -1.845807 0.010002 -4.983679 +v -1.938097 0.010002 -4.983679 +v -1.015194 0.009999 1.938097 +v -0.922904 0.009999 1.938097 +v -0.922904 0.009999 1.845807 +v -1.015194 0.009999 1.845807 +v -1.015194 0.009999 2.122678 +v -0.922904 0.009999 2.122678 +v -0.922904 0.009999 2.030388 +v -1.015194 0.009999 2.030388 +v -0.830613 0.009999 2.122678 +v -0.738323 0.009999 2.122678 +v -0.738323 0.009999 2.030388 +v -0.830613 0.009999 2.030388 +v -1.384355 0.009999 1.938097 +v -1.292065 0.009999 1.938097 +v -1.292065 0.009999 1.845807 +v -1.384355 0.009999 1.845807 +v -1.384355 0.009999 2.122678 +v -1.292065 0.009999 2.122678 +v -1.292065 0.009999 2.030388 +v -1.384355 0.009999 2.030388 +v -1.199775 0.009999 2.122678 +v -1.107484 0.009999 2.122678 +v -1.107484 0.009999 2.030388 +v -1.199775 0.009999 2.030388 +v -1.384355 0.009999 1.568936 +v -1.292065 0.009999 1.568936 +v -1.292065 0.009999 1.476646 +v -1.384355 0.009999 1.476646 +v -1.384355 0.009999 1.753517 +v -1.292065 0.009999 1.753517 +v -1.292065 0.009999 1.661226 +v -1.384355 0.009999 1.661226 +v -1.199775 0.009999 1.753517 +v -1.107484 0.009999 1.753517 +v -1.107484 0.009999 1.661226 +v -1.199775 0.009999 1.661226 +v -1.015194 0.009999 2.676420 +v -0.922904 0.009999 2.676420 +v -0.922904 0.009999 2.584130 +v -1.015194 0.009999 2.584130 +v -1.015194 0.009999 2.861001 +v -0.922904 0.009999 2.861001 +v -0.922904 0.009999 2.768711 +v -1.015194 0.009999 2.768711 +v -0.830613 0.009999 2.861001 +v -0.738323 0.009999 2.861001 +v -0.738323 0.009999 2.768711 +v -0.830613 0.009999 2.768711 +v -1.384355 0.009999 2.676420 +v -1.292065 0.009999 2.676420 +v -1.292065 0.009999 2.584130 +v -1.384355 0.009999 2.584130 +v -1.384355 0.009999 2.861001 +v -1.292065 0.009999 2.861001 +v -1.292065 0.009999 2.768711 +v -1.384355 0.009999 2.768711 +v -1.199775 0.009999 2.861001 +v -1.107484 0.009999 2.861001 +v -1.107484 0.009999 2.768711 +v -1.199775 0.009999 2.768711 +v -1.384355 0.009999 2.307259 +v -1.292065 0.009999 2.307259 +v -1.292065 0.009999 2.214968 +v -1.384355 0.009999 2.214968 +v -1.384355 0.009999 2.491840 +v -1.292065 0.009999 2.491840 +v -1.292065 0.009999 2.399549 +v -1.384355 0.009999 2.399549 +v -1.199775 0.009999 2.491840 +v -1.107484 0.009999 2.491840 +v -1.107484 0.009999 2.399549 +v -1.199775 0.009999 2.399549 +v -0.276871 0.009999 2.676420 +v -0.184581 0.009999 2.676420 +v -0.184581 0.009999 2.584130 +v -0.276871 0.009999 2.584130 +v -0.276871 0.009999 2.861001 +v -0.184581 0.009999 2.861001 +v -0.184581 0.009999 2.768711 +v -0.276871 0.009999 2.768711 +v -0.092290 0.009999 2.861001 +v 0.000000 0.009999 2.861001 +v 0.000000 0.009999 2.768711 +v -0.092290 0.009999 2.768711 +v -0.646033 0.009999 2.676420 +v -0.553742 0.009999 2.676420 +v -0.553742 0.009999 2.584130 +v -0.646033 0.009999 2.584130 +v -0.646033 0.009999 2.861001 +v -0.553742 0.009999 2.861001 +v -0.553742 0.009999 2.768711 +v -0.646033 0.009999 2.768711 +v -0.461452 0.009999 2.861001 +v -0.369161 0.009999 2.861001 +v -0.369161 0.009999 2.768711 +v -0.461452 0.009999 2.768711 +v -0.646033 0.009999 2.307259 +v -0.553742 0.009999 2.307259 +v -0.553742 0.009999 2.214968 +v -0.646033 0.009999 2.214968 +v -0.646033 0.009999 2.491840 +v -0.553742 0.009999 2.491840 +v -0.553742 0.009999 2.399549 +v -0.646033 0.009999 2.399549 +v -0.461452 0.009999 2.491840 +v -0.369161 0.009999 2.491840 +v -0.369161 0.009999 2.399549 +v -0.461452 0.009999 2.399549 +v -2.491840 0.009999 1.938097 +v -2.399549 0.009999 1.938097 +v -2.399549 0.009999 1.845807 +v -2.491840 0.009999 1.845807 +v -2.491840 0.009999 2.122678 +v -2.399549 0.009999 2.122678 +v -2.399549 0.009999 2.030388 +v -2.491840 0.009999 2.030388 +v -2.307259 0.009999 2.122678 +v -2.214968 0.009999 2.122678 +v -2.214968 0.009999 2.030388 +v -2.307259 0.009999 2.030388 +v -2.861001 0.009999 1.938097 +v -2.768711 0.009999 1.938097 +v -2.768711 0.009999 1.845807 +v -2.861001 0.009999 1.845807 +v -2.861001 0.009999 2.122678 +v -2.768711 0.009999 2.122678 +v -2.768711 0.009999 2.030388 +v -2.861001 0.009999 2.030388 +v -2.676420 0.009999 2.122678 +v -2.584130 0.009999 2.122678 +v -2.584130 0.009999 2.030388 +v -2.676420 0.009999 2.030388 +v -2.861001 0.009999 1.568936 +v -2.768711 0.009999 1.568936 +v -2.768711 0.009999 1.476646 +v -2.861001 0.009999 1.476646 +v -2.861001 0.009999 1.753517 +v -2.768711 0.009999 1.753517 +v -2.768711 0.009999 1.661226 +v -2.861001 0.009999 1.661226 +v -2.676420 0.009999 1.753517 +v -2.584130 0.009999 1.753517 +v -2.584130 0.009999 1.661226 +v -2.676420 0.009999 1.661226 +v -2.491840 0.009999 2.676420 +v -2.399549 0.009999 2.676420 +v -2.399549 0.009999 2.584130 +v -2.491840 0.009999 2.584130 +v -2.491840 0.009999 2.861001 +v -2.399549 0.009999 2.861001 +v -2.399549 0.009999 2.768711 +v -2.491840 0.009999 2.768711 +v -2.307259 0.009999 2.861001 +v -2.214968 0.009999 2.861001 +v -2.214968 0.009999 2.768711 +v -2.307259 0.009999 2.768711 +v -2.861001 0.009999 2.676420 +v -2.768711 0.009999 2.676420 +v -2.768711 0.009999 2.584130 +v -2.861001 0.009999 2.584130 +v -2.861001 0.009999 2.861001 +v -2.768711 0.009999 2.861001 +v -2.768711 0.009999 2.768711 +v -2.861001 0.009999 2.768711 +v -2.676420 0.009999 2.861001 +v -2.584130 0.009999 2.861001 +v -2.584130 0.009999 2.768711 +v -2.676420 0.009999 2.768711 +v -2.861001 0.009999 2.307259 +v -2.768711 0.009999 2.307259 +v -2.768711 0.009999 2.214968 +v -2.861001 0.009999 2.214968 +v -2.861001 0.009999 2.491840 +v -2.768711 0.009999 2.491840 +v -2.768711 0.009999 2.399549 +v -2.861001 0.009999 2.399549 +v -2.676420 0.009999 2.491840 +v -2.584130 0.009999 2.491840 +v -2.584130 0.009999 2.399549 +v -2.676420 0.009999 2.399549 +v -1.753517 0.009999 2.676420 +v -1.661226 0.009999 2.676420 +v -1.661226 0.009999 2.584130 +v -1.753517 0.009999 2.584130 +v -1.753517 0.009999 2.861001 +v -1.661226 0.009999 2.861001 +v -1.661226 0.009999 2.768711 +v -1.753517 0.009999 2.768711 +v -1.568936 0.009999 2.861001 +v -1.476646 0.009999 2.861001 +v -1.476646 0.009999 2.768711 +v -1.568936 0.009999 2.768711 +v -2.122678 0.009999 2.676420 +v -2.030388 0.009999 2.676420 +v -2.030388 0.009999 2.584130 +v -2.122678 0.009999 2.584130 +v -2.122678 0.009999 2.861001 +v -2.030388 0.009999 2.861001 +v -2.030388 0.009999 2.768711 +v -2.122678 0.009999 2.768711 +v -1.938097 0.009999 2.861001 +v -1.845807 0.009999 2.861001 +v -1.845807 0.009999 2.768711 +v -1.938097 0.009999 2.768711 +v -2.122678 0.009999 2.307259 +v -2.030388 0.009999 2.307259 +v -2.030388 0.009999 2.214968 +v -2.122678 0.009999 2.214968 +v -2.122678 0.009999 2.491840 +v -2.030388 0.009999 2.491840 +v -2.030388 0.009999 2.399549 +v -2.122678 0.009999 2.399549 +v -1.938097 0.009999 2.491840 +v -1.845807 0.009999 2.491840 +v -1.845807 0.009999 2.399549 +v -1.938097 0.009999 2.399549 +v -2.491840 0.010000 0.461452 +v -2.399549 0.010000 0.461452 +v -2.399549 0.010000 0.369161 +v -2.491840 0.010000 0.369161 +v -2.491840 0.010000 0.646033 +v -2.399549 0.010000 0.646033 +v -2.399549 0.010000 0.553742 +v -2.491840 0.010000 0.553742 +v -2.307259 0.010000 0.646033 +v -2.214968 0.010000 0.646033 +v -2.214968 0.010000 0.553742 +v -2.307259 0.010000 0.553742 +v -2.861001 0.010000 0.461452 +v -2.768711 0.010000 0.461452 +v -2.768711 0.010000 0.369161 +v -2.861001 0.010000 0.369161 +v -2.861001 0.010000 0.646033 +v -2.768711 0.010000 0.646033 +v -2.768711 0.010000 0.553742 +v -2.861001 0.010000 0.553742 +v -2.676420 0.010000 0.646033 +v -2.584130 0.010000 0.646033 +v -2.584130 0.010000 0.553742 +v -2.676420 0.010000 0.553742 +v -2.861001 0.010000 0.092290 +v -2.768711 0.010000 0.092290 +v -2.768711 0.010000 -0.000000 +v -2.861001 0.010000 -0.000000 +v -2.861001 0.010000 0.276871 +v -2.768711 0.010000 0.276871 +v -2.768711 0.010000 0.184581 +v -2.861001 0.010000 0.184581 +v -2.676420 0.010000 0.276871 +v -2.584130 0.010000 0.276871 +v -2.584130 0.010000 0.184581 +v -2.676420 0.010000 0.184581 +v -2.491840 0.010000 1.199775 +v -2.399549 0.010000 1.199775 +v -2.399549 0.010000 1.107484 +v -2.491840 0.010000 1.107484 +v -2.491840 0.009999 1.384355 +v -2.399549 0.009999 1.384355 +v -2.399549 0.009999 1.292065 +v -2.491840 0.009999 1.292065 +v -2.307259 0.009999 1.384355 +v -2.214968 0.009999 1.384355 +v -2.214968 0.009999 1.292065 +v -2.307259 0.009999 1.292065 +v -2.861001 0.010000 1.199775 +v -2.768711 0.010000 1.199775 +v -2.768711 0.010000 1.107484 +v -2.861001 0.010000 1.107484 +v -2.861001 0.009999 1.384355 +v -2.768711 0.009999 1.384355 +v -2.768711 0.009999 1.292065 +v -2.861001 0.009999 1.292065 +v -2.676420 0.009999 1.384355 +v -2.584130 0.009999 1.384355 +v -2.584130 0.009999 1.292065 +v -2.676420 0.009999 1.292065 +v -2.861001 0.010000 0.830613 +v -2.768711 0.010000 0.830613 +v -2.768711 0.010000 0.738323 +v -2.861001 0.010000 0.738323 +v -2.861001 0.010000 1.015194 +v -2.768711 0.010000 1.015194 +v -2.768711 0.010000 0.922904 +v -2.861001 0.010000 0.922904 +v -2.676420 0.010000 1.015194 +v -2.584130 0.010000 1.015194 +v -2.584130 0.010000 0.922904 +v -2.676420 0.010000 0.922904 +v -1.753517 0.010000 1.199775 +v -1.661226 0.010000 1.199775 +v -1.661226 0.010000 1.107484 +v -1.753517 0.010000 1.107484 +v -1.753517 0.009999 1.384355 +v -1.661226 0.009999 1.384355 +v -1.661226 0.009999 1.292065 +v -1.753517 0.009999 1.292065 +v -1.568936 0.009999 1.384355 +v -1.476646 0.009999 1.384355 +v -1.476646 0.009999 1.292065 +v -1.568936 0.009999 1.292065 +v -2.122678 0.010000 1.199775 +v -2.030388 0.010000 1.199775 +v -2.030388 0.010000 1.107484 +v -2.122678 0.010000 1.107484 +v -2.122678 0.009999 1.384355 +v -2.030388 0.009999 1.384355 +v -2.030388 0.009999 1.292065 +v -2.122678 0.009999 1.292065 +v -1.938097 0.009999 1.384355 +v -1.845807 0.009999 1.384355 +v -1.845807 0.009999 1.292065 +v -1.938097 0.009999 1.292065 +v -2.122678 0.010000 0.830613 +v -2.030388 0.010000 0.830613 +v -2.030388 0.010000 0.738323 +v -2.122678 0.010000 0.738323 +v -2.122678 0.010000 1.015194 +v -2.030388 0.010000 1.015194 +v -2.030388 0.010000 0.922904 +v -2.122678 0.010000 0.922904 +v -1.938097 0.010000 1.015194 +v -1.845807 0.010000 1.015194 +v -1.845807 0.010000 0.922904 +v -1.938097 0.010000 0.922904 +v 4.891389 0.009999 1.938097 +v 4.983679 0.009999 1.938097 +v 4.983679 0.009999 1.845807 +v 4.891389 0.009999 1.845807 +v 4.891389 0.009999 2.122678 +v 4.983679 0.009999 2.122678 +v 4.983679 0.009999 2.030388 +v 4.891389 0.009999 2.030388 +v 5.075970 0.009999 2.122678 +v 5.168260 0.009999 2.122678 +v 5.168260 0.009999 2.030388 +v 5.075970 0.009999 2.030388 +v 4.522227 0.009999 1.938097 +v 4.614518 0.009999 1.938097 +v 4.614518 0.009999 1.845807 +v 4.522227 0.009999 1.845807 +v 4.522227 0.009999 2.122678 +v 4.614518 0.009999 2.122678 +v 4.614518 0.009999 2.030388 +v 4.522227 0.009999 2.030388 +v 4.706808 0.009999 2.122678 +v 4.799098 0.009999 2.122678 +v 4.799098 0.009999 2.030388 +v 4.706808 0.009999 2.030388 +v 4.522227 0.009999 1.568936 +v 4.614518 0.009999 1.568936 +v 4.614518 0.009999 1.476646 +v 4.522227 0.009999 1.476646 +v 4.522227 0.009999 1.753517 +v 4.614518 0.009999 1.753517 +v 4.614518 0.009999 1.661226 +v 4.522227 0.009999 1.661226 +v 4.706808 0.009999 1.753517 +v 4.799098 0.009999 1.753517 +v 4.799098 0.009999 1.661226 +v 4.706808 0.009999 1.661226 +v 4.891389 0.009999 2.676420 +v 4.983679 0.009999 2.676420 +v 4.983679 0.009999 2.584130 +v 4.891389 0.009999 2.584130 +v 4.891389 0.009999 2.861001 +v 4.983679 0.009999 2.861001 +v 4.983679 0.009999 2.768711 +v 4.891389 0.009999 2.768711 +v 5.075970 0.009999 2.861001 +v 5.168260 0.009999 2.861001 +v 5.168260 0.009999 2.768711 +v 5.075970 0.009999 2.768711 +v 4.522227 0.009999 2.676420 +v 4.614518 0.009999 2.676420 +v 4.614518 0.009999 2.584130 +v 4.522227 0.009999 2.584130 +v 4.522227 0.009999 2.861001 +v 4.614518 0.009999 2.861001 +v 4.614518 0.009999 2.768711 +v 4.522227 0.009999 2.768711 +v 4.706808 0.009999 2.861001 +v 4.799098 0.009999 2.861001 +v 4.799098 0.009999 2.768711 +v 4.706808 0.009999 2.768711 +v 4.522227 0.009999 2.307259 +v 4.614518 0.009999 2.307259 +v 4.614518 0.009999 2.214968 +v 4.522227 0.009999 2.214968 +v 4.522227 0.009999 2.491840 +v 4.614518 0.009999 2.491840 +v 4.614518 0.009999 2.399549 +v 4.522227 0.009999 2.399549 +v 4.706808 0.009999 2.491840 +v 4.799098 0.009999 2.491840 +v 4.799098 0.009999 2.399549 +v 4.706808 0.009999 2.399549 +v 5.629711 0.009999 2.676420 +v 5.722002 0.009999 2.676420 +v 5.722002 0.009999 2.584130 +v 5.629711 0.009999 2.584130 +v 5.629711 0.009999 2.861001 +v 5.722002 0.009999 2.861001 +v 5.722002 0.009999 2.768711 +v 5.629711 0.009999 2.768711 +v 5.814293 0.009999 2.861001 +v 5.906583 0.009999 2.861001 +v 5.906583 0.009999 2.768711 +v 5.814293 0.009999 2.768711 +v 5.260550 0.009999 2.676420 +v 5.352840 0.009999 2.676420 +v 5.352840 0.009999 2.584130 +v 5.260550 0.009999 2.584130 +v 5.260550 0.009999 2.861001 +v 5.352840 0.009999 2.861001 +v 5.352840 0.009999 2.768711 +v 5.260550 0.009999 2.768711 +v 5.445131 0.009999 2.861001 +v 5.537421 0.009999 2.861001 +v 5.537421 0.009999 2.768711 +v 5.445131 0.009999 2.768711 +v 5.260550 0.009999 2.307259 +v 5.352840 0.009999 2.307259 +v 5.352840 0.009999 2.214968 +v 5.260550 0.009999 2.214968 +v 5.260550 0.009999 2.491840 +v 5.352840 0.009999 2.491840 +v 5.352840 0.009999 2.399549 +v 5.260550 0.009999 2.399549 +v 5.445131 0.009999 2.491840 +v 5.537421 0.009999 2.491840 +v 5.537421 0.009999 2.399549 +v 5.445131 0.009999 2.399549 +v 3.414743 0.009999 1.938097 +v 3.507033 0.009999 1.938097 +v 3.507033 0.009999 1.845807 +v 3.414743 0.009999 1.845807 +v 3.414743 0.009999 2.122678 +v 3.507033 0.009999 2.122678 +v 3.507033 0.009999 2.030388 +v 3.414743 0.009999 2.030388 +v 3.599324 0.009999 2.122678 +v 3.691614 0.009999 2.122678 +v 3.691614 0.009999 2.030388 +v 3.599324 0.009999 2.030388 +v 3.045582 0.009999 1.938097 +v 3.137872 0.009999 1.938097 +v 3.137872 0.009999 1.845807 +v 3.045582 0.009999 1.845807 +v 3.045582 0.009999 2.122678 +v 3.137872 0.009999 2.122678 +v 3.137872 0.009999 2.030388 +v 3.045582 0.009999 2.030388 +v 3.230163 0.009999 2.122678 +v 3.322453 0.009999 2.122678 +v 3.322453 0.009999 2.030388 +v 3.230163 0.009999 2.030388 +v 3.045582 0.009999 1.568936 +v 3.137872 0.009999 1.568936 +v 3.137872 0.009999 1.476646 +v 3.045582 0.009999 1.476646 +v 3.045582 0.009999 1.753517 +v 3.137872 0.009999 1.753517 +v 3.137872 0.009999 1.661226 +v 3.045582 0.009999 1.661226 +v 3.230163 0.009999 1.753517 +v 3.322453 0.009999 1.753517 +v 3.322453 0.009999 1.661226 +v 3.230163 0.009999 1.661226 +v 3.414743 0.009999 2.676420 +v 3.507033 0.009999 2.676420 +v 3.507033 0.009999 2.584130 +v 3.414743 0.009999 2.584130 +v 3.414743 0.009999 2.861001 +v 3.507033 0.009999 2.861001 +v 3.507033 0.009999 2.768711 +v 3.414743 0.009999 2.768711 +v 3.599324 0.009999 2.861001 +v 3.691614 0.009999 2.861001 +v 3.691614 0.009999 2.768711 +v 3.599324 0.009999 2.768711 +v 3.045582 0.009999 2.676420 +v 3.137872 0.009999 2.676420 +v 3.137872 0.009999 2.584130 +v 3.045582 0.009999 2.584130 +v 3.045582 0.009999 2.861001 +v 3.137872 0.009999 2.861001 +v 3.137872 0.009999 2.768711 +v 3.045582 0.009999 2.768711 +v 3.230163 0.009999 2.861001 +v 3.322453 0.009999 2.861001 +v 3.322453 0.009999 2.768711 +v 3.230163 0.009999 2.768711 +v 3.045582 0.009999 2.307259 +v 3.137872 0.009999 2.307259 +v 3.137872 0.009999 2.214968 +v 3.045582 0.009999 2.214968 +v 3.045582 0.009999 2.491840 +v 3.137872 0.009999 2.491840 +v 3.137872 0.009999 2.399549 +v 3.045582 0.009999 2.399549 +v 3.230163 0.009999 2.491840 +v 3.322453 0.009999 2.491840 +v 3.322453 0.009999 2.399549 +v 3.230163 0.009999 2.399549 +v 4.153066 0.009999 2.676420 +v 4.245357 0.009999 2.676420 +v 4.245357 0.009999 2.584130 +v 4.153066 0.009999 2.584130 +v 4.153066 0.009999 2.861001 +v 4.245357 0.009999 2.861001 +v 4.245357 0.009999 2.768711 +v 4.153066 0.009999 2.768711 +v 4.337647 0.009999 2.861001 +v 4.429937 0.009999 2.861001 +v 4.429937 0.009999 2.768711 +v 4.337647 0.009999 2.768711 +v 3.783905 0.009999 2.676420 +v 3.876195 0.009999 2.676420 +v 3.876195 0.009999 2.584130 +v 3.783905 0.009999 2.584130 +v 3.783905 0.009999 2.861001 +v 3.876195 0.009999 2.861001 +v 3.876195 0.009999 2.768711 +v 3.783905 0.009999 2.768711 +v 3.968485 0.009999 2.861001 +v 4.060776 0.009999 2.861001 +v 4.060776 0.009999 2.768711 +v 3.968485 0.009999 2.768711 +v 3.783905 0.009999 2.307259 +v 3.876195 0.009999 2.307259 +v 3.876195 0.009999 2.214968 +v 3.783905 0.009999 2.214968 +v 3.783905 0.009999 2.491840 +v 3.876195 0.009999 2.491840 +v 3.876195 0.009999 2.399549 +v 3.783905 0.009999 2.399549 +v 3.968485 0.009999 2.491840 +v 4.060776 0.009999 2.491840 +v 4.060776 0.009999 2.399549 +v 3.968485 0.009999 2.399549 +v 3.414743 0.010000 0.461452 +v 3.507033 0.010000 0.461452 +v 3.507033 0.010000 0.369161 +v 3.414743 0.010000 0.369161 +v 3.414743 0.010000 0.646033 +v 3.507033 0.010000 0.646033 +v 3.507033 0.010000 0.553742 +v 3.414743 0.010000 0.553742 +v 3.599324 0.010000 0.646033 +v 3.691614 0.010000 0.646033 +v 3.691614 0.010000 0.553742 +v 3.599324 0.010000 0.553742 +v 3.045582 0.010000 0.461452 +v 3.137872 0.010000 0.461452 +v 3.137872 0.010000 0.369161 +v 3.045582 0.010000 0.369161 +v 3.045582 0.010000 0.646033 +v 3.137872 0.010000 0.646033 +v 3.137872 0.010000 0.553742 +v 3.045582 0.010000 0.553742 +v 3.230163 0.010000 0.646033 +v 3.322453 0.010000 0.646033 +v 3.322453 0.010000 0.553742 +v 3.230163 0.010000 0.553742 +v 3.045582 0.010000 0.092290 +v 3.137872 0.010000 0.092290 +v 3.137872 0.010000 -0.000000 +v 3.045582 0.010000 -0.000000 +v 3.045582 0.010000 0.276871 +v 3.137872 0.010000 0.276871 +v 3.137872 0.010000 0.184581 +v 3.045582 0.010000 0.184581 +v 3.230163 0.010000 0.276871 +v 3.322453 0.010000 0.276871 +v 3.322453 0.010000 0.184581 +v 3.230163 0.010000 0.184581 +v 3.414743 0.010000 1.199775 +v 3.507033 0.010000 1.199775 +v 3.507033 0.010000 1.107484 +v 3.414743 0.010000 1.107484 +v 3.414743 0.009999 1.384355 +v 3.507033 0.009999 1.384355 +v 3.507033 0.009999 1.292065 +v 3.414743 0.009999 1.292065 +v 3.599324 0.009999 1.384355 +v 3.691614 0.009999 1.384355 +v 3.691614 0.009999 1.292065 +v 3.599324 0.009999 1.292065 +v 3.045582 0.010000 1.199775 +v 3.137872 0.010000 1.199775 +v 3.137872 0.010000 1.107484 +v 3.045582 0.010000 1.107484 +v 3.045582 0.009999 1.384355 +v 3.137872 0.009999 1.384355 +v 3.137872 0.009999 1.292065 +v 3.045582 0.009999 1.292065 +v 3.230163 0.009999 1.384355 +v 3.322453 0.009999 1.384355 +v 3.322453 0.009999 1.292065 +v 3.230163 0.009999 1.292065 +v 3.045582 0.010000 0.830613 +v 3.137872 0.010000 0.830613 +v 3.137872 0.010000 0.738323 +v 3.045582 0.010000 0.738323 +v 3.045582 0.010000 1.015194 +v 3.137872 0.010000 1.015194 +v 3.137872 0.010000 0.922904 +v 3.045582 0.010000 0.922904 +v 3.230163 0.010000 1.015194 +v 3.322453 0.010000 1.015194 +v 3.322453 0.010000 0.922904 +v 3.230163 0.010000 0.922904 +v 4.153066 0.010000 1.199775 +v 4.245357 0.010000 1.199775 +v 4.245357 0.010000 1.107484 +v 4.153066 0.010000 1.107484 +v 4.153066 0.009999 1.384355 +v 4.245357 0.009999 1.384355 +v 4.245357 0.009999 1.292065 +v 4.153066 0.009999 1.292065 +v 4.337647 0.009999 1.384355 +v 4.429937 0.009999 1.384355 +v 4.429937 0.009999 1.292065 +v 4.337647 0.009999 1.292065 +v 3.783905 0.010000 1.199775 +v 3.876195 0.010000 1.199775 +v 3.876195 0.010000 1.107484 +v 3.783905 0.010000 1.107484 +v 3.783905 0.009999 1.384355 +v 3.876195 0.009999 1.384355 +v 3.876195 0.009999 1.292065 +v 3.783905 0.009999 1.292065 +v 3.968485 0.009999 1.384355 +v 4.060776 0.009999 1.384355 +v 4.060776 0.009999 1.292065 +v 3.968485 0.009999 1.292065 +v 3.783905 0.010000 0.830613 +v 3.876195 0.010000 0.830613 +v 3.876195 0.010000 0.738323 +v 3.783905 0.010000 0.738323 +v 3.783905 0.010000 1.015194 +v 3.876195 0.010000 1.015194 +v 3.876195 0.010000 0.922904 +v 3.783905 0.010000 0.922904 +v 3.968485 0.010000 1.015194 +v 4.060776 0.010000 1.015194 +v 4.060776 0.010000 0.922904 +v 3.968485 0.010000 0.922904 +v 1.938097 0.009999 1.938097 +v 2.030388 0.009999 1.938097 +v 2.030388 0.009999 1.845807 +v 1.938097 0.009999 1.845807 +v 1.938097 0.009999 2.122678 +v 2.030388 0.009999 2.122678 +v 2.030388 0.009999 2.030388 +v 1.938097 0.009999 2.030388 +v 2.122678 0.009999 2.122678 +v 2.214968 0.009999 2.122678 +v 2.214968 0.009999 2.030388 +v 2.122678 0.009999 2.030388 +v 1.568936 0.009999 1.938097 +v 1.661226 0.009999 1.938097 +v 1.661226 0.009999 1.845807 +v 1.568936 0.009999 1.845807 +v 1.568936 0.009999 2.122678 +v 1.661226 0.009999 2.122678 +v 1.661226 0.009999 2.030388 +v 1.568936 0.009999 2.030388 +v 1.753517 0.009999 2.122678 +v 1.845807 0.009999 2.122678 +v 1.845807 0.009999 2.030388 +v 1.753517 0.009999 2.030388 +v 1.568936 0.009999 1.568936 +v 1.661226 0.009999 1.568936 +v 1.661226 0.009999 1.476646 +v 1.568936 0.009999 1.476646 +v 1.568936 0.009999 1.753517 +v 1.661226 0.009999 1.753517 +v 1.661226 0.009999 1.661226 +v 1.568936 0.009999 1.661226 +v 1.753517 0.009999 1.753517 +v 1.845807 0.009999 1.753517 +v 1.845807 0.009999 1.661226 +v 1.753517 0.009999 1.661226 +v 1.938097 0.009999 2.676420 +v 2.030388 0.009999 2.676420 +v 2.030388 0.009999 2.584130 +v 1.938097 0.009999 2.584130 +v 1.938097 0.009999 2.861001 +v 2.030388 0.009999 2.861001 +v 2.030388 0.009999 2.768711 +v 1.938097 0.009999 2.768711 +v 2.122678 0.009999 2.861001 +v 2.214968 0.009999 2.861001 +v 2.214968 0.009999 2.768711 +v 2.122678 0.009999 2.768711 +v 1.568936 0.009999 2.676420 +v 1.661226 0.009999 2.676420 +v 1.661226 0.009999 2.584130 +v 1.568936 0.009999 2.584130 +v 1.568936 0.009999 2.861001 +v 1.661226 0.009999 2.861001 +v 1.661226 0.009999 2.768711 +v 1.568936 0.009999 2.768711 +v 1.753517 0.009999 2.861001 +v 1.845807 0.009999 2.861001 +v 1.845807 0.009999 2.768711 +v 1.753517 0.009999 2.768711 +v 1.568936 0.009999 2.307259 +v 1.661226 0.009999 2.307259 +v 1.661226 0.009999 2.214968 +v 1.568936 0.009999 2.214968 +v 1.568936 0.009999 2.491840 +v 1.661226 0.009999 2.491840 +v 1.661226 0.009999 2.399549 +v 1.568936 0.009999 2.399549 +v 1.753517 0.009999 2.491840 +v 1.845807 0.009999 2.491840 +v 1.845807 0.009999 2.399549 +v 1.753517 0.009999 2.399549 +v 2.676420 0.009999 2.676420 +v 2.768711 0.009999 2.676420 +v 2.768711 0.009999 2.584130 +v 2.676420 0.009999 2.584130 +v 2.676420 0.009999 2.861001 +v 2.768711 0.009999 2.861001 +v 2.768711 0.009999 2.768711 +v 2.676420 0.009999 2.768711 +v 2.861001 0.009999 2.861001 +v 2.953291 0.009999 2.861001 +v 2.953291 0.009999 2.768711 +v 2.861001 0.009999 2.768711 +v 2.307259 0.009999 2.676420 +v 2.399549 0.009999 2.676420 +v 2.399549 0.009999 2.584130 +v 2.307259 0.009999 2.584130 +v 2.307259 0.009999 2.861001 +v 2.399549 0.009999 2.861001 +v 2.399549 0.009999 2.768711 +v 2.307259 0.009999 2.768711 +v 2.491840 0.009999 2.861001 +v 2.584130 0.009999 2.861001 +v 2.584130 0.009999 2.768711 +v 2.491840 0.009999 2.768711 +v 2.307259 0.009999 2.307259 +v 2.399549 0.009999 2.307259 +v 2.399549 0.009999 2.214968 +v 2.307259 0.009999 2.214968 +v 2.307259 0.009999 2.491840 +v 2.399549 0.009999 2.491840 +v 2.399549 0.009999 2.399549 +v 2.307259 0.009999 2.399549 +v 2.491840 0.009999 2.491840 +v 2.584130 0.009999 2.491840 +v 2.584130 0.009999 2.399549 +v 2.491840 0.009999 2.399549 +v 0.461452 0.009999 1.938097 +v 0.553742 0.009999 1.938097 +v 0.553742 0.009999 1.845807 +v 0.461452 0.009999 1.845807 +v 0.461452 0.009999 2.122678 +v 0.553742 0.009999 2.122678 +v 0.553742 0.009999 2.030388 +v 0.461452 0.009999 2.030388 +v 0.646033 0.009999 2.122678 +v 0.738323 0.009999 2.122678 +v 0.738323 0.009999 2.030388 +v 0.646033 0.009999 2.030388 +v 0.092290 0.009999 1.938097 +v 0.184581 0.009999 1.938097 +v 0.184581 0.009999 1.845807 +v 0.092290 0.009999 1.845807 +v 0.092290 0.009999 2.122678 +v 0.184581 0.009999 2.122678 +v 0.184581 0.009999 2.030388 +v 0.092290 0.009999 2.030388 +v 0.276871 0.009999 2.122678 +v 0.369161 0.009999 2.122678 +v 0.369161 0.009999 2.030388 +v 0.276871 0.009999 2.030388 +v 0.092290 0.009999 1.568936 +v 0.184581 0.009999 1.568936 +v 0.184581 0.009999 1.476646 +v 0.092290 0.009999 1.476646 +v 0.092290 0.009999 1.753517 +v 0.184581 0.009999 1.753517 +v 0.184581 0.009999 1.661226 +v 0.092290 0.009999 1.661226 +v 0.276871 0.009999 1.753517 +v 0.369161 0.009999 1.753517 +v 0.369161 0.009999 1.661226 +v 0.276871 0.009999 1.661226 +v 0.461452 0.009999 2.676420 +v 0.553742 0.009999 2.676420 +v 0.553742 0.009999 2.584130 +v 0.461452 0.009999 2.584130 +v 0.461452 0.009999 2.861001 +v 0.553742 0.009999 2.861001 +v 0.553742 0.009999 2.768711 +v 0.461452 0.009999 2.768711 +v 0.646033 0.009999 2.861001 +v 0.738323 0.009999 2.861001 +v 0.738323 0.009999 2.768711 +v 0.646033 0.009999 2.768711 +v 0.092290 0.009999 2.676420 +v 0.184581 0.009999 2.676420 +v 0.184581 0.009999 2.584130 +v 0.092290 0.009999 2.584130 +v 0.092290 0.009999 2.861001 +v 0.184581 0.009999 2.861001 +v 0.184581 0.009999 2.768711 +v 0.092290 0.009999 2.768711 +v 0.276871 0.009999 2.861001 +v 0.369161 0.009999 2.861001 +v 0.369161 0.009999 2.768711 +v 0.276871 0.009999 2.768711 +v 0.092290 0.009999 2.307259 +v 0.184581 0.009999 2.307259 +v 0.184581 0.009999 2.214968 +v 0.092290 0.009999 2.214968 +v 0.092290 0.009999 2.491840 +v 0.184581 0.009999 2.491840 +v 0.184581 0.009999 2.399549 +v 0.092290 0.009999 2.399549 +v 0.276871 0.009999 2.491840 +v 0.369161 0.009999 2.491840 +v 0.369161 0.009999 2.399549 +v 0.276871 0.009999 2.399549 +v 1.199775 0.009999 2.676420 +v 1.292065 0.009999 2.676420 +v 1.292065 0.009999 2.584130 +v 1.199775 0.009999 2.584130 +v 1.199775 0.009999 2.861001 +v 1.292065 0.009999 2.861001 +v 1.292065 0.009999 2.768711 +v 1.199775 0.009999 2.768711 +v 1.384355 0.009999 2.861001 +v 1.476646 0.009999 2.861001 +v 1.476646 0.009999 2.768711 +v 1.384355 0.009999 2.768711 +v 0.830613 0.009999 2.676420 +v 0.922904 0.009999 2.676420 +v 0.922904 0.009999 2.584130 +v 0.830613 0.009999 2.584130 +v 0.830613 0.009999 2.861001 +v 0.922904 0.009999 2.861001 +v 0.922904 0.009999 2.768711 +v 0.830613 0.009999 2.768711 +v 1.015194 0.009999 2.861001 +v 1.107484 0.009999 2.861001 +v 1.107484 0.009999 2.768711 +v 1.015194 0.009999 2.768711 +v 0.830613 0.009999 2.307259 +v 0.922904 0.009999 2.307259 +v 0.922904 0.009999 2.214968 +v 0.830613 0.009999 2.214968 +v 0.830613 0.009999 2.491840 +v 0.922904 0.009999 2.491840 +v 0.922904 0.009999 2.399549 +v 0.830613 0.009999 2.399549 +v 1.015194 0.009999 2.491840 +v 1.107484 0.009999 2.491840 +v 1.107484 0.009999 2.399549 +v 1.015194 0.009999 2.399549 +v 0.461452 0.010000 0.461452 +v 0.553742 0.010000 0.461452 +v 0.553742 0.010000 0.369161 +v 0.461452 0.010000 0.369161 +v 0.461452 0.010000 0.646033 +v 0.553742 0.010000 0.646033 +v 0.553742 0.010000 0.553742 +v 0.461452 0.010000 0.553742 +v 0.646033 0.010000 0.646033 +v 0.738323 0.010000 0.646033 +v 0.738323 0.010000 0.553742 +v 0.646033 0.010000 0.553742 +v 0.092290 0.010000 0.461452 +v 0.184581 0.010000 0.461452 +v 0.184581 0.010000 0.369161 +v 0.092290 0.010000 0.369161 +v 0.092290 0.010000 0.646033 +v 0.184581 0.010000 0.646033 +v 0.184581 0.010000 0.553742 +v 0.092290 0.010000 0.553742 +v 0.276871 0.010000 0.646033 +v 0.369161 0.010000 0.646033 +v 0.369161 0.010000 0.553742 +v 0.276871 0.010000 0.553742 +v 0.092290 0.010000 0.092290 +v 0.184581 0.010000 0.092290 +v 0.184581 0.010000 -0.000000 +v 0.092290 0.010000 -0.000000 +v 0.092290 0.010000 0.276871 +v 0.184581 0.010000 0.276871 +v 0.184581 0.010000 0.184581 +v 0.092290 0.010000 0.184581 +v 0.276871 0.010000 0.276871 +v 0.369161 0.010000 0.276871 +v 0.369161 0.010000 0.184581 +v 0.276871 0.010000 0.184581 +v 0.461452 0.010000 1.199775 +v 0.553742 0.010000 1.199775 +v 0.553742 0.010000 1.107484 +v 0.461452 0.010000 1.107484 +v 0.461452 0.009999 1.384355 +v 0.553742 0.009999 1.384355 +v 0.553742 0.009999 1.292065 +v 0.461452 0.009999 1.292065 +v 0.646033 0.009999 1.384355 +v 0.738323 0.009999 1.384355 +v 0.738323 0.009999 1.292065 +v 0.646033 0.009999 1.292065 +v 0.092290 0.010000 1.199775 +v 0.184581 0.010000 1.199775 +v 0.184581 0.010000 1.107484 +v 0.092290 0.010000 1.107484 +v 0.092290 0.009999 1.384355 +v 0.184581 0.009999 1.384355 +v 0.184581 0.009999 1.292065 +v 0.092290 0.009999 1.292065 +v 0.276871 0.009999 1.384355 +v 0.369161 0.009999 1.384355 +v 0.369161 0.009999 1.292065 +v 0.276871 0.009999 1.292065 +v 0.092290 0.010000 0.830613 +v 0.184581 0.010000 0.830613 +v 0.184581 0.010000 0.738323 +v 0.092290 0.010000 0.738323 +v 0.092290 0.010000 1.015194 +v 0.184581 0.010000 1.015194 +v 0.184581 0.010000 0.922904 +v 0.092290 0.010000 0.922904 +v 0.276871 0.010000 1.015194 +v 0.369161 0.010000 1.015194 +v 0.369161 0.010000 0.922904 +v 0.276871 0.010000 0.922904 +v 1.199775 0.010000 1.199775 +v 1.292065 0.010000 1.199775 +v 1.292065 0.010000 1.107484 +v 1.199775 0.010000 1.107484 +v 1.199775 0.009999 1.384355 +v 1.292065 0.009999 1.384355 +v 1.292065 0.009999 1.292065 +v 1.199775 0.009999 1.292065 +v 1.384355 0.009999 1.384355 +v 1.476646 0.009999 1.384355 +v 1.476646 0.009999 1.292065 +v 1.384355 0.009999 1.292065 +v 0.830613 0.010000 1.199775 +v 0.922904 0.010000 1.199775 +v 0.922904 0.010000 1.107484 +v 0.830613 0.010000 1.107484 +v 0.830613 0.009999 1.384355 +v 0.922904 0.009999 1.384355 +v 0.922904 0.009999 1.292065 +v 0.830613 0.009999 1.292065 +v 1.015194 0.009999 1.384355 +v 1.107484 0.009999 1.384355 +v 1.107484 0.009999 1.292065 +v 1.015194 0.009999 1.292065 +v 0.830613 0.010000 0.830613 +v 0.922904 0.010000 0.830613 +v 0.922904 0.010000 0.738323 +v 0.830613 0.010000 0.738323 +v 0.830613 0.010000 1.015194 +v 0.922904 0.010000 1.015194 +v 0.922904 0.010000 0.922904 +v 0.830613 0.010000 0.922904 +v 1.015194 0.010000 1.015194 +v 1.107484 0.010000 1.015194 +v 1.107484 0.010000 0.922904 +v 1.015194 0.010000 0.922904 +v 1.938097 0.009998 4.891389 +v 2.030388 0.009998 4.891389 +v 2.030388 0.009998 4.799098 +v 1.938097 0.009998 4.799098 +v 1.938097 0.009998 5.075970 +v 2.030388 0.009998 5.075970 +v 2.030388 0.009998 4.983679 +v 1.938097 0.009998 4.983679 +v 2.122678 0.009998 5.075970 +v 2.214968 0.009998 5.075970 +v 2.214968 0.009998 4.983679 +v 2.122678 0.009998 4.983679 +v 1.568936 0.009998 4.891389 +v 1.661226 0.009998 4.891389 +v 1.661226 0.009998 4.799098 +v 1.568936 0.009998 4.799098 +v 1.568936 0.009998 5.075970 +v 1.661226 0.009998 5.075970 +v 1.661226 0.009998 4.983679 +v 1.568936 0.009998 4.983679 +v 1.753517 0.009998 5.075970 +v 1.845807 0.009998 5.075970 +v 1.845807 0.009998 4.983679 +v 1.753517 0.009998 4.983679 +v 1.568936 0.009998 4.522227 +v 1.661226 0.009998 4.522227 +v 1.661226 0.009998 4.429937 +v 1.568936 0.009998 4.429937 +v 1.568936 0.009998 4.706808 +v 1.661226 0.009998 4.706808 +v 1.661226 0.009998 4.614518 +v 1.568936 0.009998 4.614518 +v 1.753517 0.009998 4.706808 +v 1.845807 0.009998 4.706808 +v 1.845807 0.009998 4.614518 +v 1.753517 0.009998 4.614518 +v 1.938097 0.009998 5.629711 +v 2.030388 0.009998 5.629711 +v 2.030388 0.009998 5.537421 +v 1.938097 0.009998 5.537421 +v 1.938097 0.009998 5.814293 +v 2.030388 0.009998 5.814293 +v 2.030388 0.009998 5.722002 +v 1.938097 0.009998 5.722002 +v 2.122678 0.009998 5.814293 +v 2.214968 0.009998 5.814293 +v 2.214968 0.009998 5.722002 +v 2.122678 0.009998 5.722002 +v 1.568936 0.009998 5.629711 +v 1.661226 0.009998 5.629711 +v 1.661226 0.009998 5.537421 +v 1.568936 0.009998 5.537421 +v 1.568936 0.009998 5.814293 +v 1.661226 0.009998 5.814293 +v 1.661226 0.009998 5.722002 +v 1.568936 0.009998 5.722002 +v 1.753517 0.009998 5.814293 +v 1.845807 0.009998 5.814293 +v 1.845807 0.009998 5.722002 +v 1.753517 0.009998 5.722002 +v 1.568936 0.009998 5.260550 +v 1.661226 0.009998 5.260550 +v 1.661226 0.009998 5.168260 +v 1.568936 0.009998 5.168260 +v 1.568936 0.009998 5.445131 +v 1.661226 0.009998 5.445131 +v 1.661226 0.009998 5.352840 +v 1.568936 0.009998 5.352840 +v 1.753517 0.009998 5.445131 +v 1.845807 0.009998 5.445131 +v 1.845807 0.009998 5.352840 +v 1.753517 0.009998 5.352840 +v 2.676420 0.009998 5.629711 +v 2.768711 0.009998 5.629711 +v 2.768711 0.009998 5.537421 +v 2.676420 0.009998 5.537421 +v 2.676420 0.009998 5.814293 +v 2.768711 0.009998 5.814293 +v 2.768711 0.009998 5.722002 +v 2.676420 0.009998 5.722002 +v 2.861001 0.009998 5.814293 +v 2.953291 0.009998 5.814293 +v 2.953291 0.009998 5.722002 +v 2.861001 0.009998 5.722002 +v 2.307259 0.009998 5.629711 +v 2.399549 0.009998 5.629711 +v 2.399549 0.009998 5.537421 +v 2.307259 0.009998 5.537421 +v 2.307259 0.009998 5.814293 +v 2.399549 0.009998 5.814293 +v 2.399549 0.009998 5.722002 +v 2.307259 0.009998 5.722002 +v 2.491840 0.009998 5.814293 +v 2.584130 0.009998 5.814293 +v 2.584130 0.009998 5.722002 +v 2.491840 0.009998 5.722002 +v 2.307259 0.009998 5.260550 +v 2.399549 0.009998 5.260550 +v 2.399549 0.009998 5.168260 +v 2.307259 0.009998 5.168260 +v 2.307259 0.009998 5.445131 +v 2.399549 0.009998 5.445131 +v 2.399549 0.009998 5.352840 +v 2.307259 0.009998 5.352840 +v 2.491840 0.009998 5.445131 +v 2.584130 0.009998 5.445131 +v 2.584130 0.009998 5.352840 +v 2.491840 0.009998 5.352840 +v 0.461452 0.009998 4.891389 +v 0.553742 0.009998 4.891389 +v 0.553742 0.009998 4.799098 +v 0.461452 0.009998 4.799098 +v 0.461452 0.009998 5.075970 +v 0.553742 0.009998 5.075970 +v 0.553742 0.009998 4.983679 +v 0.461452 0.009998 4.983679 +v 0.646033 0.009998 5.075970 +v 0.738323 0.009998 5.075970 +v 0.738323 0.009998 4.983679 +v 0.646033 0.009998 4.983679 +v 0.092290 0.009998 4.891389 +v 0.184581 0.009998 4.891389 +v 0.184581 0.009998 4.799098 +v 0.092290 0.009998 4.799098 +v 0.092290 0.009998 5.075970 +v 0.184581 0.009998 5.075970 +v 0.184581 0.009998 4.983679 +v 0.092290 0.009998 4.983679 +v 0.276871 0.009998 5.075970 +v 0.369161 0.009998 5.075970 +v 0.369161 0.009998 4.983679 +v 0.276871 0.009998 4.983679 +v 0.092290 0.009998 4.522227 +v 0.184581 0.009998 4.522227 +v 0.184581 0.009998 4.429937 +v 0.092290 0.009998 4.429937 +v 0.092290 0.009998 4.706808 +v 0.184581 0.009998 4.706808 +v 0.184581 0.009998 4.614518 +v 0.092290 0.009998 4.614518 +v 0.276871 0.009998 4.706808 +v 0.369161 0.009998 4.706808 +v 0.369161 0.009998 4.614518 +v 0.276871 0.009998 4.614518 +v 0.461452 0.009998 5.629711 +v 0.553742 0.009998 5.629711 +v 0.553742 0.009998 5.537421 +v 0.461452 0.009998 5.537421 +v 0.461452 0.009998 5.814293 +v 0.553742 0.009998 5.814293 +v 0.553742 0.009998 5.722002 +v 0.461452 0.009998 5.722002 +v 0.646033 0.009998 5.814293 +v 0.738323 0.009998 5.814293 +v 0.738323 0.009998 5.722002 +v 0.646033 0.009998 5.722002 +v 0.092290 0.009998 5.629711 +v 0.184581 0.009998 5.629711 +v 0.184581 0.009998 5.537421 +v 0.092290 0.009998 5.537421 +v 0.092290 0.009998 5.814293 +v 0.184581 0.009998 5.814293 +v 0.184581 0.009998 5.722002 +v 0.092290 0.009998 5.722002 +v 0.276871 0.009998 5.814293 +v 0.369161 0.009998 5.814293 +v 0.369161 0.009998 5.722002 +v 0.276871 0.009998 5.722002 +v 0.092290 0.009998 5.260550 +v 0.184581 0.009998 5.260550 +v 0.184581 0.009998 5.168260 +v 0.092290 0.009998 5.168260 +v 0.092290 0.009998 5.445131 +v 0.184581 0.009998 5.445131 +v 0.184581 0.009998 5.352840 +v 0.092290 0.009998 5.352840 +v 0.276871 0.009998 5.445131 +v 0.369161 0.009998 5.445131 +v 0.369161 0.009998 5.352840 +v 0.276871 0.009998 5.352840 +v 1.199775 0.009998 5.629711 +v 1.292065 0.009998 5.629711 +v 1.292065 0.009998 5.537421 +v 1.199775 0.009998 5.537421 +v 1.199775 0.009998 5.814293 +v 1.292065 0.009998 5.814293 +v 1.292065 0.009998 5.722002 +v 1.199775 0.009998 5.722002 +v 1.384355 0.009998 5.814293 +v 1.476646 0.009998 5.814293 +v 1.476646 0.009998 5.722002 +v 1.384355 0.009998 5.722002 +v 0.830613 0.009998 5.629711 +v 0.922904 0.009998 5.629711 +v 0.922904 0.009998 5.537421 +v 0.830613 0.009998 5.537421 +v 0.830613 0.009998 5.814293 +v 0.922904 0.009998 5.814293 +v 0.922904 0.009998 5.722002 +v 0.830613 0.009998 5.722002 +v 1.015194 0.009998 5.814293 +v 1.107484 0.009998 5.814293 +v 1.107484 0.009998 5.722002 +v 1.015194 0.009998 5.722002 +v 0.830613 0.009998 5.260550 +v 0.922904 0.009998 5.260550 +v 0.922904 0.009998 5.168260 +v 0.830613 0.009998 5.168260 +v 0.830613 0.009998 5.445131 +v 0.922904 0.009998 5.445131 +v 0.922904 0.009998 5.352840 +v 0.830613 0.009998 5.352840 +v 1.015194 0.009998 5.445131 +v 1.107484 0.009998 5.445131 +v 1.107484 0.009998 5.352840 +v 1.015194 0.009998 5.352840 +v 0.461452 0.009999 3.414743 +v 0.553742 0.009999 3.414743 +v 0.553742 0.009999 3.322453 +v 0.461452 0.009999 3.322453 +v 0.461452 0.009999 3.599324 +v 0.553742 0.009999 3.599324 +v 0.553742 0.009999 3.507033 +v 0.461452 0.009999 3.507033 +v 0.646033 0.009999 3.599324 +v 0.738323 0.009999 3.599324 +v 0.738323 0.009999 3.507033 +v 0.646033 0.009999 3.507033 +v 0.092290 0.009999 3.414743 +v 0.184581 0.009999 3.414743 +v 0.184581 0.009999 3.322453 +v 0.092290 0.009999 3.322453 +v 0.092290 0.009999 3.599324 +v 0.184581 0.009999 3.599324 +v 0.184581 0.009999 3.507033 +v 0.092290 0.009999 3.507033 +v 0.276871 0.009999 3.599324 +v 0.369161 0.009999 3.599324 +v 0.369161 0.009999 3.507033 +v 0.276871 0.009999 3.507033 +v 0.092290 0.009999 3.045582 +v 0.184581 0.009999 3.045582 +v 0.184581 0.009999 2.953291 +v 0.092290 0.009999 2.953291 +v 0.092290 0.009999 3.230163 +v 0.184581 0.009999 3.230163 +v 0.184581 0.009999 3.137872 +v 0.092290 0.009999 3.137872 +v 0.276871 0.009999 3.230163 +v 0.369161 0.009999 3.230163 +v 0.369161 0.009999 3.137872 +v 0.276871 0.009999 3.137872 +v 0.461452 0.009998 4.153066 +v 0.553742 0.009998 4.153066 +v 0.553742 0.009998 4.060776 +v 0.461452 0.009998 4.060776 +v 0.461452 0.009998 4.337647 +v 0.553742 0.009998 4.337647 +v 0.553742 0.009998 4.245357 +v 0.461452 0.009998 4.245357 +v 0.646033 0.009998 4.337647 +v 0.738323 0.009998 4.337647 +v 0.738323 0.009998 4.245357 +v 0.646033 0.009998 4.245357 +v 0.092290 0.009998 4.153066 +v 0.184581 0.009998 4.153066 +v 0.184581 0.009998 4.060776 +v 0.092290 0.009998 4.060776 +v 0.092290 0.009998 4.337647 +v 0.184581 0.009998 4.337647 +v 0.184581 0.009998 4.245357 +v 0.092290 0.009998 4.245357 +v 0.276871 0.009998 4.337647 +v 0.369161 0.009998 4.337647 +v 0.369161 0.009998 4.245357 +v 0.276871 0.009998 4.245357 +v 0.092290 0.009998 3.783905 +v 0.184581 0.009998 3.783905 +v 0.184581 0.009998 3.691614 +v 0.092290 0.009998 3.691614 +v 0.092290 0.009998 3.968485 +v 0.184581 0.009998 3.968485 +v 0.184581 0.009998 3.876195 +v 0.092290 0.009998 3.876195 +v 0.276871 0.009998 3.968485 +v 0.369161 0.009998 3.968485 +v 0.369161 0.009998 3.876195 +v 0.276871 0.009998 3.876195 +v 1.199775 0.009998 4.153066 +v 1.292065 0.009998 4.153066 +v 1.292065 0.009998 4.060776 +v 1.199775 0.009998 4.060776 +v 1.199775 0.009998 4.337647 +v 1.292065 0.009998 4.337647 +v 1.292065 0.009998 4.245357 +v 1.199775 0.009998 4.245357 +v 1.384355 0.009998 4.337647 +v 1.476646 0.009998 4.337647 +v 1.476646 0.009998 4.245357 +v 1.384355 0.009998 4.245357 +v 0.830613 0.009998 4.153066 +v 0.922904 0.009998 4.153066 +v 0.922904 0.009998 4.060776 +v 0.830613 0.009998 4.060776 +v 0.830613 0.009998 4.337647 +v 0.922904 0.009998 4.337647 +v 0.922904 0.009998 4.245357 +v 0.830613 0.009998 4.245357 +v 1.015194 0.009998 4.337647 +v 1.107484 0.009998 4.337647 +v 1.107484 0.009998 4.245357 +v 1.015194 0.009998 4.245357 +v 0.830613 0.009998 3.783905 +v 0.922904 0.009998 3.783905 +v 0.922904 0.009998 3.691614 +v 0.830613 0.009998 3.691614 +v 0.830613 0.009998 3.968485 +v 0.922904 0.009998 3.968485 +v 0.922904 0.009998 3.876195 +v 0.830613 0.009998 3.876195 +v 1.015194 0.009998 3.968485 +v 1.107484 0.009998 3.968485 +v 1.107484 0.009998 3.876195 +v 1.015194 0.009998 3.876195 +v 4.891389 0.009998 4.891389 +v 4.983679 0.009998 4.891389 +v 4.983679 0.009998 4.799098 +v 4.891389 0.009998 4.799098 +v 4.891389 0.009998 5.075970 +v 4.983679 0.009998 5.075970 +v 4.983679 0.009998 4.983679 +v 4.891389 0.009998 4.983679 +v 5.075970 0.009998 5.075970 +v 5.168260 0.009998 5.075970 +v 5.168260 0.009998 4.983679 +v 5.075970 0.009998 4.983679 +v 4.522227 0.009998 4.891389 +v 4.614518 0.009998 4.891389 +v 4.614518 0.009998 4.799098 +v 4.522227 0.009998 4.799098 +v 4.522227 0.009998 5.075970 +v 4.614518 0.009998 5.075970 +v 4.614518 0.009998 4.983679 +v 4.522227 0.009998 4.983679 +v 4.706808 0.009998 5.075970 +v 4.799098 0.009998 5.075970 +v 4.799098 0.009998 4.983679 +v 4.706808 0.009998 4.983679 +v 4.522227 0.009998 4.522227 +v 4.614518 0.009998 4.522227 +v 4.614518 0.009998 4.429937 +v 4.522227 0.009998 4.429937 +v 4.522227 0.009998 4.706808 +v 4.614518 0.009998 4.706808 +v 4.614518 0.009998 4.614518 +v 4.522227 0.009998 4.614518 +v 4.706808 0.009998 4.706808 +v 4.799098 0.009998 4.706808 +v 4.799098 0.009998 4.614518 +v 4.706808 0.009998 4.614518 +v 4.891389 0.009998 5.629711 +v 4.983679 0.009998 5.629711 +v 4.983679 0.009998 5.537421 +v 4.891389 0.009998 5.537421 +v 4.891389 0.009998 5.814293 +v 4.983679 0.009998 5.814293 +v 4.983679 0.009998 5.722002 +v 4.891389 0.009998 5.722002 +v 5.075970 0.009998 5.814293 +v 5.168260 0.009998 5.814293 +v 5.168260 0.009998 5.722002 +v 5.075970 0.009998 5.722002 +v 4.522227 0.009998 5.629711 +v 4.614518 0.009998 5.629711 +v 4.614518 0.009998 5.537421 +v 4.522227 0.009998 5.537421 +v 4.522227 0.009998 5.814293 +v 4.614518 0.009998 5.814293 +v 4.614518 0.009998 5.722002 +v 4.522227 0.009998 5.722002 +v 4.706808 0.009998 5.814293 +v 4.799098 0.009998 5.814293 +v 4.799098 0.009998 5.722002 +v 4.706808 0.009998 5.722002 +v 4.522227 0.009998 5.260550 +v 4.614518 0.009998 5.260550 +v 4.614518 0.009998 5.168260 +v 4.522227 0.009998 5.168260 +v 4.522227 0.009998 5.445131 +v 4.614518 0.009998 5.445131 +v 4.614518 0.009998 5.352840 +v 4.522227 0.009998 5.352840 +v 4.706808 0.009998 5.445131 +v 4.799098 0.009998 5.445131 +v 4.799098 0.009998 5.352840 +v 4.706808 0.009998 5.352840 +v 5.629711 0.009998 5.629711 +v 5.722002 0.009998 5.629711 +v 5.722002 0.009998 5.537421 +v 5.629711 0.009998 5.537421 +v 5.629711 0.009998 5.814293 +v 5.722002 0.009998 5.814293 +v 5.722002 0.009998 5.722002 +v 5.629711 0.009998 5.722002 +v 5.814293 0.009998 5.814293 +v 5.906583 0.009998 5.814293 +v 5.906583 0.009998 5.722002 +v 5.814293 0.009998 5.722002 +v 5.260550 0.009998 5.629711 +v 5.352840 0.009998 5.629711 +v 5.352840 0.009998 5.537421 +v 5.260550 0.009998 5.537421 +v 5.260550 0.009998 5.814293 +v 5.352840 0.009998 5.814293 +v 5.352840 0.009998 5.722002 +v 5.260550 0.009998 5.722002 +v 5.445131 0.009998 5.814293 +v 5.537421 0.009998 5.814293 +v 5.537421 0.009998 5.722002 +v 5.445131 0.009998 5.722002 +v 5.260550 0.009998 5.260550 +v 5.352840 0.009998 5.260550 +v 5.352840 0.009998 5.168260 +v 5.260550 0.009998 5.168260 +v 5.260550 0.009998 5.445131 +v 5.352840 0.009998 5.445131 +v 5.352840 0.009998 5.352840 +v 5.260550 0.009998 5.352840 +v 5.445131 0.009998 5.445131 +v 5.537421 0.009998 5.445131 +v 5.537421 0.009998 5.352840 +v 5.445131 0.009998 5.352840 +v 3.414743 0.009998 4.891389 +v 3.507033 0.009998 4.891389 +v 3.507033 0.009998 4.799098 +v 3.414743 0.009998 4.799098 +v 3.414743 0.009998 5.075970 +v 3.507033 0.009998 5.075970 +v 3.507033 0.009998 4.983679 +v 3.414743 0.009998 4.983679 +v 3.599324 0.009998 5.075970 +v 3.691614 0.009998 5.075970 +v 3.691614 0.009998 4.983679 +v 3.599324 0.009998 4.983679 +v 3.045582 0.009998 4.891389 +v 3.137872 0.009998 4.891389 +v 3.137872 0.009998 4.799098 +v 3.045582 0.009998 4.799098 +v 3.045582 0.009998 5.075970 +v 3.137872 0.009998 5.075970 +v 3.137872 0.009998 4.983679 +v 3.045582 0.009998 4.983679 +v 3.230163 0.009998 5.075970 +v 3.322453 0.009998 5.075970 +v 3.322453 0.009998 4.983679 +v 3.230163 0.009998 4.983679 +v 3.045582 0.009998 4.522227 +v 3.137872 0.009998 4.522227 +v 3.137872 0.009998 4.429937 +v 3.045582 0.009998 4.429937 +v 3.045582 0.009998 4.706808 +v 3.137872 0.009998 4.706808 +v 3.137872 0.009998 4.614518 +v 3.045582 0.009998 4.614518 +v 3.230163 0.009998 4.706808 +v 3.322453 0.009998 4.706808 +v 3.322453 0.009998 4.614518 +v 3.230163 0.009998 4.614518 +v 3.414743 0.009998 5.629711 +v 3.507033 0.009998 5.629711 +v 3.507033 0.009998 5.537421 +v 3.414743 0.009998 5.537421 +v 3.414743 0.009998 5.814293 +v 3.507033 0.009998 5.814293 +v 3.507033 0.009998 5.722002 +v 3.414743 0.009998 5.722002 +v 3.599324 0.009998 5.814293 +v 3.691614 0.009998 5.814293 +v 3.691614 0.009998 5.722002 +v 3.599324 0.009998 5.722002 +v 3.045582 0.009998 5.629711 +v 3.137872 0.009998 5.629711 +v 3.137872 0.009998 5.537421 +v 3.045582 0.009998 5.537421 +v 3.045582 0.009998 5.814293 +v 3.137872 0.009998 5.814293 +v 3.137872 0.009998 5.722002 +v 3.045582 0.009998 5.722002 +v 3.230163 0.009998 5.814293 +v 3.322453 0.009998 5.814293 +v 3.322453 0.009998 5.722002 +v 3.230163 0.009998 5.722002 +v 3.045582 0.009998 5.260550 +v 3.137872 0.009998 5.260550 +v 3.137872 0.009998 5.168260 +v 3.045582 0.009998 5.168260 +v 3.045582 0.009998 5.445131 +v 3.137872 0.009998 5.445131 +v 3.137872 0.009998 5.352840 +v 3.045582 0.009998 5.352840 +v 3.230163 0.009998 5.445131 +v 3.322453 0.009998 5.445131 +v 3.322453 0.009998 5.352840 +v 3.230163 0.009998 5.352840 +v 4.153066 0.009998 5.629711 +v 4.245357 0.009998 5.629711 +v 4.245357 0.009998 5.537421 +v 4.153066 0.009998 5.537421 +v 4.153066 0.009998 5.814293 +v 4.245357 0.009998 5.814293 +v 4.245357 0.009998 5.722002 +v 4.153066 0.009998 5.722002 +v 4.337647 0.009998 5.814293 +v 4.429937 0.009998 5.814293 +v 4.429937 0.009998 5.722002 +v 4.337647 0.009998 5.722002 +v 3.783905 0.009998 5.629711 +v 3.876195 0.009998 5.629711 +v 3.876195 0.009998 5.537421 +v 3.783905 0.009998 5.537421 +v 3.783905 0.009998 5.814293 +v 3.876195 0.009998 5.814293 +v 3.876195 0.009998 5.722002 +v 3.783905 0.009998 5.722002 +v 3.968485 0.009998 5.814293 +v 4.060776 0.009998 5.814293 +v 4.060776 0.009998 5.722002 +v 3.968485 0.009998 5.722002 +v 3.783905 0.009998 5.260550 +v 3.876195 0.009998 5.260550 +v 3.876195 0.009998 5.168260 +v 3.783905 0.009998 5.168260 +v 3.783905 0.009998 5.445131 +v 3.876195 0.009998 5.445131 +v 3.876195 0.009998 5.352840 +v 3.783905 0.009998 5.352840 +v 3.968485 0.009998 5.445131 +v 4.060776 0.009998 5.445131 +v 4.060776 0.009998 5.352840 +v 3.968485 0.009998 5.352840 +v 3.414743 0.009999 3.414743 +v 3.507033 0.009999 3.414743 +v 3.507033 0.009999 3.322453 +v 3.414743 0.009999 3.322453 +v 3.414743 0.009999 3.599324 +v 3.507033 0.009999 3.599324 +v 3.507033 0.009999 3.507033 +v 3.414743 0.009999 3.507033 +v 3.599324 0.009999 3.599324 +v 3.691614 0.009999 3.599324 +v 3.691614 0.009999 3.507033 +v 3.599324 0.009999 3.507033 +v 3.045582 0.009999 3.414743 +v 3.137872 0.009999 3.414743 +v 3.137872 0.009999 3.322453 +v 3.045582 0.009999 3.322453 +v 3.045582 0.009999 3.599324 +v 3.137872 0.009999 3.599324 +v 3.137872 0.009999 3.507033 +v 3.045582 0.009999 3.507033 +v 3.230163 0.009999 3.599324 +v 3.322453 0.009999 3.599324 +v 3.322453 0.009999 3.507033 +v 3.230163 0.009999 3.507033 +v 3.045582 0.009999 3.045582 +v 3.137872 0.009999 3.045582 +v 3.137872 0.009999 2.953291 +v 3.045582 0.009999 2.953291 +v 3.045582 0.009999 3.230163 +v 3.137872 0.009999 3.230163 +v 3.137872 0.009999 3.137872 +v 3.045582 0.009999 3.137872 +v 3.230163 0.009999 3.230163 +v 3.322453 0.009999 3.230163 +v 3.322453 0.009999 3.137872 +v 3.230163 0.009999 3.137872 +v 3.414743 0.009998 4.153066 +v 3.507033 0.009998 4.153066 +v 3.507033 0.009998 4.060776 +v 3.414743 0.009998 4.060776 +v 3.414743 0.009998 4.337647 +v 3.507033 0.009998 4.337647 +v 3.507033 0.009998 4.245357 +v 3.414743 0.009998 4.245357 +v 3.599324 0.009998 4.337647 +v 3.691614 0.009998 4.337647 +v 3.691614 0.009998 4.245357 +v 3.599324 0.009998 4.245357 +v 3.045582 0.009998 4.153066 +v 3.137872 0.009998 4.153066 +v 3.137872 0.009998 4.060776 +v 3.045582 0.009998 4.060776 +v 3.045582 0.009998 4.337647 +v 3.137872 0.009998 4.337647 +v 3.137872 0.009998 4.245357 +v 3.045582 0.009998 4.245357 +v 3.230163 0.009998 4.337647 +v 3.322453 0.009998 4.337647 +v 3.322453 0.009998 4.245357 +v 3.230163 0.009998 4.245357 +v 3.045582 0.009998 3.783905 +v 3.137872 0.009998 3.783905 +v 3.137872 0.009998 3.691614 +v 3.045582 0.009998 3.691614 +v 3.045582 0.009998 3.968485 +v 3.137872 0.009998 3.968485 +v 3.137872 0.009998 3.876195 +v 3.045582 0.009998 3.876195 +v 3.230163 0.009998 3.968485 +v 3.322453 0.009998 3.968485 +v 3.322453 0.009998 3.876195 +v 3.230163 0.009998 3.876195 +v 4.153066 0.009998 4.153066 +v 4.245357 0.009998 4.153066 +v 4.245357 0.009998 4.060776 +v 4.153066 0.009998 4.060776 +v 4.153066 0.009998 4.337647 +v 4.245357 0.009998 4.337647 +v 4.245357 0.009998 4.245357 +v 4.153066 0.009998 4.245357 +v 4.337647 0.009998 4.337647 +v 4.429937 0.009998 4.337647 +v 4.429937 0.009998 4.245357 +v 4.337647 0.009998 4.245357 +v 3.783905 0.009998 4.153066 +v 3.876195 0.009998 4.153066 +v 3.876195 0.009998 4.060776 +v 3.783905 0.009998 4.060776 +v 3.783905 0.009998 4.337647 +v 3.876195 0.009998 4.337647 +v 3.876195 0.009998 4.245357 +v 3.783905 0.009998 4.245357 +v 3.968485 0.009998 4.337647 +v 4.060776 0.009998 4.337647 +v 4.060776 0.009998 4.245357 +v 3.968485 0.009998 4.245357 +v 3.783905 0.009998 3.783905 +v 3.876195 0.009998 3.783905 +v 3.876195 0.009998 3.691614 +v 3.783905 0.009998 3.691614 +v 3.783905 0.009998 3.968485 +v 3.876195 0.009998 3.968485 +v 3.876195 0.009998 3.876195 +v 3.783905 0.009998 3.876195 +v 3.968485 0.009998 3.968485 +v 4.060776 0.009998 3.968485 +v 4.060776 0.009998 3.876195 +v 3.968485 0.009998 3.876195 +v -3.968485 0.009999 1.938097 +v -3.876195 0.009999 1.938097 +v -3.876195 0.009999 1.845807 +v -3.968485 0.009999 1.845807 +v -3.968485 0.009999 2.122678 +v -3.876195 0.009999 2.122678 +v -3.876195 0.009999 2.030388 +v -3.968485 0.009999 2.030388 +v -3.783905 0.009999 2.122678 +v -3.691614 0.009999 2.122678 +v -3.691614 0.009999 2.030388 +v -3.783905 0.009999 2.030388 +v -4.337647 0.009999 1.938097 +v -4.245357 0.009999 1.938097 +v -4.245357 0.009999 1.845807 +v -4.337647 0.009999 1.845807 +v -4.337647 0.009999 2.122678 +v -4.245357 0.009999 2.122678 +v -4.245357 0.009999 2.030388 +v -4.337647 0.009999 2.030388 +v -4.153066 0.009999 2.122678 +v -4.060776 0.009999 2.122678 +v -4.060776 0.009999 2.030388 +v -4.153066 0.009999 2.030388 +v -4.337647 0.009999 1.568936 +v -4.245357 0.009999 1.568936 +v -4.245357 0.009999 1.476646 +v -4.337647 0.009999 1.476646 +v -4.337647 0.009999 1.753517 +v -4.245357 0.009999 1.753517 +v -4.245357 0.009999 1.661226 +v -4.337647 0.009999 1.661226 +v -4.153066 0.009999 1.753517 +v -4.060776 0.009999 1.753517 +v -4.060776 0.009999 1.661226 +v -4.153066 0.009999 1.661226 +v -3.968485 0.009999 2.676420 +v -3.876195 0.009999 2.676420 +v -3.876195 0.009999 2.584130 +v -3.968485 0.009999 2.584130 +v -3.968485 0.009999 2.861001 +v -3.876195 0.009999 2.861001 +v -3.876195 0.009999 2.768711 +v -3.968485 0.009999 2.768711 +v -3.783905 0.009999 2.861001 +v -3.691614 0.009999 2.861001 +v -3.691614 0.009999 2.768711 +v -3.783905 0.009999 2.768711 +v -4.337647 0.009999 2.676420 +v -4.245357 0.009999 2.676420 +v -4.245357 0.009999 2.584130 +v -4.337647 0.009999 2.584130 +v -4.337647 0.009999 2.861001 +v -4.245357 0.009999 2.861001 +v -4.245357 0.009999 2.768711 +v -4.337647 0.009999 2.768711 +v -4.153066 0.009999 2.861001 +v -4.060776 0.009999 2.861001 +v -4.060776 0.009999 2.768711 +v -4.153066 0.009999 2.768711 +v -4.337647 0.009999 2.307259 +v -4.245357 0.009999 2.307259 +v -4.245357 0.009999 2.214968 +v -4.337647 0.009999 2.214968 +v -4.337647 0.009999 2.491840 +v -4.245357 0.009999 2.491840 +v -4.245357 0.009999 2.399549 +v -4.337647 0.009999 2.399549 +v -4.153066 0.009999 2.491840 +v -4.060776 0.009999 2.491840 +v -4.060776 0.009999 2.399549 +v -4.153066 0.009999 2.399549 +v -3.230163 0.009999 2.676420 +v -3.137872 0.009999 2.676420 +v -3.137872 0.009999 2.584130 +v -3.230163 0.009999 2.584130 +v -3.230163 0.009999 2.861001 +v -3.137872 0.009999 2.861001 +v -3.137872 0.009999 2.768711 +v -3.230163 0.009999 2.768711 +v -3.045582 0.009999 2.861001 +v -2.953291 0.009999 2.861001 +v -2.953291 0.009999 2.768711 +v -3.045582 0.009999 2.768711 +v -3.599324 0.009999 2.676420 +v -3.507033 0.009999 2.676420 +v -3.507033 0.009999 2.584130 +v -3.599324 0.009999 2.584130 +v -3.599324 0.009999 2.861001 +v -3.507033 0.009999 2.861001 +v -3.507033 0.009999 2.768711 +v -3.599324 0.009999 2.768711 +v -3.414743 0.009999 2.861001 +v -3.322453 0.009999 2.861001 +v -3.322453 0.009999 2.768711 +v -3.414743 0.009999 2.768711 +v -3.599324 0.009999 2.307259 +v -3.507033 0.009999 2.307259 +v -3.507033 0.009999 2.214968 +v -3.599324 0.009999 2.214968 +v -3.599324 0.009999 2.491840 +v -3.507033 0.009999 2.491840 +v -3.507033 0.009999 2.399549 +v -3.599324 0.009999 2.399549 +v -3.414743 0.009999 2.491840 +v -3.322453 0.009999 2.491840 +v -3.322453 0.009999 2.399549 +v -3.414743 0.009999 2.399549 +v -5.445131 0.009999 1.938097 +v -5.352840 0.009999 1.938097 +v -5.352840 0.009999 1.845807 +v -5.445131 0.009999 1.845807 +v -5.445131 0.009999 2.122678 +v -5.352840 0.009999 2.122678 +v -5.352840 0.009999 2.030388 +v -5.445131 0.009999 2.030388 +v -5.260550 0.009999 2.122678 +v -5.168260 0.009999 2.122678 +v -5.168260 0.009999 2.030388 +v -5.260550 0.009999 2.030388 +v -5.814293 0.009999 1.938097 +v -5.722002 0.009999 1.938097 +v -5.722002 0.009999 1.845807 +v -5.814293 0.009999 1.845807 +v -5.814293 0.009999 2.122678 +v -5.722002 0.009999 2.122678 +v -5.722002 0.009999 2.030388 +v -5.814293 0.009999 2.030388 +v -5.629711 0.009999 2.122678 +v -5.537421 0.009999 2.122678 +v -5.537421 0.009999 2.030388 +v -5.629711 0.009999 2.030388 +v -5.814293 0.009999 1.568936 +v -5.722002 0.009999 1.568936 +v -5.722002 0.009999 1.476646 +v -5.814293 0.009999 1.476646 +v -5.814293 0.009999 1.753517 +v -5.722002 0.009999 1.753517 +v -5.722002 0.009999 1.661226 +v -5.814293 0.009999 1.661226 +v -5.629711 0.009999 1.753517 +v -5.537421 0.009999 1.753517 +v -5.537421 0.009999 1.661226 +v -5.629711 0.009999 1.661226 +v -5.445131 0.009999 2.676420 +v -5.352840 0.009999 2.676420 +v -5.352840 0.009999 2.584130 +v -5.445131 0.009999 2.584130 +v -5.445131 0.009999 2.861001 +v -5.352840 0.009999 2.861001 +v -5.352840 0.009999 2.768711 +v -5.445131 0.009999 2.768711 +v -5.260550 0.009999 2.861001 +v -5.168260 0.009999 2.861001 +v -5.168260 0.009999 2.768711 +v -5.260550 0.009999 2.768711 +v -5.814293 0.009999 2.676420 +v -5.722002 0.009999 2.676420 +v -5.722002 0.009999 2.584130 +v -5.814293 0.009999 2.584130 +v -5.814293 0.009999 2.861001 +v -5.722002 0.009999 2.861001 +v -5.722002 0.009999 2.768711 +v -5.814293 0.009999 2.768711 +v -5.629711 0.009999 2.861001 +v -5.537421 0.009999 2.861001 +v -5.537421 0.009999 2.768711 +v -5.629711 0.009999 2.768711 +v -5.814293 0.009999 2.307259 +v -5.722002 0.009999 2.307259 +v -5.722002 0.009999 2.214968 +v -5.814293 0.009999 2.214968 +v -5.814293 0.009999 2.491840 +v -5.722002 0.009999 2.491840 +v -5.722002 0.009999 2.399549 +v -5.814293 0.009999 2.399549 +v -5.629711 0.009999 2.491840 +v -5.537421 0.009999 2.491840 +v -5.537421 0.009999 2.399549 +v -5.629711 0.009999 2.399549 +v -4.706808 0.009999 2.676420 +v -4.614518 0.009999 2.676420 +v -4.614518 0.009999 2.584130 +v -4.706808 0.009999 2.584130 +v -4.706808 0.009999 2.861001 +v -4.614518 0.009999 2.861001 +v -4.614518 0.009999 2.768711 +v -4.706808 0.009999 2.768711 +v -4.522227 0.009999 2.861001 +v -4.429937 0.009999 2.861001 +v -4.429937 0.009999 2.768711 +v -4.522227 0.009999 2.768711 +v -5.075970 0.009999 2.676420 +v -4.983679 0.009999 2.676420 +v -4.983679 0.009999 2.584130 +v -5.075970 0.009999 2.584130 +v -5.075970 0.009999 2.861001 +v -4.983679 0.009999 2.861001 +v -4.983679 0.009999 2.768711 +v -5.075970 0.009999 2.768711 +v -4.891389 0.009999 2.861001 +v -4.799098 0.009999 2.861001 +v -4.799098 0.009999 2.768711 +v -4.891389 0.009999 2.768711 +v -5.075970 0.009999 2.307259 +v -4.983679 0.009999 2.307259 +v -4.983679 0.009999 2.214968 +v -5.075970 0.009999 2.214968 +v -5.075970 0.009999 2.491840 +v -4.983679 0.009999 2.491840 +v -4.983679 0.009999 2.399549 +v -5.075970 0.009999 2.399549 +v -4.891389 0.009999 2.491840 +v -4.799098 0.009999 2.491840 +v -4.799098 0.009999 2.399549 +v -4.891389 0.009999 2.399549 +v -5.445131 0.010000 0.461452 +v -5.352840 0.010000 0.461452 +v -5.352840 0.010000 0.369161 +v -5.445131 0.010000 0.369161 +v -5.445131 0.010000 0.646033 +v -5.352840 0.010000 0.646033 +v -5.352840 0.010000 0.553742 +v -5.445131 0.010000 0.553742 +v -5.260550 0.010000 0.646033 +v -5.168260 0.010000 0.646033 +v -5.168260 0.010000 0.553742 +v -5.260550 0.010000 0.553742 +v -5.814293 0.010000 0.461452 +v -5.722002 0.010000 0.461452 +v -5.722002 0.010000 0.369161 +v -5.814293 0.010000 0.369161 +v -5.814293 0.010000 0.646033 +v -5.722002 0.010000 0.646033 +v -5.722002 0.010000 0.553742 +v -5.814293 0.010000 0.553742 +v -5.629711 0.010000 0.646033 +v -5.537421 0.010000 0.646033 +v -5.537421 0.010000 0.553742 +v -5.629711 0.010000 0.553742 +v -5.814293 0.010000 0.092290 +v -5.722002 0.010000 0.092290 +v -5.722002 0.010000 -0.000000 +v -5.814293 0.010000 -0.000000 +v -5.814293 0.010000 0.276871 +v -5.722002 0.010000 0.276871 +v -5.722002 0.010000 0.184581 +v -5.814293 0.010000 0.184581 +v -5.629711 0.010000 0.276871 +v -5.537421 0.010000 0.276871 +v -5.537421 0.010000 0.184581 +v -5.629711 0.010000 0.184581 +v -5.445131 0.010000 1.199775 +v -5.352840 0.010000 1.199775 +v -5.352840 0.010000 1.107484 +v -5.445131 0.010000 1.107484 +v -5.445131 0.009999 1.384355 +v -5.352840 0.009999 1.384355 +v -5.352840 0.009999 1.292065 +v -5.445131 0.009999 1.292065 +v -5.260550 0.009999 1.384355 +v -5.168260 0.009999 1.384355 +v -5.168260 0.009999 1.292065 +v -5.260550 0.009999 1.292065 +v -5.814293 0.010000 1.199775 +v -5.722002 0.010000 1.199775 +v -5.722002 0.010000 1.107484 +v -5.814293 0.010000 1.107484 +v -5.814293 0.009999 1.384355 +v -5.722002 0.009999 1.384355 +v -5.722002 0.009999 1.292065 +v -5.814293 0.009999 1.292065 +v -5.629711 0.009999 1.384355 +v -5.537421 0.009999 1.384355 +v -5.537421 0.009999 1.292065 +v -5.629711 0.009999 1.292065 +v -5.814293 0.010000 0.830613 +v -5.722002 0.010000 0.830613 +v -5.722002 0.010000 0.738323 +v -5.814293 0.010000 0.738323 +v -5.814293 0.010000 1.015194 +v -5.722002 0.010000 1.015194 +v -5.722002 0.010000 0.922904 +v -5.814293 0.010000 0.922904 +v -5.629711 0.010000 1.015194 +v -5.537421 0.010000 1.015194 +v -5.537421 0.010000 0.922904 +v -5.629711 0.010000 0.922904 +v -4.706808 0.010000 1.199775 +v -4.614518 0.010000 1.199775 +v -4.614518 0.010000 1.107484 +v -4.706808 0.010000 1.107484 +v -4.706808 0.009999 1.384355 +v -4.614518 0.009999 1.384355 +v -4.614518 0.009999 1.292065 +v -4.706808 0.009999 1.292065 +v -4.522227 0.009999 1.384355 +v -4.429937 0.009999 1.384355 +v -4.429937 0.009999 1.292065 +v -4.522227 0.009999 1.292065 +v -5.075970 0.010000 1.199775 +v -4.983679 0.010000 1.199775 +v -4.983679 0.010000 1.107484 +v -5.075970 0.010000 1.107484 +v -5.075970 0.009999 1.384355 +v -4.983679 0.009999 1.384355 +v -4.983679 0.009999 1.292065 +v -5.075970 0.009999 1.292065 +v -4.891389 0.009999 1.384355 +v -4.799098 0.009999 1.384355 +v -4.799098 0.009999 1.292065 +v -4.891389 0.009999 1.292065 +v -5.075970 0.010000 0.830613 +v -4.983679 0.010000 0.830613 +v -4.983679 0.010000 0.738323 +v -5.075970 0.010000 0.738323 +v -5.075970 0.010000 1.015194 +v -4.983679 0.010000 1.015194 +v -4.983679 0.010000 0.922904 +v -5.075970 0.010000 0.922904 +v -4.891389 0.010000 1.015194 +v -4.799098 0.010000 1.015194 +v -4.799098 0.010000 0.922904 +v -4.891389 0.010000 0.922904 +v -3.968485 0.009998 4.891389 +v -3.876195 0.009998 4.891389 +v -3.876195 0.009998 4.799098 +v -3.968485 0.009998 4.799098 +v -3.968485 0.009998 5.075970 +v -3.876195 0.009998 5.075970 +v -3.876195 0.009998 4.983679 +v -3.968485 0.009998 4.983679 +v -3.783905 0.009998 5.075970 +v -3.691614 0.009998 5.075970 +v -3.691614 0.009998 4.983679 +v -3.783905 0.009998 4.983679 +v -4.337647 0.009998 4.891389 +v -4.245357 0.009998 4.891389 +v -4.245357 0.009998 4.799098 +v -4.337647 0.009998 4.799098 +v -4.337647 0.009998 5.075970 +v -4.245357 0.009998 5.075970 +v -4.245357 0.009998 4.983679 +v -4.337647 0.009998 4.983679 +v -4.153066 0.009998 5.075970 +v -4.060776 0.009998 5.075970 +v -4.060776 0.009998 4.983679 +v -4.153066 0.009998 4.983679 +v -4.337647 0.009998 4.522227 +v -4.245357 0.009998 4.522227 +v -4.245357 0.009998 4.429937 +v -4.337647 0.009998 4.429937 +v -4.337647 0.009998 4.706808 +v -4.245357 0.009998 4.706808 +v -4.245357 0.009998 4.614518 +v -4.337647 0.009998 4.614518 +v -4.153066 0.009998 4.706808 +v -4.060776 0.009998 4.706808 +v -4.060776 0.009998 4.614518 +v -4.153066 0.009998 4.614518 +v -3.968485 0.009998 5.629711 +v -3.876195 0.009998 5.629711 +v -3.876195 0.009998 5.537421 +v -3.968485 0.009998 5.537421 +v -3.968485 0.009998 5.814293 +v -3.876195 0.009998 5.814293 +v -3.876195 0.009998 5.722002 +v -3.968485 0.009998 5.722002 +v -3.783905 0.009998 5.814293 +v -3.691614 0.009998 5.814293 +v -3.691614 0.009998 5.722002 +v -3.783905 0.009998 5.722002 +v -4.337647 0.009998 5.629711 +v -4.245357 0.009998 5.629711 +v -4.245357 0.009998 5.537421 +v -4.337647 0.009998 5.537421 +v -4.337647 0.009998 5.814293 +v -4.245357 0.009998 5.814293 +v -4.245357 0.009998 5.722002 +v -4.337647 0.009998 5.722002 +v -4.153066 0.009998 5.814293 +v -4.060776 0.009998 5.814293 +v -4.060776 0.009998 5.722002 +v -4.153066 0.009998 5.722002 +v -4.337647 0.009998 5.260550 +v -4.245357 0.009998 5.260550 +v -4.245357 0.009998 5.168260 +v -4.337647 0.009998 5.168260 +v -4.337647 0.009998 5.445131 +v -4.245357 0.009998 5.445131 +v -4.245357 0.009998 5.352840 +v -4.337647 0.009998 5.352840 +v -4.153066 0.009998 5.445131 +v -4.060776 0.009998 5.445131 +v -4.060776 0.009998 5.352840 +v -4.153066 0.009998 5.352840 +v -3.230163 0.009998 5.629711 +v -3.137872 0.009998 5.629711 +v -3.137872 0.009998 5.537421 +v -3.230163 0.009998 5.537421 +v -3.230163 0.009998 5.814293 +v -3.137872 0.009998 5.814293 +v -3.137872 0.009998 5.722002 +v -3.230163 0.009998 5.722002 +v -3.045582 0.009998 5.814293 +v -2.953291 0.009998 5.814293 +v -2.953291 0.009998 5.722002 +v -3.045582 0.009998 5.722002 +v -3.599324 0.009998 5.629711 +v -3.507033 0.009998 5.629711 +v -3.507033 0.009998 5.537421 +v -3.599324 0.009998 5.537421 +v -3.599324 0.009998 5.814293 +v -3.507033 0.009998 5.814293 +v -3.507033 0.009998 5.722002 +v -3.599324 0.009998 5.722002 +v -3.414743 0.009998 5.814293 +v -3.322453 0.009998 5.814293 +v -3.322453 0.009998 5.722002 +v -3.414743 0.009998 5.722002 +v -3.599324 0.009998 5.260550 +v -3.507033 0.009998 5.260550 +v -3.507033 0.009998 5.168260 +v -3.599324 0.009998 5.168260 +v -3.599324 0.009998 5.445131 +v -3.507033 0.009998 5.445131 +v -3.507033 0.009998 5.352840 +v -3.599324 0.009998 5.352840 +v -3.414743 0.009998 5.445131 +v -3.322453 0.009998 5.445131 +v -3.322453 0.009998 5.352840 +v -3.414743 0.009998 5.352840 +v -5.445131 0.009998 4.891389 +v -5.352840 0.009998 4.891389 +v -5.352840 0.009998 4.799098 +v -5.445131 0.009998 4.799098 +v -5.445131 0.009998 5.075970 +v -5.352840 0.009998 5.075970 +v -5.352840 0.009998 4.983679 +v -5.445131 0.009998 4.983679 +v -5.260550 0.009998 5.075970 +v -5.168260 0.009998 5.075970 +v -5.168260 0.009998 4.983679 +v -5.260550 0.009998 4.983679 +v -5.814293 0.009998 4.891389 +v -5.722002 0.009998 4.891389 +v -5.722002 0.009998 4.799098 +v -5.814293 0.009998 4.799098 +v -5.814293 0.009998 5.075970 +v -5.722002 0.009998 5.075970 +v -5.722002 0.009998 4.983679 +v -5.814293 0.009998 4.983679 +v -5.629711 0.009998 5.075970 +v -5.537421 0.009998 5.075970 +v -5.537421 0.009998 4.983679 +v -5.629711 0.009998 4.983679 +v -5.814293 0.009998 4.522227 +v -5.722002 0.009998 4.522227 +v -5.722002 0.009998 4.429937 +v -5.814293 0.009998 4.429937 +v -5.814293 0.009998 4.706808 +v -5.722002 0.009998 4.706808 +v -5.722002 0.009998 4.614518 +v -5.814293 0.009998 4.614518 +v -5.629711 0.009998 4.706808 +v -5.537421 0.009998 4.706808 +v -5.537421 0.009998 4.614518 +v -5.629711 0.009998 4.614518 +v -5.445131 0.009998 5.629711 +v -5.352840 0.009998 5.629711 +v -5.352840 0.009998 5.537421 +v -5.445131 0.009998 5.537421 +v -5.445131 0.009998 5.814293 +v -5.352840 0.009998 5.814293 +v -5.352840 0.009998 5.722002 +v -5.445131 0.009998 5.722002 +v -5.260550 0.009998 5.814293 +v -5.168260 0.009998 5.814293 +v -5.168260 0.009998 5.722002 +v -5.260550 0.009998 5.722002 +v -5.814293 0.009998 5.629711 +v -5.722002 0.009998 5.629711 +v -5.722002 0.009998 5.537421 +v -5.814293 0.009998 5.537421 +v -5.814293 0.009998 5.814293 +v -5.722002 0.009998 5.814293 +v -5.722002 0.009998 5.722002 +v -5.814293 0.009998 5.722002 +v -5.629711 0.009998 5.814293 +v -5.537421 0.009998 5.814293 +v -5.537421 0.009998 5.722002 +v -5.629711 0.009998 5.722002 +v -5.814293 0.009998 5.260550 +v -5.722002 0.009998 5.260550 +v -5.722002 0.009998 5.168260 +v -5.814293 0.009998 5.168260 +v -5.814293 0.009998 5.445131 +v -5.722002 0.009998 5.445131 +v -5.722002 0.009998 5.352840 +v -5.814293 0.009998 5.352840 +v -5.629711 0.009998 5.445131 +v -5.537421 0.009998 5.445131 +v -5.537421 0.009998 5.352840 +v -5.629711 0.009998 5.352840 +v -4.706808 0.009998 5.629711 +v -4.614518 0.009998 5.629711 +v -4.614518 0.009998 5.537421 +v -4.706808 0.009998 5.537421 +v -4.706808 0.009998 5.814293 +v -4.614518 0.009998 5.814293 +v -4.614518 0.009998 5.722002 +v -4.706808 0.009998 5.722002 +v -4.522227 0.009998 5.814293 +v -4.429937 0.009998 5.814293 +v -4.429937 0.009998 5.722002 +v -4.522227 0.009998 5.722002 +v -5.075970 0.009998 5.629711 +v -4.983679 0.009998 5.629711 +v -4.983679 0.009998 5.537421 +v -5.075970 0.009998 5.537421 +v -5.075970 0.009998 5.814293 +v -4.983679 0.009998 5.814293 +v -4.983679 0.009998 5.722002 +v -5.075970 0.009998 5.722002 +v -4.891389 0.009998 5.814293 +v -4.799098 0.009998 5.814293 +v -4.799098 0.009998 5.722002 +v -4.891389 0.009998 5.722002 +v -5.075970 0.009998 5.260550 +v -4.983679 0.009998 5.260550 +v -4.983679 0.009998 5.168260 +v -5.075970 0.009998 5.168260 +v -5.075970 0.009998 5.445131 +v -4.983679 0.009998 5.445131 +v -4.983679 0.009998 5.352840 +v -5.075970 0.009998 5.352840 +v -4.891389 0.009998 5.445131 +v -4.799098 0.009998 5.445131 +v -4.799098 0.009998 5.352840 +v -4.891389 0.009998 5.352840 +v -5.445131 0.009999 3.414743 +v -5.352840 0.009999 3.414743 +v -5.352840 0.009999 3.322453 +v -5.445131 0.009999 3.322453 +v -5.445131 0.009999 3.599324 +v -5.352840 0.009999 3.599324 +v -5.352840 0.009999 3.507033 +v -5.445131 0.009999 3.507033 +v -5.260550 0.009999 3.599324 +v -5.168260 0.009999 3.599324 +v -5.168260 0.009999 3.507033 +v -5.260550 0.009999 3.507033 +v -5.814293 0.009999 3.414743 +v -5.722002 0.009999 3.414743 +v -5.722002 0.009999 3.322453 +v -5.814293 0.009999 3.322453 +v -5.814293 0.009999 3.599324 +v -5.722002 0.009999 3.599324 +v -5.722002 0.009999 3.507033 +v -5.814293 0.009999 3.507033 +v -5.629711 0.009999 3.599324 +v -5.537421 0.009999 3.599324 +v -5.537421 0.009999 3.507033 +v -5.629711 0.009999 3.507033 +v -5.814293 0.009999 3.045582 +v -5.722002 0.009999 3.045582 +v -5.722002 0.009999 2.953291 +v -5.814293 0.009999 2.953291 +v -5.814293 0.009999 3.230163 +v -5.722002 0.009999 3.230163 +v -5.722002 0.009999 3.137872 +v -5.814293 0.009999 3.137872 +v -5.629711 0.009999 3.230163 +v -5.537421 0.009999 3.230163 +v -5.537421 0.009999 3.137872 +v -5.629711 0.009999 3.137872 +v -5.445131 0.009998 4.153066 +v -5.352840 0.009998 4.153066 +v -5.352840 0.009998 4.060776 +v -5.445131 0.009998 4.060776 +v -5.445131 0.009998 4.337647 +v -5.352840 0.009998 4.337647 +v -5.352840 0.009998 4.245357 +v -5.445131 0.009998 4.245357 +v -5.260550 0.009998 4.337647 +v -5.168260 0.009998 4.337647 +v -5.168260 0.009998 4.245357 +v -5.260550 0.009998 4.245357 +v -5.814293 0.009998 4.153066 +v -5.722002 0.009998 4.153066 +v -5.722002 0.009998 4.060776 +v -5.814293 0.009998 4.060776 +v -5.814293 0.009998 4.337647 +v -5.722002 0.009998 4.337647 +v -5.722002 0.009998 4.245357 +v -5.814293 0.009998 4.245357 +v -5.629711 0.009998 4.337647 +v -5.537421 0.009998 4.337647 +v -5.537421 0.009998 4.245357 +v -5.629711 0.009998 4.245357 +v -5.814293 0.009998 3.783905 +v -5.722002 0.009998 3.783905 +v -5.722002 0.009998 3.691614 +v -5.814293 0.009998 3.691614 +v -5.814293 0.009998 3.968485 +v -5.722002 0.009998 3.968485 +v -5.722002 0.009998 3.876195 +v -5.814293 0.009998 3.876195 +v -5.629711 0.009998 3.968485 +v -5.537421 0.009998 3.968485 +v -5.537421 0.009998 3.876195 +v -5.629711 0.009998 3.876195 +v -4.706808 0.009998 4.153066 +v -4.614518 0.009998 4.153066 +v -4.614518 0.009998 4.060776 +v -4.706808 0.009998 4.060776 +v -4.706808 0.009998 4.337647 +v -4.614518 0.009998 4.337647 +v -4.614518 0.009998 4.245357 +v -4.706808 0.009998 4.245357 +v -4.522227 0.009998 4.337647 +v -4.429937 0.009998 4.337647 +v -4.429937 0.009998 4.245357 +v -4.522227 0.009998 4.245357 +v -5.075970 0.009998 4.153066 +v -4.983679 0.009998 4.153066 +v -4.983679 0.009998 4.060776 +v -5.075970 0.009998 4.060776 +v -5.075970 0.009998 4.337647 +v -4.983679 0.009998 4.337647 +v -4.983679 0.009998 4.245357 +v -5.075970 0.009998 4.245357 +v -4.891389 0.009998 4.337647 +v -4.799098 0.009998 4.337647 +v -4.799098 0.009998 4.245357 +v -4.891389 0.009998 4.245357 +v -5.075970 0.009998 3.783905 +v -4.983679 0.009998 3.783905 +v -4.983679 0.009998 3.691614 +v -5.075970 0.009998 3.691614 +v -5.075970 0.009998 3.968485 +v -4.983679 0.009998 3.968485 +v -4.983679 0.009998 3.876195 +v -5.075970 0.009998 3.876195 +v -4.891389 0.009998 3.968485 +v -4.799098 0.009998 3.968485 +v -4.799098 0.009998 3.876195 +v -4.891389 0.009998 3.876195 +v -1.015194 0.009998 4.891389 +v -0.922904 0.009998 4.891389 +v -0.922904 0.009998 4.799098 +v -1.015194 0.009998 4.799098 +v -1.015194 0.009998 5.075970 +v -0.922904 0.009998 5.075970 +v -0.922904 0.009998 4.983679 +v -1.015194 0.009998 4.983679 +v -0.830613 0.009998 5.075970 +v -0.738323 0.009998 5.075970 +v -0.738323 0.009998 4.983679 +v -0.830613 0.009998 4.983679 +v -1.384355 0.009998 4.891389 +v -1.292065 0.009998 4.891389 +v -1.292065 0.009998 4.799098 +v -1.384355 0.009998 4.799098 +v -1.384355 0.009998 5.075970 +v -1.292065 0.009998 5.075970 +v -1.292065 0.009998 4.983679 +v -1.384355 0.009998 4.983679 +v -1.199775 0.009998 5.075970 +v -1.107484 0.009998 5.075970 +v -1.107484 0.009998 4.983679 +v -1.199775 0.009998 4.983679 +v -1.384355 0.009998 4.522227 +v -1.292065 0.009998 4.522227 +v -1.292065 0.009998 4.429937 +v -1.384355 0.009998 4.429937 +v -1.384355 0.009998 4.706808 +v -1.292065 0.009998 4.706808 +v -1.292065 0.009998 4.614518 +v -1.384355 0.009998 4.614518 +v -1.199775 0.009998 4.706808 +v -1.107484 0.009998 4.706808 +v -1.107484 0.009998 4.614518 +v -1.199775 0.009998 4.614518 +v -1.015194 0.009998 5.629711 +v -0.922904 0.009998 5.629711 +v -0.922904 0.009998 5.537421 +v -1.015194 0.009998 5.537421 +v -1.015194 0.009998 5.814293 +v -0.922904 0.009998 5.814293 +v -0.922904 0.009998 5.722002 +v -1.015194 0.009998 5.722002 +v -0.830613 0.009998 5.814293 +v -0.738323 0.009998 5.814293 +v -0.738323 0.009998 5.722002 +v -0.830613 0.009998 5.722002 +v -1.384355 0.009998 5.629711 +v -1.292065 0.009998 5.629711 +v -1.292065 0.009998 5.537421 +v -1.384355 0.009998 5.537421 +v -1.384355 0.009998 5.814293 +v -1.292065 0.009998 5.814293 +v -1.292065 0.009998 5.722002 +v -1.384355 0.009998 5.722002 +v -1.199775 0.009998 5.814293 +v -1.107484 0.009998 5.814293 +v -1.107484 0.009998 5.722002 +v -1.199775 0.009998 5.722002 +v -1.384355 0.009998 5.260550 +v -1.292065 0.009998 5.260550 +v -1.292065 0.009998 5.168260 +v -1.384355 0.009998 5.168260 +v -1.384355 0.009998 5.445131 +v -1.292065 0.009998 5.445131 +v -1.292065 0.009998 5.352840 +v -1.384355 0.009998 5.352840 +v -1.199775 0.009998 5.445131 +v -1.107484 0.009998 5.445131 +v -1.107484 0.009998 5.352840 +v -1.199775 0.009998 5.352840 +v -0.276871 0.009998 5.629711 +v -0.184581 0.009998 5.629711 +v -0.184581 0.009998 5.537421 +v -0.276871 0.009998 5.537421 +v -0.276871 0.009998 5.814293 +v -0.184581 0.009998 5.814293 +v -0.184581 0.009998 5.722002 +v -0.276871 0.009998 5.722002 +v -0.092290 0.009998 5.814293 +v 0.000000 0.009998 5.814293 +v 0.000000 0.009998 5.722002 +v -0.092290 0.009998 5.722002 +v -0.646033 0.009998 5.629711 +v -0.553742 0.009998 5.629711 +v -0.553742 0.009998 5.537421 +v -0.646033 0.009998 5.537421 +v -0.646033 0.009998 5.814293 +v -0.553742 0.009998 5.814293 +v -0.553742 0.009998 5.722002 +v -0.646033 0.009998 5.722002 +v -0.461452 0.009998 5.814293 +v -0.369161 0.009998 5.814293 +v -0.369161 0.009998 5.722002 +v -0.461452 0.009998 5.722002 +v -0.646033 0.009998 5.260550 +v -0.553742 0.009998 5.260550 +v -0.553742 0.009998 5.168260 +v -0.646033 0.009998 5.168260 +v -0.646033 0.009998 5.445131 +v -0.553742 0.009998 5.445131 +v -0.553742 0.009998 5.352840 +v -0.646033 0.009998 5.352840 +v -0.461452 0.009998 5.445131 +v -0.369161 0.009998 5.445131 +v -0.369161 0.009998 5.352840 +v -0.461452 0.009998 5.352840 +v -2.491840 0.009998 4.891389 +v -2.399549 0.009998 4.891389 +v -2.399549 0.009998 4.799098 +v -2.491840 0.009998 4.799098 +v -2.491840 0.009998 5.075970 +v -2.399549 0.009998 5.075970 +v -2.399549 0.009998 4.983679 +v -2.491840 0.009998 4.983679 +v -2.307259 0.009998 5.075970 +v -2.214968 0.009998 5.075970 +v -2.214968 0.009998 4.983679 +v -2.307259 0.009998 4.983679 +v -2.861001 0.009998 4.891389 +v -2.768711 0.009998 4.891389 +v -2.768711 0.009998 4.799098 +v -2.861001 0.009998 4.799098 +v -2.861001 0.009998 5.075970 +v -2.768711 0.009998 5.075970 +v -2.768711 0.009998 4.983679 +v -2.861001 0.009998 4.983679 +v -2.676420 0.009998 5.075970 +v -2.584130 0.009998 5.075970 +v -2.584130 0.009998 4.983679 +v -2.676420 0.009998 4.983679 +v -2.861001 0.009998 4.522227 +v -2.768711 0.009998 4.522227 +v -2.768711 0.009998 4.429937 +v -2.861001 0.009998 4.429937 +v -2.861001 0.009998 4.706808 +v -2.768711 0.009998 4.706808 +v -2.768711 0.009998 4.614518 +v -2.861001 0.009998 4.614518 +v -2.676420 0.009998 4.706808 +v -2.584130 0.009998 4.706808 +v -2.584130 0.009998 4.614518 +v -2.676420 0.009998 4.614518 +v -2.491840 0.009998 5.629711 +v -2.399549 0.009998 5.629711 +v -2.399549 0.009998 5.537421 +v -2.491840 0.009998 5.537421 +v -2.491840 0.009998 5.814293 +v -2.399549 0.009998 5.814293 +v -2.399549 0.009998 5.722002 +v -2.491840 0.009998 5.722002 +v -2.307259 0.009998 5.814293 +v -2.214968 0.009998 5.814293 +v -2.214968 0.009998 5.722002 +v -2.307259 0.009998 5.722002 +v -2.861001 0.009998 5.629711 +v -2.768711 0.009998 5.629711 +v -2.768711 0.009998 5.537421 +v -2.861001 0.009998 5.537421 +v -2.861001 0.009998 5.814293 +v -2.768711 0.009998 5.814293 +v -2.768711 0.009998 5.722002 +v -2.861001 0.009998 5.722002 +v -2.676420 0.009998 5.814293 +v -2.584130 0.009998 5.814293 +v -2.584130 0.009998 5.722002 +v -2.676420 0.009998 5.722002 +v -2.861001 0.009998 5.260550 +v -2.768711 0.009998 5.260550 +v -2.768711 0.009998 5.168260 +v -2.861001 0.009998 5.168260 +v -2.861001 0.009998 5.445131 +v -2.768711 0.009998 5.445131 +v -2.768711 0.009998 5.352840 +v -2.861001 0.009998 5.352840 +v -2.676420 0.009998 5.445131 +v -2.584130 0.009998 5.445131 +v -2.584130 0.009998 5.352840 +v -2.676420 0.009998 5.352840 +v -1.753517 0.009998 5.629711 +v -1.661226 0.009998 5.629711 +v -1.661226 0.009998 5.537421 +v -1.753517 0.009998 5.537421 +v -1.753517 0.009998 5.814293 +v -1.661226 0.009998 5.814293 +v -1.661226 0.009998 5.722002 +v -1.753517 0.009998 5.722002 +v -1.568936 0.009998 5.814293 +v -1.476646 0.009998 5.814293 +v -1.476646 0.009998 5.722002 +v -1.568936 0.009998 5.722002 +v -2.122678 0.009998 5.629711 +v -2.030388 0.009998 5.629711 +v -2.030388 0.009998 5.537421 +v -2.122678 0.009998 5.537421 +v -2.122678 0.009998 5.814293 +v -2.030388 0.009998 5.814293 +v -2.030388 0.009998 5.722002 +v -2.122678 0.009998 5.722002 +v -1.938097 0.009998 5.814293 +v -1.845807 0.009998 5.814293 +v -1.845807 0.009998 5.722002 +v -1.938097 0.009998 5.722002 +v -2.122678 0.009998 5.260550 +v -2.030388 0.009998 5.260550 +v -2.030388 0.009998 5.168260 +v -2.122678 0.009998 5.168260 +v -2.122678 0.009998 5.445131 +v -2.030388 0.009998 5.445131 +v -2.030388 0.009998 5.352840 +v -2.122678 0.009998 5.352840 +v -1.938097 0.009998 5.445131 +v -1.845807 0.009998 5.445131 +v -1.845807 0.009998 5.352840 +v -1.938097 0.009998 5.352840 +v -2.491840 0.009999 3.414743 +v -2.399549 0.009999 3.414743 +v -2.399549 0.009999 3.322453 +v -2.491840 0.009999 3.322453 +v -2.491840 0.009999 3.599324 +v -2.399549 0.009999 3.599324 +v -2.399549 0.009999 3.507033 +v -2.491840 0.009999 3.507033 +v -2.307259 0.009999 3.599324 +v -2.214968 0.009999 3.599324 +v -2.214968 0.009999 3.507033 +v -2.307259 0.009999 3.507033 +v -2.861001 0.009999 3.414743 +v -2.768711 0.009999 3.414743 +v -2.768711 0.009999 3.322453 +v -2.861001 0.009999 3.322453 +v -2.861001 0.009999 3.599324 +v -2.768711 0.009999 3.599324 +v -2.768711 0.009999 3.507033 +v -2.861001 0.009999 3.507033 +v -2.676420 0.009999 3.599324 +v -2.584130 0.009999 3.599324 +v -2.584130 0.009999 3.507033 +v -2.676420 0.009999 3.507033 +v -2.861001 0.009999 3.045582 +v -2.768711 0.009999 3.045582 +v -2.768711 0.009999 2.953291 +v -2.861001 0.009999 2.953291 +v -2.861001 0.009999 3.230163 +v -2.768711 0.009999 3.230163 +v -2.768711 0.009999 3.137872 +v -2.861001 0.009999 3.137872 +v -2.676420 0.009999 3.230163 +v -2.584130 0.009999 3.230163 +v -2.584130 0.009999 3.137872 +v -2.676420 0.009999 3.137872 +v -2.491840 0.009998 4.153066 +v -2.399549 0.009998 4.153066 +v -2.399549 0.009998 4.060776 +v -2.491840 0.009998 4.060776 +v -2.491840 0.009998 4.337647 +v -2.399549 0.009998 4.337647 +v -2.399549 0.009998 4.245357 +v -2.491840 0.009998 4.245357 +v -2.307259 0.009998 4.337647 +v -2.214968 0.009998 4.337647 +v -2.214968 0.009998 4.245357 +v -2.307259 0.009998 4.245357 +v -2.861001 0.009998 4.153066 +v -2.768711 0.009998 4.153066 +v -2.768711 0.009998 4.060776 +v -2.861001 0.009998 4.060776 +v -2.861001 0.009998 4.337647 +v -2.768711 0.009998 4.337647 +v -2.768711 0.009998 4.245357 +v -2.861001 0.009998 4.245357 +v -2.676420 0.009998 4.337647 +v -2.584130 0.009998 4.337647 +v -2.584130 0.009998 4.245357 +v -2.676420 0.009998 4.245357 +v -2.861001 0.009998 3.783905 +v -2.768711 0.009998 3.783905 +v -2.768711 0.009998 3.691614 +v -2.861001 0.009998 3.691614 +v -2.861001 0.009998 3.968485 +v -2.768711 0.009998 3.968485 +v -2.768711 0.009998 3.876195 +v -2.861001 0.009998 3.876195 +v -2.676420 0.009998 3.968485 +v -2.584130 0.009998 3.968485 +v -2.584130 0.009998 3.876195 +v -2.676420 0.009998 3.876195 +v -1.753517 0.009998 4.153066 +v -1.661226 0.009998 4.153066 +v -1.661226 0.009998 4.060776 +v -1.753517 0.009998 4.060776 +v -1.753517 0.009998 4.337647 +v -1.661226 0.009998 4.337647 +v -1.661226 0.009998 4.245357 +v -1.753517 0.009998 4.245357 +v -1.568936 0.009998 4.337647 +v -1.476646 0.009998 4.337647 +v -1.476646 0.009998 4.245357 +v -1.568936 0.009998 4.245357 +v -2.122678 0.009998 4.153066 +v -2.030388 0.009998 4.153066 +v -2.030388 0.009998 4.060776 +v -2.122678 0.009998 4.060776 +v -2.122678 0.009998 4.337647 +v -2.030388 0.009998 4.337647 +v -2.030388 0.009998 4.245357 +v -2.122678 0.009998 4.245357 +v -1.938097 0.009998 4.337647 +v -1.845807 0.009998 4.337647 +v -1.845807 0.009998 4.245357 +v -1.938097 0.009998 4.245357 +v -2.122678 0.009998 3.783905 +v -2.030388 0.009998 3.783905 +v -2.030388 0.009998 3.691614 +v -2.122678 0.009998 3.691614 +v -2.122678 0.009998 3.968485 +v -2.030388 0.009998 3.968485 +v -2.030388 0.009998 3.876195 +v -2.122678 0.009998 3.876195 +v -1.938097 0.009998 3.968485 +v -1.845807 0.009998 3.968485 +v -1.845807 0.009998 3.876195 +v -1.938097 0.009998 3.876195 +v -3.968485 0.010002 -3.968485 +v -3.876195 0.010002 -3.968485 +v -3.876195 0.010002 -4.060776 +v -3.968485 0.010002 -4.060776 +v -3.968485 0.010002 -3.783905 +v -3.876195 0.010002 -3.783905 +v -3.876195 0.010002 -3.876195 +v -3.968485 0.010002 -3.876195 +v -3.783905 0.010002 -3.783905 +v -3.691614 0.010002 -3.783905 +v -3.691614 0.010002 -3.876195 +v -3.783905 0.010002 -3.876195 +v -4.337647 0.010002 -3.968485 +v -4.245357 0.010002 -3.968485 +v -4.245357 0.010002 -4.060776 +v -4.337647 0.010002 -4.060776 +v -4.337647 0.010002 -3.783905 +v -4.245357 0.010002 -3.783905 +v -4.245357 0.010002 -3.876195 +v -4.337647 0.010002 -3.876195 +v -4.153066 0.010002 -3.783905 +v -4.060776 0.010002 -3.783905 +v -4.060776 0.010002 -3.876195 +v -4.153066 0.010002 -3.876195 +v -4.337647 0.010002 -4.337647 +v -4.245357 0.010002 -4.337647 +v -4.245357 0.010002 -4.429937 +v -4.337647 0.010002 -4.429937 +v -4.337647 0.010002 -4.153066 +v -4.245357 0.010002 -4.153066 +v -4.245357 0.010002 -4.245357 +v -4.337647 0.010002 -4.245357 +v -4.153066 0.010002 -4.153066 +v -4.060776 0.010002 -4.153066 +v -4.060776 0.010002 -4.245357 +v -4.153066 0.010002 -4.245357 +v -3.968485 0.010001 -3.230163 +v -3.876195 0.010001 -3.230163 +v -3.876195 0.010001 -3.322453 +v -3.968485 0.010001 -3.322453 +v -3.968485 0.010001 -3.045582 +v -3.876195 0.010001 -3.045582 +v -3.876195 0.010001 -3.137872 +v -3.968485 0.010001 -3.137872 +v -3.783905 0.010001 -3.045582 +v -3.691614 0.010001 -3.045582 +v -3.691614 0.010001 -3.137872 +v -3.783905 0.010001 -3.137872 +v -4.337647 0.010001 -3.230163 +v -4.245357 0.010001 -3.230163 +v -4.245357 0.010001 -3.322453 +v -4.337647 0.010001 -3.322453 +v -4.337647 0.010001 -3.045582 +v -4.245357 0.010001 -3.045582 +v -4.245357 0.010001 -3.137872 +v -4.337647 0.010001 -3.137872 +v -4.153066 0.010001 -3.045582 +v -4.060776 0.010001 -3.045582 +v -4.060776 0.010001 -3.137872 +v -4.153066 0.010001 -3.137872 +v -4.337647 0.010001 -3.599324 +v -4.245357 0.010001 -3.599324 +v -4.245357 0.010002 -3.691614 +v -4.337647 0.010002 -3.691614 +v -4.337647 0.010001 -3.414743 +v -4.245357 0.010001 -3.414743 +v -4.245357 0.010001 -3.507033 +v -4.337647 0.010001 -3.507033 +v -4.153066 0.010001 -3.414743 +v -4.060776 0.010001 -3.414743 +v -4.060776 0.010001 -3.507033 +v -4.153066 0.010001 -3.507033 +v -3.230163 0.010001 -3.230163 +v -3.137872 0.010001 -3.230163 +v -3.137872 0.010001 -3.322453 +v -3.230163 0.010001 -3.322453 +v -3.230163 0.010001 -3.045582 +v -3.137872 0.010001 -3.045582 +v -3.137872 0.010001 -3.137872 +v -3.230163 0.010001 -3.137872 +v -3.045582 0.010001 -3.045582 +v -2.953291 0.010001 -3.045582 +v -2.953291 0.010001 -3.137872 +v -3.045582 0.010001 -3.137872 +v -3.599324 0.010001 -3.230163 +v -3.507033 0.010001 -3.230163 +v -3.507033 0.010001 -3.322453 +v -3.599324 0.010001 -3.322453 +v -3.599324 0.010001 -3.045582 +v -3.507033 0.010001 -3.045582 +v -3.507033 0.010001 -3.137872 +v -3.599324 0.010001 -3.137872 +v -3.414743 0.010001 -3.045582 +v -3.322453 0.010001 -3.045582 +v -3.322453 0.010001 -3.137872 +v -3.414743 0.010001 -3.137872 +v -3.599324 0.010001 -3.599324 +v -3.507033 0.010001 -3.599324 +v -3.507033 0.010002 -3.691614 +v -3.599324 0.010002 -3.691614 +v -3.599324 0.010001 -3.414743 +v -3.507033 0.010001 -3.414743 +v -3.507033 0.010001 -3.507033 +v -3.599324 0.010001 -3.507033 +v -3.414743 0.010001 -3.414743 +v -3.322453 0.010001 -3.414743 +v -3.322453 0.010001 -3.507033 +v -3.414743 0.010001 -3.507033 +v -5.445131 0.010002 -3.968485 +v -5.352840 0.010002 -3.968485 +v -5.352840 0.010002 -4.060776 +v -5.445131 0.010002 -4.060776 +v -5.445131 0.010002 -3.783905 +v -5.352840 0.010002 -3.783905 +v -5.352840 0.010002 -3.876195 +v -5.445131 0.010002 -3.876195 +v -5.260550 0.010002 -3.783905 +v -5.168260 0.010002 -3.783905 +v -5.168260 0.010002 -3.876195 +v -5.260550 0.010002 -3.876195 +v -5.814293 0.010002 -3.968485 +v -5.722002 0.010002 -3.968485 +v -5.722002 0.010002 -4.060776 +v -5.814293 0.010002 -4.060776 +v -5.814293 0.010002 -3.783905 +v -5.722002 0.010002 -3.783905 +v -5.722002 0.010002 -3.876195 +v -5.814293 0.010002 -3.876195 +v -5.629711 0.010002 -3.783905 +v -5.537421 0.010002 -3.783905 +v -5.537421 0.010002 -3.876195 +v -5.629711 0.010002 -3.876195 +v -5.814293 0.010002 -4.337647 +v -5.722002 0.010002 -4.337647 +v -5.722002 0.010002 -4.429937 +v -5.814293 0.010002 -4.429937 +v -5.814293 0.010002 -4.153066 +v -5.722002 0.010002 -4.153066 +v -5.722002 0.010002 -4.245357 +v -5.814293 0.010002 -4.245357 +v -5.629711 0.010002 -4.153066 +v -5.537421 0.010002 -4.153066 +v -5.537421 0.010002 -4.245357 +v -5.629711 0.010002 -4.245357 +v -5.445131 0.010001 -3.230163 +v -5.352840 0.010001 -3.230163 +v -5.352840 0.010001 -3.322453 +v -5.445131 0.010001 -3.322453 +v -5.445131 0.010001 -3.045582 +v -5.352840 0.010001 -3.045582 +v -5.352840 0.010001 -3.137872 +v -5.445131 0.010001 -3.137872 +v -5.260550 0.010001 -3.045582 +v -5.168260 0.010001 -3.045582 +v -5.168260 0.010001 -3.137872 +v -5.260550 0.010001 -3.137872 +v -5.814293 0.010001 -3.230163 +v -5.722002 0.010001 -3.230163 +v -5.722002 0.010001 -3.322453 +v -5.814293 0.010001 -3.322453 +v -5.814293 0.010001 -3.045582 +v -5.722002 0.010001 -3.045582 +v -5.722002 0.010001 -3.137872 +v -5.814293 0.010001 -3.137872 +v -5.629711 0.010001 -3.045582 +v -5.537421 0.010001 -3.045582 +v -5.537421 0.010001 -3.137872 +v -5.629711 0.010001 -3.137872 +v -5.814293 0.010001 -3.599324 +v -5.722002 0.010001 -3.599324 +v -5.722002 0.010002 -3.691614 +v -5.814293 0.010002 -3.691614 +v -5.814293 0.010001 -3.414743 +v -5.722002 0.010001 -3.414743 +v -5.722002 0.010001 -3.507033 +v -5.814293 0.010001 -3.507033 +v -5.629711 0.010001 -3.414743 +v -5.537421 0.010001 -3.414743 +v -5.537421 0.010001 -3.507033 +v -5.629711 0.010001 -3.507033 +v -4.706808 0.010001 -3.230163 +v -4.614518 0.010001 -3.230163 +v -4.614518 0.010001 -3.322453 +v -4.706808 0.010001 -3.322453 +v -4.706808 0.010001 -3.045582 +v -4.614518 0.010001 -3.045582 +v -4.614518 0.010001 -3.137872 +v -4.706808 0.010001 -3.137872 +v -4.522227 0.010001 -3.045582 +v -4.429937 0.010001 -3.045582 +v -4.429937 0.010001 -3.137872 +v -4.522227 0.010001 -3.137872 +v -5.075970 0.010001 -3.230163 +v -4.983679 0.010001 -3.230163 +v -4.983679 0.010001 -3.322453 +v -5.075970 0.010001 -3.322453 +v -5.075970 0.010001 -3.045582 +v -4.983679 0.010001 -3.045582 +v -4.983679 0.010001 -3.137872 +v -5.075970 0.010001 -3.137872 +v -4.891389 0.010001 -3.045582 +v -4.799098 0.010001 -3.045582 +v -4.799098 0.010001 -3.137872 +v -4.891389 0.010001 -3.137872 +v -5.075970 0.010001 -3.599324 +v -4.983679 0.010001 -3.599324 +v -4.983679 0.010002 -3.691614 +v -5.075970 0.010002 -3.691614 +v -5.075970 0.010001 -3.414743 +v -4.983679 0.010001 -3.414743 +v -4.983679 0.010001 -3.507033 +v -5.075970 0.010001 -3.507033 +v -4.891389 0.010001 -3.414743 +v -4.799098 0.010001 -3.414743 +v -4.799098 0.010001 -3.507033 +v -4.891389 0.010001 -3.507033 +v -5.445131 0.010002 -5.445131 +v -5.352840 0.010002 -5.445131 +v -5.352840 0.010002 -5.537421 +v -5.445131 0.010002 -5.537421 +v -5.445131 0.010002 -5.260550 +v -5.352840 0.010002 -5.260550 +v -5.352840 0.010002 -5.352840 +v -5.445131 0.010002 -5.352840 +v -5.260550 0.010002 -5.260550 +v -5.168260 0.010002 -5.260550 +v -5.168260 0.010002 -5.352840 +v -5.260550 0.010002 -5.352840 +v -5.814293 0.010002 -5.445131 +v -5.722002 0.010002 -5.445131 +v -5.722002 0.010002 -5.537421 +v -5.814293 0.010002 -5.537421 +v -5.814293 0.010002 -5.260550 +v -5.722002 0.010002 -5.260550 +v -5.722002 0.010002 -5.352840 +v -5.814293 0.010002 -5.352840 +v -5.629711 0.010002 -5.260550 +v -5.537421 0.010002 -5.260550 +v -5.537421 0.010002 -5.352840 +v -5.629711 0.010002 -5.352840 +v -5.814293 0.010002 -5.814293 +v -5.722002 0.010002 -5.814293 +v -5.722002 0.010002 -5.906583 +v -5.814293 0.010002 -5.906583 +v -5.814293 0.010002 -5.629711 +v -5.722002 0.010002 -5.629711 +v -5.722002 0.010002 -5.722002 +v -5.814293 0.010002 -5.722002 +v -5.629711 0.010002 -5.629711 +v -5.537421 0.010002 -5.629711 +v -5.537421 0.010002 -5.722002 +v -5.629711 0.010002 -5.722002 +v -5.445131 0.010002 -4.706808 +v -5.352840 0.010002 -4.706808 +v -5.352840 0.010002 -4.799098 +v -5.445131 0.010002 -4.799098 +v -5.445131 0.010002 -4.522227 +v -5.352840 0.010002 -4.522227 +v -5.352840 0.010002 -4.614518 +v -5.445131 0.010002 -4.614518 +v -5.260550 0.010002 -4.522227 +v -5.168260 0.010002 -4.522227 +v -5.168260 0.010002 -4.614518 +v -5.260550 0.010002 -4.614518 +v -5.814293 0.010002 -4.706808 +v -5.722002 0.010002 -4.706808 +v -5.722002 0.010002 -4.799098 +v -5.814293 0.010002 -4.799098 +v -5.814293 0.010002 -4.522227 +v -5.722002 0.010002 -4.522227 +v -5.722002 0.010002 -4.614518 +v -5.814293 0.010002 -4.614518 +v -5.629711 0.010002 -4.522227 +v -5.537421 0.010002 -4.522227 +v -5.537421 0.010002 -4.614518 +v -5.629711 0.010002 -4.614518 +v -5.814293 0.010002 -5.075970 +v -5.722002 0.010002 -5.075970 +v -5.722002 0.010002 -5.168260 +v -5.814293 0.010002 -5.168260 +v -5.814293 0.010002 -4.891389 +v -5.722002 0.010002 -4.891389 +v -5.722002 0.010002 -4.983679 +v -5.814293 0.010002 -4.983679 +v -5.629711 0.010002 -4.891389 +v -5.537421 0.010002 -4.891389 +v -5.537421 0.010002 -4.983679 +v -5.629711 0.010002 -4.983679 +v -4.706808 0.010002 -4.706808 +v -4.614518 0.010002 -4.706808 +v -4.614518 0.010002 -4.799098 +v -4.706808 0.010002 -4.799098 +v -4.706808 0.010002 -4.522227 +v -4.614518 0.010002 -4.522227 +v -4.614518 0.010002 -4.614518 +v -4.706808 0.010002 -4.614518 +v -4.522227 0.010002 -4.522227 +v -4.429937 0.010002 -4.522227 +v -4.429937 0.010002 -4.614518 +v -4.522227 0.010002 -4.614518 +v -5.075970 0.010002 -4.706808 +v -4.983679 0.010002 -4.706808 +v -4.983679 0.010002 -4.799098 +v -5.075970 0.010002 -4.799098 +v -5.075970 0.010002 -4.522227 +v -4.983679 0.010002 -4.522227 +v -4.983679 0.010002 -4.614518 +v -5.075970 0.010002 -4.614518 +v -4.891389 0.010002 -4.522227 +v -4.799098 0.010002 -4.522227 +v -4.799098 0.010002 -4.614518 +v -4.891389 0.010002 -4.614518 +v -5.075970 0.010002 -5.075970 +v -4.983679 0.010002 -5.075970 +v -4.983679 0.010002 -5.168260 +v -5.075970 0.010002 -5.168260 +v -5.075970 0.010002 -4.891389 +v -4.983679 0.010002 -4.891389 +v -4.983679 0.010002 -4.983679 +v -5.075970 0.010002 -4.983679 +v -4.891389 0.010002 -4.891389 +v -4.799098 0.010002 -4.891389 +v -4.799098 0.010002 -4.983679 +v -4.891389 0.010002 -4.983679 +v -3.968485 0.010000 -1.015194 +v -3.876195 0.010000 -1.015194 +v -3.876195 0.010000 -1.107484 +v -3.968485 0.010000 -1.107484 +v -3.968485 0.010000 -0.830613 +v -3.876195 0.010000 -0.830613 +v -3.876195 0.010000 -0.922904 +v -3.968485 0.010000 -0.922904 +v -3.783905 0.010000 -0.830613 +v -3.691614 0.010000 -0.830613 +v -3.691614 0.010000 -0.922904 +v -3.783905 0.010000 -0.922904 +v -4.337647 0.010000 -1.015194 +v -4.245357 0.010000 -1.015194 +v -4.245357 0.010000 -1.107484 +v -4.337647 0.010000 -1.107484 +v -4.337647 0.010000 -0.830613 +v -4.245357 0.010000 -0.830613 +v -4.245357 0.010000 -0.922904 +v -4.337647 0.010000 -0.922904 +v -4.153066 0.010000 -0.830613 +v -4.060776 0.010000 -0.830613 +v -4.060776 0.010000 -0.922904 +v -4.153066 0.010000 -0.922904 +v -4.337647 0.010001 -1.384355 +v -4.245357 0.010001 -1.384355 +v -4.245357 0.010001 -1.476646 +v -4.337647 0.010001 -1.476646 +v -4.337647 0.010000 -1.199775 +v -4.245357 0.010000 -1.199775 +v -4.245357 0.010001 -1.292065 +v -4.337647 0.010001 -1.292065 +v -4.153066 0.010000 -1.199775 +v -4.060776 0.010000 -1.199775 +v -4.060776 0.010001 -1.292065 +v -4.153066 0.010001 -1.292065 +v -3.968485 0.010000 -0.276871 +v -3.876195 0.010000 -0.276871 +v -3.876195 0.010000 -0.369161 +v -3.968485 0.010000 -0.369161 +v -3.968485 0.010000 -0.092290 +v -3.876195 0.010000 -0.092290 +v -3.876195 0.010000 -0.184581 +v -3.968485 0.010000 -0.184581 +v -3.783905 0.010000 -0.092290 +v -3.691614 0.010000 -0.092290 +v -3.691614 0.010000 -0.184581 +v -3.783905 0.010000 -0.184581 +v -4.337647 0.010000 -0.276871 +v -4.245357 0.010000 -0.276871 +v -4.245357 0.010000 -0.369161 +v -4.337647 0.010000 -0.369161 +v -4.337647 0.010000 -0.092290 +v -4.245357 0.010000 -0.092290 +v -4.245357 0.010000 -0.184581 +v -4.337647 0.010000 -0.184581 +v -4.153066 0.010000 -0.092290 +v -4.060776 0.010000 -0.092290 +v -4.060776 0.010000 -0.184581 +v -4.153066 0.010000 -0.184581 +v -4.337647 0.010000 -0.646033 +v -4.245357 0.010000 -0.646033 +v -4.245357 0.010000 -0.738323 +v -4.337647 0.010000 -0.738323 +v -4.337647 0.010000 -0.461452 +v -4.245357 0.010000 -0.461452 +v -4.245357 0.010000 -0.553742 +v -4.337647 0.010000 -0.553742 +v -4.153066 0.010000 -0.461452 +v -4.060776 0.010000 -0.461452 +v -4.060776 0.010000 -0.553742 +v -4.153066 0.010000 -0.553742 +v -3.230163 0.010000 -0.276871 +v -3.137872 0.010000 -0.276871 +v -3.137872 0.010000 -0.369161 +v -3.230163 0.010000 -0.369161 +v -3.230163 0.010000 -0.092290 +v -3.137872 0.010000 -0.092290 +v -3.137872 0.010000 -0.184581 +v -3.230163 0.010000 -0.184581 +v -3.045582 0.010000 -0.092290 +v -2.953291 0.010000 -0.092290 +v -2.953291 0.010000 -0.184581 +v -3.045582 0.010000 -0.184581 +v -3.599324 0.010000 -0.276871 +v -3.507033 0.010000 -0.276871 +v -3.507033 0.010000 -0.369161 +v -3.599324 0.010000 -0.369161 +v -3.599324 0.010000 -0.092290 +v -3.507033 0.010000 -0.092290 +v -3.507033 0.010000 -0.184581 +v -3.599324 0.010000 -0.184581 +v -3.414743 0.010000 -0.092290 +v -3.322453 0.010000 -0.092290 +v -3.322453 0.010000 -0.184581 +v -3.414743 0.010000 -0.184581 +v -3.599324 0.010000 -0.646033 +v -3.507033 0.010000 -0.646033 +v -3.507033 0.010000 -0.738323 +v -3.599324 0.010000 -0.738323 +v -3.599324 0.010000 -0.461452 +v -3.507033 0.010000 -0.461452 +v -3.507033 0.010000 -0.553742 +v -3.599324 0.010000 -0.553742 +v -3.414743 0.010000 -0.461452 +v -3.322453 0.010000 -0.461452 +v -3.322453 0.010000 -0.553742 +v -3.414743 0.010000 -0.553742 +v -5.445131 0.010000 -1.015194 +v -5.352840 0.010000 -1.015194 +v -5.352840 0.010000 -1.107484 +v -5.445131 0.010000 -1.107484 +v -5.445131 0.010000 -0.830613 +v -5.352840 0.010000 -0.830613 +v -5.352840 0.010000 -0.922904 +v -5.445131 0.010000 -0.922904 +v -5.260550 0.010000 -0.830613 +v -5.168260 0.010000 -0.830613 +v -5.168260 0.010000 -0.922904 +v -5.260550 0.010000 -0.922904 +v -5.814293 0.010000 -1.015194 +v -5.722002 0.010000 -1.015194 +v -5.722002 0.010000 -1.107484 +v -5.814293 0.010000 -1.107484 +v -5.814293 0.010000 -0.830613 +v -5.722002 0.010000 -0.830613 +v -5.722002 0.010000 -0.922904 +v -5.814293 0.010000 -0.922904 +v -5.629711 0.010000 -0.830613 +v -5.537421 0.010000 -0.830613 +v -5.537421 0.010000 -0.922904 +v -5.629711 0.010000 -0.922904 +v -5.814293 0.010001 -1.384355 +v -5.722002 0.010001 -1.384355 +v -5.722002 0.010001 -1.476646 +v -5.814293 0.010001 -1.476646 +v -5.814293 0.010000 -1.199775 +v -5.722002 0.010000 -1.199775 +v -5.722002 0.010001 -1.292065 +v -5.814293 0.010001 -1.292065 +v -5.629711 0.010000 -1.199775 +v -5.537421 0.010000 -1.199775 +v -5.537421 0.010001 -1.292065 +v -5.629711 0.010001 -1.292065 +v -5.445131 0.010000 -0.276871 +v -5.352840 0.010000 -0.276871 +v -5.352840 0.010000 -0.369161 +v -5.445131 0.010000 -0.369161 +v -5.445131 0.010000 -0.092290 +v -5.352840 0.010000 -0.092290 +v -5.352840 0.010000 -0.184581 +v -5.445131 0.010000 -0.184581 +v -5.260550 0.010000 -0.092290 +v -5.168260 0.010000 -0.092290 +v -5.168260 0.010000 -0.184581 +v -5.260550 0.010000 -0.184581 +v -5.814293 0.010000 -0.276871 +v -5.722002 0.010000 -0.276871 +v -5.722002 0.010000 -0.369161 +v -5.814293 0.010000 -0.369161 +v -5.814293 0.010000 -0.092290 +v -5.722002 0.010000 -0.092290 +v -5.722002 0.010000 -0.184581 +v -5.814293 0.010000 -0.184581 +v -5.629711 0.010000 -0.092290 +v -5.537421 0.010000 -0.092290 +v -5.537421 0.010000 -0.184581 +v -5.629711 0.010000 -0.184581 +v -5.814293 0.010000 -0.646033 +v -5.722002 0.010000 -0.646033 +v -5.722002 0.010000 -0.738323 +v -5.814293 0.010000 -0.738323 +v -5.814293 0.010000 -0.461452 +v -5.722002 0.010000 -0.461452 +v -5.722002 0.010000 -0.553742 +v -5.814293 0.010000 -0.553742 +v -5.629711 0.010000 -0.461452 +v -5.537421 0.010000 -0.461452 +v -5.537421 0.010000 -0.553742 +v -5.629711 0.010000 -0.553742 +v -4.706808 0.010000 -0.276871 +v -4.614518 0.010000 -0.276871 +v -4.614518 0.010000 -0.369161 +v -4.706808 0.010000 -0.369161 +v -4.706808 0.010000 -0.092290 +v -4.614518 0.010000 -0.092290 +v -4.614518 0.010000 -0.184581 +v -4.706808 0.010000 -0.184581 +v -4.522227 0.010000 -0.092290 +v -4.429937 0.010000 -0.092290 +v -4.429937 0.010000 -0.184581 +v -4.522227 0.010000 -0.184581 +v -5.075970 0.010000 -0.276871 +v -4.983679 0.010000 -0.276871 +v -4.983679 0.010000 -0.369161 +v -5.075970 0.010000 -0.369161 +v -5.075970 0.010000 -0.092290 +v -4.983679 0.010000 -0.092290 +v -4.983679 0.010000 -0.184581 +v -5.075970 0.010000 -0.184581 +v -4.891389 0.010000 -0.092290 +v -4.799098 0.010000 -0.092290 +v -4.799098 0.010000 -0.184581 +v -4.891389 0.010000 -0.184581 +v -5.075970 0.010000 -0.646033 +v -4.983679 0.010000 -0.646033 +v -4.983679 0.010000 -0.738323 +v -5.075970 0.010000 -0.738323 +v -5.075970 0.010000 -0.461452 +v -4.983679 0.010000 -0.461452 +v -4.983679 0.010000 -0.553742 +v -5.075970 0.010000 -0.553742 +v -4.891389 0.010000 -0.461452 +v -4.799098 0.010000 -0.461452 +v -4.799098 0.010000 -0.553742 +v -4.891389 0.010000 -0.553742 +v -5.445131 0.010001 -2.491840 +v -5.352840 0.010001 -2.491840 +v -5.352840 0.010001 -2.584130 +v -5.445131 0.010001 -2.584130 +v -5.445131 0.010001 -2.307259 +v -5.352840 0.010001 -2.307259 +v -5.352840 0.010001 -2.399549 +v -5.445131 0.010001 -2.399549 +v -5.260550 0.010001 -2.307259 +v -5.168260 0.010001 -2.307259 +v -5.168260 0.010001 -2.399549 +v -5.260550 0.010001 -2.399549 +v -5.814293 0.010001 -2.491840 +v -5.722002 0.010001 -2.491840 +v -5.722002 0.010001 -2.584130 +v -5.814293 0.010001 -2.584130 +v -5.814293 0.010001 -2.307259 +v -5.722002 0.010001 -2.307259 +v -5.722002 0.010001 -2.399549 +v -5.814293 0.010001 -2.399549 +v -5.629711 0.010001 -2.307259 +v -5.537421 0.010001 -2.307259 +v -5.537421 0.010001 -2.399549 +v -5.629711 0.010001 -2.399549 +v -5.814293 0.010001 -2.861001 +v -5.722002 0.010001 -2.861001 +v -5.722002 0.010001 -2.953291 +v -5.814293 0.010001 -2.953291 +v -5.814293 0.010001 -2.676420 +v -5.722002 0.010001 -2.676420 +v -5.722002 0.010001 -2.768711 +v -5.814293 0.010001 -2.768711 +v -5.629711 0.010001 -2.676420 +v -5.537421 0.010001 -2.676420 +v -5.537421 0.010001 -2.768711 +v -5.629711 0.010001 -2.768711 +v -5.445131 0.010001 -1.753517 +v -5.352840 0.010001 -1.753517 +v -5.352840 0.010001 -1.845807 +v -5.445131 0.010001 -1.845807 +v -5.445131 0.010001 -1.568936 +v -5.352840 0.010001 -1.568936 +v -5.352840 0.010001 -1.661226 +v -5.445131 0.010001 -1.661226 +v -5.260550 0.010001 -1.568936 +v -5.168260 0.010001 -1.568936 +v -5.168260 0.010001 -1.661226 +v -5.260550 0.010001 -1.661226 +v -5.814293 0.010001 -1.753517 +v -5.722002 0.010001 -1.753517 +v -5.722002 0.010001 -1.845807 +v -5.814293 0.010001 -1.845807 +v -5.814293 0.010001 -1.568936 +v -5.722002 0.010001 -1.568936 +v -5.722002 0.010001 -1.661226 +v -5.814293 0.010001 -1.661226 +v -5.629711 0.010001 -1.568936 +v -5.537421 0.010001 -1.568936 +v -5.537421 0.010001 -1.661226 +v -5.629711 0.010001 -1.661226 +v -5.814293 0.010001 -2.122678 +v -5.722002 0.010001 -2.122678 +v -5.722002 0.010001 -2.214968 +v -5.814293 0.010001 -2.214968 +v -5.814293 0.010001 -1.938097 +v -5.722002 0.010001 -1.938097 +v -5.722002 0.010001 -2.030388 +v -5.814293 0.010001 -2.030388 +v -5.629711 0.010001 -1.938097 +v -5.537421 0.010001 -1.938097 +v -5.537421 0.010001 -2.030388 +v -5.629711 0.010001 -2.030388 +v -4.706808 0.010001 -1.753517 +v -4.614518 0.010001 -1.753517 +v -4.614518 0.010001 -1.845807 +v -4.706808 0.010001 -1.845807 +v -4.706808 0.010001 -1.568936 +v -4.614518 0.010001 -1.568936 +v -4.614518 0.010001 -1.661226 +v -4.706808 0.010001 -1.661226 +v -4.522227 0.010001 -1.568936 +v -4.429937 0.010001 -1.568936 +v -4.429937 0.010001 -1.661226 +v -4.522227 0.010001 -1.661226 +v -5.075970 0.010001 -1.753517 +v -4.983679 0.010001 -1.753517 +v -4.983679 0.010001 -1.845807 +v -5.075970 0.010001 -1.845807 +v -5.075970 0.010001 -1.568936 +v -4.983679 0.010001 -1.568936 +v -4.983679 0.010001 -1.661226 +v -5.075970 0.010001 -1.661226 +v -4.891389 0.010001 -1.568936 +v -4.799098 0.010001 -1.568936 +v -4.799098 0.010001 -1.661226 +v -4.891389 0.010001 -1.661226 +v -5.075970 0.010001 -2.122678 +v -4.983679 0.010001 -2.122678 +v -4.983679 0.010001 -2.214968 +v -5.075970 0.010001 -2.214968 +v -5.075970 0.010001 -1.938097 +v -4.983679 0.010001 -1.938097 +v -4.983679 0.010001 -2.030388 +v -5.075970 0.010001 -2.030388 +v -4.891389 0.010001 -1.938097 +v -4.799098 0.010001 -1.938097 +v -4.799098 0.010001 -2.030388 +v -4.891389 0.010001 -2.030388 +v -1.015194 0.010000 -1.015194 +v -0.922904 0.010000 -1.015194 +v -0.922904 0.010000 -1.107484 +v -1.015194 0.010000 -1.107484 +v -1.015194 0.010000 -0.830613 +v -0.922904 0.010000 -0.830613 +v -0.922904 0.010000 -0.922904 +v -1.015194 0.010000 -0.922904 +v -0.830613 0.010000 -0.830613 +v -0.738323 0.010000 -0.830613 +v -0.738323 0.010000 -0.922904 +v -0.830613 0.010000 -0.922904 +v -1.384355 0.010000 -1.015194 +v -1.292065 0.010000 -1.015194 +v -1.292065 0.010000 -1.107484 +v -1.384355 0.010000 -1.107484 +v -1.384355 0.010000 -0.830613 +v -1.292065 0.010000 -0.830613 +v -1.292065 0.010000 -0.922904 +v -1.384355 0.010000 -0.922904 +v -1.199775 0.010000 -0.830613 +v -1.107484 0.010000 -0.830613 +v -1.107484 0.010000 -0.922904 +v -1.199775 0.010000 -0.922904 +v -1.384355 0.010001 -1.384355 +v -1.292065 0.010001 -1.384355 +v -1.292065 0.010001 -1.476646 +v -1.384355 0.010001 -1.476646 +v -1.384355 0.010000 -1.199775 +v -1.292065 0.010000 -1.199775 +v -1.292065 0.010001 -1.292065 +v -1.384355 0.010001 -1.292065 +v -1.199775 0.010000 -1.199775 +v -1.107484 0.010000 -1.199775 +v -1.107484 0.010001 -1.292065 +v -1.199775 0.010001 -1.292065 +v -1.015194 0.010000 -0.276871 +v -0.922904 0.010000 -0.276871 +v -0.922904 0.010000 -0.369161 +v -1.015194 0.010000 -0.369161 +v -1.015194 0.010000 -0.092290 +v -0.922904 0.010000 -0.092290 +v -0.922904 0.010000 -0.184581 +v -1.015194 0.010000 -0.184581 +v -0.830613 0.010000 -0.092290 +v -0.738323 0.010000 -0.092290 +v -0.738323 0.010000 -0.184581 +v -0.830613 0.010000 -0.184581 +v -1.384355 0.010000 -0.276871 +v -1.292065 0.010000 -0.276871 +v -1.292065 0.010000 -0.369161 +v -1.384355 0.010000 -0.369161 +v -1.384355 0.010000 -0.092290 +v -1.292065 0.010000 -0.092290 +v -1.292065 0.010000 -0.184581 +v -1.384355 0.010000 -0.184581 +v -1.199775 0.010000 -0.092290 +v -1.107484 0.010000 -0.092290 +v -1.107484 0.010000 -0.184581 +v -1.199775 0.010000 -0.184581 +v -1.384355 0.010000 -0.646033 +v -1.292065 0.010000 -0.646033 +v -1.292065 0.010000 -0.738323 +v -1.384355 0.010000 -0.738323 +v -1.384355 0.010000 -0.461452 +v -1.292065 0.010000 -0.461452 +v -1.292065 0.010000 -0.553742 +v -1.384355 0.010000 -0.553742 +v -1.199775 0.010000 -0.461452 +v -1.107484 0.010000 -0.461452 +v -1.107484 0.010000 -0.553742 +v -1.199775 0.010000 -0.553742 +v -0.276871 0.010000 -0.276871 +v -0.184581 0.010000 -0.276871 +v -0.184581 0.010000 -0.369161 +v -0.276871 0.010000 -0.369161 +v -0.276871 0.010000 -0.092290 +v -0.184581 0.010000 -0.092290 +v -0.184581 0.010000 -0.184581 +v -0.276871 0.010000 -0.184581 +v -0.092290 0.010000 -0.092290 +v 0.000000 0.010000 -0.092290 +v 0.000000 0.010000 -0.184581 +v -0.092290 0.010000 -0.184581 +v -0.646033 0.010000 -0.276871 +v -0.553742 0.010000 -0.276871 +v -0.553742 0.010000 -0.369161 +v -0.646033 0.010000 -0.369161 +v -0.646033 0.010000 -0.092290 +v -0.553742 0.010000 -0.092290 +v -0.553742 0.010000 -0.184581 +v -0.646033 0.010000 -0.184581 +v -0.461452 0.010000 -0.092290 +v -0.369161 0.010000 -0.092290 +v -0.369161 0.010000 -0.184581 +v -0.461452 0.010000 -0.184581 +v -0.646033 0.010000 -0.646033 +v -0.553742 0.010000 -0.646033 +v -0.553742 0.010000 -0.738323 +v -0.646033 0.010000 -0.738323 +v -0.646033 0.010000 -0.461452 +v -0.553742 0.010000 -0.461452 +v -0.553742 0.010000 -0.553742 +v -0.646033 0.010000 -0.553742 +v -0.461452 0.010000 -0.461452 +v -0.369161 0.010000 -0.461452 +v -0.369161 0.010000 -0.553742 +v -0.461452 0.010000 -0.553742 +v -2.491840 0.010000 -1.015194 +v -2.399549 0.010000 -1.015194 +v -2.399549 0.010000 -1.107484 +v -2.491840 0.010000 -1.107484 +v -2.491840 0.010000 -0.830613 +v -2.399549 0.010000 -0.830613 +v -2.399549 0.010000 -0.922904 +v -2.491840 0.010000 -0.922904 +v -2.307259 0.010000 -0.830613 +v -2.214968 0.010000 -0.830613 +v -2.214968 0.010000 -0.922904 +v -2.307259 0.010000 -0.922904 +v -2.861001 0.010000 -1.015194 +v -2.768711 0.010000 -1.015194 +v -2.768711 0.010000 -1.107484 +v -2.861001 0.010000 -1.107484 +v -2.861001 0.010000 -0.830613 +v -2.768711 0.010000 -0.830613 +v -2.768711 0.010000 -0.922904 +v -2.861001 0.010000 -0.922904 +v -2.676420 0.010000 -0.830613 +v -2.584130 0.010000 -0.830613 +v -2.584130 0.010000 -0.922904 +v -2.676420 0.010000 -0.922904 +v -2.861001 0.010001 -1.384355 +v -2.768711 0.010001 -1.384355 +v -2.768711 0.010001 -1.476646 +v -2.861001 0.010001 -1.476646 +v -2.861001 0.010000 -1.199775 +v -2.768711 0.010000 -1.199775 +v -2.768711 0.010001 -1.292065 +v -2.861001 0.010001 -1.292065 +v -2.676420 0.010000 -1.199775 +v -2.584130 0.010000 -1.199775 +v -2.584130 0.010001 -1.292065 +v -2.676420 0.010001 -1.292065 +v -2.491840 0.010000 -0.276871 +v -2.399549 0.010000 -0.276871 +v -2.399549 0.010000 -0.369161 +v -2.491840 0.010000 -0.369161 +v -2.491840 0.010000 -0.092290 +v -2.399549 0.010000 -0.092290 +v -2.399549 0.010000 -0.184581 +v -2.491840 0.010000 -0.184581 +v -2.307259 0.010000 -0.092290 +v -2.214968 0.010000 -0.092290 +v -2.214968 0.010000 -0.184581 +v -2.307259 0.010000 -0.184581 +v -2.861001 0.010000 -0.276871 +v -2.768711 0.010000 -0.276871 +v -2.768711 0.010000 -0.369161 +v -2.861001 0.010000 -0.369161 +v -2.861001 0.010000 -0.092290 +v -2.768711 0.010000 -0.092290 +v -2.768711 0.010000 -0.184581 +v -2.861001 0.010000 -0.184581 +v -2.676420 0.010000 -0.092290 +v -2.584130 0.010000 -0.092290 +v -2.584130 0.010000 -0.184581 +v -2.676420 0.010000 -0.184581 +v -2.861001 0.010000 -0.646033 +v -2.768711 0.010000 -0.646033 +v -2.768711 0.010000 -0.738323 +v -2.861001 0.010000 -0.738323 +v -2.861001 0.010000 -0.461452 +v -2.768711 0.010000 -0.461452 +v -2.768711 0.010000 -0.553742 +v -2.861001 0.010000 -0.553742 +v -2.676420 0.010000 -0.461452 +v -2.584130 0.010000 -0.461452 +v -2.584130 0.010000 -0.553742 +v -2.676420 0.010000 -0.553742 +v -1.753517 0.010000 -0.276871 +v -1.661226 0.010000 -0.276871 +v -1.661226 0.010000 -0.369161 +v -1.753517 0.010000 -0.369161 +v -1.753517 0.010000 -0.092290 +v -1.661226 0.010000 -0.092290 +v -1.661226 0.010000 -0.184581 +v -1.753517 0.010000 -0.184581 +v -1.568936 0.010000 -0.092290 +v -1.476646 0.010000 -0.092290 +v -1.476646 0.010000 -0.184581 +v -1.568936 0.010000 -0.184581 +v -2.122678 0.010000 -0.276871 +v -2.030388 0.010000 -0.276871 +v -2.030388 0.010000 -0.369161 +v -2.122678 0.010000 -0.369161 +v -2.122678 0.010000 -0.092290 +v -2.030388 0.010000 -0.092290 +v -2.030388 0.010000 -0.184581 +v -2.122678 0.010000 -0.184581 +v -1.938097 0.010000 -0.092290 +v -1.845807 0.010000 -0.092290 +v -1.845807 0.010000 -0.184581 +v -1.938097 0.010000 -0.184581 +v -2.122678 0.010000 -0.646033 +v -2.030388 0.010000 -0.646033 +v -2.030388 0.010000 -0.738323 +v -2.122678 0.010000 -0.738323 +v -2.122678 0.010000 -0.461452 +v -2.030388 0.010000 -0.461452 +v -2.030388 0.010000 -0.553742 +v -2.122678 0.010000 -0.553742 +v -1.938097 0.010000 -0.461452 +v -1.845807 0.010000 -0.461452 +v -1.845807 0.010000 -0.553742 +v -1.938097 0.010000 -0.553742 +v -2.491840 0.010001 -2.491840 +v -2.399549 0.010001 -2.491840 +v -2.399549 0.010001 -2.584130 +v -2.491840 0.010001 -2.584130 +v -2.491840 0.010001 -2.307259 +v -2.399549 0.010001 -2.307259 +v -2.399549 0.010001 -2.399549 +v -2.491840 0.010001 -2.399549 +v -2.307259 0.010001 -2.307259 +v -2.214968 0.010001 -2.307259 +v -2.214968 0.010001 -2.399549 +v -2.307259 0.010001 -2.399549 +v -2.861001 0.010001 -2.491840 +v -2.768711 0.010001 -2.491840 +v -2.768711 0.010001 -2.584130 +v -2.861001 0.010001 -2.584130 +v -2.861001 0.010001 -2.307259 +v -2.768711 0.010001 -2.307259 +v -2.768711 0.010001 -2.399549 +v -2.861001 0.010001 -2.399549 +v -2.676420 0.010001 -2.307259 +v -2.584130 0.010001 -2.307259 +v -2.584130 0.010001 -2.399549 +v -2.676420 0.010001 -2.399549 +v -2.861001 0.010001 -2.861001 +v -2.768711 0.010001 -2.861001 +v -2.768711 0.010001 -2.953291 +v -2.861001 0.010001 -2.953291 +v -2.861001 0.010001 -2.676420 +v -2.768711 0.010001 -2.676420 +v -2.768711 0.010001 -2.768711 +v -2.861001 0.010001 -2.768711 +v -2.676420 0.010001 -2.676420 +v -2.584130 0.010001 -2.676420 +v -2.584130 0.010001 -2.768711 +v -2.676420 0.010001 -2.768711 +v -2.491840 0.010001 -1.753517 +v -2.399549 0.010001 -1.753517 +v -2.399549 0.010001 -1.845807 +v -2.491840 0.010001 -1.845807 +v -2.491840 0.010001 -1.568936 +v -2.399549 0.010001 -1.568936 +v -2.399549 0.010001 -1.661226 +v -2.491840 0.010001 -1.661226 +v -2.307259 0.010001 -1.568936 +v -2.214968 0.010001 -1.568936 +v -2.214968 0.010001 -1.661226 +v -2.307259 0.010001 -1.661226 +v -2.861001 0.010001 -1.753517 +v -2.768711 0.010001 -1.753517 +v -2.768711 0.010001 -1.845807 +v -2.861001 0.010001 -1.845807 +v -2.861001 0.010001 -1.568936 +v -2.768711 0.010001 -1.568936 +v -2.768711 0.010001 -1.661226 +v -2.861001 0.010001 -1.661226 +v -2.676420 0.010001 -1.568936 +v -2.584130 0.010001 -1.568936 +v -2.584130 0.010001 -1.661226 +v -2.676420 0.010001 -1.661226 +v -2.861001 0.010001 -2.122678 +v -2.768711 0.010001 -2.122678 +v -2.768711 0.010001 -2.214968 +v -2.861001 0.010001 -2.214968 +v -2.861001 0.010001 -1.938097 +v -2.768711 0.010001 -1.938097 +v -2.768711 0.010001 -2.030388 +v -2.861001 0.010001 -2.030388 +v -2.676420 0.010001 -1.938097 +v -2.584130 0.010001 -1.938097 +v -2.584130 0.010001 -2.030388 +v -2.676420 0.010001 -2.030388 +v -1.753517 0.010001 -1.753517 +v -1.661226 0.010001 -1.753517 +v -1.661226 0.010001 -1.845807 +v -1.753517 0.010001 -1.845807 +v -1.753517 0.010001 -1.568936 +v -1.661226 0.010001 -1.568936 +v -1.661226 0.010001 -1.661226 +v -1.753517 0.010001 -1.661226 +v -1.568936 0.010001 -1.568936 +v -1.476646 0.010001 -1.568936 +v -1.476646 0.010001 -1.661226 +v -1.568936 0.010001 -1.661226 +v -2.122678 0.010001 -1.753517 +v -2.030388 0.010001 -1.753517 +v -2.030388 0.010001 -1.845807 +v -2.122678 0.010001 -1.845807 +v -2.122678 0.010001 -1.568936 +v -2.030388 0.010001 -1.568936 +v -2.030388 0.010001 -1.661226 +v -2.122678 0.010001 -1.661226 +v -1.938097 0.010001 -1.568936 +v -1.845807 0.010001 -1.568936 +v -1.845807 0.010001 -1.661226 +v -1.938097 0.010001 -1.661226 +v -2.122678 0.010001 -2.122678 +v -2.030388 0.010001 -2.122678 +v -2.030388 0.010001 -2.214968 +v -2.122678 0.010001 -2.214968 +v -2.122678 0.010001 -1.938097 +v -2.030388 0.010001 -1.938097 +v -2.030388 0.010001 -2.030388 +v -2.122678 0.010001 -2.030388 +v -1.938097 0.010001 -1.938097 +v -1.845807 0.010001 -1.938097 +v -1.845807 0.010001 -2.030388 +v -1.938097 0.010001 -2.030388 +v 1.938097 0.010002 -3.968485 +v 2.030388 0.010002 -3.968485 +v 2.030388 0.010002 -4.060776 +v 1.938097 0.010002 -4.060776 +v 1.938097 0.010002 -3.783905 +v 2.030388 0.010002 -3.783905 +v 2.030388 0.010002 -3.876195 +v 1.938097 0.010002 -3.876195 +v 2.122678 0.010002 -3.783905 +v 2.214968 0.010002 -3.783905 +v 2.214968 0.010002 -3.876195 +v 2.122678 0.010002 -3.876195 +v 1.568936 0.010002 -3.968485 +v 1.661226 0.010002 -3.968485 +v 1.661226 0.010002 -4.060776 +v 1.568936 0.010002 -4.060776 +v 1.568936 0.010002 -3.783905 +v 1.661226 0.010002 -3.783905 +v 1.661226 0.010002 -3.876195 +v 1.568936 0.010002 -3.876195 +v 1.753517 0.010002 -3.783905 +v 1.845807 0.010002 -3.783905 +v 1.845807 0.010002 -3.876195 +v 1.753517 0.010002 -3.876195 +v 1.568936 0.010002 -4.337647 +v 1.661226 0.010002 -4.337647 +v 1.661226 0.010002 -4.429937 +v 1.568936 0.010002 -4.429937 +v 1.568936 0.010002 -4.153066 +v 1.661226 0.010002 -4.153066 +v 1.661226 0.010002 -4.245357 +v 1.568936 0.010002 -4.245357 +v 1.753517 0.010002 -4.153066 +v 1.845807 0.010002 -4.153066 +v 1.845807 0.010002 -4.245357 +v 1.753517 0.010002 -4.245357 +v 1.938097 0.010001 -3.230163 +v 2.030388 0.010001 -3.230163 +v 2.030388 0.010001 -3.322453 +v 1.938097 0.010001 -3.322453 +v 1.938097 0.010001 -3.045582 +v 2.030388 0.010001 -3.045582 +v 2.030388 0.010001 -3.137872 +v 1.938097 0.010001 -3.137872 +v 2.122678 0.010001 -3.045582 +v 2.214968 0.010001 -3.045582 +v 2.214968 0.010001 -3.137872 +v 2.122678 0.010001 -3.137872 +v 1.568936 0.010001 -3.230163 +v 1.661226 0.010001 -3.230163 +v 1.661226 0.010001 -3.322453 +v 1.568936 0.010001 -3.322453 +v 1.568936 0.010001 -3.045582 +v 1.661226 0.010001 -3.045582 +v 1.661226 0.010001 -3.137872 +v 1.568936 0.010001 -3.137872 +v 1.753517 0.010001 -3.045582 +v 1.845807 0.010001 -3.045582 +v 1.845807 0.010001 -3.137872 +v 1.753517 0.010001 -3.137872 +v 1.568936 0.010001 -3.599324 +v 1.661226 0.010001 -3.599324 +v 1.661226 0.010002 -3.691614 +v 1.568936 0.010002 -3.691614 +v 1.568936 0.010001 -3.414743 +v 1.661226 0.010001 -3.414743 +v 1.661226 0.010001 -3.507033 +v 1.568936 0.010001 -3.507033 +v 1.753517 0.010001 -3.414743 +v 1.845807 0.010001 -3.414743 +v 1.845807 0.010001 -3.507033 +v 1.753517 0.010001 -3.507033 +v 2.676420 0.010001 -3.230163 +v 2.768711 0.010001 -3.230163 +v 2.768711 0.010001 -3.322453 +v 2.676420 0.010001 -3.322453 +v 2.676420 0.010001 -3.045582 +v 2.768711 0.010001 -3.045582 +v 2.768711 0.010001 -3.137872 +v 2.676420 0.010001 -3.137872 +v 2.861001 0.010001 -3.045582 +v 2.953291 0.010001 -3.045582 +v 2.953291 0.010001 -3.137872 +v 2.861001 0.010001 -3.137872 +v 2.307259 0.010001 -3.230163 +v 2.399549 0.010001 -3.230163 +v 2.399549 0.010001 -3.322453 +v 2.307259 0.010001 -3.322453 +v 2.307259 0.010001 -3.045582 +v 2.399549 0.010001 -3.045582 +v 2.399549 0.010001 -3.137872 +v 2.307259 0.010001 -3.137872 +v 2.491840 0.010001 -3.045582 +v 2.584130 0.010001 -3.045582 +v 2.584130 0.010001 -3.137872 +v 2.491840 0.010001 -3.137872 +v 2.307259 0.010001 -3.599324 +v 2.399549 0.010001 -3.599324 +v 2.399549 0.010002 -3.691614 +v 2.307259 0.010002 -3.691614 +v 2.307259 0.010001 -3.414743 +v 2.399549 0.010001 -3.414743 +v 2.399549 0.010001 -3.507033 +v 2.307259 0.010001 -3.507033 +v 2.491840 0.010001 -3.414743 +v 2.584130 0.010001 -3.414743 +v 2.584130 0.010001 -3.507033 +v 2.491840 0.010001 -3.507033 +v 0.461452 0.010002 -3.968485 +v 0.553742 0.010002 -3.968485 +v 0.553742 0.010002 -4.060776 +v 0.461452 0.010002 -4.060776 +v 0.461452 0.010002 -3.783905 +v 0.553742 0.010002 -3.783905 +v 0.553742 0.010002 -3.876195 +v 0.461452 0.010002 -3.876195 +v 0.646033 0.010002 -3.783905 +v 0.738323 0.010002 -3.783905 +v 0.738323 0.010002 -3.876195 +v 0.646033 0.010002 -3.876195 +v 0.092290 0.010002 -3.968485 +v 0.184581 0.010002 -3.968485 +v 0.184581 0.010002 -4.060776 +v 0.092290 0.010002 -4.060776 +v 0.092290 0.010002 -3.783905 +v 0.184581 0.010002 -3.783905 +v 0.184581 0.010002 -3.876195 +v 0.092290 0.010002 -3.876195 +v 0.276871 0.010002 -3.783905 +v 0.369161 0.010002 -3.783905 +v 0.369161 0.010002 -3.876195 +v 0.276871 0.010002 -3.876195 +v 0.092290 0.010002 -4.337647 +v 0.184581 0.010002 -4.337647 +v 0.184581 0.010002 -4.429937 +v 0.092290 0.010002 -4.429937 +v 0.092290 0.010002 -4.153066 +v 0.184581 0.010002 -4.153066 +v 0.184581 0.010002 -4.245357 +v 0.092290 0.010002 -4.245357 +v 0.276871 0.010002 -4.153066 +v 0.369161 0.010002 -4.153066 +v 0.369161 0.010002 -4.245357 +v 0.276871 0.010002 -4.245357 +v 0.461452 0.010001 -3.230163 +v 0.553742 0.010001 -3.230163 +v 0.553742 0.010001 -3.322453 +v 0.461452 0.010001 -3.322453 +v 0.461452 0.010001 -3.045582 +v 0.553742 0.010001 -3.045582 +v 0.553742 0.010001 -3.137872 +v 0.461452 0.010001 -3.137872 +v 0.646033 0.010001 -3.045582 +v 0.738323 0.010001 -3.045582 +v 0.738323 0.010001 -3.137872 +v 0.646033 0.010001 -3.137872 +v 0.092290 0.010001 -3.230163 +v 0.184581 0.010001 -3.230163 +v 0.184581 0.010001 -3.322453 +v 0.092290 0.010001 -3.322453 +v 0.092290 0.010001 -3.045582 +v 0.184581 0.010001 -3.045582 +v 0.184581 0.010001 -3.137872 +v 0.092290 0.010001 -3.137872 +v 0.276871 0.010001 -3.045582 +v 0.369161 0.010001 -3.045582 +v 0.369161 0.010001 -3.137872 +v 0.276871 0.010001 -3.137872 +v 0.092290 0.010001 -3.599324 +v 0.184581 0.010001 -3.599324 +v 0.184581 0.010002 -3.691614 +v 0.092290 0.010002 -3.691614 +v 0.092290 0.010001 -3.414743 +v 0.184581 0.010001 -3.414743 +v 0.184581 0.010001 -3.507033 +v 0.092290 0.010001 -3.507033 +v 0.276871 0.010001 -3.414743 +v 0.369161 0.010001 -3.414743 +v 0.369161 0.010001 -3.507033 +v 0.276871 0.010001 -3.507033 +v 1.199775 0.010001 -3.230163 +v 1.292065 0.010001 -3.230163 +v 1.292065 0.010001 -3.322453 +v 1.199775 0.010001 -3.322453 +v 1.199775 0.010001 -3.045582 +v 1.292065 0.010001 -3.045582 +v 1.292065 0.010001 -3.137872 +v 1.199775 0.010001 -3.137872 +v 1.384355 0.010001 -3.045582 +v 1.476646 0.010001 -3.045582 +v 1.476646 0.010001 -3.137872 +v 1.384355 0.010001 -3.137872 +v 0.830613 0.010001 -3.230163 +v 0.922904 0.010001 -3.230163 +v 0.922904 0.010001 -3.322453 +v 0.830613 0.010001 -3.322453 +v 0.830613 0.010001 -3.045582 +v 0.922904 0.010001 -3.045582 +v 0.922904 0.010001 -3.137872 +v 0.830613 0.010001 -3.137872 +v 1.015194 0.010001 -3.045582 +v 1.107484 0.010001 -3.045582 +v 1.107484 0.010001 -3.137872 +v 1.015194 0.010001 -3.137872 +v 0.830613 0.010001 -3.599324 +v 0.922904 0.010001 -3.599324 +v 0.922904 0.010002 -3.691614 +v 0.830613 0.010002 -3.691614 +v 0.830613 0.010001 -3.414743 +v 0.922904 0.010001 -3.414743 +v 0.922904 0.010001 -3.507033 +v 0.830613 0.010001 -3.507033 +v 1.015194 0.010001 -3.414743 +v 1.107484 0.010001 -3.414743 +v 1.107484 0.010001 -3.507033 +v 1.015194 0.010001 -3.507033 +v 0.461452 0.010002 -5.445131 +v 0.553742 0.010002 -5.445131 +v 0.553742 0.010002 -5.537421 +v 0.461452 0.010002 -5.537421 +v 0.461452 0.010002 -5.260550 +v 0.553742 0.010002 -5.260550 +v 0.553742 0.010002 -5.352840 +v 0.461452 0.010002 -5.352840 +v 0.646033 0.010002 -5.260550 +v 0.738323 0.010002 -5.260550 +v 0.738323 0.010002 -5.352840 +v 0.646033 0.010002 -5.352840 +v 0.092290 0.010002 -5.445131 +v 0.184581 0.010002 -5.445131 +v 0.184581 0.010002 -5.537421 +v 0.092290 0.010002 -5.537421 +v 0.092290 0.010002 -5.260550 +v 0.184581 0.010002 -5.260550 +v 0.184581 0.010002 -5.352840 +v 0.092290 0.010002 -5.352840 +v 0.276871 0.010002 -5.260550 +v 0.369161 0.010002 -5.260550 +v 0.369161 0.010002 -5.352840 +v 0.276871 0.010002 -5.352840 +v 0.092290 0.010002 -5.814293 +v 0.184581 0.010002 -5.814293 +v 0.184581 0.010002 -5.906583 +v 0.092290 0.010002 -5.906583 +v 0.092290 0.010002 -5.629711 +v 0.184581 0.010002 -5.629711 +v 0.184581 0.010002 -5.722002 +v 0.092290 0.010002 -5.722002 +v 0.276871 0.010002 -5.629711 +v 0.369161 0.010002 -5.629711 +v 0.369161 0.010002 -5.722002 +v 0.276871 0.010002 -5.722002 +v 0.461452 0.010002 -4.706808 +v 0.553742 0.010002 -4.706808 +v 0.553742 0.010002 -4.799098 +v 0.461452 0.010002 -4.799098 +v 0.461452 0.010002 -4.522227 +v 0.553742 0.010002 -4.522227 +v 0.553742 0.010002 -4.614518 +v 0.461452 0.010002 -4.614518 +v 0.646033 0.010002 -4.522227 +v 0.738323 0.010002 -4.522227 +v 0.738323 0.010002 -4.614518 +v 0.646033 0.010002 -4.614518 +v 0.092290 0.010002 -4.706808 +v 0.184581 0.010002 -4.706808 +v 0.184581 0.010002 -4.799098 +v 0.092290 0.010002 -4.799098 +v 0.092290 0.010002 -4.522227 +v 0.184581 0.010002 -4.522227 +v 0.184581 0.010002 -4.614518 +v 0.092290 0.010002 -4.614518 +v 0.276871 0.010002 -4.522227 +v 0.369161 0.010002 -4.522227 +v 0.369161 0.010002 -4.614518 +v 0.276871 0.010002 -4.614518 +v 0.092290 0.010002 -5.075970 +v 0.184581 0.010002 -5.075970 +v 0.184581 0.010002 -5.168260 +v 0.092290 0.010002 -5.168260 +v 0.092290 0.010002 -4.891389 +v 0.184581 0.010002 -4.891389 +v 0.184581 0.010002 -4.983679 +v 0.092290 0.010002 -4.983679 +v 0.276871 0.010002 -4.891389 +v 0.369161 0.010002 -4.891389 +v 0.369161 0.010002 -4.983679 +v 0.276871 0.010002 -4.983679 +v 1.199775 0.010002 -4.706808 +v 1.292065 0.010002 -4.706808 +v 1.292065 0.010002 -4.799098 +v 1.199775 0.010002 -4.799098 +v 1.199775 0.010002 -4.522227 +v 1.292065 0.010002 -4.522227 +v 1.292065 0.010002 -4.614518 +v 1.199775 0.010002 -4.614518 +v 1.384355 0.010002 -4.522227 +v 1.476646 0.010002 -4.522227 +v 1.476646 0.010002 -4.614518 +v 1.384355 0.010002 -4.614518 +v 0.830613 0.010002 -4.706808 +v 0.922904 0.010002 -4.706808 +v 0.922904 0.010002 -4.799098 +v 0.830613 0.010002 -4.799098 +v 0.830613 0.010002 -4.522227 +v 0.922904 0.010002 -4.522227 +v 0.922904 0.010002 -4.614518 +v 0.830613 0.010002 -4.614518 +v 1.015194 0.010002 -4.522227 +v 1.107484 0.010002 -4.522227 +v 1.107484 0.010002 -4.614518 +v 1.015194 0.010002 -4.614518 +v 0.830613 0.010002 -5.075970 +v 0.922904 0.010002 -5.075970 +v 0.922904 0.010002 -5.168260 +v 0.830613 0.010002 -5.168260 +v 0.830613 0.010002 -4.891389 +v 0.922904 0.010002 -4.891389 +v 0.922904 0.010002 -4.983679 +v 0.830613 0.010002 -4.983679 +v 1.015194 0.010002 -4.891389 +v 1.107484 0.010002 -4.891389 +v 1.107484 0.010002 -4.983679 +v 1.015194 0.010002 -4.983679 +v 1.938097 0.010000 -1.015194 +v 2.030388 0.010000 -1.015194 +v 2.030388 0.010000 -1.107484 +v 1.938097 0.010000 -1.107484 +v 1.938097 0.010000 -0.830613 +v 2.030388 0.010000 -0.830613 +v 2.030388 0.010000 -0.922904 +v 1.938097 0.010000 -0.922904 +v 2.122678 0.010000 -0.830613 +v 2.214968 0.010000 -0.830613 +v 2.214968 0.010000 -0.922904 +v 2.122678 0.010000 -0.922904 +v 1.568936 0.010000 -1.015194 +v 1.661226 0.010000 -1.015194 +v 1.661226 0.010000 -1.107484 +v 1.568936 0.010000 -1.107484 +v 1.568936 0.010000 -0.830613 +v 1.661226 0.010000 -0.830613 +v 1.661226 0.010000 -0.922904 +v 1.568936 0.010000 -0.922904 +v 1.753517 0.010000 -0.830613 +v 1.845807 0.010000 -0.830613 +v 1.845807 0.010000 -0.922904 +v 1.753517 0.010000 -0.922904 +v 1.568936 0.010001 -1.384355 +v 1.661226 0.010001 -1.384355 +v 1.661226 0.010001 -1.476646 +v 1.568936 0.010001 -1.476646 +v 1.568936 0.010000 -1.199775 +v 1.661226 0.010000 -1.199775 +v 1.661226 0.010001 -1.292065 +v 1.568936 0.010001 -1.292065 +v 1.753517 0.010000 -1.199775 +v 1.845807 0.010000 -1.199775 +v 1.845807 0.010001 -1.292065 +v 1.753517 0.010001 -1.292065 +v 1.938097 0.010000 -0.276871 +v 2.030388 0.010000 -0.276871 +v 2.030388 0.010000 -0.369161 +v 1.938097 0.010000 -0.369161 +v 1.938097 0.010000 -0.092290 +v 2.030388 0.010000 -0.092290 +v 2.030388 0.010000 -0.184581 +v 1.938097 0.010000 -0.184581 +v 2.122678 0.010000 -0.092290 +v 2.214968 0.010000 -0.092290 +v 2.214968 0.010000 -0.184581 +v 2.122678 0.010000 -0.184581 +v 1.568936 0.010000 -0.276871 +v 1.661226 0.010000 -0.276871 +v 1.661226 0.010000 -0.369161 +v 1.568936 0.010000 -0.369161 +v 1.568936 0.010000 -0.092290 +v 1.661226 0.010000 -0.092290 +v 1.661226 0.010000 -0.184581 +v 1.568936 0.010000 -0.184581 +v 1.753517 0.010000 -0.092290 +v 1.845807 0.010000 -0.092290 +v 1.845807 0.010000 -0.184581 +v 1.753517 0.010000 -0.184581 +v 1.568936 0.010000 -0.646033 +v 1.661226 0.010000 -0.646033 +v 1.661226 0.010000 -0.738323 +v 1.568936 0.010000 -0.738323 +v 1.568936 0.010000 -0.461452 +v 1.661226 0.010000 -0.461452 +v 1.661226 0.010000 -0.553742 +v 1.568936 0.010000 -0.553742 +v 1.753517 0.010000 -0.461452 +v 1.845807 0.010000 -0.461452 +v 1.845807 0.010000 -0.553742 +v 1.753517 0.010000 -0.553742 +v 2.676420 0.010000 -0.276871 +v 2.768711 0.010000 -0.276871 +v 2.768711 0.010000 -0.369161 +v 2.676420 0.010000 -0.369161 +v 2.676420 0.010000 -0.092290 +v 2.768711 0.010000 -0.092290 +v 2.768711 0.010000 -0.184581 +v 2.676420 0.010000 -0.184581 +v 2.861001 0.010000 -0.092290 +v 2.953291 0.010000 -0.092290 +v 2.953291 0.010000 -0.184581 +v 2.861001 0.010000 -0.184581 +v 2.307259 0.010000 -0.276871 +v 2.399549 0.010000 -0.276871 +v 2.399549 0.010000 -0.369161 +v 2.307259 0.010000 -0.369161 +v 2.307259 0.010000 -0.092290 +v 2.399549 0.010000 -0.092290 +v 2.399549 0.010000 -0.184581 +v 2.307259 0.010000 -0.184581 +v 2.491840 0.010000 -0.092290 +v 2.584130 0.010000 -0.092290 +v 2.584130 0.010000 -0.184581 +v 2.491840 0.010000 -0.184581 +v 2.307259 0.010000 -0.646033 +v 2.399549 0.010000 -0.646033 +v 2.399549 0.010000 -0.738323 +v 2.307259 0.010000 -0.738323 +v 2.307259 0.010000 -0.461452 +v 2.399549 0.010000 -0.461452 +v 2.399549 0.010000 -0.553742 +v 2.307259 0.010000 -0.553742 +v 2.491840 0.010000 -0.461452 +v 2.584130 0.010000 -0.461452 +v 2.584130 0.010000 -0.553742 +v 2.491840 0.010000 -0.553742 +v 0.461452 0.010000 -1.015194 +v 0.553742 0.010000 -1.015194 +v 0.553742 0.010000 -1.107484 +v 0.461452 0.010000 -1.107484 +v 0.461452 0.010000 -0.830613 +v 0.553742 0.010000 -0.830613 +v 0.553742 0.010000 -0.922904 +v 0.461452 0.010000 -0.922904 +v 0.646033 0.010000 -0.830613 +v 0.738323 0.010000 -0.830613 +v 0.738323 0.010000 -0.922904 +v 0.646033 0.010000 -0.922904 +v 0.092290 0.010000 -1.015194 +v 0.184581 0.010000 -1.015194 +v 0.184581 0.010000 -1.107484 +v 0.092290 0.010000 -1.107484 +v 0.092290 0.010000 -0.830613 +v 0.184581 0.010000 -0.830613 +v 0.184581 0.010000 -0.922904 +v 0.092290 0.010000 -0.922904 +v 0.276871 0.010000 -0.830613 +v 0.369161 0.010000 -0.830613 +v 0.369161 0.010000 -0.922904 +v 0.276871 0.010000 -0.922904 +v 0.092290 0.010001 -1.384355 +v 0.184581 0.010001 -1.384355 +v 0.184581 0.010001 -1.476646 +v 0.092290 0.010001 -1.476646 +v 0.092290 0.010000 -1.199775 +v 0.184581 0.010000 -1.199775 +v 0.184581 0.010001 -1.292065 +v 0.092290 0.010001 -1.292065 +v 0.276871 0.010000 -1.199775 +v 0.369161 0.010000 -1.199775 +v 0.369161 0.010001 -1.292065 +v 0.276871 0.010001 -1.292065 +v 0.461452 0.010000 -0.276871 +v 0.553742 0.010000 -0.276871 +v 0.553742 0.010000 -0.369161 +v 0.461452 0.010000 -0.369161 +v 0.461452 0.010000 -0.092290 +v 0.553742 0.010000 -0.092290 +v 0.553742 0.010000 -0.184581 +v 0.461452 0.010000 -0.184581 +v 0.646033 0.010000 -0.092290 +v 0.738323 0.010000 -0.092290 +v 0.738323 0.010000 -0.184581 +v 0.646033 0.010000 -0.184581 +v 0.092290 0.010000 -0.276871 +v 0.184581 0.010000 -0.276871 +v 0.184581 0.010000 -0.369161 +v 0.092290 0.010000 -0.369161 +v 0.092290 0.010000 -0.092290 +v 0.184581 0.010000 -0.092290 +v 0.184581 0.010000 -0.184581 +v 0.092290 0.010000 -0.184581 +v 0.276871 0.010000 -0.092290 +v 0.369161 0.010000 -0.092290 +v 0.369161 0.010000 -0.184581 +v 0.276871 0.010000 -0.184581 +v 0.092290 0.010000 -0.646033 +v 0.184581 0.010000 -0.646033 +v 0.184581 0.010000 -0.738323 +v 0.092290 0.010000 -0.738323 +v 0.092290 0.010000 -0.461452 +v 0.184581 0.010000 -0.461452 +v 0.184581 0.010000 -0.553742 +v 0.092290 0.010000 -0.553742 +v 0.276871 0.010000 -0.461452 +v 0.369161 0.010000 -0.461452 +v 0.369161 0.010000 -0.553742 +v 0.276871 0.010000 -0.553742 +v 1.199775 0.010000 -0.276871 +v 1.292065 0.010000 -0.276871 +v 1.292065 0.010000 -0.369161 +v 1.199775 0.010000 -0.369161 +v 1.199775 0.010000 -0.092290 +v 1.292065 0.010000 -0.092290 +v 1.292065 0.010000 -0.184581 +v 1.199775 0.010000 -0.184581 +v 1.384355 0.010000 -0.092290 +v 1.476646 0.010000 -0.092290 +v 1.476646 0.010000 -0.184581 +v 1.384355 0.010000 -0.184581 +v 0.830613 0.010000 -0.276871 +v 0.922904 0.010000 -0.276871 +v 0.922904 0.010000 -0.369161 +v 0.830613 0.010000 -0.369161 +v 0.830613 0.010000 -0.092290 +v 0.922904 0.010000 -0.092290 +v 0.922904 0.010000 -0.184581 +v 0.830613 0.010000 -0.184581 +v 1.015194 0.010000 -0.092290 +v 1.107484 0.010000 -0.092290 +v 1.107484 0.010000 -0.184581 +v 1.015194 0.010000 -0.184581 +v 0.830613 0.010000 -0.646033 +v 0.922904 0.010000 -0.646033 +v 0.922904 0.010000 -0.738323 +v 0.830613 0.010000 -0.738323 +v 0.830613 0.010000 -0.461452 +v 0.922904 0.010000 -0.461452 +v 0.922904 0.010000 -0.553742 +v 0.830613 0.010000 -0.553742 +v 1.015194 0.010000 -0.461452 +v 1.107484 0.010000 -0.461452 +v 1.107484 0.010000 -0.553742 +v 1.015194 0.010000 -0.553742 +v 0.461452 0.010001 -2.491840 +v 0.553742 0.010001 -2.491840 +v 0.553742 0.010001 -2.584130 +v 0.461452 0.010001 -2.584130 +v 0.461452 0.010001 -2.307259 +v 0.553742 0.010001 -2.307259 +v 0.553742 0.010001 -2.399549 +v 0.461452 0.010001 -2.399549 +v 0.646033 0.010001 -2.307259 +v 0.738323 0.010001 -2.307259 +v 0.738323 0.010001 -2.399549 +v 0.646033 0.010001 -2.399549 +v 0.092290 0.010001 -2.491840 +v 0.184581 0.010001 -2.491840 +v 0.184581 0.010001 -2.584130 +v 0.092290 0.010001 -2.584130 +v 0.092290 0.010001 -2.307259 +v 0.184581 0.010001 -2.307259 +v 0.184581 0.010001 -2.399549 +v 0.092290 0.010001 -2.399549 +v 0.276871 0.010001 -2.307259 +v 0.369161 0.010001 -2.307259 +v 0.369161 0.010001 -2.399549 +v 0.276871 0.010001 -2.399549 +v 0.092290 0.010001 -2.861001 +v 0.184581 0.010001 -2.861001 +v 0.184581 0.010001 -2.953291 +v 0.092290 0.010001 -2.953291 +v 0.092290 0.010001 -2.676420 +v 0.184581 0.010001 -2.676420 +v 0.184581 0.010001 -2.768711 +v 0.092290 0.010001 -2.768711 +v 0.276871 0.010001 -2.676420 +v 0.369161 0.010001 -2.676420 +v 0.369161 0.010001 -2.768711 +v 0.276871 0.010001 -2.768711 +v 0.461452 0.010001 -1.753517 +v 0.553742 0.010001 -1.753517 +v 0.553742 0.010001 -1.845807 +v 0.461452 0.010001 -1.845807 +v 0.461452 0.010001 -1.568936 +v 0.553742 0.010001 -1.568936 +v 0.553742 0.010001 -1.661226 +v 0.461452 0.010001 -1.661226 +v 0.646033 0.010001 -1.568936 +v 0.738323 0.010001 -1.568936 +v 0.738323 0.010001 -1.661226 +v 0.646033 0.010001 -1.661226 +v 0.092290 0.010001 -1.753517 +v 0.184581 0.010001 -1.753517 +v 0.184581 0.010001 -1.845807 +v 0.092290 0.010001 -1.845807 +v 0.092290 0.010001 -1.568936 +v 0.184581 0.010001 -1.568936 +v 0.184581 0.010001 -1.661226 +v 0.092290 0.010001 -1.661226 +v 0.276871 0.010001 -1.568936 +v 0.369161 0.010001 -1.568936 +v 0.369161 0.010001 -1.661226 +v 0.276871 0.010001 -1.661226 +v 0.092290 0.010001 -2.122678 +v 0.184581 0.010001 -2.122678 +v 0.184581 0.010001 -2.214968 +v 0.092290 0.010001 -2.214968 +v 0.092290 0.010001 -1.938097 +v 0.184581 0.010001 -1.938097 +v 0.184581 0.010001 -2.030388 +v 0.092290 0.010001 -2.030388 +v 0.276871 0.010001 -1.938097 +v 0.369161 0.010001 -1.938097 +v 0.369161 0.010001 -2.030388 +v 0.276871 0.010001 -2.030388 +v 1.199775 0.010001 -1.753517 +v 1.292065 0.010001 -1.753517 +v 1.292065 0.010001 -1.845807 +v 1.199775 0.010001 -1.845807 +v 1.199775 0.010001 -1.568936 +v 1.292065 0.010001 -1.568936 +v 1.292065 0.010001 -1.661226 +v 1.199775 0.010001 -1.661226 +v 1.384355 0.010001 -1.568936 +v 1.476646 0.010001 -1.568936 +v 1.476646 0.010001 -1.661226 +v 1.384355 0.010001 -1.661226 +v 0.830613 0.010001 -1.753517 +v 0.922904 0.010001 -1.753517 +v 0.922904 0.010001 -1.845807 +v 0.830613 0.010001 -1.845807 +v 0.830613 0.010001 -1.568936 +v 0.922904 0.010001 -1.568936 +v 0.922904 0.010001 -1.661226 +v 0.830613 0.010001 -1.661226 +v 1.015194 0.010001 -1.568936 +v 1.107484 0.010001 -1.568936 +v 1.107484 0.010001 -1.661226 +v 1.015194 0.010001 -1.661226 +v 0.830613 0.010001 -2.122678 +v 0.922904 0.010001 -2.122678 +v 0.922904 0.010001 -2.214968 +v 0.830613 0.010001 -2.214968 +v 0.830613 0.010001 -1.938097 +v 0.922904 0.010001 -1.938097 +v 0.922904 0.010001 -2.030388 +v 0.830613 0.010001 -2.030388 +v 1.015194 0.010001 -1.938097 +v 1.107484 0.010001 -1.938097 +v 1.107484 0.010001 -2.030388 +v 1.015194 0.010001 -2.030388 +v 4.891389 0.010000 -1.015194 +v 4.983679 0.010000 -1.015194 +v 4.983679 0.010000 -1.107484 +v 4.891389 0.010000 -1.107484 +v 4.891389 0.010000 -0.830613 +v 4.983679 0.010000 -0.830613 +v 4.983679 0.010000 -0.922904 +v 4.891389 0.010000 -0.922904 +v 5.075970 0.010000 -0.830613 +v 5.168260 0.010000 -0.830613 +v 5.168260 0.010000 -0.922904 +v 5.075970 0.010000 -0.922904 +v 4.522227 0.010000 -1.015194 +v 4.614518 0.010000 -1.015194 +v 4.614518 0.010000 -1.107484 +v 4.522227 0.010000 -1.107484 +v 4.522227 0.010000 -0.830613 +v 4.614518 0.010000 -0.830613 +v 4.614518 0.010000 -0.922904 +v 4.522227 0.010000 -0.922904 +v 4.706808 0.010000 -0.830613 +v 4.799098 0.010000 -0.830613 +v 4.799098 0.010000 -0.922904 +v 4.706808 0.010000 -0.922904 +v 4.522227 0.010001 -1.384355 +v 4.614518 0.010001 -1.384355 +v 4.614518 0.010001 -1.476646 +v 4.522227 0.010001 -1.476646 +v 4.522227 0.010000 -1.199775 +v 4.614518 0.010000 -1.199775 +v 4.614518 0.010001 -1.292065 +v 4.522227 0.010001 -1.292065 +v 4.706808 0.010000 -1.199775 +v 4.799098 0.010000 -1.199775 +v 4.799098 0.010001 -1.292065 +v 4.706808 0.010001 -1.292065 +v 4.891389 0.010000 -0.276871 +v 4.983679 0.010000 -0.276871 +v 4.983679 0.010000 -0.369161 +v 4.891389 0.010000 -0.369161 +v 4.891389 0.010000 -0.092290 +v 4.983679 0.010000 -0.092290 +v 4.983679 0.010000 -0.184581 +v 4.891389 0.010000 -0.184581 +v 5.075970 0.010000 -0.092290 +v 5.168260 0.010000 -0.092290 +v 5.168260 0.010000 -0.184581 +v 5.075970 0.010000 -0.184581 +v 4.522227 0.010000 -0.276871 +v 4.614518 0.010000 -0.276871 +v 4.614518 0.010000 -0.369161 +v 4.522227 0.010000 -0.369161 +v 4.522227 0.010000 -0.092290 +v 4.614518 0.010000 -0.092290 +v 4.614518 0.010000 -0.184581 +v 4.522227 0.010000 -0.184581 +v 4.706808 0.010000 -0.092290 +v 4.799098 0.010000 -0.092290 +v 4.799098 0.010000 -0.184581 +v 4.706808 0.010000 -0.184581 +v 4.522227 0.010000 -0.646033 +v 4.614518 0.010000 -0.646033 +v 4.614518 0.010000 -0.738323 +v 4.522227 0.010000 -0.738323 +v 4.522227 0.010000 -0.461452 +v 4.614518 0.010000 -0.461452 +v 4.614518 0.010000 -0.553742 +v 4.522227 0.010000 -0.553742 +v 4.706808 0.010000 -0.461452 +v 4.799098 0.010000 -0.461452 +v 4.799098 0.010000 -0.553742 +v 4.706808 0.010000 -0.553742 +v 5.629711 0.010000 -0.276871 +v 5.722002 0.010000 -0.276871 +v 5.722002 0.010000 -0.369161 +v 5.629711 0.010000 -0.369161 +v 5.629711 0.010000 -0.092290 +v 5.722002 0.010000 -0.092290 +v 5.722002 0.010000 -0.184581 +v 5.629711 0.010000 -0.184581 +v 5.814293 0.010000 -0.092290 +v 5.906583 0.010000 -0.092290 +v 5.906583 0.010000 -0.184581 +v 5.814293 0.010000 -0.184581 +v 5.260550 0.010000 -0.276871 +v 5.352840 0.010000 -0.276871 +v 5.352840 0.010000 -0.369161 +v 5.260550 0.010000 -0.369161 +v 5.260550 0.010000 -0.092290 +v 5.352840 0.010000 -0.092290 +v 5.352840 0.010000 -0.184581 +v 5.260550 0.010000 -0.184581 +v 5.445131 0.010000 -0.092290 +v 5.537421 0.010000 -0.092290 +v 5.537421 0.010000 -0.184581 +v 5.445131 0.010000 -0.184581 +v 5.260550 0.010000 -0.646033 +v 5.352840 0.010000 -0.646033 +v 5.352840 0.010000 -0.738323 +v 5.260550 0.010000 -0.738323 +v 5.260550 0.010000 -0.461452 +v 5.352840 0.010000 -0.461452 +v 5.352840 0.010000 -0.553742 +v 5.260550 0.010000 -0.553742 +v 5.445131 0.010000 -0.461452 +v 5.537421 0.010000 -0.461452 +v 5.537421 0.010000 -0.553742 +v 5.445131 0.010000 -0.553742 +v 3.414743 0.010000 -1.015194 +v 3.507033 0.010000 -1.015194 +v 3.507033 0.010000 -1.107484 +v 3.414743 0.010000 -1.107484 +v 3.414743 0.010000 -0.830613 +v 3.507033 0.010000 -0.830613 +v 3.507033 0.010000 -0.922904 +v 3.414743 0.010000 -0.922904 +v 3.599324 0.010000 -0.830613 +v 3.691614 0.010000 -0.830613 +v 3.691614 0.010000 -0.922904 +v 3.599324 0.010000 -0.922904 +v 3.045582 0.010000 -1.015194 +v 3.137872 0.010000 -1.015194 +v 3.137872 0.010000 -1.107484 +v 3.045582 0.010000 -1.107484 +v 3.045582 0.010000 -0.830613 +v 3.137872 0.010000 -0.830613 +v 3.137872 0.010000 -0.922904 +v 3.045582 0.010000 -0.922904 +v 3.230163 0.010000 -0.830613 +v 3.322453 0.010000 -0.830613 +v 3.322453 0.010000 -0.922904 +v 3.230163 0.010000 -0.922904 +v 3.045582 0.010001 -1.384355 +v 3.137872 0.010001 -1.384355 +v 3.137872 0.010001 -1.476646 +v 3.045582 0.010001 -1.476646 +v 3.045582 0.010000 -1.199775 +v 3.137872 0.010000 -1.199775 +v 3.137872 0.010001 -1.292065 +v 3.045582 0.010001 -1.292065 +v 3.230163 0.010000 -1.199775 +v 3.322453 0.010000 -1.199775 +v 3.322453 0.010001 -1.292065 +v 3.230163 0.010001 -1.292065 +v 3.414743 0.010000 -0.276871 +v 3.507033 0.010000 -0.276871 +v 3.507033 0.010000 -0.369161 +v 3.414743 0.010000 -0.369161 +v 3.414743 0.010000 -0.092290 +v 3.507033 0.010000 -0.092290 +v 3.507033 0.010000 -0.184581 +v 3.414743 0.010000 -0.184581 +v 3.599324 0.010000 -0.092290 +v 3.691614 0.010000 -0.092290 +v 3.691614 0.010000 -0.184581 +v 3.599324 0.010000 -0.184581 +v 3.045582 0.010000 -0.276871 +v 3.137872 0.010000 -0.276871 +v 3.137872 0.010000 -0.369161 +v 3.045582 0.010000 -0.369161 +v 3.045582 0.010000 -0.092290 +v 3.137872 0.010000 -0.092290 +v 3.137872 0.010000 -0.184581 +v 3.045582 0.010000 -0.184581 +v 3.230163 0.010000 -0.092290 +v 3.322453 0.010000 -0.092290 +v 3.322453 0.010000 -0.184581 +v 3.230163 0.010000 -0.184581 +v 3.045582 0.010000 -0.646033 +v 3.137872 0.010000 -0.646033 +v 3.137872 0.010000 -0.738323 +v 3.045582 0.010000 -0.738323 +v 3.045582 0.010000 -0.461452 +v 3.137872 0.010000 -0.461452 +v 3.137872 0.010000 -0.553742 +v 3.045582 0.010000 -0.553742 +v 3.230163 0.010000 -0.461452 +v 3.322453 0.010000 -0.461452 +v 3.322453 0.010000 -0.553742 +v 3.230163 0.010000 -0.553742 +v 4.153066 0.010000 -0.276871 +v 4.245357 0.010000 -0.276871 +v 4.245357 0.010000 -0.369161 +v 4.153066 0.010000 -0.369161 +v 4.153066 0.010000 -0.092290 +v 4.245357 0.010000 -0.092290 +v 4.245357 0.010000 -0.184581 +v 4.153066 0.010000 -0.184581 +v 4.337647 0.010000 -0.092290 +v 4.429937 0.010000 -0.092290 +v 4.429937 0.010000 -0.184581 +v 4.337647 0.010000 -0.184581 +v 3.783905 0.010000 -0.276871 +v 3.876195 0.010000 -0.276871 +v 3.876195 0.010000 -0.369161 +v 3.783905 0.010000 -0.369161 +v 3.783905 0.010000 -0.092290 +v 3.876195 0.010000 -0.092290 +v 3.876195 0.010000 -0.184581 +v 3.783905 0.010000 -0.184581 +v 3.968485 0.010000 -0.092290 +v 4.060776 0.010000 -0.092290 +v 4.060776 0.010000 -0.184581 +v 3.968485 0.010000 -0.184581 +v 3.783905 0.010000 -0.646033 +v 3.876195 0.010000 -0.646033 +v 3.876195 0.010000 -0.738323 +v 3.783905 0.010000 -0.738323 +v 3.783905 0.010000 -0.461452 +v 3.876195 0.010000 -0.461452 +v 3.876195 0.010000 -0.553742 +v 3.783905 0.010000 -0.553742 +v 3.968485 0.010000 -0.461452 +v 4.060776 0.010000 -0.461452 +v 4.060776 0.010000 -0.553742 +v 3.968485 0.010000 -0.553742 +v 3.414743 0.010001 -2.491840 +v 3.507033 0.010001 -2.491840 +v 3.507033 0.010001 -2.584130 +v 3.414743 0.010001 -2.584130 +v 3.414743 0.010001 -2.307259 +v 3.507033 0.010001 -2.307259 +v 3.507033 0.010001 -2.399549 +v 3.414743 0.010001 -2.399549 +v 3.599324 0.010001 -2.307259 +v 3.691614 0.010001 -2.307259 +v 3.691614 0.010001 -2.399549 +v 3.599324 0.010001 -2.399549 +v 3.045582 0.010001 -2.491840 +v 3.137872 0.010001 -2.491840 +v 3.137872 0.010001 -2.584130 +v 3.045582 0.010001 -2.584130 +v 3.045582 0.010001 -2.307259 +v 3.137872 0.010001 -2.307259 +v 3.137872 0.010001 -2.399549 +v 3.045582 0.010001 -2.399549 +v 3.230163 0.010001 -2.307259 +v 3.322453 0.010001 -2.307259 +v 3.322453 0.010001 -2.399549 +v 3.230163 0.010001 -2.399549 +v 3.045582 0.010001 -2.861001 +v 3.137872 0.010001 -2.861001 +v 3.137872 0.010001 -2.953291 +v 3.045582 0.010001 -2.953291 +v 3.045582 0.010001 -2.676420 +v 3.137872 0.010001 -2.676420 +v 3.137872 0.010001 -2.768711 +v 3.045582 0.010001 -2.768711 +v 3.230163 0.010001 -2.676420 +v 3.322453 0.010001 -2.676420 +v 3.322453 0.010001 -2.768711 +v 3.230163 0.010001 -2.768711 +v 3.414743 0.010001 -1.753517 +v 3.507033 0.010001 -1.753517 +v 3.507033 0.010001 -1.845807 +v 3.414743 0.010001 -1.845807 +v 3.414743 0.010001 -1.568936 +v 3.507033 0.010001 -1.568936 +v 3.507033 0.010001 -1.661226 +v 3.414743 0.010001 -1.661226 +v 3.599324 0.010001 -1.568936 +v 3.691614 0.010001 -1.568936 +v 3.691614 0.010001 -1.661226 +v 3.599324 0.010001 -1.661226 +v 3.045582 0.010001 -1.753517 +v 3.137872 0.010001 -1.753517 +v 3.137872 0.010001 -1.845807 +v 3.045582 0.010001 -1.845807 +v 3.045582 0.010001 -1.568936 +v 3.137872 0.010001 -1.568936 +v 3.137872 0.010001 -1.661226 +v 3.045582 0.010001 -1.661226 +v 3.230163 0.010001 -1.568936 +v 3.322453 0.010001 -1.568936 +v 3.322453 0.010001 -1.661226 +v 3.230163 0.010001 -1.661226 +v 3.045582 0.010001 -2.122678 +v 3.137872 0.010001 -2.122678 +v 3.137872 0.010001 -2.214968 +v 3.045582 0.010001 -2.214968 +v 3.045582 0.010001 -1.938097 +v 3.137872 0.010001 -1.938097 +v 3.137872 0.010001 -2.030388 +v 3.045582 0.010001 -2.030388 +v 3.230163 0.010001 -1.938097 +v 3.322453 0.010001 -1.938097 +v 3.322453 0.010001 -2.030388 +v 3.230163 0.010001 -2.030388 +v 4.153066 0.010001 -1.753517 +v 4.245357 0.010001 -1.753517 +v 4.245357 0.010001 -1.845807 +v 4.153066 0.010001 -1.845807 +v 4.153066 0.010001 -1.568936 +v 4.245357 0.010001 -1.568936 +v 4.245357 0.010001 -1.661226 +v 4.153066 0.010001 -1.661226 +v 4.337647 0.010001 -1.568936 +v 4.429937 0.010001 -1.568936 +v 4.429937 0.010001 -1.661226 +v 4.337647 0.010001 -1.661226 +v 3.783905 0.010001 -1.753517 +v 3.876195 0.010001 -1.753517 +v 3.876195 0.010001 -1.845807 +v 3.783905 0.010001 -1.845807 +v 3.783905 0.010001 -1.568936 +v 3.876195 0.010001 -1.568936 +v 3.876195 0.010001 -1.661226 +v 3.783905 0.010001 -1.661226 +v 3.968485 0.010001 -1.568936 +v 4.060776 0.010001 -1.568936 +v 4.060776 0.010001 -1.661226 +v 3.968485 0.010001 -1.661226 +v 3.783905 0.010001 -2.122678 +v 3.876195 0.010001 -2.122678 +v 3.876195 0.010001 -2.214968 +v 3.783905 0.010001 -2.214968 +v 3.783905 0.010001 -1.938097 +v 3.876195 0.010001 -1.938097 +v 3.876195 0.010001 -2.030388 +v 3.783905 0.010001 -2.030388 +v 3.968485 0.010001 -1.938097 +v 4.060776 0.010001 -1.938097 +v 4.060776 0.010001 -2.030388 +v 3.968485 0.010001 -2.030388 +v 4.891389 0.010001 -2.491840 +v 4.983679 0.010001 -2.491840 +v 4.983679 0.010001 -2.584130 +v 4.891389 0.010001 -2.584130 +v 4.891389 0.010001 -2.307259 +v 4.983679 0.010001 -2.307259 +v 4.983679 0.010001 -2.399549 +v 4.891389 0.010001 -2.399549 +v 5.075970 0.010001 -2.307259 +v 5.168260 0.010001 -2.307259 +v 5.168260 0.010001 -2.399549 +v 5.075970 0.010001 -2.399549 +v 4.522227 0.010001 -2.491840 +v 4.614518 0.010001 -2.491840 +v 4.614518 0.010001 -2.584130 +v 4.522227 0.010001 -2.584130 +v 4.522227 0.010001 -2.307259 +v 4.614518 0.010001 -2.307259 +v 4.614518 0.010001 -2.399549 +v 4.522227 0.010001 -2.399549 +v 4.706808 0.010001 -2.307259 +v 4.799098 0.010001 -2.307259 +v 4.799098 0.010001 -2.399549 +v 4.706808 0.010001 -2.399549 +v 4.522227 0.010001 -2.861001 +v 4.614518 0.010001 -2.861001 +v 4.614518 0.010001 -2.953291 +v 4.522227 0.010001 -2.953291 +v 4.522227 0.010001 -2.676420 +v 4.614518 0.010001 -2.676420 +v 4.614518 0.010001 -2.768711 +v 4.522227 0.010001 -2.768711 +v 4.706808 0.010001 -2.676420 +v 4.799098 0.010001 -2.676420 +v 4.799098 0.010001 -2.768711 +v 4.706808 0.010001 -2.768711 +v 4.891389 0.010001 -1.753517 +v 4.983679 0.010001 -1.753517 +v 4.983679 0.010001 -1.845807 +v 4.891389 0.010001 -1.845807 +v 4.891389 0.010001 -1.568936 +v 4.983679 0.010001 -1.568936 +v 4.983679 0.010001 -1.661226 +v 4.891389 0.010001 -1.661226 +v 5.075970 0.010001 -1.568936 +v 5.168260 0.010001 -1.568936 +v 5.168260 0.010001 -1.661226 +v 5.075970 0.010001 -1.661226 +v 4.522227 0.010001 -1.753517 +v 4.614518 0.010001 -1.753517 +v 4.614518 0.010001 -1.845807 +v 4.522227 0.010001 -1.845807 +v 4.522227 0.010001 -1.568936 +v 4.614518 0.010001 -1.568936 +v 4.614518 0.010001 -1.661226 +v 4.522227 0.010001 -1.661226 +v 4.706808 0.010001 -1.568936 +v 4.799098 0.010001 -1.568936 +v 4.799098 0.010001 -1.661226 +v 4.706808 0.010001 -1.661226 +v 4.522227 0.010001 -2.122678 +v 4.614518 0.010001 -2.122678 +v 4.614518 0.010001 -2.214968 +v 4.522227 0.010001 -2.214968 +v 4.522227 0.010001 -1.938097 +v 4.614518 0.010001 -1.938097 +v 4.614518 0.010001 -2.030388 +v 4.522227 0.010001 -2.030388 +v 4.706808 0.010001 -1.938097 +v 4.799098 0.010001 -1.938097 +v 4.799098 0.010001 -2.030388 +v 4.706808 0.010001 -2.030388 +v 5.629711 0.010001 -1.753517 +v 5.722002 0.010001 -1.753517 +v 5.722002 0.010001 -1.845807 +v 5.629711 0.010001 -1.845807 +v 5.629711 0.010001 -1.568936 +v 5.722002 0.010001 -1.568936 +v 5.722002 0.010001 -1.661226 +v 5.629711 0.010001 -1.661226 +v 5.814293 0.010001 -1.568936 +v 5.906583 0.010001 -1.568936 +v 5.906583 0.010001 -1.661226 +v 5.814293 0.010001 -1.661226 +v 5.260550 0.010001 -1.753517 +v 5.352840 0.010001 -1.753517 +v 5.352840 0.010001 -1.845807 +v 5.260550 0.010001 -1.845807 +v 5.260550 0.010001 -1.568936 +v 5.352840 0.010001 -1.568936 +v 5.352840 0.010001 -1.661226 +v 5.260550 0.010001 -1.661226 +v 5.445131 0.010001 -1.568936 +v 5.537421 0.010001 -1.568936 +v 5.537421 0.010001 -1.661226 +v 5.445131 0.010001 -1.661226 +v 5.260550 0.010001 -2.122678 +v 5.352840 0.010001 -2.122678 +v 5.352840 0.010001 -2.214968 +v 5.260550 0.010001 -2.214968 +v 5.260550 0.010001 -1.938097 +v 5.352840 0.010001 -1.938097 +v 5.352840 0.010001 -2.030388 +v 5.260550 0.010001 -2.030388 +v 5.445131 0.010001 -1.938097 +v 5.537421 0.010001 -1.938097 +v 5.537421 0.010001 -2.030388 +v 5.445131 0.010001 -2.030388 +v 1.938097 0.010001 -2.491840 +v 2.030388 0.010001 -2.491840 +v 2.030388 0.010001 -2.584130 +v 1.938097 0.010001 -2.584130 +v 1.938097 0.010001 -2.307259 +v 2.030388 0.010001 -2.307259 +v 2.030388 0.010001 -2.399549 +v 1.938097 0.010001 -2.399549 +v 2.122678 0.010001 -2.307259 +v 2.214968 0.010001 -2.307259 +v 2.214968 0.010001 -2.399549 +v 2.122678 0.010001 -2.399549 +v 1.568936 0.010001 -2.491840 +v 1.661226 0.010001 -2.491840 +v 1.661226 0.010001 -2.584130 +v 1.568936 0.010001 -2.584130 +v 1.568936 0.010001 -2.307259 +v 1.661226 0.010001 -2.307259 +v 1.661226 0.010001 -2.399549 +v 1.568936 0.010001 -2.399549 +v 1.753517 0.010001 -2.307259 +v 1.845807 0.010001 -2.307259 +v 1.845807 0.010001 -2.399549 +v 1.753517 0.010001 -2.399549 +v 1.568936 0.010001 -2.861001 +v 1.661226 0.010001 -2.861001 +v 1.661226 0.010001 -2.953291 +v 1.568936 0.010001 -2.953291 +v 1.568936 0.010001 -2.676420 +v 1.661226 0.010001 -2.676420 +v 1.661226 0.010001 -2.768711 +v 1.568936 0.010001 -2.768711 +v 1.753517 0.010001 -2.676420 +v 1.845807 0.010001 -2.676420 +v 1.845807 0.010001 -2.768711 +v 1.753517 0.010001 -2.768711 +v 1.938097 0.010001 -1.753517 +v 2.030388 0.010001 -1.753517 +v 2.030388 0.010001 -1.845807 +v 1.938097 0.010001 -1.845807 +v 1.938097 0.010001 -1.568936 +v 2.030388 0.010001 -1.568936 +v 2.030388 0.010001 -1.661226 +v 1.938097 0.010001 -1.661226 +v 2.122678 0.010001 -1.568936 +v 2.214968 0.010001 -1.568936 +v 2.214968 0.010001 -1.661226 +v 2.122678 0.010001 -1.661226 +v 1.568936 0.010001 -1.753517 +v 1.661226 0.010001 -1.753517 +v 1.661226 0.010001 -1.845807 +v 1.568936 0.010001 -1.845807 +v 1.568936 0.010001 -1.568936 +v 1.661226 0.010001 -1.568936 +v 1.661226 0.010001 -1.661226 +v 1.568936 0.010001 -1.661226 +v 1.753517 0.010001 -1.568936 +v 1.845807 0.010001 -1.568936 +v 1.845807 0.010001 -1.661226 +v 1.753517 0.010001 -1.661226 +v 1.568936 0.010001 -2.122678 +v 1.661226 0.010001 -2.122678 +v 1.661226 0.010001 -2.214968 +v 1.568936 0.010001 -2.214968 +v 1.568936 0.010001 -1.938097 +v 1.661226 0.010001 -1.938097 +v 1.661226 0.010001 -2.030388 +v 1.568936 0.010001 -2.030388 +v 1.753517 0.010001 -1.938097 +v 1.845807 0.010001 -1.938097 +v 1.845807 0.010001 -2.030388 +v 1.753517 0.010001 -2.030388 +v 2.676420 0.010001 -1.753517 +v 2.768711 0.010001 -1.753517 +v 2.768711 0.010001 -1.845807 +v 2.676420 0.010001 -1.845807 +v 2.676420 0.010001 -1.568936 +v 2.768711 0.010001 -1.568936 +v 2.768711 0.010001 -1.661226 +v 2.676420 0.010001 -1.661226 +v 2.861001 0.010001 -1.568936 +v 2.953291 0.010001 -1.568936 +v 2.953291 0.010001 -1.661226 +v 2.861001 0.010001 -1.661226 +v 2.307259 0.010001 -1.753517 +v 2.399549 0.010001 -1.753517 +v 2.399549 0.010001 -1.845807 +v 2.307259 0.010001 -1.845807 +v 2.307259 0.010001 -1.568936 +v 2.399549 0.010001 -1.568936 +v 2.399549 0.010001 -1.661226 +v 2.307259 0.010001 -1.661226 +v 2.491840 0.010001 -1.568936 +v 2.584130 0.010001 -1.568936 +v 2.584130 0.010001 -1.661226 +v 2.491840 0.010001 -1.661226 +v 2.307259 0.010001 -2.122678 +v 2.399549 0.010001 -2.122678 +v 2.399549 0.010001 -2.214968 +v 2.307259 0.010001 -2.214968 +v 2.307259 0.010001 -1.938097 +v 2.399549 0.010001 -1.938097 +v 2.399549 0.010001 -2.030388 +v 2.307259 0.010001 -2.030388 +v 2.491840 0.010001 -1.938097 +v 2.584130 0.010001 -1.938097 +v 2.584130 0.010001 -2.030388 +v 2.491840 0.010001 -2.030388 +v 1.938097 0.010002 -5.445131 +v 2.030388 0.010002 -5.445131 +v 2.030388 0.010002 -5.537421 +v 1.938097 0.010002 -5.537421 +v 1.938097 0.010002 -5.260550 +v 2.030388 0.010002 -5.260550 +v 2.030388 0.010002 -5.352840 +v 1.938097 0.010002 -5.352840 +v 2.122678 0.010002 -5.260550 +v 2.214968 0.010002 -5.260550 +v 2.214968 0.010002 -5.352840 +v 2.122678 0.010002 -5.352840 +v 1.568936 0.010002 -5.445131 +v 1.661226 0.010002 -5.445131 +v 1.661226 0.010002 -5.537421 +v 1.568936 0.010002 -5.537421 +v 1.568936 0.010002 -5.260550 +v 1.661226 0.010002 -5.260550 +v 1.661226 0.010002 -5.352840 +v 1.568936 0.010002 -5.352840 +v 1.753517 0.010002 -5.260550 +v 1.845807 0.010002 -5.260550 +v 1.845807 0.010002 -5.352840 +v 1.753517 0.010002 -5.352840 +v 1.568936 0.010002 -5.814293 +v 1.661226 0.010002 -5.814293 +v 1.661226 0.010002 -5.906583 +v 1.568936 0.010002 -5.906583 +v 1.568936 0.010002 -5.629711 +v 1.661226 0.010002 -5.629711 +v 1.661226 0.010002 -5.722002 +v 1.568936 0.010002 -5.722002 +v 1.753517 0.010002 -5.629711 +v 1.845807 0.010002 -5.629711 +v 1.845807 0.010002 -5.722002 +v 1.753517 0.010002 -5.722002 +v 1.938097 0.010002 -4.706808 +v 2.030388 0.010002 -4.706808 +v 2.030388 0.010002 -4.799098 +v 1.938097 0.010002 -4.799098 +v 1.938097 0.010002 -4.522227 +v 2.030388 0.010002 -4.522227 +v 2.030388 0.010002 -4.614518 +v 1.938097 0.010002 -4.614518 +v 2.122678 0.010002 -4.522227 +v 2.214968 0.010002 -4.522227 +v 2.214968 0.010002 -4.614518 +v 2.122678 0.010002 -4.614518 +v 1.568936 0.010002 -4.706808 +v 1.661226 0.010002 -4.706808 +v 1.661226 0.010002 -4.799098 +v 1.568936 0.010002 -4.799098 +v 1.568936 0.010002 -4.522227 +v 1.661226 0.010002 -4.522227 +v 1.661226 0.010002 -4.614518 +v 1.568936 0.010002 -4.614518 +v 1.753517 0.010002 -4.522227 +v 1.845807 0.010002 -4.522227 +v 1.845807 0.010002 -4.614518 +v 1.753517 0.010002 -4.614518 +v 1.568936 0.010002 -5.075970 +v 1.661226 0.010002 -5.075970 +v 1.661226 0.010002 -5.168260 +v 1.568936 0.010002 -5.168260 +v 1.568936 0.010002 -4.891389 +v 1.661226 0.010002 -4.891389 +v 1.661226 0.010002 -4.983679 +v 1.568936 0.010002 -4.983679 +v 1.753517 0.010002 -4.891389 +v 1.845807 0.010002 -4.891389 +v 1.845807 0.010002 -4.983679 +v 1.753517 0.010002 -4.983679 +v 2.676420 0.010002 -4.706808 +v 2.768711 0.010002 -4.706808 +v 2.768711 0.010002 -4.799098 +v 2.676420 0.010002 -4.799098 +v 2.676420 0.010002 -4.522227 +v 2.768711 0.010002 -4.522227 +v 2.768711 0.010002 -4.614518 +v 2.676420 0.010002 -4.614518 +v 2.861001 0.010002 -4.522227 +v 2.953291 0.010002 -4.522227 +v 2.953291 0.010002 -4.614518 +v 2.861001 0.010002 -4.614518 +v 2.307259 0.010002 -4.706808 +v 2.399549 0.010002 -4.706808 +v 2.399549 0.010002 -4.799098 +v 2.307259 0.010002 -4.799098 +v 2.307259 0.010002 -4.522227 +v 2.399549 0.010002 -4.522227 +v 2.399549 0.010002 -4.614518 +v 2.307259 0.010002 -4.614518 +v 2.491840 0.010002 -4.522227 +v 2.584130 0.010002 -4.522227 +v 2.584130 0.010002 -4.614518 +v 2.491840 0.010002 -4.614518 +v 2.307259 0.010002 -5.075970 +v 2.399549 0.010002 -5.075970 +v 2.399549 0.010002 -5.168260 +v 2.307259 0.010002 -5.168260 +v 2.307259 0.010002 -4.891389 +v 2.399549 0.010002 -4.891389 +v 2.399549 0.010002 -4.983679 +v 2.307259 0.010002 -4.983679 +v 2.491840 0.010002 -4.891389 +v 2.584130 0.010002 -4.891389 +v 2.584130 0.010002 -4.983679 +v 2.491840 0.010002 -4.983679 +v -1.015194 0.010001 -2.491840 +v -0.922904 0.010001 -2.491840 +v -0.922904 0.010001 -2.584130 +v -1.015194 0.010001 -2.584130 +v -1.015194 0.010001 -2.307259 +v -0.922904 0.010001 -2.307259 +v -0.922904 0.010001 -2.399549 +v -1.015194 0.010001 -2.399549 +v -0.830613 0.010001 -2.307259 +v -0.738323 0.010001 -2.307259 +v -0.738323 0.010001 -2.399549 +v -0.830613 0.010001 -2.399549 +v -1.384355 0.010001 -2.491840 +v -1.292065 0.010001 -2.491840 +v -1.292065 0.010001 -2.584130 +v -1.384355 0.010001 -2.584130 +v -1.384355 0.010001 -2.307259 +v -1.292065 0.010001 -2.307259 +v -1.292065 0.010001 -2.399549 +v -1.384355 0.010001 -2.399549 +v -1.199775 0.010001 -2.307259 +v -1.107484 0.010001 -2.307259 +v -1.107484 0.010001 -2.399549 +v -1.199775 0.010001 -2.399549 +v -1.384355 0.010001 -2.861001 +v -1.292065 0.010001 -2.861001 +v -1.292065 0.010001 -2.953291 +v -1.384355 0.010001 -2.953291 +v -1.384355 0.010001 -2.676420 +v -1.292065 0.010001 -2.676420 +v -1.292065 0.010001 -2.768711 +v -1.384355 0.010001 -2.768711 +v -1.199775 0.010001 -2.676420 +v -1.107484 0.010001 -2.676420 +v -1.107484 0.010001 -2.768711 +v -1.199775 0.010001 -2.768711 +v -1.015194 0.010001 -1.753517 +v -0.922904 0.010001 -1.753517 +v -0.922904 0.010001 -1.845807 +v -1.015194 0.010001 -1.845807 +v -1.015194 0.010001 -1.568936 +v -0.922904 0.010001 -1.568936 +v -0.922904 0.010001 -1.661226 +v -1.015194 0.010001 -1.661226 +v -0.830613 0.010001 -1.568936 +v -0.738323 0.010001 -1.568936 +v -0.738323 0.010001 -1.661226 +v -0.830613 0.010001 -1.661226 +v -1.384355 0.010001 -1.753517 +v -1.292065 0.010001 -1.753517 +v -1.292065 0.010001 -1.845807 +v -1.384355 0.010001 -1.845807 +v -1.384355 0.010001 -1.568936 +v -1.292065 0.010001 -1.568936 +v -1.292065 0.010001 -1.661226 +v -1.384355 0.010001 -1.661226 +v -1.199775 0.010001 -1.568936 +v -1.107484 0.010001 -1.568936 +v -1.107484 0.010001 -1.661226 +v -1.199775 0.010001 -1.661226 +v -1.384355 0.010001 -2.122678 +v -1.292065 0.010001 -2.122678 +v -1.292065 0.010001 -2.214968 +v -1.384355 0.010001 -2.214968 +v -1.384355 0.010001 -1.938097 +v -1.292065 0.010001 -1.938097 +v -1.292065 0.010001 -2.030388 +v -1.384355 0.010001 -2.030388 +v -1.199775 0.010001 -1.938097 +v -1.107484 0.010001 -1.938097 +v -1.107484 0.010001 -2.030388 +v -1.199775 0.010001 -2.030388 +v -0.276871 0.010001 -1.753517 +v -0.184581 0.010001 -1.753517 +v -0.184581 0.010001 -1.845807 +v -0.276871 0.010001 -1.845807 +v -0.276871 0.010001 -1.568936 +v -0.184581 0.010001 -1.568936 +v -0.184581 0.010001 -1.661226 +v -0.276871 0.010001 -1.661226 +v -0.092290 0.010001 -1.568936 +v 0.000000 0.010001 -1.568936 +v 0.000000 0.010001 -1.661226 +v -0.092290 0.010001 -1.661226 +v -0.646033 0.010001 -1.753517 +v -0.553742 0.010001 -1.753517 +v -0.553742 0.010001 -1.845807 +v -0.646033 0.010001 -1.845807 +v -0.646033 0.010001 -1.568936 +v -0.553742 0.010001 -1.568936 +v -0.553742 0.010001 -1.661226 +v -0.646033 0.010001 -1.661226 +v -0.461452 0.010001 -1.568936 +v -0.369161 0.010001 -1.568936 +v -0.369161 0.010001 -1.661226 +v -0.461452 0.010001 -1.661226 +v -0.646033 0.010001 -2.122678 +v -0.553742 0.010001 -2.122678 +v -0.553742 0.010001 -2.214968 +v -0.646033 0.010001 -2.214968 +v -0.646033 0.010001 -1.938097 +v -0.553742 0.010001 -1.938097 +v -0.553742 0.010001 -2.030388 +v -0.646033 0.010001 -2.030388 +v -0.461452 0.010001 -1.938097 +v -0.369161 0.010001 -1.938097 +v -0.369161 0.010001 -2.030388 +v -0.461452 0.010001 -2.030388 +v -3.968485 0.010001 -2.491840 +v -3.876195 0.010001 -2.491840 +v -3.876195 0.010001 -2.584130 +v -3.968485 0.010001 -2.584130 +v -3.968485 0.010001 -2.307259 +v -3.876195 0.010001 -2.307259 +v -3.876195 0.010001 -2.399549 +v -3.968485 0.010001 -2.399549 +v -3.783905 0.010001 -2.307259 +v -3.691614 0.010001 -2.307259 +v -3.691614 0.010001 -2.399549 +v -3.783905 0.010001 -2.399549 +v -4.337647 0.010001 -2.491840 +v -4.245357 0.010001 -2.491840 +v -4.245357 0.010001 -2.584130 +v -4.337647 0.010001 -2.584130 +v -4.337647 0.010001 -2.307259 +v -4.245357 0.010001 -2.307259 +v -4.245357 0.010001 -2.399549 +v -4.337647 0.010001 -2.399549 +v -4.153066 0.010001 -2.307259 +v -4.060776 0.010001 -2.307259 +v -4.060776 0.010001 -2.399549 +v -4.153066 0.010001 -2.399549 +v -4.337647 0.010001 -2.861001 +v -4.245357 0.010001 -2.861001 +v -4.245357 0.010001 -2.953291 +v -4.337647 0.010001 -2.953291 +v -4.337647 0.010001 -2.676420 +v -4.245357 0.010001 -2.676420 +v -4.245357 0.010001 -2.768711 +v -4.337647 0.010001 -2.768711 +v -4.153066 0.010001 -2.676420 +v -4.060776 0.010001 -2.676420 +v -4.060776 0.010001 -2.768711 +v -4.153066 0.010001 -2.768711 +v -3.968485 0.010001 -1.753517 +v -3.876195 0.010001 -1.753517 +v -3.876195 0.010001 -1.845807 +v -3.968485 0.010001 -1.845807 +v -3.968485 0.010001 -1.568936 +v -3.876195 0.010001 -1.568936 +v -3.876195 0.010001 -1.661226 +v -3.968485 0.010001 -1.661226 +v -3.783905 0.010001 -1.568936 +v -3.691614 0.010001 -1.568936 +v -3.691614 0.010001 -1.661226 +v -3.783905 0.010001 -1.661226 +v -4.337647 0.010001 -1.753517 +v -4.245357 0.010001 -1.753517 +v -4.245357 0.010001 -1.845807 +v -4.337647 0.010001 -1.845807 +v -4.337647 0.010001 -1.568936 +v -4.245357 0.010001 -1.568936 +v -4.245357 0.010001 -1.661226 +v -4.337647 0.010001 -1.661226 +v -4.153066 0.010001 -1.568936 +v -4.060776 0.010001 -1.568936 +v -4.060776 0.010001 -1.661226 +v -4.153066 0.010001 -1.661226 +v -4.337647 0.010001 -2.122678 +v -4.245357 0.010001 -2.122678 +v -4.245357 0.010001 -2.214968 +v -4.337647 0.010001 -2.214968 +v -4.337647 0.010001 -1.938097 +v -4.245357 0.010001 -1.938097 +v -4.245357 0.010001 -2.030388 +v -4.337647 0.010001 -2.030388 +v -4.153066 0.010001 -1.938097 +v -4.060776 0.010001 -1.938097 +v -4.060776 0.010001 -2.030388 +v -4.153066 0.010001 -2.030388 +v -3.230163 0.010001 -1.753517 +v -3.137872 0.010001 -1.753517 +v -3.137872 0.010001 -1.845807 +v -3.230163 0.010001 -1.845807 +v -3.230163 0.010001 -1.568936 +v -3.137872 0.010001 -1.568936 +v -3.137872 0.010001 -1.661226 +v -3.230163 0.010001 -1.661226 +v -3.045582 0.010001 -1.568936 +v -2.953291 0.010001 -1.568936 +v -2.953291 0.010001 -1.661226 +v -3.045582 0.010001 -1.661226 +v -3.599324 0.010001 -1.753517 +v -3.507033 0.010001 -1.753517 +v -3.507033 0.010001 -1.845807 +v -3.599324 0.010001 -1.845807 +v -3.599324 0.010001 -1.568936 +v -3.507033 0.010001 -1.568936 +v -3.507033 0.010001 -1.661226 +v -3.599324 0.010001 -1.661226 +v -3.414743 0.010001 -1.568936 +v -3.322453 0.010001 -1.568936 +v -3.322453 0.010001 -1.661226 +v -3.414743 0.010001 -1.661226 +v -3.599324 0.010001 -2.122678 +v -3.507033 0.010001 -2.122678 +v -3.507033 0.010001 -2.214968 +v -3.599324 0.010001 -2.214968 +v -3.599324 0.010001 -1.938097 +v -3.507033 0.010001 -1.938097 +v -3.507033 0.010001 -2.030388 +v -3.599324 0.010001 -2.030388 +v -3.414743 0.010001 -1.938097 +v -3.322453 0.010001 -1.938097 +v -3.322453 0.010001 -2.030388 +v -3.414743 0.010001 -2.030388 +v -3.968485 0.010002 -5.445131 +v -3.876195 0.010002 -5.445131 +v -3.876195 0.010002 -5.537421 +v -3.968485 0.010002 -5.537421 +v -3.968485 0.010002 -5.260550 +v -3.876195 0.010002 -5.260550 +v -3.876195 0.010002 -5.352840 +v -3.968485 0.010002 -5.352840 +v -3.783905 0.010002 -5.260550 +v -3.691614 0.010002 -5.260550 +v -3.691614 0.010002 -5.352840 +v -3.783905 0.010002 -5.352840 +v -4.337647 0.010002 -5.445131 +v -4.245357 0.010002 -5.445131 +v -4.245357 0.010002 -5.537421 +v -4.337647 0.010002 -5.537421 +v -4.337647 0.010002 -5.260550 +v -4.245357 0.010002 -5.260550 +v -4.245357 0.010002 -5.352840 +v -4.337647 0.010002 -5.352840 +v -4.153066 0.010002 -5.260550 +v -4.060776 0.010002 -5.260550 +v -4.060776 0.010002 -5.352840 +v -4.153066 0.010002 -5.352840 +v -4.337647 0.010002 -5.814293 +v -4.245357 0.010002 -5.814293 +v -4.245357 0.010002 -5.906583 +v -4.337647 0.010002 -5.906583 +v -4.337647 0.010002 -5.629711 +v -4.245357 0.010002 -5.629711 +v -4.245357 0.010002 -5.722002 +v -4.337647 0.010002 -5.722002 +v -4.153066 0.010002 -5.629711 +v -4.060776 0.010002 -5.629711 +v -4.060776 0.010002 -5.722002 +v -4.153066 0.010002 -5.722002 +v -3.968485 0.010002 -4.706808 +v -3.876195 0.010002 -4.706808 +v -3.876195 0.010002 -4.799098 +v -3.968485 0.010002 -4.799098 +v -3.968485 0.010002 -4.522227 +v -3.876195 0.010002 -4.522227 +v -3.876195 0.010002 -4.614518 +v -3.968485 0.010002 -4.614518 +v -3.783905 0.010002 -4.522227 +v -3.691614 0.010002 -4.522227 +v -3.691614 0.010002 -4.614518 +v -3.783905 0.010002 -4.614518 +v -4.337647 0.010002 -4.706808 +v -4.245357 0.010002 -4.706808 +v -4.245357 0.010002 -4.799098 +v -4.337647 0.010002 -4.799098 +v -4.337647 0.010002 -4.522227 +v -4.245357 0.010002 -4.522227 +v -4.245357 0.010002 -4.614518 +v -4.337647 0.010002 -4.614518 +v -4.153066 0.010002 -4.522227 +v -4.060776 0.010002 -4.522227 +v -4.060776 0.010002 -4.614518 +v -4.153066 0.010002 -4.614518 +v -4.337647 0.010002 -5.075970 +v -4.245357 0.010002 -5.075970 +v -4.245357 0.010002 -5.168260 +v -4.337647 0.010002 -5.168260 +v -4.337647 0.010002 -4.891389 +v -4.245357 0.010002 -4.891389 +v -4.245357 0.010002 -4.983679 +v -4.337647 0.010002 -4.983679 +v -4.153066 0.010002 -4.891389 +v -4.060776 0.010002 -4.891389 +v -4.060776 0.010002 -4.983679 +v -4.153066 0.010002 -4.983679 +v -3.230163 0.010002 -4.706808 +v -3.137872 0.010002 -4.706808 +v -3.137872 0.010002 -4.799098 +v -3.230163 0.010002 -4.799098 +v -3.230163 0.010002 -4.522227 +v -3.137872 0.010002 -4.522227 +v -3.137872 0.010002 -4.614518 +v -3.230163 0.010002 -4.614518 +v -3.045582 0.010002 -4.522227 +v -2.953291 0.010002 -4.522227 +v -2.953291 0.010002 -4.614518 +v -3.045582 0.010002 -4.614518 +v -3.599324 0.010002 -4.706808 +v -3.507033 0.010002 -4.706808 +v -3.507033 0.010002 -4.799098 +v -3.599324 0.010002 -4.799098 +v -3.599324 0.010002 -4.522227 +v -3.507033 0.010002 -4.522227 +v -3.507033 0.010002 -4.614518 +v -3.599324 0.010002 -4.614518 +v -3.414743 0.010002 -4.522227 +v -3.322453 0.010002 -4.522227 +v -3.322453 0.010002 -4.614518 +v -3.414743 0.010002 -4.614518 +v -3.599324 0.010002 -5.075970 +v -3.507033 0.010002 -5.075970 +v -3.507033 0.010002 -5.168260 +v -3.599324 0.010002 -5.168260 +v -3.599324 0.010002 -4.891389 +v -3.507033 0.010002 -4.891389 +v -3.507033 0.010002 -4.983679 +v -3.599324 0.010002 -4.983679 +v -3.414743 0.010002 -4.891389 +v -3.322453 0.010002 -4.891389 +v -3.322453 0.010002 -4.983679 +v -3.414743 0.010002 -4.983679 +v -1.015194 0.009999 3.414743 +v -0.922904 0.009999 3.414743 +v -0.922904 0.009999 3.322453 +v -1.015194 0.009999 3.322453 +v -1.015194 0.009999 3.599324 +v -0.922904 0.009999 3.599324 +v -0.922904 0.009999 3.507033 +v -1.015194 0.009999 3.507033 +v -0.830613 0.009999 3.599324 +v -0.738323 0.009999 3.599324 +v -0.738323 0.009999 3.507033 +v -0.830613 0.009999 3.507033 +v -1.384355 0.009999 3.414743 +v -1.292065 0.009999 3.414743 +v -1.292065 0.009999 3.322453 +v -1.384355 0.009999 3.322453 +v -1.384355 0.009999 3.599324 +v -1.292065 0.009999 3.599324 +v -1.292065 0.009999 3.507033 +v -1.384355 0.009999 3.507033 +v -1.199775 0.009999 3.599324 +v -1.107484 0.009999 3.599324 +v -1.107484 0.009999 3.507033 +v -1.199775 0.009999 3.507033 +v -1.384355 0.009999 3.045582 +v -1.292065 0.009999 3.045582 +v -1.292065 0.009999 2.953291 +v -1.384355 0.009999 2.953291 +v -1.384355 0.009999 3.230163 +v -1.292065 0.009999 3.230163 +v -1.292065 0.009999 3.137872 +v -1.384355 0.009999 3.137872 +v -1.199775 0.009999 3.230163 +v -1.107484 0.009999 3.230163 +v -1.107484 0.009999 3.137872 +v -1.199775 0.009999 3.137872 +v -1.015194 0.009998 4.153066 +v -0.922904 0.009998 4.153066 +v -0.922904 0.009998 4.060776 +v -1.015194 0.009998 4.060776 +v -1.015194 0.009998 4.337647 +v -0.922904 0.009998 4.337647 +v -0.922904 0.009998 4.245357 +v -1.015194 0.009998 4.245357 +v -0.830613 0.009998 4.337647 +v -0.738323 0.009998 4.337647 +v -0.738323 0.009998 4.245357 +v -0.830613 0.009998 4.245357 +v -1.384355 0.009998 4.153066 +v -1.292065 0.009998 4.153066 +v -1.292065 0.009998 4.060776 +v -1.384355 0.009998 4.060776 +v -1.384355 0.009998 4.337647 +v -1.292065 0.009998 4.337647 +v -1.292065 0.009998 4.245357 +v -1.384355 0.009998 4.245357 +v -1.199775 0.009998 4.337647 +v -1.107484 0.009998 4.337647 +v -1.107484 0.009998 4.245357 +v -1.199775 0.009998 4.245357 +v -1.384355 0.009998 3.783905 +v -1.292065 0.009998 3.783905 +v -1.292065 0.009998 3.691614 +v -1.384355 0.009998 3.691614 +v -1.384355 0.009998 3.968485 +v -1.292065 0.009998 3.968485 +v -1.292065 0.009998 3.876195 +v -1.384355 0.009998 3.876195 +v -1.199775 0.009998 3.968485 +v -1.107484 0.009998 3.968485 +v -1.107484 0.009998 3.876195 +v -1.199775 0.009998 3.876195 +v -0.276871 0.009998 4.153066 +v -0.184581 0.009998 4.153066 +v -0.184581 0.009998 4.060776 +v -0.276871 0.009998 4.060776 +v -0.276871 0.009998 4.337647 +v -0.184581 0.009998 4.337647 +v -0.184581 0.009998 4.245357 +v -0.276871 0.009998 4.245357 +v -0.092290 0.009998 4.337647 +v 0.000000 0.009998 4.337647 +v 0.000000 0.009998 4.245357 +v -0.092290 0.009998 4.245357 +v -0.646033 0.009998 4.153066 +v -0.553742 0.009998 4.153066 +v -0.553742 0.009998 4.060776 +v -0.646033 0.009998 4.060776 +v -0.646033 0.009998 4.337647 +v -0.553742 0.009998 4.337647 +v -0.553742 0.009998 4.245357 +v -0.646033 0.009998 4.245357 +v -0.461452 0.009998 4.337647 +v -0.369161 0.009998 4.337647 +v -0.369161 0.009998 4.245357 +v -0.461452 0.009998 4.245357 +v -0.646033 0.009998 3.783905 +v -0.553742 0.009998 3.783905 +v -0.553742 0.009998 3.691614 +v -0.646033 0.009998 3.691614 +v -0.646033 0.009998 3.968485 +v -0.553742 0.009998 3.968485 +v -0.553742 0.009998 3.876195 +v -0.646033 0.009998 3.876195 +v -0.461452 0.009998 3.968485 +v -0.369161 0.009998 3.968485 +v -0.369161 0.009998 3.876195 +v -0.461452 0.009998 3.876195 +v -3.968485 0.009999 3.414743 +v -3.876195 0.009999 3.414743 +v -3.876195 0.009999 3.322453 +v -3.968485 0.009999 3.322453 +v -3.968485 0.009999 3.599324 +v -3.876195 0.009999 3.599324 +v -3.876195 0.009999 3.507033 +v -3.968485 0.009999 3.507033 +v -3.783905 0.009999 3.599324 +v -3.691614 0.009999 3.599324 +v -3.691614 0.009999 3.507033 +v -3.783905 0.009999 3.507033 +v -4.337647 0.009999 3.414743 +v -4.245357 0.009999 3.414743 +v -4.245357 0.009999 3.322453 +v -4.337647 0.009999 3.322453 +v -4.337647 0.009999 3.599324 +v -4.245357 0.009999 3.599324 +v -4.245357 0.009999 3.507033 +v -4.337647 0.009999 3.507033 +v -4.153066 0.009999 3.599324 +v -4.060776 0.009999 3.599324 +v -4.060776 0.009999 3.507033 +v -4.153066 0.009999 3.507033 +v -4.337647 0.009999 3.045582 +v -4.245357 0.009999 3.045582 +v -4.245357 0.009999 2.953291 +v -4.337647 0.009999 2.953291 +v -4.337647 0.009999 3.230163 +v -4.245357 0.009999 3.230163 +v -4.245357 0.009999 3.137872 +v -4.337647 0.009999 3.137872 +v -4.153066 0.009999 3.230163 +v -4.060776 0.009999 3.230163 +v -4.060776 0.009999 3.137872 +v -4.153066 0.009999 3.137872 +v -3.968485 0.009998 4.153066 +v -3.876195 0.009998 4.153066 +v -3.876195 0.009998 4.060776 +v -3.968485 0.009998 4.060776 +v -3.968485 0.009998 4.337647 +v -3.876195 0.009998 4.337647 +v -3.876195 0.009998 4.245357 +v -3.968485 0.009998 4.245357 +v -3.783905 0.009998 4.337647 +v -3.691614 0.009998 4.337647 +v -3.691614 0.009998 4.245357 +v -3.783905 0.009998 4.245357 +v -4.337647 0.009998 4.153066 +v -4.245357 0.009998 4.153066 +v -4.245357 0.009998 4.060776 +v -4.337647 0.009998 4.060776 +v -4.337647 0.009998 4.337647 +v -4.245357 0.009998 4.337647 +v -4.245357 0.009998 4.245357 +v -4.337647 0.009998 4.245357 +v -4.153066 0.009998 4.337647 +v -4.060776 0.009998 4.337647 +v -4.060776 0.009998 4.245357 +v -4.153066 0.009998 4.245357 +v -4.337647 0.009998 3.783905 +v -4.245357 0.009998 3.783905 +v -4.245357 0.009998 3.691614 +v -4.337647 0.009998 3.691614 +v -4.337647 0.009998 3.968485 +v -4.245357 0.009998 3.968485 +v -4.245357 0.009998 3.876195 +v -4.337647 0.009998 3.876195 +v -4.153066 0.009998 3.968485 +v -4.060776 0.009998 3.968485 +v -4.060776 0.009998 3.876195 +v -4.153066 0.009998 3.876195 +v -3.230163 0.009998 4.153066 +v -3.137872 0.009998 4.153066 +v -3.137872 0.009998 4.060776 +v -3.230163 0.009998 4.060776 +v -3.230163 0.009998 4.337647 +v -3.137872 0.009998 4.337647 +v -3.137872 0.009998 4.245357 +v -3.230163 0.009998 4.245357 +v -3.045582 0.009998 4.337647 +v -2.953291 0.009998 4.337647 +v -2.953291 0.009998 4.245357 +v -3.045582 0.009998 4.245357 +v -3.599324 0.009998 4.153066 +v -3.507033 0.009998 4.153066 +v -3.507033 0.009998 4.060776 +v -3.599324 0.009998 4.060776 +v -3.599324 0.009998 4.337647 +v -3.507033 0.009998 4.337647 +v -3.507033 0.009998 4.245357 +v -3.599324 0.009998 4.245357 +v -3.414743 0.009998 4.337647 +v -3.322453 0.009998 4.337647 +v -3.322453 0.009998 4.245357 +v -3.414743 0.009998 4.245357 +v -3.599324 0.009998 3.783905 +v -3.507033 0.009998 3.783905 +v -3.507033 0.009998 3.691614 +v -3.599324 0.009998 3.691614 +v -3.599324 0.009998 3.968485 +v -3.507033 0.009998 3.968485 +v -3.507033 0.009998 3.876195 +v -3.599324 0.009998 3.876195 +v -3.414743 0.009998 3.968485 +v -3.322453 0.009998 3.968485 +v -3.322453 0.009998 3.876195 +v -3.414743 0.009998 3.876195 +v -3.968485 0.010000 0.461452 +v -3.876195 0.010000 0.461452 +v -3.876195 0.010000 0.369161 +v -3.968485 0.010000 0.369161 +v -3.968485 0.010000 0.646033 +v -3.876195 0.010000 0.646033 +v -3.876195 0.010000 0.553742 +v -3.968485 0.010000 0.553742 +v -3.783905 0.010000 0.646033 +v -3.691614 0.010000 0.646033 +v -3.691614 0.010000 0.553742 +v -3.783905 0.010000 0.553742 +v -4.337647 0.010000 0.461452 +v -4.245357 0.010000 0.461452 +v -4.245357 0.010000 0.369161 +v -4.337647 0.010000 0.369161 +v -4.337647 0.010000 0.646033 +v -4.245357 0.010000 0.646033 +v -4.245357 0.010000 0.553742 +v -4.337647 0.010000 0.553742 +v -4.153066 0.010000 0.646033 +v -4.060776 0.010000 0.646033 +v -4.060776 0.010000 0.553742 +v -4.153066 0.010000 0.553742 +v -4.337647 0.010000 0.092290 +v -4.245357 0.010000 0.092290 +v -4.245357 0.010000 -0.000000 +v -4.337647 0.010000 -0.000000 +v -4.337647 0.010000 0.276871 +v -4.245357 0.010000 0.276871 +v -4.245357 0.010000 0.184581 +v -4.337647 0.010000 0.184581 +v -4.153066 0.010000 0.276871 +v -4.060776 0.010000 0.276871 +v -4.060776 0.010000 0.184581 +v -4.153066 0.010000 0.184581 +v -3.968485 0.010000 1.199775 +v -3.876195 0.010000 1.199775 +v -3.876195 0.010000 1.107484 +v -3.968485 0.010000 1.107484 +v -3.968485 0.009999 1.384355 +v -3.876195 0.009999 1.384355 +v -3.876195 0.009999 1.292065 +v -3.968485 0.009999 1.292065 +v -3.783905 0.009999 1.384355 +v -3.691614 0.009999 1.384355 +v -3.691614 0.009999 1.292065 +v -3.783905 0.009999 1.292065 +v -4.337647 0.010000 1.199775 +v -4.245357 0.010000 1.199775 +v -4.245357 0.010000 1.107484 +v -4.337647 0.010000 1.107484 +v -4.337647 0.009999 1.384355 +v -4.245357 0.009999 1.384355 +v -4.245357 0.009999 1.292065 +v -4.337647 0.009999 1.292065 +v -4.153066 0.009999 1.384355 +v -4.060776 0.009999 1.384355 +v -4.060776 0.009999 1.292065 +v -4.153066 0.009999 1.292065 +v -4.337647 0.010000 0.830613 +v -4.245357 0.010000 0.830613 +v -4.245357 0.010000 0.738323 +v -4.337647 0.010000 0.738323 +v -4.337647 0.010000 1.015194 +v -4.245357 0.010000 1.015194 +v -4.245357 0.010000 0.922904 +v -4.337647 0.010000 0.922904 +v -4.153066 0.010000 1.015194 +v -4.060776 0.010000 1.015194 +v -4.060776 0.010000 0.922904 +v -4.153066 0.010000 0.922904 +v -3.230163 0.010000 1.199775 +v -3.137872 0.010000 1.199775 +v -3.137872 0.010000 1.107484 +v -3.230163 0.010000 1.107484 +v -3.230163 0.009999 1.384355 +v -3.137872 0.009999 1.384355 +v -3.137872 0.009999 1.292065 +v -3.230163 0.009999 1.292065 +v -3.045582 0.009999 1.384355 +v -2.953291 0.009999 1.384355 +v -2.953291 0.009999 1.292065 +v -3.045582 0.009999 1.292065 +v -3.599324 0.010000 1.199775 +v -3.507033 0.010000 1.199775 +v -3.507033 0.010000 1.107484 +v -3.599324 0.010000 1.107484 +v -3.599324 0.009999 1.384355 +v -3.507033 0.009999 1.384355 +v -3.507033 0.009999 1.292065 +v -3.599324 0.009999 1.292065 +v -3.414743 0.009999 1.384355 +v -3.322453 0.009999 1.384355 +v -3.322453 0.009999 1.292065 +v -3.414743 0.009999 1.292065 +v -3.599324 0.010000 0.830613 +v -3.507033 0.010000 0.830613 +v -3.507033 0.010000 0.738323 +v -3.599324 0.010000 0.738323 +v -3.599324 0.010000 1.015194 +v -3.507033 0.010000 1.015194 +v -3.507033 0.010000 0.922904 +v -3.599324 0.010000 0.922904 +v -3.414743 0.010000 1.015194 +v -3.322453 0.010000 1.015194 +v -3.322453 0.010000 0.922904 +v -3.414743 0.010000 0.922904 +v 4.891389 0.009999 3.414743 +v 4.983679 0.009999 3.414743 +v 4.983679 0.009999 3.322453 +v 4.891389 0.009999 3.322453 +v 4.891389 0.009999 3.599324 +v 4.983679 0.009999 3.599324 +v 4.983679 0.009999 3.507033 +v 4.891389 0.009999 3.507033 +v 5.075970 0.009999 3.599324 +v 5.168260 0.009999 3.599324 +v 5.168260 0.009999 3.507033 +v 5.075970 0.009999 3.507033 +v 4.522227 0.009999 3.414743 +v 4.614518 0.009999 3.414743 +v 4.614518 0.009999 3.322453 +v 4.522227 0.009999 3.322453 +v 4.522227 0.009999 3.599324 +v 4.614518 0.009999 3.599324 +v 4.614518 0.009999 3.507033 +v 4.522227 0.009999 3.507033 +v 4.706808 0.009999 3.599324 +v 4.799098 0.009999 3.599324 +v 4.799098 0.009999 3.507033 +v 4.706808 0.009999 3.507033 +v 4.522227 0.009999 3.045582 +v 4.614518 0.009999 3.045582 +v 4.614518 0.009999 2.953291 +v 4.522227 0.009999 2.953291 +v 4.522227 0.009999 3.230163 +v 4.614518 0.009999 3.230163 +v 4.614518 0.009999 3.137872 +v 4.522227 0.009999 3.137872 +v 4.706808 0.009999 3.230163 +v 4.799098 0.009999 3.230163 +v 4.799098 0.009999 3.137872 +v 4.706808 0.009999 3.137872 +v 4.891389 0.009998 4.153066 +v 4.983679 0.009998 4.153066 +v 4.983679 0.009998 4.060776 +v 4.891389 0.009998 4.060776 +v 4.891389 0.009998 4.337647 +v 4.983679 0.009998 4.337647 +v 4.983679 0.009998 4.245357 +v 4.891389 0.009998 4.245357 +v 5.075970 0.009998 4.337647 +v 5.168260 0.009998 4.337647 +v 5.168260 0.009998 4.245357 +v 5.075970 0.009998 4.245357 +v 4.522227 0.009998 4.153066 +v 4.614518 0.009998 4.153066 +v 4.614518 0.009998 4.060776 +v 4.522227 0.009998 4.060776 +v 4.522227 0.009998 4.337647 +v 4.614518 0.009998 4.337647 +v 4.614518 0.009998 4.245357 +v 4.522227 0.009998 4.245357 +v 4.706808 0.009998 4.337647 +v 4.799098 0.009998 4.337647 +v 4.799098 0.009998 4.245357 +v 4.706808 0.009998 4.245357 +v 4.522227 0.009998 3.783905 +v 4.614518 0.009998 3.783905 +v 4.614518 0.009998 3.691614 +v 4.522227 0.009998 3.691614 +v 4.522227 0.009998 3.968485 +v 4.614518 0.009998 3.968485 +v 4.614518 0.009998 3.876195 +v 4.522227 0.009998 3.876195 +v 4.706808 0.009998 3.968485 +v 4.799098 0.009998 3.968485 +v 4.799098 0.009998 3.876195 +v 4.706808 0.009998 3.876195 +v 5.629711 0.009998 4.153066 +v 5.722002 0.009998 4.153066 +v 5.722002 0.009998 4.060776 +v 5.629711 0.009998 4.060776 +v 5.629711 0.009998 4.337647 +v 5.722002 0.009998 4.337647 +v 5.722002 0.009998 4.245357 +v 5.629711 0.009998 4.245357 +v 5.814293 0.009998 4.337647 +v 5.906583 0.009998 4.337647 +v 5.906583 0.009998 4.245357 +v 5.814293 0.009998 4.245357 +v 5.260550 0.009998 4.153066 +v 5.352840 0.009998 4.153066 +v 5.352840 0.009998 4.060776 +v 5.260550 0.009998 4.060776 +v 5.260550 0.009998 4.337647 +v 5.352840 0.009998 4.337647 +v 5.352840 0.009998 4.245357 +v 5.260550 0.009998 4.245357 +v 5.445131 0.009998 4.337647 +v 5.537421 0.009998 4.337647 +v 5.537421 0.009998 4.245357 +v 5.445131 0.009998 4.245357 +v 5.260550 0.009998 3.783905 +v 5.352840 0.009998 3.783905 +v 5.352840 0.009998 3.691614 +v 5.260550 0.009998 3.691614 +v 5.260550 0.009998 3.968485 +v 5.352840 0.009998 3.968485 +v 5.352840 0.009998 3.876195 +v 5.260550 0.009998 3.876195 +v 5.445131 0.009998 3.968485 +v 5.537421 0.009998 3.968485 +v 5.537421 0.009998 3.876195 +v 5.445131 0.009998 3.876195 +v 1.938097 0.009999 3.414743 +v 2.030388 0.009999 3.414743 +v 2.030388 0.009999 3.322453 +v 1.938097 0.009999 3.322453 +v 1.938097 0.009999 3.599324 +v 2.030388 0.009999 3.599324 +v 2.030388 0.009999 3.507033 +v 1.938097 0.009999 3.507033 +v 2.122678 0.009999 3.599324 +v 2.214968 0.009999 3.599324 +v 2.214968 0.009999 3.507033 +v 2.122678 0.009999 3.507033 +v 1.568936 0.009999 3.414743 +v 1.661226 0.009999 3.414743 +v 1.661226 0.009999 3.322453 +v 1.568936 0.009999 3.322453 +v 1.568936 0.009999 3.599324 +v 1.661226 0.009999 3.599324 +v 1.661226 0.009999 3.507033 +v 1.568936 0.009999 3.507033 +v 1.753517 0.009999 3.599324 +v 1.845807 0.009999 3.599324 +v 1.845807 0.009999 3.507033 +v 1.753517 0.009999 3.507033 +v 1.568936 0.009999 3.045582 +v 1.661226 0.009999 3.045582 +v 1.661226 0.009999 2.953291 +v 1.568936 0.009999 2.953291 +v 1.568936 0.009999 3.230163 +v 1.661226 0.009999 3.230163 +v 1.661226 0.009999 3.137872 +v 1.568936 0.009999 3.137872 +v 1.753517 0.009999 3.230163 +v 1.845807 0.009999 3.230163 +v 1.845807 0.009999 3.137872 +v 1.753517 0.009999 3.137872 +v 1.938097 0.009998 4.153066 +v 2.030388 0.009998 4.153066 +v 2.030388 0.009998 4.060776 +v 1.938097 0.009998 4.060776 +v 1.938097 0.009998 4.337647 +v 2.030388 0.009998 4.337647 +v 2.030388 0.009998 4.245357 +v 1.938097 0.009998 4.245357 +v 2.122678 0.009998 4.337647 +v 2.214968 0.009998 4.337647 +v 2.214968 0.009998 4.245357 +v 2.122678 0.009998 4.245357 +v 1.568936 0.009998 4.153066 +v 1.661226 0.009998 4.153066 +v 1.661226 0.009998 4.060776 +v 1.568936 0.009998 4.060776 +v 1.568936 0.009998 4.337647 +v 1.661226 0.009998 4.337647 +v 1.661226 0.009998 4.245357 +v 1.568936 0.009998 4.245357 +v 1.753517 0.009998 4.337647 +v 1.845807 0.009998 4.337647 +v 1.845807 0.009998 4.245357 +v 1.753517 0.009998 4.245357 +v 1.568936 0.009998 3.783905 +v 1.661226 0.009998 3.783905 +v 1.661226 0.009998 3.691614 +v 1.568936 0.009998 3.691614 +v 1.568936 0.009998 3.968485 +v 1.661226 0.009998 3.968485 +v 1.661226 0.009998 3.876195 +v 1.568936 0.009998 3.876195 +v 1.753517 0.009998 3.968485 +v 1.845807 0.009998 3.968485 +v 1.845807 0.009998 3.876195 +v 1.753517 0.009998 3.876195 +v 2.676420 0.009998 4.153066 +v 2.768711 0.009998 4.153066 +v 2.768711 0.009998 4.060776 +v 2.676420 0.009998 4.060776 +v 2.676420 0.009998 4.337647 +v 2.768711 0.009998 4.337647 +v 2.768711 0.009998 4.245357 +v 2.676420 0.009998 4.245357 +v 2.861001 0.009998 4.337647 +v 2.953291 0.009998 4.337647 +v 2.953291 0.009998 4.245357 +v 2.861001 0.009998 4.245357 +v 2.307259 0.009998 4.153066 +v 2.399549 0.009998 4.153066 +v 2.399549 0.009998 4.060776 +v 2.307259 0.009998 4.060776 +v 2.307259 0.009998 4.337647 +v 2.399549 0.009998 4.337647 +v 2.399549 0.009998 4.245357 +v 2.307259 0.009998 4.245357 +v 2.491840 0.009998 4.337647 +v 2.584130 0.009998 4.337647 +v 2.584130 0.009998 4.245357 +v 2.491840 0.009998 4.245357 +v 2.307259 0.009998 3.783905 +v 2.399549 0.009998 3.783905 +v 2.399549 0.009998 3.691614 +v 2.307259 0.009998 3.691614 +v 2.307259 0.009998 3.968485 +v 2.399549 0.009998 3.968485 +v 2.399549 0.009998 3.876195 +v 2.307259 0.009998 3.876195 +v 2.491840 0.009998 3.968485 +v 2.584130 0.009998 3.968485 +v 2.584130 0.009998 3.876195 +v 2.491840 0.009998 3.876195 +v 1.938097 0.010000 0.461452 +v 2.030388 0.010000 0.461452 +v 2.030388 0.010000 0.369161 +v 1.938097 0.010000 0.369161 +v 1.938097 0.010000 0.646033 +v 2.030388 0.010000 0.646033 +v 2.030388 0.010000 0.553742 +v 1.938097 0.010000 0.553742 +v 2.122678 0.010000 0.646033 +v 2.214968 0.010000 0.646033 +v 2.214968 0.010000 0.553742 +v 2.122678 0.010000 0.553742 +v 1.568936 0.010000 0.461452 +v 1.661226 0.010000 0.461452 +v 1.661226 0.010000 0.369161 +v 1.568936 0.010000 0.369161 +v 1.568936 0.010000 0.646033 +v 1.661226 0.010000 0.646033 +v 1.661226 0.010000 0.553742 +v 1.568936 0.010000 0.553742 +v 1.753517 0.010000 0.646033 +v 1.845807 0.010000 0.646033 +v 1.845807 0.010000 0.553742 +v 1.753517 0.010000 0.553742 +v 1.568936 0.010000 0.092290 +v 1.661226 0.010000 0.092290 +v 1.661226 0.010000 -0.000000 +v 1.568936 0.010000 -0.000000 +v 1.568936 0.010000 0.276871 +v 1.661226 0.010000 0.276871 +v 1.661226 0.010000 0.184581 +v 1.568936 0.010000 0.184581 +v 1.753517 0.010000 0.276871 +v 1.845807 0.010000 0.276871 +v 1.845807 0.010000 0.184581 +v 1.753517 0.010000 0.184581 +v 1.938097 0.010000 1.199775 +v 2.030388 0.010000 1.199775 +v 2.030388 0.010000 1.107484 +v 1.938097 0.010000 1.107484 +v 1.938097 0.009999 1.384355 +v 2.030388 0.009999 1.384355 +v 2.030388 0.009999 1.292065 +v 1.938097 0.009999 1.292065 +v 2.122678 0.009999 1.384355 +v 2.214968 0.009999 1.384355 +v 2.214968 0.009999 1.292065 +v 2.122678 0.009999 1.292065 +v 1.568936 0.010000 1.199775 +v 1.661226 0.010000 1.199775 +v 1.661226 0.010000 1.107484 +v 1.568936 0.010000 1.107484 +v 1.568936 0.009999 1.384355 +v 1.661226 0.009999 1.384355 +v 1.661226 0.009999 1.292065 +v 1.568936 0.009999 1.292065 +v 1.753517 0.009999 1.384355 +v 1.845807 0.009999 1.384355 +v 1.845807 0.009999 1.292065 +v 1.753517 0.009999 1.292065 +v 1.568936 0.010000 0.830613 +v 1.661226 0.010000 0.830613 +v 1.661226 0.010000 0.738323 +v 1.568936 0.010000 0.738323 +v 1.568936 0.010000 1.015194 +v 1.661226 0.010000 1.015194 +v 1.661226 0.010000 0.922904 +v 1.568936 0.010000 0.922904 +v 1.753517 0.010000 1.015194 +v 1.845807 0.010000 1.015194 +v 1.845807 0.010000 0.922904 +v 1.753517 0.010000 0.922904 +v 2.676420 0.010000 1.199775 +v 2.768711 0.010000 1.199775 +v 2.768711 0.010000 1.107484 +v 2.676420 0.010000 1.107484 +v 2.676420 0.009999 1.384355 +v 2.768711 0.009999 1.384355 +v 2.768711 0.009999 1.292065 +v 2.676420 0.009999 1.292065 +v 2.861001 0.009999 1.384355 +v 2.953291 0.009999 1.384355 +v 2.953291 0.009999 1.292065 +v 2.861001 0.009999 1.292065 +v 2.307259 0.010000 1.199775 +v 2.399549 0.010000 1.199775 +v 2.399549 0.010000 1.107484 +v 2.307259 0.010000 1.107484 +v 2.307259 0.009999 1.384355 +v 2.399549 0.009999 1.384355 +v 2.399549 0.009999 1.292065 +v 2.307259 0.009999 1.292065 +v 2.491840 0.009999 1.384355 +v 2.584130 0.009999 1.384355 +v 2.584130 0.009999 1.292065 +v 2.491840 0.009999 1.292065 +v 2.307259 0.010000 0.830613 +v 2.399549 0.010000 0.830613 +v 2.399549 0.010000 0.738323 +v 2.307259 0.010000 0.738323 +v 2.307259 0.010000 1.015194 +v 2.399549 0.010000 1.015194 +v 2.399549 0.010000 0.922904 +v 2.307259 0.010000 0.922904 +v 2.491840 0.010000 1.015194 +v 2.584130 0.010000 1.015194 +v 2.584130 0.010000 0.922904 +v 2.491840 0.010000 0.922904 +v 4.891389 0.010000 0.461452 +v 4.983679 0.010000 0.461452 +v 4.983679 0.010000 0.369161 +v 4.891389 0.010000 0.369161 +v 4.891389 0.010000 0.646033 +v 4.983679 0.010000 0.646033 +v 4.983679 0.010000 0.553742 +v 4.891389 0.010000 0.553742 +v 5.075970 0.010000 0.646033 +v 5.168260 0.010000 0.646033 +v 5.168260 0.010000 0.553742 +v 5.075970 0.010000 0.553742 +v 4.522227 0.010000 0.461452 +v 4.614518 0.010000 0.461452 +v 4.614518 0.010000 0.369161 +v 4.522227 0.010000 0.369161 +v 4.522227 0.010000 0.646033 +v 4.614518 0.010000 0.646033 +v 4.614518 0.010000 0.553742 +v 4.522227 0.010000 0.553742 +v 4.706808 0.010000 0.646033 +v 4.799098 0.010000 0.646033 +v 4.799098 0.010000 0.553742 +v 4.706808 0.010000 0.553742 +v 4.522227 0.010000 0.092290 +v 4.614518 0.010000 0.092290 +v 4.614518 0.010000 -0.000000 +v 4.522227 0.010000 -0.000000 +v 4.522227 0.010000 0.276871 +v 4.614518 0.010000 0.276871 +v 4.614518 0.010000 0.184581 +v 4.522227 0.010000 0.184581 +v 4.706808 0.010000 0.276871 +v 4.799098 0.010000 0.276871 +v 4.799098 0.010000 0.184581 +v 4.706808 0.010000 0.184581 +v 4.891389 0.010000 1.199775 +v 4.983679 0.010000 1.199775 +v 4.983679 0.010000 1.107484 +v 4.891389 0.010000 1.107484 +v 4.891389 0.009999 1.384355 +v 4.983679 0.009999 1.384355 +v 4.983679 0.009999 1.292065 +v 4.891389 0.009999 1.292065 +v 5.075970 0.009999 1.384355 +v 5.168260 0.009999 1.384355 +v 5.168260 0.009999 1.292065 +v 5.075970 0.009999 1.292065 +v 4.522227 0.010000 1.199775 +v 4.614518 0.010000 1.199775 +v 4.614518 0.010000 1.107484 +v 4.522227 0.010000 1.107484 +v 4.522227 0.009999 1.384355 +v 4.614518 0.009999 1.384355 +v 4.614518 0.009999 1.292065 +v 4.522227 0.009999 1.292065 +v 4.706808 0.009999 1.384355 +v 4.799098 0.009999 1.384355 +v 4.799098 0.009999 1.292065 +v 4.706808 0.009999 1.292065 +v 4.522227 0.010000 0.830613 +v 4.614518 0.010000 0.830613 +v 4.614518 0.010000 0.738323 +v 4.522227 0.010000 0.738323 +v 4.522227 0.010000 1.015194 +v 4.614518 0.010000 1.015194 +v 4.614518 0.010000 0.922904 +v 4.522227 0.010000 0.922904 +v 4.706808 0.010000 1.015194 +v 4.799098 0.010000 1.015194 +v 4.799098 0.010000 0.922904 +v 4.706808 0.010000 0.922904 +v 5.629711 0.010000 1.199775 +v 5.722002 0.010000 1.199775 +v 5.722002 0.010000 1.107484 +v 5.629711 0.010000 1.107484 +v 5.629711 0.009999 1.384355 +v 5.722002 0.009999 1.384355 +v 5.722002 0.009999 1.292065 +v 5.629711 0.009999 1.292065 +v 5.814293 0.009999 1.384355 +v 5.906583 0.009999 1.384355 +v 5.906583 0.009999 1.292065 +v 5.814293 0.009999 1.292065 +v 5.260550 0.010000 1.199775 +v 5.352840 0.010000 1.199775 +v 5.352840 0.010000 1.107484 +v 5.260550 0.010000 1.107484 +v 5.260550 0.009999 1.384355 +v 5.352840 0.009999 1.384355 +v 5.352840 0.009999 1.292065 +v 5.260550 0.009999 1.292065 +v 5.445131 0.009999 1.384355 +v 5.537421 0.009999 1.384355 +v 5.537421 0.009999 1.292065 +v 5.445131 0.009999 1.292065 +v 5.260550 0.010000 0.830613 +v 5.352840 0.010000 0.830613 +v 5.352840 0.010000 0.738323 +v 5.260550 0.010000 0.738323 +v 5.260550 0.010000 1.015194 +v 5.352840 0.010000 1.015194 +v 5.352840 0.010000 0.922904 +v 5.260550 0.010000 0.922904 +v 5.445131 0.010000 1.015194 +v 5.537421 0.010000 1.015194 +v 5.537421 0.010000 0.922904 +v 5.445131 0.010000 0.922904 +v -1.015194 0.010000 0.461452 +v -0.922904 0.010000 0.461452 +v -0.922904 0.010000 0.369161 +v -1.015194 0.010000 0.369161 +v -1.015194 0.010000 0.646033 +v -0.922904 0.010000 0.646033 +v -0.922904 0.010000 0.553742 +v -1.015194 0.010000 0.553742 +v -0.830613 0.010000 0.646033 +v -0.738323 0.010000 0.646033 +v -0.738323 0.010000 0.553742 +v -0.830613 0.010000 0.553742 +v -1.384355 0.010000 0.461452 +v -1.292065 0.010000 0.461452 +v -1.292065 0.010000 0.369161 +v -1.384355 0.010000 0.369161 +v -1.384355 0.010000 0.646033 +v -1.292065 0.010000 0.646033 +v -1.292065 0.010000 0.553742 +v -1.384355 0.010000 0.553742 +v -1.199775 0.010000 0.646033 +v -1.107484 0.010000 0.646033 +v -1.107484 0.010000 0.553742 +v -1.199775 0.010000 0.553742 +v -1.384355 0.010000 0.092290 +v -1.292065 0.010000 0.092290 +v -1.292065 0.010000 -0.000000 +v -1.384355 0.010000 -0.000000 +v -1.384355 0.010000 0.276871 +v -1.292065 0.010000 0.276871 +v -1.292065 0.010000 0.184581 +v -1.384355 0.010000 0.184581 +v -1.199775 0.010000 0.276871 +v -1.107484 0.010000 0.276871 +v -1.107484 0.010000 0.184581 +v -1.199775 0.010000 0.184581 +v -1.015194 0.010000 1.199775 +v -0.922904 0.010000 1.199775 +v -0.922904 0.010000 1.107484 +v -1.015194 0.010000 1.107484 +v -1.015194 0.009999 1.384355 +v -0.922904 0.009999 1.384355 +v -0.922904 0.009999 1.292065 +v -1.015194 0.009999 1.292065 +v -0.830613 0.009999 1.384355 +v -0.738323 0.009999 1.384355 +v -0.738323 0.009999 1.292065 +v -0.830613 0.009999 1.292065 +v -1.384355 0.010000 1.199775 +v -1.292065 0.010000 1.199775 +v -1.292065 0.010000 1.107484 +v -1.384355 0.010000 1.107484 +v -1.384355 0.009999 1.384355 +v -1.292065 0.009999 1.384355 +v -1.292065 0.009999 1.292065 +v -1.384355 0.009999 1.292065 +v -1.199775 0.009999 1.384355 +v -1.107484 0.009999 1.384355 +v -1.107484 0.009999 1.292065 +v -1.199775 0.009999 1.292065 +v -1.384355 0.010000 0.830613 +v -1.292065 0.010000 0.830613 +v -1.292065 0.010000 0.738323 +v -1.384355 0.010000 0.738323 +v -1.384355 0.010000 1.015194 +v -1.292065 0.010000 1.015194 +v -1.292065 0.010000 0.922904 +v -1.384355 0.010000 0.922904 +v -1.199775 0.010000 1.015194 +v -1.107484 0.010000 1.015194 +v -1.107484 0.010000 0.922904 +v -1.199775 0.010000 0.922904 +v -0.276871 0.010000 1.199775 +v -0.184581 0.010000 1.199775 +v -0.184581 0.010000 1.107484 +v -0.276871 0.010000 1.107484 +v -0.276871 0.009999 1.384355 +v -0.184581 0.009999 1.384355 +v -0.184581 0.009999 1.292065 +v -0.276871 0.009999 1.292065 +v -0.092290 0.009999 1.384355 +v 0.000000 0.009999 1.384355 +v 0.000000 0.009999 1.292065 +v -0.092290 0.009999 1.292065 +v -0.646033 0.010000 1.199775 +v -0.553742 0.010000 1.199775 +v -0.553742 0.010000 1.107484 +v -0.646033 0.010000 1.107484 +v -0.646033 0.009999 1.384355 +v -0.553742 0.009999 1.384355 +v -0.553742 0.009999 1.292065 +v -0.646033 0.009999 1.292065 +v -0.461452 0.009999 1.384355 +v -0.369161 0.009999 1.384355 +v -0.369161 0.009999 1.292065 +v -0.461452 0.009999 1.292065 +v -0.646033 0.010000 0.830613 +v -0.553742 0.010000 0.830613 +v -0.553742 0.010000 0.738323 +v -0.646033 0.010000 0.738323 +v -0.646033 0.010000 1.015194 +v -0.553742 0.010000 1.015194 +v -0.553742 0.010000 0.922904 +v -0.646033 0.010000 0.922904 +v -0.461452 0.010000 1.015194 +v -0.369161 0.010000 1.015194 +v -0.369161 0.010000 0.922904 +v -0.461452 0.010000 0.922904 +v -1.015194 0.010002 -5.445131 +v -0.922904 0.010002 -5.445131 +v -0.922904 0.010002 -5.537421 +v -1.015194 0.010002 -5.537421 +v -1.015194 0.010002 -5.260550 +v -0.922904 0.010002 -5.260550 +v -0.922904 0.010002 -5.352840 +v -1.015194 0.010002 -5.352840 +v -0.830613 0.010002 -5.260550 +v -0.738323 0.010002 -5.260550 +v -0.738323 0.010002 -5.352840 +v -0.830613 0.010002 -5.352840 +v -1.384355 0.010002 -5.445131 +v -1.292065 0.010002 -5.445131 +v -1.292065 0.010002 -5.537421 +v -1.384355 0.010002 -5.537421 +v -1.384355 0.010002 -5.260550 +v -1.292065 0.010002 -5.260550 +v -1.292065 0.010002 -5.352840 +v -1.384355 0.010002 -5.352840 +v -1.199775 0.010002 -5.260550 +v -1.107484 0.010002 -5.260550 +v -1.107484 0.010002 -5.352840 +v -1.199775 0.010002 -5.352840 +v -1.384355 0.010002 -5.814293 +v -1.292065 0.010002 -5.814293 +v -1.292065 0.010002 -5.906583 +v -1.384355 0.010002 -5.906583 +v -1.384355 0.010002 -5.629711 +v -1.292065 0.010002 -5.629711 +v -1.292065 0.010002 -5.722002 +v -1.384355 0.010002 -5.722002 +v -1.199775 0.010002 -5.629711 +v -1.107484 0.010002 -5.629711 +v -1.107484 0.010002 -5.722002 +v -1.199775 0.010002 -5.722002 +v -1.015194 0.010002 -4.706808 +v -0.922904 0.010002 -4.706808 +v -0.922904 0.010002 -4.799098 +v -1.015194 0.010002 -4.799098 +v -1.015194 0.010002 -4.522227 +v -0.922904 0.010002 -4.522227 +v -0.922904 0.010002 -4.614518 +v -1.015194 0.010002 -4.614518 +v -0.830613 0.010002 -4.522227 +v -0.738323 0.010002 -4.522227 +v -0.738323 0.010002 -4.614518 +v -0.830613 0.010002 -4.614518 +v -1.384355 0.010002 -4.706808 +v -1.292065 0.010002 -4.706808 +v -1.292065 0.010002 -4.799098 +v -1.384355 0.010002 -4.799098 +v -1.384355 0.010002 -4.522227 +v -1.292065 0.010002 -4.522227 +v -1.292065 0.010002 -4.614518 +v -1.384355 0.010002 -4.614518 +v -1.199775 0.010002 -4.522227 +v -1.107484 0.010002 -4.522227 +v -1.107484 0.010002 -4.614518 +v -1.199775 0.010002 -4.614518 +v -1.384355 0.010002 -5.075970 +v -1.292065 0.010002 -5.075970 +v -1.292065 0.010002 -5.168260 +v -1.384355 0.010002 -5.168260 +v -1.384355 0.010002 -4.891389 +v -1.292065 0.010002 -4.891389 +v -1.292065 0.010002 -4.983679 +v -1.384355 0.010002 -4.983679 +v -1.199775 0.010002 -4.891389 +v -1.107484 0.010002 -4.891389 +v -1.107484 0.010002 -4.983679 +v -1.199775 0.010002 -4.983679 +v -0.276871 0.010002 -4.706808 +v -0.184581 0.010002 -4.706808 +v -0.184581 0.010002 -4.799098 +v -0.276871 0.010002 -4.799098 +v -0.276871 0.010002 -4.522227 +v -0.184581 0.010002 -4.522227 +v -0.184581 0.010002 -4.614518 +v -0.276871 0.010002 -4.614518 +v -0.092290 0.010002 -4.522227 +v 0.000000 0.010002 -4.522227 +v 0.000000 0.010002 -4.614518 +v -0.092290 0.010002 -4.614518 +v -0.646033 0.010002 -4.706808 +v -0.553742 0.010002 -4.706808 +v -0.553742 0.010002 -4.799098 +v -0.646033 0.010002 -4.799098 +v -0.646033 0.010002 -4.522227 +v -0.553742 0.010002 -4.522227 +v -0.553742 0.010002 -4.614518 +v -0.646033 0.010002 -4.614518 +v -0.461452 0.010002 -4.522227 +v -0.369161 0.010002 -4.522227 +v -0.369161 0.010002 -4.614518 +v -0.461452 0.010002 -4.614518 +v -0.646033 0.010002 -5.075970 +v -0.553742 0.010002 -5.075970 +v -0.553742 0.010002 -5.168260 +v -0.646033 0.010002 -5.168260 +v -0.646033 0.010002 -4.891389 +v -0.553742 0.010002 -4.891389 +v -0.553742 0.010002 -4.983679 +v -0.646033 0.010002 -4.983679 +v -0.461452 0.010002 -4.891389 +v -0.369161 0.010002 -4.891389 +v -0.369161 0.010002 -4.983679 +v -0.461452 0.010002 -4.983679 +v 4.891389 0.010002 -5.445131 +v 4.983679 0.010002 -5.445131 +v 4.983679 0.010002 -5.537421 +v 4.891389 0.010002 -5.537421 +v 4.891389 0.010002 -5.260550 +v 4.983679 0.010002 -5.260550 +v 4.983679 0.010002 -5.352840 +v 4.891389 0.010002 -5.352840 +v 5.075970 0.010002 -5.260550 +v 5.168260 0.010002 -5.260550 +v 5.168260 0.010002 -5.352840 +v 5.075970 0.010002 -5.352840 +v 4.522227 0.010002 -5.445131 +v 4.614518 0.010002 -5.445131 +v 4.614518 0.010002 -5.537421 +v 4.522227 0.010002 -5.537421 +v 4.522227 0.010002 -5.260550 +v 4.614518 0.010002 -5.260550 +v 4.614518 0.010002 -5.352840 +v 4.522227 0.010002 -5.352840 +v 4.706808 0.010002 -5.260550 +v 4.799098 0.010002 -5.260550 +v 4.799098 0.010002 -5.352840 +v 4.706808 0.010002 -5.352840 +v 4.522227 0.010002 -5.814293 +v 4.614518 0.010002 -5.814293 +v 4.614518 0.010002 -5.906583 +v 4.522227 0.010002 -5.906583 +v 4.522227 0.010002 -5.629711 +v 4.614518 0.010002 -5.629711 +v 4.614518 0.010002 -5.722002 +v 4.522227 0.010002 -5.722002 +v 4.706808 0.010002 -5.629711 +v 4.799098 0.010002 -5.629711 +v 4.799098 0.010002 -5.722002 +v 4.706808 0.010002 -5.722002 +v 4.891389 0.010002 -4.706808 +v 4.983679 0.010002 -4.706808 +v 4.983679 0.010002 -4.799098 +v 4.891389 0.010002 -4.799098 +v 4.891389 0.010002 -4.522227 +v 4.983679 0.010002 -4.522227 +v 4.983679 0.010002 -4.614518 +v 4.891389 0.010002 -4.614518 +v 5.075970 0.010002 -4.522227 +v 5.168260 0.010002 -4.522227 +v 5.168260 0.010002 -4.614518 +v 5.075970 0.010002 -4.614518 +v 4.522227 0.010002 -4.706808 +v 4.614518 0.010002 -4.706808 +v 4.614518 0.010002 -4.799098 +v 4.522227 0.010002 -4.799098 +v 4.522227 0.010002 -4.522227 +v 4.614518 0.010002 -4.522227 +v 4.614518 0.010002 -4.614518 +v 4.522227 0.010002 -4.614518 +v 4.706808 0.010002 -4.522227 +v 4.799098 0.010002 -4.522227 +v 4.799098 0.010002 -4.614518 +v 4.706808 0.010002 -4.614518 +v 4.522227 0.010002 -5.075970 +v 4.614518 0.010002 -5.075970 +v 4.614518 0.010002 -5.168260 +v 4.522227 0.010002 -5.168260 +v 4.522227 0.010002 -4.891389 +v 4.614518 0.010002 -4.891389 +v 4.614518 0.010002 -4.983679 +v 4.522227 0.010002 -4.983679 +v 4.706808 0.010002 -4.891389 +v 4.799098 0.010002 -4.891389 +v 4.799098 0.010002 -4.983679 +v 4.706808 0.010002 -4.983679 +v 5.629711 0.010002 -4.706808 +v 5.722002 0.010002 -4.706808 +v 5.722002 0.010002 -4.799098 +v 5.629711 0.010002 -4.799098 +v 5.629711 0.010002 -4.522227 +v 5.722002 0.010002 -4.522227 +v 5.722002 0.010002 -4.614518 +v 5.629711 0.010002 -4.614518 +v 5.814293 0.010002 -4.522227 +v 5.906583 0.010002 -4.522227 +v 5.906583 0.010002 -4.614518 +v 5.814293 0.010002 -4.614518 +v 5.260550 0.010002 -4.706808 +v 5.352840 0.010002 -4.706808 +v 5.352840 0.010002 -4.799098 +v 5.260550 0.010002 -4.799098 +v 5.260550 0.010002 -4.522227 +v 5.352840 0.010002 -4.522227 +v 5.352840 0.010002 -4.614518 +v 5.260550 0.010002 -4.614518 +v 5.445131 0.010002 -4.522227 +v 5.537421 0.010002 -4.522227 +v 5.537421 0.010002 -4.614518 +v 5.445131 0.010002 -4.614518 +v 5.260550 0.010002 -5.075970 +v 5.352840 0.010002 -5.075970 +v 5.352840 0.010002 -5.168260 +v 5.260550 0.010002 -5.168260 +v 5.260550 0.010002 -4.891389 +v 5.352840 0.010002 -4.891389 +v 5.352840 0.010002 -4.983679 +v 5.260550 0.010002 -4.983679 +v 5.445131 0.010002 -4.891389 +v 5.537421 0.010002 -4.891389 +v 5.537421 0.010002 -4.983679 +v 5.445131 0.010002 -4.983679 +v 5.629711 0.010002 -5.075970 +v 5.722002 0.010002 -5.075970 +v 5.722002 0.010002 -5.168260 +v 5.629711 0.010002 -5.168260 +v 5.629711 0.010002 -4.891389 +v 5.722002 0.010002 -4.891389 +v 5.722002 0.010002 -4.983679 +v 5.629711 0.010002 -4.983679 +v 5.814293 0.010002 -4.891389 +v 5.906583 0.010002 -4.891389 +v 5.906583 0.010002 -4.983679 +v 5.814293 0.010002 -4.983679 +v 4.891389 0.010002 -5.075970 +v 4.983679 0.010002 -5.075970 +v 4.983679 0.010002 -5.168260 +v 4.891389 0.010002 -5.168260 +v 4.891389 0.010002 -4.891389 +v 4.983679 0.010002 -4.891389 +v 4.983679 0.010002 -4.983679 +v 4.891389 0.010002 -4.983679 +v 5.075970 0.010002 -4.891389 +v 5.168260 0.010002 -4.891389 +v 5.168260 0.010002 -4.983679 +v 5.075970 0.010002 -4.983679 +v 4.891389 0.010002 -5.814293 +v 4.983679 0.010002 -5.814293 +v 4.983679 0.010002 -5.906583 +v 4.891389 0.010002 -5.906583 +v 4.891389 0.010002 -5.629711 +v 4.983679 0.010002 -5.629711 +v 4.983679 0.010002 -5.722002 +v 4.891389 0.010002 -5.722002 +v 5.075970 0.010002 -5.629711 +v 5.168260 0.010002 -5.629711 +v 5.168260 0.010002 -5.722002 +v 5.075970 0.010002 -5.722002 +v -0.276871 0.010002 -5.075970 +v -0.184581 0.010002 -5.075970 +v -0.184581 0.010002 -5.168260 +v -0.276871 0.010002 -5.168260 +v -0.276871 0.010002 -4.891389 +v -0.184581 0.010002 -4.891389 +v -0.184581 0.010002 -4.983679 +v -0.276871 0.010002 -4.983679 +v -0.092290 0.010002 -4.891389 +v 0.000000 0.010002 -4.891389 +v 0.000000 0.010002 -4.983679 +v -0.092290 0.010002 -4.983679 +v -1.015194 0.010002 -5.075970 +v -0.922904 0.010002 -5.075970 +v -0.922904 0.010002 -5.168260 +v -1.015194 0.010002 -5.168260 +v -1.015194 0.010002 -4.891389 +v -0.922904 0.010002 -4.891389 +v -0.922904 0.010002 -4.983679 +v -1.015194 0.010002 -4.983679 +v -0.830613 0.010002 -4.891389 +v -0.738323 0.010002 -4.891389 +v -0.738323 0.010002 -4.983679 +v -0.830613 0.010002 -4.983679 +v -1.015194 0.010002 -5.814293 +v -0.922904 0.010002 -5.814293 +v -0.922904 0.010002 -5.906583 +v -1.015194 0.010002 -5.906583 +v -1.015194 0.010002 -5.629711 +v -0.922904 0.010002 -5.629711 +v -0.922904 0.010002 -5.722002 +v -1.015194 0.010002 -5.722002 +v -0.830613 0.010002 -5.629711 +v -0.738323 0.010002 -5.629711 +v -0.738323 0.010002 -5.722002 +v -0.830613 0.010002 -5.722002 +v -0.276871 0.010000 0.830613 +v -0.184581 0.010000 0.830613 +v -0.184581 0.010000 0.738323 +v -0.276871 0.010000 0.738323 +v -0.276871 0.010000 1.015194 +v -0.184581 0.010000 1.015194 +v -0.184581 0.010000 0.922904 +v -0.276871 0.010000 0.922904 +v -0.092290 0.010000 1.015194 +v 0.000000 0.010000 1.015194 +v 0.000000 0.010000 0.922904 +v -0.092290 0.010000 0.922904 +v -1.015194 0.010000 0.830613 +v -0.922904 0.010000 0.830613 +v -0.922904 0.010000 0.738323 +v -1.015194 0.010000 0.738323 +v -1.015194 0.010000 1.015194 +v -0.922904 0.010000 1.015194 +v -0.922904 0.010000 0.922904 +v -1.015194 0.010000 0.922904 +v -0.830613 0.010000 1.015194 +v -0.738323 0.010000 1.015194 +v -0.738323 0.010000 0.922904 +v -0.830613 0.010000 0.922904 +v -1.015194 0.010000 0.092290 +v -0.922904 0.010000 0.092290 +v -0.922904 0.010000 -0.000000 +v -1.015194 0.010000 -0.000000 +v -1.015194 0.010000 0.276871 +v -0.922904 0.010000 0.276871 +v -0.922904 0.010000 0.184581 +v -1.015194 0.010000 0.184581 +v -0.830613 0.010000 0.276871 +v -0.738323 0.010000 0.276871 +v -0.738323 0.010000 0.184581 +v -0.830613 0.010000 0.184581 +v 5.629711 0.010000 0.830613 +v 5.722002 0.010000 0.830613 +v 5.722002 0.010000 0.738323 +v 5.629711 0.010000 0.738323 +v 5.629711 0.010000 1.015194 +v 5.722002 0.010000 1.015194 +v 5.722002 0.010000 0.922904 +v 5.629711 0.010000 0.922904 +v 5.814293 0.010000 1.015194 +v 5.906583 0.010000 1.015194 +v 5.906583 0.010000 0.922904 +v 5.814293 0.010000 0.922904 +v 4.891389 0.010000 0.830613 +v 4.983679 0.010000 0.830613 +v 4.983679 0.010000 0.738323 +v 4.891389 0.010000 0.738323 +v 4.891389 0.010000 1.015194 +v 4.983679 0.010000 1.015194 +v 4.983679 0.010000 0.922904 +v 4.891389 0.010000 0.922904 +v 5.075970 0.010000 1.015194 +v 5.168260 0.010000 1.015194 +v 5.168260 0.010000 0.922904 +v 5.075970 0.010000 0.922904 +v 4.891389 0.010000 0.092290 +v 4.983679 0.010000 0.092290 +v 4.983679 0.010000 -0.000000 +v 4.891389 0.010000 -0.000000 +v 4.891389 0.010000 0.276871 +v 4.983679 0.010000 0.276871 +v 4.983679 0.010000 0.184581 +v 4.891389 0.010000 0.184581 +v 5.075970 0.010000 0.276871 +v 5.168260 0.010000 0.276871 +v 5.168260 0.010000 0.184581 +v 5.075970 0.010000 0.184581 +v 2.676420 0.010000 0.830613 +v 2.768711 0.010000 0.830613 +v 2.768711 0.010000 0.738323 +v 2.676420 0.010000 0.738323 +v 2.676420 0.010000 1.015194 +v 2.768711 0.010000 1.015194 +v 2.768711 0.010000 0.922904 +v 2.676420 0.010000 0.922904 +v 2.861001 0.010000 1.015194 +v 2.953291 0.010000 1.015194 +v 2.953291 0.010000 0.922904 +v 2.861001 0.010000 0.922904 +v 1.938097 0.010000 0.830613 +v 2.030388 0.010000 0.830613 +v 2.030388 0.010000 0.738323 +v 1.938097 0.010000 0.738323 +v 1.938097 0.010000 1.015194 +v 2.030388 0.010000 1.015194 +v 2.030388 0.010000 0.922904 +v 1.938097 0.010000 0.922904 +v 2.122678 0.010000 1.015194 +v 2.214968 0.010000 1.015194 +v 2.214968 0.010000 0.922904 +v 2.122678 0.010000 0.922904 +v 1.938097 0.010000 0.092290 +v 2.030388 0.010000 0.092290 +v 2.030388 0.010000 -0.000000 +v 1.938097 0.010000 -0.000000 +v 1.938097 0.010000 0.276871 +v 2.030388 0.010000 0.276871 +v 2.030388 0.010000 0.184581 +v 1.938097 0.010000 0.184581 +v 2.122678 0.010000 0.276871 +v 2.214968 0.010000 0.276871 +v 2.214968 0.010000 0.184581 +v 2.122678 0.010000 0.184581 +v 2.676420 0.009998 3.783905 +v 2.768711 0.009998 3.783905 +v 2.768711 0.009998 3.691614 +v 2.676420 0.009998 3.691614 +v 2.676420 0.009998 3.968485 +v 2.768711 0.009998 3.968485 +v 2.768711 0.009998 3.876195 +v 2.676420 0.009998 3.876195 +v 2.861001 0.009998 3.968485 +v 2.953291 0.009998 3.968485 +v 2.953291 0.009998 3.876195 +v 2.861001 0.009998 3.876195 +v 1.938097 0.009998 3.783905 +v 2.030388 0.009998 3.783905 +v 2.030388 0.009998 3.691614 +v 1.938097 0.009998 3.691614 +v 1.938097 0.009998 3.968485 +v 2.030388 0.009998 3.968485 +v 2.030388 0.009998 3.876195 +v 1.938097 0.009998 3.876195 +v 2.122678 0.009998 3.968485 +v 2.214968 0.009998 3.968485 +v 2.214968 0.009998 3.876195 +v 2.122678 0.009998 3.876195 +v 1.938097 0.009999 3.045582 +v 2.030388 0.009999 3.045582 +v 2.030388 0.009999 2.953291 +v 1.938097 0.009999 2.953291 +v 1.938097 0.009999 3.230163 +v 2.030388 0.009999 3.230163 +v 2.030388 0.009999 3.137872 +v 1.938097 0.009999 3.137872 +v 2.122678 0.009999 3.230163 +v 2.214968 0.009999 3.230163 +v 2.214968 0.009999 3.137872 +v 2.122678 0.009999 3.137872 +v 5.629711 0.009998 3.783905 +v 5.722002 0.009998 3.783905 +v 5.722002 0.009998 3.691614 +v 5.629711 0.009998 3.691614 +v 5.629711 0.009998 3.968485 +v 5.722002 0.009998 3.968485 +v 5.722002 0.009998 3.876195 +v 5.629711 0.009998 3.876195 +v 5.814293 0.009998 3.968485 +v 5.906583 0.009998 3.968485 +v 5.906583 0.009998 3.876195 +v 5.814293 0.009998 3.876195 +v 4.891389 0.009998 3.783905 +v 4.983679 0.009998 3.783905 +v 4.983679 0.009998 3.691614 +v 4.891389 0.009998 3.691614 +v 4.891389 0.009998 3.968485 +v 4.983679 0.009998 3.968485 +v 4.983679 0.009998 3.876195 +v 4.891389 0.009998 3.876195 +v 5.075970 0.009998 3.968485 +v 5.168260 0.009998 3.968485 +v 5.168260 0.009998 3.876195 +v 5.075970 0.009998 3.876195 +v 4.891389 0.009999 3.045582 +v 4.983679 0.009999 3.045582 +v 4.983679 0.009999 2.953291 +v 4.891389 0.009999 2.953291 +v 4.891389 0.009999 3.230163 +v 4.983679 0.009999 3.230163 +v 4.983679 0.009999 3.137872 +v 4.891389 0.009999 3.137872 +v 5.075970 0.009999 3.230163 +v 5.168260 0.009999 3.230163 +v 5.168260 0.009999 3.137872 +v 5.075970 0.009999 3.137872 +v -3.230163 0.010000 0.830613 +v -3.137872 0.010000 0.830613 +v -3.137872 0.010000 0.738323 +v -3.230163 0.010000 0.738323 +v -3.230163 0.010000 1.015194 +v -3.137872 0.010000 1.015194 +v -3.137872 0.010000 0.922904 +v -3.230163 0.010000 0.922904 +v -3.045582 0.010000 1.015194 +v -2.953291 0.010000 1.015194 +v -2.953291 0.010000 0.922904 +v -3.045582 0.010000 0.922904 +v -3.968485 0.010000 0.830613 +v -3.876195 0.010000 0.830613 +v -3.876195 0.010000 0.738323 +v -3.968485 0.010000 0.738323 +v -3.968485 0.010000 1.015194 +v -3.876195 0.010000 1.015194 +v -3.876195 0.010000 0.922904 +v -3.968485 0.010000 0.922904 +v -3.783905 0.010000 1.015194 +v -3.691614 0.010000 1.015194 +v -3.691614 0.010000 0.922904 +v -3.783905 0.010000 0.922904 +v -3.968485 0.010000 0.092290 +v -3.876195 0.010000 0.092290 +v -3.876195 0.010000 -0.000000 +v -3.968485 0.010000 -0.000000 +v -3.968485 0.010000 0.276871 +v -3.876195 0.010000 0.276871 +v -3.876195 0.010000 0.184581 +v -3.968485 0.010000 0.184581 +v -3.783905 0.010000 0.276871 +v -3.691614 0.010000 0.276871 +v -3.691614 0.010000 0.184581 +v -3.783905 0.010000 0.184581 +v -3.230163 0.009998 3.783905 +v -3.137872 0.009998 3.783905 +v -3.137872 0.009998 3.691614 +v -3.230163 0.009998 3.691614 +v -3.230163 0.009998 3.968485 +v -3.137872 0.009998 3.968485 +v -3.137872 0.009998 3.876195 +v -3.230163 0.009998 3.876195 +v -3.045582 0.009998 3.968485 +v -2.953291 0.009998 3.968485 +v -2.953291 0.009998 3.876195 +v -3.045582 0.009998 3.876195 +v -3.968485 0.009998 3.783905 +v -3.876195 0.009998 3.783905 +v -3.876195 0.009998 3.691614 +v -3.968485 0.009998 3.691614 +v -3.968485 0.009998 3.968485 +v -3.876195 0.009998 3.968485 +v -3.876195 0.009998 3.876195 +v -3.968485 0.009998 3.876195 +v -3.783905 0.009998 3.968485 +v -3.691614 0.009998 3.968485 +v -3.691614 0.009998 3.876195 +v -3.783905 0.009998 3.876195 +v -3.968485 0.009999 3.045582 +v -3.876195 0.009999 3.045582 +v -3.876195 0.009999 2.953291 +v -3.968485 0.009999 2.953291 +v -3.968485 0.009999 3.230163 +v -3.876195 0.009999 3.230163 +v -3.876195 0.009999 3.137872 +v -3.968485 0.009999 3.137872 +v -3.783905 0.009999 3.230163 +v -3.691614 0.009999 3.230163 +v -3.691614 0.009999 3.137872 +v -3.783905 0.009999 3.137872 +v -0.276871 0.009998 3.783905 +v -0.184581 0.009998 3.783905 +v -0.184581 0.009998 3.691614 +v -0.276871 0.009998 3.691614 +v -0.276871 0.009998 3.968485 +v -0.184581 0.009998 3.968485 +v -0.184581 0.009998 3.876195 +v -0.276871 0.009998 3.876195 +v -0.092290 0.009998 3.968485 +v 0.000000 0.009998 3.968485 +v 0.000000 0.009998 3.876195 +v -0.092290 0.009998 3.876195 +v -1.015194 0.009998 3.783905 +v -0.922904 0.009998 3.783905 +v -0.922904 0.009998 3.691614 +v -1.015194 0.009998 3.691614 +v -1.015194 0.009998 3.968485 +v -0.922904 0.009998 3.968485 +v -0.922904 0.009998 3.876195 +v -1.015194 0.009998 3.876195 +v -0.830613 0.009998 3.968485 +v -0.738323 0.009998 3.968485 +v -0.738323 0.009998 3.876195 +v -0.830613 0.009998 3.876195 +v -1.015194 0.009999 3.045582 +v -0.922904 0.009999 3.045582 +v -0.922904 0.009999 2.953291 +v -1.015194 0.009999 2.953291 +v -1.015194 0.009999 3.230163 +v -0.922904 0.009999 3.230163 +v -0.922904 0.009999 3.137872 +v -1.015194 0.009999 3.137872 +v -0.830613 0.009999 3.230163 +v -0.738323 0.009999 3.230163 +v -0.738323 0.009999 3.137872 +v -0.830613 0.009999 3.137872 +v -3.230163 0.010002 -5.075970 +v -3.137872 0.010002 -5.075970 +v -3.137872 0.010002 -5.168260 +v -3.230163 0.010002 -5.168260 +v -3.230163 0.010002 -4.891389 +v -3.137872 0.010002 -4.891389 +v -3.137872 0.010002 -4.983679 +v -3.230163 0.010002 -4.983679 +v -3.045582 0.010002 -4.891389 +v -2.953291 0.010002 -4.891389 +v -2.953291 0.010002 -4.983679 +v -3.045582 0.010002 -4.983679 +v -3.968485 0.010002 -5.075970 +v -3.876195 0.010002 -5.075970 +v -3.876195 0.010002 -5.168260 +v -3.968485 0.010002 -5.168260 +v -3.968485 0.010002 -4.891389 +v -3.876195 0.010002 -4.891389 +v -3.876195 0.010002 -4.983679 +v -3.968485 0.010002 -4.983679 +v -3.783905 0.010002 -4.891389 +v -3.691614 0.010002 -4.891389 +v -3.691614 0.010002 -4.983679 +v -3.783905 0.010002 -4.983679 +v -3.968485 0.010002 -5.814293 +v -3.876195 0.010002 -5.814293 +v -3.876195 0.010002 -5.906583 +v -3.968485 0.010002 -5.906583 +v -3.968485 0.010002 -5.629711 +v -3.876195 0.010002 -5.629711 +v -3.876195 0.010002 -5.722002 +v -3.968485 0.010002 -5.722002 +v -3.783905 0.010002 -5.629711 +v -3.691614 0.010002 -5.629711 +v -3.691614 0.010002 -5.722002 +v -3.783905 0.010002 -5.722002 +v -3.230163 0.010001 -2.122678 +v -3.137872 0.010001 -2.122678 +v -3.137872 0.010001 -2.214968 +v -3.230163 0.010001 -2.214968 +v -3.230163 0.010001 -1.938097 +v -3.137872 0.010001 -1.938097 +v -3.137872 0.010001 -2.030388 +v -3.230163 0.010001 -2.030388 +v -3.045582 0.010001 -1.938097 +v -2.953291 0.010001 -1.938097 +v -2.953291 0.010001 -2.030388 +v -3.045582 0.010001 -2.030388 +v -3.968485 0.010001 -2.122678 +v -3.876195 0.010001 -2.122678 +v -3.876195 0.010001 -2.214968 +v -3.968485 0.010001 -2.214968 +v -3.968485 0.010001 -1.938097 +v -3.876195 0.010001 -1.938097 +v -3.876195 0.010001 -2.030388 +v -3.968485 0.010001 -2.030388 +v -3.783905 0.010001 -1.938097 +v -3.691614 0.010001 -1.938097 +v -3.691614 0.010001 -2.030388 +v -3.783905 0.010001 -2.030388 +v -3.968485 0.010001 -2.861001 +v -3.876195 0.010001 -2.861001 +v -3.876195 0.010001 -2.953291 +v -3.968485 0.010001 -2.953291 +v -3.968485 0.010001 -2.676420 +v -3.876195 0.010001 -2.676420 +v -3.876195 0.010001 -2.768711 +v -3.968485 0.010001 -2.768711 +v -3.783905 0.010001 -2.676420 +v -3.691614 0.010001 -2.676420 +v -3.691614 0.010001 -2.768711 +v -3.783905 0.010001 -2.768711 +v -0.276871 0.010001 -2.122678 +v -0.184581 0.010001 -2.122678 +v -0.184581 0.010001 -2.214968 +v -0.276871 0.010001 -2.214968 +v -0.276871 0.010001 -1.938097 +v -0.184581 0.010001 -1.938097 +v -0.184581 0.010001 -2.030388 +v -0.276871 0.010001 -2.030388 +v -0.092290 0.010001 -1.938097 +v 0.000000 0.010001 -1.938097 +v 0.000000 0.010001 -2.030388 +v -0.092290 0.010001 -2.030388 +v -1.015194 0.010001 -2.122678 +v -0.922904 0.010001 -2.122678 +v -0.922904 0.010001 -2.214968 +v -1.015194 0.010001 -2.214968 +v -1.015194 0.010001 -1.938097 +v -0.922904 0.010001 -1.938097 +v -0.922904 0.010001 -2.030388 +v -1.015194 0.010001 -2.030388 +v -0.830613 0.010001 -1.938097 +v -0.738323 0.010001 -1.938097 +v -0.738323 0.010001 -2.030388 +v -0.830613 0.010001 -2.030388 +v -1.015194 0.010001 -2.861001 +v -0.922904 0.010001 -2.861001 +v -0.922904 0.010001 -2.953291 +v -1.015194 0.010001 -2.953291 +v -1.015194 0.010001 -2.676420 +v -0.922904 0.010001 -2.676420 +v -0.922904 0.010001 -2.768711 +v -1.015194 0.010001 -2.768711 +v -0.830613 0.010001 -2.676420 +v -0.738323 0.010001 -2.676420 +v -0.738323 0.010001 -2.768711 +v -0.830613 0.010001 -2.768711 +v 2.676420 0.010002 -5.075970 +v 2.768711 0.010002 -5.075970 +v 2.768711 0.010002 -5.168260 +v 2.676420 0.010002 -5.168260 +v 2.676420 0.010002 -4.891389 +v 2.768711 0.010002 -4.891389 +v 2.768711 0.010002 -4.983679 +v 2.676420 0.010002 -4.983679 +v 2.861001 0.010002 -4.891389 +v 2.953291 0.010002 -4.891389 +v 2.953291 0.010002 -4.983679 +v 2.861001 0.010002 -4.983679 +v 1.938097 0.010002 -5.075970 +v 2.030388 0.010002 -5.075970 +v 2.030388 0.010002 -5.168260 +v 1.938097 0.010002 -5.168260 +v 1.938097 0.010002 -4.891389 +v 2.030388 0.010002 -4.891389 +v 2.030388 0.010002 -4.983679 +v 1.938097 0.010002 -4.983679 +v 2.122678 0.010002 -4.891389 +v 2.214968 0.010002 -4.891389 +v 2.214968 0.010002 -4.983679 +v 2.122678 0.010002 -4.983679 +v 1.938097 0.010002 -5.814293 +v 2.030388 0.010002 -5.814293 +v 2.030388 0.010002 -5.906583 +v 1.938097 0.010002 -5.906583 +v 1.938097 0.010002 -5.629711 +v 2.030388 0.010002 -5.629711 +v 2.030388 0.010002 -5.722002 +v 1.938097 0.010002 -5.722002 +v 2.122678 0.010002 -5.629711 +v 2.214968 0.010002 -5.629711 +v 2.214968 0.010002 -5.722002 +v 2.122678 0.010002 -5.722002 +v 2.676420 0.010001 -2.122678 +v 2.768711 0.010001 -2.122678 +v 2.768711 0.010001 -2.214968 +v 2.676420 0.010001 -2.214968 +v 2.676420 0.010001 -1.938097 +v 2.768711 0.010001 -1.938097 +v 2.768711 0.010001 -2.030388 +v 2.676420 0.010001 -2.030388 +v 2.861001 0.010001 -1.938097 +v 2.953291 0.010001 -1.938097 +v 2.953291 0.010001 -2.030388 +v 2.861001 0.010001 -2.030388 +v 1.938097 0.010001 -2.122678 +v 2.030388 0.010001 -2.122678 +v 2.030388 0.010001 -2.214968 +v 1.938097 0.010001 -2.214968 +v 1.938097 0.010001 -1.938097 +v 2.030388 0.010001 -1.938097 +v 2.030388 0.010001 -2.030388 +v 1.938097 0.010001 -2.030388 +v 2.122678 0.010001 -1.938097 +v 2.214968 0.010001 -1.938097 +v 2.214968 0.010001 -2.030388 +v 2.122678 0.010001 -2.030388 +v 1.938097 0.010001 -2.861001 +v 2.030388 0.010001 -2.861001 +v 2.030388 0.010001 -2.953291 +v 1.938097 0.010001 -2.953291 +v 1.938097 0.010001 -2.676420 +v 2.030388 0.010001 -2.676420 +v 2.030388 0.010001 -2.768711 +v 1.938097 0.010001 -2.768711 +v 2.122678 0.010001 -2.676420 +v 2.214968 0.010001 -2.676420 +v 2.214968 0.010001 -2.768711 +v 2.122678 0.010001 -2.768711 +v 5.629711 0.010001 -2.122678 +v 5.722002 0.010001 -2.122678 +v 5.722002 0.010001 -2.214968 +v 5.629711 0.010001 -2.214968 +v 5.629711 0.010001 -1.938097 +v 5.722002 0.010001 -1.938097 +v 5.722002 0.010001 -2.030388 +v 5.629711 0.010001 -2.030388 +v 5.814293 0.010001 -1.938097 +v 5.906583 0.010001 -1.938097 +v 5.906583 0.010001 -2.030388 +v 5.814293 0.010001 -2.030388 +v 4.891389 0.010001 -2.122678 +v 4.983679 0.010001 -2.122678 +v 4.983679 0.010001 -2.214968 +v 4.891389 0.010001 -2.214968 +v 4.891389 0.010001 -1.938097 +v 4.983679 0.010001 -1.938097 +v 4.983679 0.010001 -2.030388 +v 4.891389 0.010001 -2.030388 +v 5.075970 0.010001 -1.938097 +v 5.168260 0.010001 -1.938097 +v 5.168260 0.010001 -2.030388 +v 5.075970 0.010001 -2.030388 +v 4.891389 0.010001 -2.861001 +v 4.983679 0.010001 -2.861001 +v 4.983679 0.010001 -2.953291 +v 4.891389 0.010001 -2.953291 +v 4.891389 0.010001 -2.676420 +v 4.983679 0.010001 -2.676420 +v 4.983679 0.010001 -2.768711 +v 4.891389 0.010001 -2.768711 +v 5.075970 0.010001 -2.676420 +v 5.168260 0.010001 -2.676420 +v 5.168260 0.010001 -2.768711 +v 5.075970 0.010001 -2.768711 +v 4.153066 0.010001 -2.122678 +v 4.245357 0.010001 -2.122678 +v 4.245357 0.010001 -2.214968 +v 4.153066 0.010001 -2.214968 +v 4.153066 0.010001 -1.938097 +v 4.245357 0.010001 -1.938097 +v 4.245357 0.010001 -2.030388 +v 4.153066 0.010001 -2.030388 +v 4.337647 0.010001 -1.938097 +v 4.429937 0.010001 -1.938097 +v 4.429937 0.010001 -2.030388 +v 4.337647 0.010001 -2.030388 +v 3.414743 0.010001 -2.122678 +v 3.507033 0.010001 -2.122678 +v 3.507033 0.010001 -2.214968 +v 3.414743 0.010001 -2.214968 +v 3.414743 0.010001 -1.938097 +v 3.507033 0.010001 -1.938097 +v 3.507033 0.010001 -2.030388 +v 3.414743 0.010001 -2.030388 +v 3.599324 0.010001 -1.938097 +v 3.691614 0.010001 -1.938097 +v 3.691614 0.010001 -2.030388 +v 3.599324 0.010001 -2.030388 +v 3.414743 0.010001 -2.861001 +v 3.507033 0.010001 -2.861001 +v 3.507033 0.010001 -2.953291 +v 3.414743 0.010001 -2.953291 +v 3.414743 0.010001 -2.676420 +v 3.507033 0.010001 -2.676420 +v 3.507033 0.010001 -2.768711 +v 3.414743 0.010001 -2.768711 +v 3.599324 0.010001 -2.676420 +v 3.691614 0.010001 -2.676420 +v 3.691614 0.010001 -2.768711 +v 3.599324 0.010001 -2.768711 +v 4.153066 0.010000 -0.646033 +v 4.245357 0.010000 -0.646033 +v 4.245357 0.010000 -0.738323 +v 4.153066 0.010000 -0.738323 +v 4.153066 0.010000 -0.461452 +v 4.245357 0.010000 -0.461452 +v 4.245357 0.010000 -0.553742 +v 4.153066 0.010000 -0.553742 +v 4.337647 0.010000 -0.461452 +v 4.429937 0.010000 -0.461452 +v 4.429937 0.010000 -0.553742 +v 4.337647 0.010000 -0.553742 +v 3.414743 0.010000 -0.646033 +v 3.507033 0.010000 -0.646033 +v 3.507033 0.010000 -0.738323 +v 3.414743 0.010000 -0.738323 +v 3.414743 0.010000 -0.461452 +v 3.507033 0.010000 -0.461452 +v 3.507033 0.010000 -0.553742 +v 3.414743 0.010000 -0.553742 +v 3.599324 0.010000 -0.461452 +v 3.691614 0.010000 -0.461452 +v 3.691614 0.010000 -0.553742 +v 3.599324 0.010000 -0.553742 +v 3.414743 0.010001 -1.384355 +v 3.507033 0.010001 -1.384355 +v 3.507033 0.010001 -1.476646 +v 3.414743 0.010001 -1.476646 +v 3.414743 0.010000 -1.199775 +v 3.507033 0.010000 -1.199775 +v 3.507033 0.010001 -1.292065 +v 3.414743 0.010001 -1.292065 +v 3.599324 0.010000 -1.199775 +v 3.691614 0.010000 -1.199775 +v 3.691614 0.010001 -1.292065 +v 3.599324 0.010001 -1.292065 +v 5.629711 0.010000 -0.646033 +v 5.722002 0.010000 -0.646033 +v 5.722002 0.010000 -0.738323 +v 5.629711 0.010000 -0.738323 +v 5.629711 0.010000 -0.461452 +v 5.722002 0.010000 -0.461452 +v 5.722002 0.010000 -0.553742 +v 5.629711 0.010000 -0.553742 +v 5.814293 0.010000 -0.461452 +v 5.906583 0.010000 -0.461452 +v 5.906583 0.010000 -0.553742 +v 5.814293 0.010000 -0.553742 +v 4.891389 0.010000 -0.646033 +v 4.983679 0.010000 -0.646033 +v 4.983679 0.010000 -0.738323 +v 4.891389 0.010000 -0.738323 +v 4.891389 0.010000 -0.461452 +v 4.983679 0.010000 -0.461452 +v 4.983679 0.010000 -0.553742 +v 4.891389 0.010000 -0.553742 +v 5.075970 0.010000 -0.461452 +v 5.168260 0.010000 -0.461452 +v 5.168260 0.010000 -0.553742 +v 5.075970 0.010000 -0.553742 +v 4.891389 0.010001 -1.384355 +v 4.983679 0.010001 -1.384355 +v 4.983679 0.010001 -1.476646 +v 4.891389 0.010001 -1.476646 +v 4.891389 0.010000 -1.199775 +v 4.983679 0.010000 -1.199775 +v 4.983679 0.010001 -1.292065 +v 4.891389 0.010001 -1.292065 +v 5.075970 0.010000 -1.199775 +v 5.168260 0.010000 -1.199775 +v 5.168260 0.010001 -1.292065 +v 5.075970 0.010001 -1.292065 +v 1.199775 0.010001 -2.122678 +v 1.292065 0.010001 -2.122678 +v 1.292065 0.010001 -2.214968 +v 1.199775 0.010001 -2.214968 +v 1.199775 0.010001 -1.938097 +v 1.292065 0.010001 -1.938097 +v 1.292065 0.010001 -2.030388 +v 1.199775 0.010001 -2.030388 +v 1.384355 0.010001 -1.938097 +v 1.476646 0.010001 -1.938097 +v 1.476646 0.010001 -2.030388 +v 1.384355 0.010001 -2.030388 +v 0.461452 0.010001 -2.122678 +v 0.553742 0.010001 -2.122678 +v 0.553742 0.010001 -2.214968 +v 0.461452 0.010001 -2.214968 +v 0.461452 0.010001 -1.938097 +v 0.553742 0.010001 -1.938097 +v 0.553742 0.010001 -2.030388 +v 0.461452 0.010001 -2.030388 +v 0.646033 0.010001 -1.938097 +v 0.738323 0.010001 -1.938097 +v 0.738323 0.010001 -2.030388 +v 0.646033 0.010001 -2.030388 +v 0.461452 0.010001 -2.861001 +v 0.553742 0.010001 -2.861001 +v 0.553742 0.010001 -2.953291 +v 0.461452 0.010001 -2.953291 +v 0.461452 0.010001 -2.676420 +v 0.553742 0.010001 -2.676420 +v 0.553742 0.010001 -2.768711 +v 0.461452 0.010001 -2.768711 +v 0.646033 0.010001 -2.676420 +v 0.738323 0.010001 -2.676420 +v 0.738323 0.010001 -2.768711 +v 0.646033 0.010001 -2.768711 +v 1.199775 0.010000 -0.646033 +v 1.292065 0.010000 -0.646033 +v 1.292065 0.010000 -0.738323 +v 1.199775 0.010000 -0.738323 +v 1.199775 0.010000 -0.461452 +v 1.292065 0.010000 -0.461452 +v 1.292065 0.010000 -0.553742 +v 1.199775 0.010000 -0.553742 +v 1.384355 0.010000 -0.461452 +v 1.476646 0.010000 -0.461452 +v 1.476646 0.010000 -0.553742 +v 1.384355 0.010000 -0.553742 +v 0.461452 0.010000 -0.646033 +v 0.553742 0.010000 -0.646033 +v 0.553742 0.010000 -0.738323 +v 0.461452 0.010000 -0.738323 +v 0.461452 0.010000 -0.461452 +v 0.553742 0.010000 -0.461452 +v 0.553742 0.010000 -0.553742 +v 0.461452 0.010000 -0.553742 +v 0.646033 0.010000 -0.461452 +v 0.738323 0.010000 -0.461452 +v 0.738323 0.010000 -0.553742 +v 0.646033 0.010000 -0.553742 +v 0.461452 0.010001 -1.384355 +v 0.553742 0.010001 -1.384355 +v 0.553742 0.010001 -1.476646 +v 0.461452 0.010001 -1.476646 +v 0.461452 0.010000 -1.199775 +v 0.553742 0.010000 -1.199775 +v 0.553742 0.010001 -1.292065 +v 0.461452 0.010001 -1.292065 +v 0.646033 0.010000 -1.199775 +v 0.738323 0.010000 -1.199775 +v 0.738323 0.010001 -1.292065 +v 0.646033 0.010001 -1.292065 +v 2.676420 0.010000 -0.646033 +v 2.768711 0.010000 -0.646033 +v 2.768711 0.010000 -0.738323 +v 2.676420 0.010000 -0.738323 +v 2.676420 0.010000 -0.461452 +v 2.768711 0.010000 -0.461452 +v 2.768711 0.010000 -0.553742 +v 2.676420 0.010000 -0.553742 +v 2.861001 0.010000 -0.461452 +v 2.953291 0.010000 -0.461452 +v 2.953291 0.010000 -0.553742 +v 2.861001 0.010000 -0.553742 +v 1.938097 0.010000 -0.646033 +v 2.030388 0.010000 -0.646033 +v 2.030388 0.010000 -0.738323 +v 1.938097 0.010000 -0.738323 +v 1.938097 0.010000 -0.461452 +v 2.030388 0.010000 -0.461452 +v 2.030388 0.010000 -0.553742 +v 1.938097 0.010000 -0.553742 +v 2.122678 0.010000 -0.461452 +v 2.214968 0.010000 -0.461452 +v 2.214968 0.010000 -0.553742 +v 2.122678 0.010000 -0.553742 +v 1.938097 0.010001 -1.384355 +v 2.030388 0.010001 -1.384355 +v 2.030388 0.010001 -1.476646 +v 1.938097 0.010001 -1.476646 +v 1.938097 0.010000 -1.199775 +v 2.030388 0.010000 -1.199775 +v 2.030388 0.010001 -1.292065 +v 1.938097 0.010001 -1.292065 +v 2.122678 0.010000 -1.199775 +v 2.214968 0.010000 -1.199775 +v 2.214968 0.010001 -1.292065 +v 2.122678 0.010001 -1.292065 +v 1.199775 0.010002 -5.075970 +v 1.292065 0.010002 -5.075970 +v 1.292065 0.010002 -5.168260 +v 1.199775 0.010002 -5.168260 +v 1.199775 0.010002 -4.891389 +v 1.292065 0.010002 -4.891389 +v 1.292065 0.010002 -4.983679 +v 1.199775 0.010002 -4.983679 +v 1.384355 0.010002 -4.891389 +v 1.476646 0.010002 -4.891389 +v 1.476646 0.010002 -4.983679 +v 1.384355 0.010002 -4.983679 +v 0.461452 0.010002 -5.075970 +v 0.553742 0.010002 -5.075970 +v 0.553742 0.010002 -5.168260 +v 0.461452 0.010002 -5.168260 +v 0.461452 0.010002 -4.891389 +v 0.553742 0.010002 -4.891389 +v 0.553742 0.010002 -4.983679 +v 0.461452 0.010002 -4.983679 +v 0.646033 0.010002 -4.891389 +v 0.738323 0.010002 -4.891389 +v 0.738323 0.010002 -4.983679 +v 0.646033 0.010002 -4.983679 +v 0.461452 0.010002 -5.814293 +v 0.553742 0.010002 -5.814293 +v 0.553742 0.010002 -5.906583 +v 0.461452 0.010002 -5.906583 +v 0.461452 0.010002 -5.629711 +v 0.553742 0.010002 -5.629711 +v 0.553742 0.010002 -5.722002 +v 0.461452 0.010002 -5.722002 +v 0.646033 0.010002 -5.629711 +v 0.738323 0.010002 -5.629711 +v 0.738323 0.010002 -5.722002 +v 0.646033 0.010002 -5.722002 +v 1.199775 0.010001 -3.599324 +v 1.292065 0.010001 -3.599324 +v 1.292065 0.010002 -3.691614 +v 1.199775 0.010002 -3.691614 +v 1.199775 0.010001 -3.414743 +v 1.292065 0.010001 -3.414743 +v 1.292065 0.010001 -3.507033 +v 1.199775 0.010001 -3.507033 +v 1.384355 0.010001 -3.414743 +v 1.476646 0.010001 -3.414743 +v 1.476646 0.010001 -3.507033 +v 1.384355 0.010001 -3.507033 +v 0.461452 0.010001 -3.599324 +v 0.553742 0.010001 -3.599324 +v 0.553742 0.010002 -3.691614 +v 0.461452 0.010002 -3.691614 +v 0.461452 0.010001 -3.414743 +v 0.553742 0.010001 -3.414743 +v 0.553742 0.010001 -3.507033 +v 0.461452 0.010001 -3.507033 +v 0.646033 0.010001 -3.414743 +v 0.738323 0.010001 -3.414743 +v 0.738323 0.010001 -3.507033 +v 0.646033 0.010001 -3.507033 +v 0.461452 0.010002 -4.337647 +v 0.553742 0.010002 -4.337647 +v 0.553742 0.010002 -4.429937 +v 0.461452 0.010002 -4.429937 +v 0.461452 0.010002 -4.153066 +v 0.553742 0.010002 -4.153066 +v 0.553742 0.010002 -4.245357 +v 0.461452 0.010002 -4.245357 +v 0.646033 0.010002 -4.153066 +v 0.738323 0.010002 -4.153066 +v 0.738323 0.010002 -4.245357 +v 0.646033 0.010002 -4.245357 +v 2.676420 0.010001 -3.599324 +v 2.768711 0.010001 -3.599324 +v 2.768711 0.010002 -3.691614 +v 2.676420 0.010002 -3.691614 +v 2.676420 0.010001 -3.414743 +v 2.768711 0.010001 -3.414743 +v 2.768711 0.010001 -3.507033 +v 2.676420 0.010001 -3.507033 +v 2.861001 0.010001 -3.414743 +v 2.953291 0.010001 -3.414743 +v 2.953291 0.010001 -3.507033 +v 2.861001 0.010001 -3.507033 +v 1.938097 0.010001 -3.599324 +v 2.030388 0.010001 -3.599324 +v 2.030388 0.010002 -3.691614 +v 1.938097 0.010002 -3.691614 +v 1.938097 0.010001 -3.414743 +v 2.030388 0.010001 -3.414743 +v 2.030388 0.010001 -3.507033 +v 1.938097 0.010001 -3.507033 +v 2.122678 0.010001 -3.414743 +v 2.214968 0.010001 -3.414743 +v 2.214968 0.010001 -3.507033 +v 2.122678 0.010001 -3.507033 +v 1.938097 0.010002 -4.337647 +v 2.030388 0.010002 -4.337647 +v 2.030388 0.010002 -4.429937 +v 1.938097 0.010002 -4.429937 +v 1.938097 0.010002 -4.153066 +v 2.030388 0.010002 -4.153066 +v 2.030388 0.010002 -4.245357 +v 1.938097 0.010002 -4.245357 +v 2.122678 0.010002 -4.153066 +v 2.214968 0.010002 -4.153066 +v 2.214968 0.010002 -4.245357 +v 2.122678 0.010002 -4.245357 +v -1.753517 0.010001 -2.122678 +v -1.661226 0.010001 -2.122678 +v -1.661226 0.010001 -2.214968 +v -1.753517 0.010001 -2.214968 +v -1.753517 0.010001 -1.938097 +v -1.661226 0.010001 -1.938097 +v -1.661226 0.010001 -2.030388 +v -1.753517 0.010001 -2.030388 +v -1.568936 0.010001 -1.938097 +v -1.476646 0.010001 -1.938097 +v -1.476646 0.010001 -2.030388 +v -1.568936 0.010001 -2.030388 +v -2.491840 0.010001 -2.122678 +v -2.399549 0.010001 -2.122678 +v -2.399549 0.010001 -2.214968 +v -2.491840 0.010001 -2.214968 +v -2.491840 0.010001 -1.938097 +v -2.399549 0.010001 -1.938097 +v -2.399549 0.010001 -2.030388 +v -2.491840 0.010001 -2.030388 +v -2.307259 0.010001 -1.938097 +v -2.214968 0.010001 -1.938097 +v -2.214968 0.010001 -2.030388 +v -2.307259 0.010001 -2.030388 +v -2.491840 0.010001 -2.861001 +v -2.399549 0.010001 -2.861001 +v -2.399549 0.010001 -2.953291 +v -2.491840 0.010001 -2.953291 +v -2.491840 0.010001 -2.676420 +v -2.399549 0.010001 -2.676420 +v -2.399549 0.010001 -2.768711 +v -2.491840 0.010001 -2.768711 +v -2.307259 0.010001 -2.676420 +v -2.214968 0.010001 -2.676420 +v -2.214968 0.010001 -2.768711 +v -2.307259 0.010001 -2.768711 +v -1.753517 0.010000 -0.646033 +v -1.661226 0.010000 -0.646033 +v -1.661226 0.010000 -0.738323 +v -1.753517 0.010000 -0.738323 +v -1.753517 0.010000 -0.461452 +v -1.661226 0.010000 -0.461452 +v -1.661226 0.010000 -0.553742 +v -1.753517 0.010000 -0.553742 +v -1.568936 0.010000 -0.461452 +v -1.476646 0.010000 -0.461452 +v -1.476646 0.010000 -0.553742 +v -1.568936 0.010000 -0.553742 +v -2.491840 0.010000 -0.646033 +v -2.399549 0.010000 -0.646033 +v -2.399549 0.010000 -0.738323 +v -2.491840 0.010000 -0.738323 +v -2.491840 0.010000 -0.461452 +v -2.399549 0.010000 -0.461452 +v -2.399549 0.010000 -0.553742 +v -2.491840 0.010000 -0.553742 +v -2.307259 0.010000 -0.461452 +v -2.214968 0.010000 -0.461452 +v -2.214968 0.010000 -0.553742 +v -2.307259 0.010000 -0.553742 +v -2.491840 0.010001 -1.384355 +v -2.399549 0.010001 -1.384355 +v -2.399549 0.010001 -1.476646 +v -2.491840 0.010001 -1.476646 +v -2.491840 0.010000 -1.199775 +v -2.399549 0.010000 -1.199775 +v -2.399549 0.010001 -1.292065 +v -2.491840 0.010001 -1.292065 +v -2.307259 0.010000 -1.199775 +v -2.214968 0.010000 -1.199775 +v -2.214968 0.010001 -1.292065 +v -2.307259 0.010001 -1.292065 +v -0.276871 0.010000 -0.646033 +v -0.184581 0.010000 -0.646033 +v -0.184581 0.010000 -0.738323 +v -0.276871 0.010000 -0.738323 +v -0.276871 0.010000 -0.461452 +v -0.184581 0.010000 -0.461452 +v -0.184581 0.010000 -0.553742 +v -0.276871 0.010000 -0.553742 +v -0.092290 0.010000 -0.461452 +v 0.000000 0.010000 -0.461452 +v 0.000000 0.010000 -0.553742 +v -0.092290 0.010000 -0.553742 +v -1.015194 0.010000 -0.646033 +v -0.922904 0.010000 -0.646033 +v -0.922904 0.010000 -0.738323 +v -1.015194 0.010000 -0.738323 +v -1.015194 0.010000 -0.461452 +v -0.922904 0.010000 -0.461452 +v -0.922904 0.010000 -0.553742 +v -1.015194 0.010000 -0.553742 +v -0.830613 0.010000 -0.461452 +v -0.738323 0.010000 -0.461452 +v -0.738323 0.010000 -0.553742 +v -0.830613 0.010000 -0.553742 +v -1.015194 0.010001 -1.384355 +v -0.922904 0.010001 -1.384355 +v -0.922904 0.010001 -1.476646 +v -1.015194 0.010001 -1.476646 +v -1.015194 0.010000 -1.199775 +v -0.922904 0.010000 -1.199775 +v -0.922904 0.010001 -1.292065 +v -1.015194 0.010001 -1.292065 +v -0.830613 0.010000 -1.199775 +v -0.738323 0.010000 -1.199775 +v -0.738323 0.010001 -1.292065 +v -0.830613 0.010001 -1.292065 +v -4.706808 0.010001 -2.122678 +v -4.614518 0.010001 -2.122678 +v -4.614518 0.010001 -2.214968 +v -4.706808 0.010001 -2.214968 +v -4.706808 0.010001 -1.938097 +v -4.614518 0.010001 -1.938097 +v -4.614518 0.010001 -2.030388 +v -4.706808 0.010001 -2.030388 +v -4.522227 0.010001 -1.938097 +v -4.429937 0.010001 -1.938097 +v -4.429937 0.010001 -2.030388 +v -4.522227 0.010001 -2.030388 +v -5.445131 0.010001 -2.122678 +v -5.352840 0.010001 -2.122678 +v -5.352840 0.010001 -2.214968 +v -5.445131 0.010001 -2.214968 +v -5.445131 0.010001 -1.938097 +v -5.352840 0.010001 -1.938097 +v -5.352840 0.010001 -2.030388 +v -5.445131 0.010001 -2.030388 +v -5.260550 0.010001 -1.938097 +v -5.168260 0.010001 -1.938097 +v -5.168260 0.010001 -2.030388 +v -5.260550 0.010001 -2.030388 +v -5.445131 0.010001 -2.861001 +v -5.352840 0.010001 -2.861001 +v -5.352840 0.010001 -2.953291 +v -5.445131 0.010001 -2.953291 +v -5.445131 0.010001 -2.676420 +v -5.352840 0.010001 -2.676420 +v -5.352840 0.010001 -2.768711 +v -5.445131 0.010001 -2.768711 +v -5.260550 0.010001 -2.676420 +v -5.168260 0.010001 -2.676420 +v -5.168260 0.010001 -2.768711 +v -5.260550 0.010001 -2.768711 +v -4.706808 0.010000 -0.646033 +v -4.614518 0.010000 -0.646033 +v -4.614518 0.010000 -0.738323 +v -4.706808 0.010000 -0.738323 +v -4.706808 0.010000 -0.461452 +v -4.614518 0.010000 -0.461452 +v -4.614518 0.010000 -0.553742 +v -4.706808 0.010000 -0.553742 +v -4.522227 0.010000 -0.461452 +v -4.429937 0.010000 -0.461452 +v -4.429937 0.010000 -0.553742 +v -4.522227 0.010000 -0.553742 +v -5.445131 0.010000 -0.646033 +v -5.352840 0.010000 -0.646033 +v -5.352840 0.010000 -0.738323 +v -5.445131 0.010000 -0.738323 +v -5.445131 0.010000 -0.461452 +v -5.352840 0.010000 -0.461452 +v -5.352840 0.010000 -0.553742 +v -5.445131 0.010000 -0.553742 +v -5.260550 0.010000 -0.461452 +v -5.168260 0.010000 -0.461452 +v -5.168260 0.010000 -0.553742 +v -5.260550 0.010000 -0.553742 +v -5.445131 0.010001 -1.384355 +v -5.352840 0.010001 -1.384355 +v -5.352840 0.010001 -1.476646 +v -5.445131 0.010001 -1.476646 +v -5.445131 0.010000 -1.199775 +v -5.352840 0.010000 -1.199775 +v -5.352840 0.010001 -1.292065 +v -5.445131 0.010001 -1.292065 +v -5.260550 0.010000 -1.199775 +v -5.168260 0.010000 -1.199775 +v -5.168260 0.010001 -1.292065 +v -5.260550 0.010001 -1.292065 +v -3.230163 0.010000 -0.646033 +v -3.137872 0.010000 -0.646033 +v -3.137872 0.010000 -0.738323 +v -3.230163 0.010000 -0.738323 +v -3.230163 0.010000 -0.461452 +v -3.137872 0.010000 -0.461452 +v -3.137872 0.010000 -0.553742 +v -3.230163 0.010000 -0.553742 +v -3.045582 0.010000 -0.461452 +v -2.953291 0.010000 -0.461452 +v -2.953291 0.010000 -0.553742 +v -3.045582 0.010000 -0.553742 +v -3.968485 0.010000 -0.646033 +v -3.876195 0.010000 -0.646033 +v -3.876195 0.010000 -0.738323 +v -3.968485 0.010000 -0.738323 +v -3.968485 0.010000 -0.461452 +v -3.876195 0.010000 -0.461452 +v -3.876195 0.010000 -0.553742 +v -3.968485 0.010000 -0.553742 +v -3.783905 0.010000 -0.461452 +v -3.691614 0.010000 -0.461452 +v -3.691614 0.010000 -0.553742 +v -3.783905 0.010000 -0.553742 +v -3.968485 0.010001 -1.384355 +v -3.876195 0.010001 -1.384355 +v -3.876195 0.010001 -1.476646 +v -3.968485 0.010001 -1.476646 +v -3.968485 0.010000 -1.199775 +v -3.876195 0.010000 -1.199775 +v -3.876195 0.010001 -1.292065 +v -3.968485 0.010001 -1.292065 +v -3.783905 0.010000 -1.199775 +v -3.691614 0.010000 -1.199775 +v -3.691614 0.010001 -1.292065 +v -3.783905 0.010001 -1.292065 +v -4.706808 0.010002 -5.075970 +v -4.614518 0.010002 -5.075970 +v -4.614518 0.010002 -5.168260 +v -4.706808 0.010002 -5.168260 +v -4.706808 0.010002 -4.891389 +v -4.614518 0.010002 -4.891389 +v -4.614518 0.010002 -4.983679 +v -4.706808 0.010002 -4.983679 +v -4.522227 0.010002 -4.891389 +v -4.429937 0.010002 -4.891389 +v -4.429937 0.010002 -4.983679 +v -4.522227 0.010002 -4.983679 +v -5.445131 0.010002 -5.075970 +v -5.352840 0.010002 -5.075970 +v -5.352840 0.010002 -5.168260 +v -5.445131 0.010002 -5.168260 +v -5.445131 0.010002 -4.891389 +v -5.352840 0.010002 -4.891389 +v -5.352840 0.010002 -4.983679 +v -5.445131 0.010002 -4.983679 +v -5.260550 0.010002 -4.891389 +v -5.168260 0.010002 -4.891389 +v -5.168260 0.010002 -4.983679 +v -5.260550 0.010002 -4.983679 +v -5.445131 0.010002 -5.814293 +v -5.352840 0.010002 -5.814293 +v -5.352840 0.010002 -5.906583 +v -5.445131 0.010002 -5.906583 +v -5.445131 0.010002 -5.629711 +v -5.352840 0.010002 -5.629711 +v -5.352840 0.010002 -5.722002 +v -5.445131 0.010002 -5.722002 +v -5.260550 0.010002 -5.629711 +v -5.168260 0.010002 -5.629711 +v -5.168260 0.010002 -5.722002 +v -5.260550 0.010002 -5.722002 +v -4.706808 0.010001 -3.599324 +v -4.614518 0.010001 -3.599324 +v -4.614518 0.010002 -3.691614 +v -4.706808 0.010002 -3.691614 +v -4.706808 0.010001 -3.414743 +v -4.614518 0.010001 -3.414743 +v -4.614518 0.010001 -3.507033 +v -4.706808 0.010001 -3.507033 +v -4.522227 0.010001 -3.414743 +v -4.429937 0.010001 -3.414743 +v -4.429937 0.010001 -3.507033 +v -4.522227 0.010001 -3.507033 +v -5.445131 0.010001 -3.599324 +v -5.352840 0.010001 -3.599324 +v -5.352840 0.010002 -3.691614 +v -5.445131 0.010002 -3.691614 +v -5.445131 0.010001 -3.414743 +v -5.352840 0.010001 -3.414743 +v -5.352840 0.010001 -3.507033 +v -5.445131 0.010001 -3.507033 +v -5.260550 0.010001 -3.414743 +v -5.168260 0.010001 -3.414743 +v -5.168260 0.010001 -3.507033 +v -5.260550 0.010001 -3.507033 +v -5.445131 0.010002 -4.337647 +v -5.352840 0.010002 -4.337647 +v -5.352840 0.010002 -4.429937 +v -5.445131 0.010002 -4.429937 +v -5.445131 0.010002 -4.153066 +v -5.352840 0.010002 -4.153066 +v -5.352840 0.010002 -4.245357 +v -5.445131 0.010002 -4.245357 +v -5.260550 0.010002 -4.153066 +v -5.168260 0.010002 -4.153066 +v -5.168260 0.010002 -4.245357 +v -5.260550 0.010002 -4.245357 +v -3.230163 0.010001 -3.599324 +v -3.137872 0.010001 -3.599324 +v -3.137872 0.010002 -3.691614 +v -3.230163 0.010002 -3.691614 +v -3.230163 0.010001 -3.414743 +v -3.137872 0.010001 -3.414743 +v -3.137872 0.010001 -3.507033 +v -3.230163 0.010001 -3.507033 +v -3.045582 0.010001 -3.414743 +v -2.953291 0.010001 -3.414743 +v -2.953291 0.010001 -3.507033 +v -3.045582 0.010001 -3.507033 +v -3.968485 0.010001 -3.599324 +v -3.876195 0.010001 -3.599324 +v -3.876195 0.010002 -3.691614 +v -3.968485 0.010002 -3.691614 +v -3.968485 0.010001 -3.414743 +v -3.876195 0.010001 -3.414743 +v -3.876195 0.010001 -3.507033 +v -3.968485 0.010001 -3.507033 +v -3.783905 0.010001 -3.414743 +v -3.691614 0.010001 -3.414743 +v -3.691614 0.010001 -3.507033 +v -3.783905 0.010001 -3.507033 +v -3.968485 0.010002 -4.337647 +v -3.876195 0.010002 -4.337647 +v -3.876195 0.010002 -4.429937 +v -3.968485 0.010002 -4.429937 +v -3.968485 0.010002 -4.153066 +v -3.876195 0.010002 -4.153066 +v -3.876195 0.010002 -4.245357 +v -3.968485 0.010002 -4.245357 +v -3.783905 0.010002 -4.153066 +v -3.691614 0.010002 -4.153066 +v -3.691614 0.010002 -4.245357 +v -3.783905 0.010002 -4.245357 +v -1.753517 0.009998 3.783905 +v -1.661226 0.009998 3.783905 +v -1.661226 0.009998 3.691614 +v -1.753517 0.009998 3.691614 +v -1.753517 0.009998 3.968485 +v -1.661226 0.009998 3.968485 +v -1.661226 0.009998 3.876195 +v -1.753517 0.009998 3.876195 +v -1.568936 0.009998 3.968485 +v -1.476646 0.009998 3.968485 +v -1.476646 0.009998 3.876195 +v -1.568936 0.009998 3.876195 +v -2.491840 0.009998 3.783905 +v -2.399549 0.009998 3.783905 +v -2.399549 0.009998 3.691614 +v -2.491840 0.009998 3.691614 +v -2.491840 0.009998 3.968485 +v -2.399549 0.009998 3.968485 +v -2.399549 0.009998 3.876195 +v -2.491840 0.009998 3.876195 +v -2.307259 0.009998 3.968485 +v -2.214968 0.009998 3.968485 +v -2.214968 0.009998 3.876195 +v -2.307259 0.009998 3.876195 +v -2.491840 0.009999 3.045582 +v -2.399549 0.009999 3.045582 +v -2.399549 0.009999 2.953291 +v -2.491840 0.009999 2.953291 +v -2.491840 0.009999 3.230163 +v -2.399549 0.009999 3.230163 +v -2.399549 0.009999 3.137872 +v -2.491840 0.009999 3.137872 +v -2.307259 0.009999 3.230163 +v -2.214968 0.009999 3.230163 +v -2.214968 0.009999 3.137872 +v -2.307259 0.009999 3.137872 +v -1.753517 0.009998 5.260550 +v -1.661226 0.009998 5.260550 +v -1.661226 0.009998 5.168260 +v -1.753517 0.009998 5.168260 +v -1.753517 0.009998 5.445131 +v -1.661226 0.009998 5.445131 +v -1.661226 0.009998 5.352840 +v -1.753517 0.009998 5.352840 +v -1.568936 0.009998 5.445131 +v -1.476646 0.009998 5.445131 +v -1.476646 0.009998 5.352840 +v -1.568936 0.009998 5.352840 +v -2.491840 0.009998 5.260550 +v -2.399549 0.009998 5.260550 +v -2.399549 0.009998 5.168260 +v -2.491840 0.009998 5.168260 +v -2.491840 0.009998 5.445131 +v -2.399549 0.009998 5.445131 +v -2.399549 0.009998 5.352840 +v -2.491840 0.009998 5.352840 +v -2.307259 0.009998 5.445131 +v -2.214968 0.009998 5.445131 +v -2.214968 0.009998 5.352840 +v -2.307259 0.009998 5.352840 +v -2.491840 0.009998 4.522227 +v -2.399549 0.009998 4.522227 +v -2.399549 0.009998 4.429937 +v -2.491840 0.009998 4.429937 +v -2.491840 0.009998 4.706808 +v -2.399549 0.009998 4.706808 +v -2.399549 0.009998 4.614518 +v -2.491840 0.009998 4.614518 +v -2.307259 0.009998 4.706808 +v -2.214968 0.009998 4.706808 +v -2.214968 0.009998 4.614518 +v -2.307259 0.009998 4.614518 +v -0.276871 0.009998 5.260550 +v -0.184581 0.009998 5.260550 +v -0.184581 0.009998 5.168260 +v -0.276871 0.009998 5.168260 +v -0.276871 0.009998 5.445131 +v -0.184581 0.009998 5.445131 +v -0.184581 0.009998 5.352840 +v -0.276871 0.009998 5.352840 +v -0.092290 0.009998 5.445131 +v 0.000000 0.009998 5.445131 +v 0.000000 0.009998 5.352840 +v -0.092290 0.009998 5.352840 +v -1.015194 0.009998 5.260550 +v -0.922904 0.009998 5.260550 +v -0.922904 0.009998 5.168260 +v -1.015194 0.009998 5.168260 +v -1.015194 0.009998 5.445131 +v -0.922904 0.009998 5.445131 +v -0.922904 0.009998 5.352840 +v -1.015194 0.009998 5.352840 +v -0.830613 0.009998 5.445131 +v -0.738323 0.009998 5.445131 +v -0.738323 0.009998 5.352840 +v -0.830613 0.009998 5.352840 +v -1.015194 0.009998 4.522227 +v -0.922904 0.009998 4.522227 +v -0.922904 0.009998 4.429937 +v -1.015194 0.009998 4.429937 +v -1.015194 0.009998 4.706808 +v -0.922904 0.009998 4.706808 +v -0.922904 0.009998 4.614518 +v -1.015194 0.009998 4.614518 +v -0.830613 0.009998 4.706808 +v -0.738323 0.009998 4.706808 +v -0.738323 0.009998 4.614518 +v -0.830613 0.009998 4.614518 +v -4.706808 0.009998 3.783905 +v -4.614518 0.009998 3.783905 +v -4.614518 0.009998 3.691614 +v -4.706808 0.009998 3.691614 +v -4.706808 0.009998 3.968485 +v -4.614518 0.009998 3.968485 +v -4.614518 0.009998 3.876195 +v -4.706808 0.009998 3.876195 +v -4.522227 0.009998 3.968485 +v -4.429937 0.009998 3.968485 +v -4.429937 0.009998 3.876195 +v -4.522227 0.009998 3.876195 +v -5.445131 0.009998 3.783905 +v -5.352840 0.009998 3.783905 +v -5.352840 0.009998 3.691614 +v -5.445131 0.009998 3.691614 +v -5.445131 0.009998 3.968485 +v -5.352840 0.009998 3.968485 +v -5.352840 0.009998 3.876195 +v -5.445131 0.009998 3.876195 +v -5.260550 0.009998 3.968485 +v -5.168260 0.009998 3.968485 +v -5.168260 0.009998 3.876195 +v -5.260550 0.009998 3.876195 +v -5.445131 0.009999 3.045582 +v -5.352840 0.009999 3.045582 +v -5.352840 0.009999 2.953291 +v -5.445131 0.009999 2.953291 +v -5.445131 0.009999 3.230163 +v -5.352840 0.009999 3.230163 +v -5.352840 0.009999 3.137872 +v -5.445131 0.009999 3.137872 +v -5.260550 0.009999 3.230163 +v -5.168260 0.009999 3.230163 +v -5.168260 0.009999 3.137872 +v -5.260550 0.009999 3.137872 +v -4.706808 0.009998 5.260550 +v -4.614518 0.009998 5.260550 +v -4.614518 0.009998 5.168260 +v -4.706808 0.009998 5.168260 +v -4.706808 0.009998 5.445131 +v -4.614518 0.009998 5.445131 +v -4.614518 0.009998 5.352840 +v -4.706808 0.009998 5.352840 +v -4.522227 0.009998 5.445131 +v -4.429937 0.009998 5.445131 +v -4.429937 0.009998 5.352840 +v -4.522227 0.009998 5.352840 +v -5.445131 0.009998 5.260550 +v -5.352840 0.009998 5.260550 +v -5.352840 0.009998 5.168260 +v -5.445131 0.009998 5.168260 +v -5.445131 0.009998 5.445131 +v -5.352840 0.009998 5.445131 +v -5.352840 0.009998 5.352840 +v -5.445131 0.009998 5.352840 +v -5.260550 0.009998 5.445131 +v -5.168260 0.009998 5.445131 +v -5.168260 0.009998 5.352840 +v -5.260550 0.009998 5.352840 +v -5.445131 0.009998 4.522227 +v -5.352840 0.009998 4.522227 +v -5.352840 0.009998 4.429937 +v -5.445131 0.009998 4.429937 +v -5.445131 0.009998 4.706808 +v -5.352840 0.009998 4.706808 +v -5.352840 0.009998 4.614518 +v -5.445131 0.009998 4.614518 +v -5.260550 0.009998 4.706808 +v -5.168260 0.009998 4.706808 +v -5.168260 0.009998 4.614518 +v -5.260550 0.009998 4.614518 +v -3.230163 0.009998 5.260550 +v -3.137872 0.009998 5.260550 +v -3.137872 0.009998 5.168260 +v -3.230163 0.009998 5.168260 +v -3.230163 0.009998 5.445131 +v -3.137872 0.009998 5.445131 +v -3.137872 0.009998 5.352840 +v -3.230163 0.009998 5.352840 +v -3.045582 0.009998 5.445131 +v -2.953291 0.009998 5.445131 +v -2.953291 0.009998 5.352840 +v -3.045582 0.009998 5.352840 +v -3.968485 0.009998 5.260550 +v -3.876195 0.009998 5.260550 +v -3.876195 0.009998 5.168260 +v -3.968485 0.009998 5.168260 +v -3.968485 0.009998 5.445131 +v -3.876195 0.009998 5.445131 +v -3.876195 0.009998 5.352840 +v -3.968485 0.009998 5.352840 +v -3.783905 0.009998 5.445131 +v -3.691614 0.009998 5.445131 +v -3.691614 0.009998 5.352840 +v -3.783905 0.009998 5.352840 +v -3.968485 0.009998 4.522227 +v -3.876195 0.009998 4.522227 +v -3.876195 0.009998 4.429937 +v -3.968485 0.009998 4.429937 +v -3.968485 0.009998 4.706808 +v -3.876195 0.009998 4.706808 +v -3.876195 0.009998 4.614518 +v -3.968485 0.009998 4.614518 +v -3.783905 0.009998 4.706808 +v -3.691614 0.009998 4.706808 +v -3.691614 0.009998 4.614518 +v -3.783905 0.009998 4.614518 +v -4.706808 0.010000 0.830613 +v -4.614518 0.010000 0.830613 +v -4.614518 0.010000 0.738323 +v -4.706808 0.010000 0.738323 +v -4.706808 0.010000 1.015194 +v -4.614518 0.010000 1.015194 +v -4.614518 0.010000 0.922904 +v -4.706808 0.010000 0.922904 +v -4.522227 0.010000 1.015194 +v -4.429937 0.010000 1.015194 +v -4.429937 0.010000 0.922904 +v -4.522227 0.010000 0.922904 +v -5.445131 0.010000 0.830613 +v -5.352840 0.010000 0.830613 +v -5.352840 0.010000 0.738323 +v -5.445131 0.010000 0.738323 +v -5.445131 0.010000 1.015194 +v -5.352840 0.010000 1.015194 +v -5.352840 0.010000 0.922904 +v -5.445131 0.010000 0.922904 +v -5.260550 0.010000 1.015194 +v -5.168260 0.010000 1.015194 +v -5.168260 0.010000 0.922904 +v -5.260550 0.010000 0.922904 +v -5.445131 0.010000 0.092290 +v -5.352840 0.010000 0.092290 +v -5.352840 0.010000 -0.000000 +v -5.445131 0.010000 -0.000000 +v -5.445131 0.010000 0.276871 +v -5.352840 0.010000 0.276871 +v -5.352840 0.010000 0.184581 +v -5.445131 0.010000 0.184581 +v -5.260550 0.010000 0.276871 +v -5.168260 0.010000 0.276871 +v -5.168260 0.010000 0.184581 +v -5.260550 0.010000 0.184581 +v -4.706808 0.009999 2.307259 +v -4.614518 0.009999 2.307259 +v -4.614518 0.009999 2.214968 +v -4.706808 0.009999 2.214968 +v -4.706808 0.009999 2.491840 +v -4.614518 0.009999 2.491840 +v -4.614518 0.009999 2.399549 +v -4.706808 0.009999 2.399549 +v -4.522227 0.009999 2.491840 +v -4.429937 0.009999 2.491840 +v -4.429937 0.009999 2.399549 +v -4.522227 0.009999 2.399549 +v -5.445131 0.009999 2.307259 +v -5.352840 0.009999 2.307259 +v -5.352840 0.009999 2.214968 +v -5.445131 0.009999 2.214968 +v -5.445131 0.009999 2.491840 +v -5.352840 0.009999 2.491840 +v -5.352840 0.009999 2.399549 +v -5.445131 0.009999 2.399549 +v -5.260550 0.009999 2.491840 +v -5.168260 0.009999 2.491840 +v -5.168260 0.009999 2.399549 +v -5.260550 0.009999 2.399549 +v -5.445131 0.009999 1.568936 +v -5.352840 0.009999 1.568936 +v -5.352840 0.009999 1.476646 +v -5.445131 0.009999 1.476646 +v -5.445131 0.009999 1.753517 +v -5.352840 0.009999 1.753517 +v -5.352840 0.009999 1.661226 +v -5.445131 0.009999 1.661226 +v -5.260550 0.009999 1.753517 +v -5.168260 0.009999 1.753517 +v -5.168260 0.009999 1.661226 +v -5.260550 0.009999 1.661226 +v -3.230163 0.009999 2.307259 +v -3.137872 0.009999 2.307259 +v -3.137872 0.009999 2.214968 +v -3.230163 0.009999 2.214968 +v -3.230163 0.009999 2.491840 +v -3.137872 0.009999 2.491840 +v -3.137872 0.009999 2.399549 +v -3.230163 0.009999 2.399549 +v -3.045582 0.009999 2.491840 +v -2.953291 0.009999 2.491840 +v -2.953291 0.009999 2.399549 +v -3.045582 0.009999 2.399549 +v -3.968485 0.009999 2.307259 +v -3.876195 0.009999 2.307259 +v -3.876195 0.009999 2.214968 +v -3.968485 0.009999 2.214968 +v -3.968485 0.009999 2.491840 +v -3.876195 0.009999 2.491840 +v -3.876195 0.009999 2.399549 +v -3.968485 0.009999 2.399549 +v -3.783905 0.009999 2.491840 +v -3.691614 0.009999 2.491840 +v -3.691614 0.009999 2.399549 +v -3.783905 0.009999 2.399549 +v -3.968485 0.009999 1.568936 +v -3.876195 0.009999 1.568936 +v -3.876195 0.009999 1.476646 +v -3.968485 0.009999 1.476646 +v -3.968485 0.009999 1.753517 +v -3.876195 0.009999 1.753517 +v -3.876195 0.009999 1.661226 +v -3.968485 0.009999 1.661226 +v -3.783905 0.009999 1.753517 +v -3.691614 0.009999 1.753517 +v -3.691614 0.009999 1.661226 +v -3.783905 0.009999 1.661226 +v 4.153066 0.009998 3.783905 +v 4.245357 0.009998 3.783905 +v 4.245357 0.009998 3.691614 +v 4.153066 0.009998 3.691614 +v 4.153066 0.009998 3.968485 +v 4.245357 0.009998 3.968485 +v 4.245357 0.009998 3.876195 +v 4.153066 0.009998 3.876195 +v 4.337647 0.009998 3.968485 +v 4.429937 0.009998 3.968485 +v 4.429937 0.009998 3.876195 +v 4.337647 0.009998 3.876195 +v 3.414743 0.009998 3.783905 +v 3.507033 0.009998 3.783905 +v 3.507033 0.009998 3.691614 +v 3.414743 0.009998 3.691614 +v 3.414743 0.009998 3.968485 +v 3.507033 0.009998 3.968485 +v 3.507033 0.009998 3.876195 +v 3.414743 0.009998 3.876195 +v 3.599324 0.009998 3.968485 +v 3.691614 0.009998 3.968485 +v 3.691614 0.009998 3.876195 +v 3.599324 0.009998 3.876195 +v 3.414743 0.009999 3.045582 +v 3.507033 0.009999 3.045582 +v 3.507033 0.009999 2.953291 +v 3.414743 0.009999 2.953291 +v 3.414743 0.009999 3.230163 +v 3.507033 0.009999 3.230163 +v 3.507033 0.009999 3.137872 +v 3.414743 0.009999 3.137872 +v 3.599324 0.009999 3.230163 +v 3.691614 0.009999 3.230163 +v 3.691614 0.009999 3.137872 +v 3.599324 0.009999 3.137872 +v 4.153066 0.009998 5.260550 +v 4.245357 0.009998 5.260550 +v 4.245357 0.009998 5.168260 +v 4.153066 0.009998 5.168260 +v 4.153066 0.009998 5.445131 +v 4.245357 0.009998 5.445131 +v 4.245357 0.009998 5.352840 +v 4.153066 0.009998 5.352840 +v 4.337647 0.009998 5.445131 +v 4.429937 0.009998 5.445131 +v 4.429937 0.009998 5.352840 +v 4.337647 0.009998 5.352840 +v 3.414743 0.009998 5.260550 +v 3.507033 0.009998 5.260550 +v 3.507033 0.009998 5.168260 +v 3.414743 0.009998 5.168260 +v 3.414743 0.009998 5.445131 +v 3.507033 0.009998 5.445131 +v 3.507033 0.009998 5.352840 +v 3.414743 0.009998 5.352840 +v 3.599324 0.009998 5.445131 +v 3.691614 0.009998 5.445131 +v 3.691614 0.009998 5.352840 +v 3.599324 0.009998 5.352840 +v 3.414743 0.009998 4.522227 +v 3.507033 0.009998 4.522227 +v 3.507033 0.009998 4.429937 +v 3.414743 0.009998 4.429937 +v 3.414743 0.009998 4.706808 +v 3.507033 0.009998 4.706808 +v 3.507033 0.009998 4.614518 +v 3.414743 0.009998 4.614518 +v 3.599324 0.009998 4.706808 +v 3.691614 0.009998 4.706808 +v 3.691614 0.009998 4.614518 +v 3.599324 0.009998 4.614518 +v 5.629711 0.009998 5.260550 +v 5.722002 0.009998 5.260550 +v 5.722002 0.009998 5.168260 +v 5.629711 0.009998 5.168260 +v 5.629711 0.009998 5.445131 +v 5.722002 0.009998 5.445131 +v 5.722002 0.009998 5.352840 +v 5.629711 0.009998 5.352840 +v 5.814293 0.009998 5.445131 +v 5.906583 0.009998 5.445131 +v 5.906583 0.009998 5.352840 +v 5.814293 0.009998 5.352840 +v 4.891389 0.009998 5.260550 +v 4.983679 0.009998 5.260550 +v 4.983679 0.009998 5.168260 +v 4.891389 0.009998 5.168260 +v 4.891389 0.009998 5.445131 +v 4.983679 0.009998 5.445131 +v 4.983679 0.009998 5.352840 +v 4.891389 0.009998 5.352840 +v 5.075970 0.009998 5.445131 +v 5.168260 0.009998 5.445131 +v 5.168260 0.009998 5.352840 +v 5.075970 0.009998 5.352840 +v 4.891389 0.009998 4.522227 +v 4.983679 0.009998 4.522227 +v 4.983679 0.009998 4.429937 +v 4.891389 0.009998 4.429937 +v 4.891389 0.009998 4.706808 +v 4.983679 0.009998 4.706808 +v 4.983679 0.009998 4.614518 +v 4.891389 0.009998 4.614518 +v 5.075970 0.009998 4.706808 +v 5.168260 0.009998 4.706808 +v 5.168260 0.009998 4.614518 +v 5.075970 0.009998 4.614518 +v 1.199775 0.009998 3.783905 +v 1.292065 0.009998 3.783905 +v 1.292065 0.009998 3.691614 +v 1.199775 0.009998 3.691614 +v 1.199775 0.009998 3.968485 +v 1.292065 0.009998 3.968485 +v 1.292065 0.009998 3.876195 +v 1.199775 0.009998 3.876195 +v 1.384355 0.009998 3.968485 +v 1.476646 0.009998 3.968485 +v 1.476646 0.009998 3.876195 +v 1.384355 0.009998 3.876195 +v 0.461452 0.009998 3.783905 +v 0.553742 0.009998 3.783905 +v 0.553742 0.009998 3.691614 +v 0.461452 0.009998 3.691614 +v 0.461452 0.009998 3.968485 +v 0.553742 0.009998 3.968485 +v 0.553742 0.009998 3.876195 +v 0.461452 0.009998 3.876195 +v 0.646033 0.009998 3.968485 +v 0.738323 0.009998 3.968485 +v 0.738323 0.009998 3.876195 +v 0.646033 0.009998 3.876195 +v 0.461452 0.009999 3.045582 +v 0.553742 0.009999 3.045582 +v 0.553742 0.009999 2.953291 +v 0.461452 0.009999 2.953291 +v 0.461452 0.009999 3.230163 +v 0.553742 0.009999 3.230163 +v 0.553742 0.009999 3.137872 +v 0.461452 0.009999 3.137872 +v 0.646033 0.009999 3.230163 +v 0.738323 0.009999 3.230163 +v 0.738323 0.009999 3.137872 +v 0.646033 0.009999 3.137872 +v 1.199775 0.009998 5.260550 +v 1.292065 0.009998 5.260550 +v 1.292065 0.009998 5.168260 +v 1.199775 0.009998 5.168260 +v 1.199775 0.009998 5.445131 +v 1.292065 0.009998 5.445131 +v 1.292065 0.009998 5.352840 +v 1.199775 0.009998 5.352840 +v 1.384355 0.009998 5.445131 +v 1.476646 0.009998 5.445131 +v 1.476646 0.009998 5.352840 +v 1.384355 0.009998 5.352840 +v 0.461452 0.009998 5.260550 +v 0.553742 0.009998 5.260550 +v 0.553742 0.009998 5.168260 +v 0.461452 0.009998 5.168260 +v 0.461452 0.009998 5.445131 +v 0.553742 0.009998 5.445131 +v 0.553742 0.009998 5.352840 +v 0.461452 0.009998 5.352840 +v 0.646033 0.009998 5.445131 +v 0.738323 0.009998 5.445131 +v 0.738323 0.009998 5.352840 +v 0.646033 0.009998 5.352840 +v 0.461452 0.009998 4.522227 +v 0.553742 0.009998 4.522227 +v 0.553742 0.009998 4.429937 +v 0.461452 0.009998 4.429937 +v 0.461452 0.009998 4.706808 +v 0.553742 0.009998 4.706808 +v 0.553742 0.009998 4.614518 +v 0.461452 0.009998 4.614518 +v 0.646033 0.009998 4.706808 +v 0.738323 0.009998 4.706808 +v 0.738323 0.009998 4.614518 +v 0.646033 0.009998 4.614518 +v 2.676420 0.009998 5.260550 +v 2.768711 0.009998 5.260550 +v 2.768711 0.009998 5.168260 +v 2.676420 0.009998 5.168260 +v 2.676420 0.009998 5.445131 +v 2.768711 0.009998 5.445131 +v 2.768711 0.009998 5.352840 +v 2.676420 0.009998 5.352840 +v 2.861001 0.009998 5.445131 +v 2.953291 0.009998 5.445131 +v 2.953291 0.009998 5.352840 +v 2.861001 0.009998 5.352840 +v 1.938097 0.009998 5.260550 +v 2.030388 0.009998 5.260550 +v 2.030388 0.009998 5.168260 +v 1.938097 0.009998 5.168260 +v 1.938097 0.009998 5.445131 +v 2.030388 0.009998 5.445131 +v 2.030388 0.009998 5.352840 +v 1.938097 0.009998 5.352840 +v 2.122678 0.009998 5.445131 +v 2.214968 0.009998 5.445131 +v 2.214968 0.009998 5.352840 +v 2.122678 0.009998 5.352840 +v 1.938097 0.009998 4.522227 +v 2.030388 0.009998 4.522227 +v 2.030388 0.009998 4.429937 +v 1.938097 0.009998 4.429937 +v 1.938097 0.009998 4.706808 +v 2.030388 0.009998 4.706808 +v 2.030388 0.009998 4.614518 +v 1.938097 0.009998 4.614518 +v 2.122678 0.009998 4.706808 +v 2.214968 0.009998 4.706808 +v 2.214968 0.009998 4.614518 +v 2.122678 0.009998 4.614518 +v 1.199775 0.010000 0.830613 +v 1.292065 0.010000 0.830613 +v 1.292065 0.010000 0.738323 +v 1.199775 0.010000 0.738323 +v 1.199775 0.010000 1.015194 +v 1.292065 0.010000 1.015194 +v 1.292065 0.010000 0.922904 +v 1.199775 0.010000 0.922904 +v 1.384355 0.010000 1.015194 +v 1.476646 0.010000 1.015194 +v 1.476646 0.010000 0.922904 +v 1.384355 0.010000 0.922904 +v 0.461452 0.010000 0.830613 +v 0.553742 0.010000 0.830613 +v 0.553742 0.010000 0.738323 +v 0.461452 0.010000 0.738323 +v 0.461452 0.010000 1.015194 +v 0.553742 0.010000 1.015194 +v 0.553742 0.010000 0.922904 +v 0.461452 0.010000 0.922904 +v 0.646033 0.010000 1.015194 +v 0.738323 0.010000 1.015194 +v 0.738323 0.010000 0.922904 +v 0.646033 0.010000 0.922904 +v 0.461452 0.010000 0.092290 +v 0.553742 0.010000 0.092290 +v 0.553742 0.010000 -0.000000 +v 0.461452 0.010000 -0.000000 +v 0.461452 0.010000 0.276871 +v 0.553742 0.010000 0.276871 +v 0.553742 0.010000 0.184581 +v 0.461452 0.010000 0.184581 +v 0.646033 0.010000 0.276871 +v 0.738323 0.010000 0.276871 +v 0.738323 0.010000 0.184581 +v 0.646033 0.010000 0.184581 +v 1.199775 0.009999 2.307259 +v 1.292065 0.009999 2.307259 +v 1.292065 0.009999 2.214968 +v 1.199775 0.009999 2.214968 +v 1.199775 0.009999 2.491840 +v 1.292065 0.009999 2.491840 +v 1.292065 0.009999 2.399549 +v 1.199775 0.009999 2.399549 +v 1.384355 0.009999 2.491840 +v 1.476646 0.009999 2.491840 +v 1.476646 0.009999 2.399549 +v 1.384355 0.009999 2.399549 +v 0.461452 0.009999 2.307259 +v 0.553742 0.009999 2.307259 +v 0.553742 0.009999 2.214968 +v 0.461452 0.009999 2.214968 +v 0.461452 0.009999 2.491840 +v 0.553742 0.009999 2.491840 +v 0.553742 0.009999 2.399549 +v 0.461452 0.009999 2.399549 +v 0.646033 0.009999 2.491840 +v 0.738323 0.009999 2.491840 +v 0.738323 0.009999 2.399549 +v 0.646033 0.009999 2.399549 +v 0.461452 0.009999 1.568936 +v 0.553742 0.009999 1.568936 +v 0.553742 0.009999 1.476646 +v 0.461452 0.009999 1.476646 +v 0.461452 0.009999 1.753517 +v 0.553742 0.009999 1.753517 +v 0.553742 0.009999 1.661226 +v 0.461452 0.009999 1.661226 +v 0.646033 0.009999 1.753517 +v 0.738323 0.009999 1.753517 +v 0.738323 0.009999 1.661226 +v 0.646033 0.009999 1.661226 +v 2.676420 0.009999 2.307259 +v 2.768711 0.009999 2.307259 +v 2.768711 0.009999 2.214968 +v 2.676420 0.009999 2.214968 +v 2.676420 0.009999 2.491840 +v 2.768711 0.009999 2.491840 +v 2.768711 0.009999 2.399549 +v 2.676420 0.009999 2.399549 +v 2.861001 0.009999 2.491840 +v 2.953291 0.009999 2.491840 +v 2.953291 0.009999 2.399549 +v 2.861001 0.009999 2.399549 +v 1.938097 0.009999 2.307259 +v 2.030388 0.009999 2.307259 +v 2.030388 0.009999 2.214968 +v 1.938097 0.009999 2.214968 +v 1.938097 0.009999 2.491840 +v 2.030388 0.009999 2.491840 +v 2.030388 0.009999 2.399549 +v 1.938097 0.009999 2.399549 +v 2.122678 0.009999 2.491840 +v 2.214968 0.009999 2.491840 +v 2.214968 0.009999 2.399549 +v 2.122678 0.009999 2.399549 +v 1.938097 0.009999 1.568936 +v 2.030388 0.009999 1.568936 +v 2.030388 0.009999 1.476646 +v 1.938097 0.009999 1.476646 +v 1.938097 0.009999 1.753517 +v 2.030388 0.009999 1.753517 +v 2.030388 0.009999 1.661226 +v 1.938097 0.009999 1.661226 +v 2.122678 0.009999 1.753517 +v 2.214968 0.009999 1.753517 +v 2.214968 0.009999 1.661226 +v 2.122678 0.009999 1.661226 +v 4.153066 0.010000 0.830613 +v 4.245357 0.010000 0.830613 +v 4.245357 0.010000 0.738323 +v 4.153066 0.010000 0.738323 +v 4.153066 0.010000 1.015194 +v 4.245357 0.010000 1.015194 +v 4.245357 0.010000 0.922904 +v 4.153066 0.010000 0.922904 +v 4.337647 0.010000 1.015194 +v 4.429937 0.010000 1.015194 +v 4.429937 0.010000 0.922904 +v 4.337647 0.010000 0.922904 +v 3.414743 0.010000 0.830613 +v 3.507033 0.010000 0.830613 +v 3.507033 0.010000 0.738323 +v 3.414743 0.010000 0.738323 +v 3.414743 0.010000 1.015194 +v 3.507033 0.010000 1.015194 +v 3.507033 0.010000 0.922904 +v 3.414743 0.010000 0.922904 +v 3.599324 0.010000 1.015194 +v 3.691614 0.010000 1.015194 +v 3.691614 0.010000 0.922904 +v 3.599324 0.010000 0.922904 +v 3.414743 0.010000 0.092290 +v 3.507033 0.010000 0.092290 +v 3.507033 0.010000 -0.000000 +v 3.414743 0.010000 -0.000000 +v 3.414743 0.010000 0.276871 +v 3.507033 0.010000 0.276871 +v 3.507033 0.010000 0.184581 +v 3.414743 0.010000 0.184581 +v 3.599324 0.010000 0.276871 +v 3.691614 0.010000 0.276871 +v 3.691614 0.010000 0.184581 +v 3.599324 0.010000 0.184581 +v 4.153066 0.009999 2.307259 +v 4.245357 0.009999 2.307259 +v 4.245357 0.009999 2.214968 +v 4.153066 0.009999 2.214968 +v 4.153066 0.009999 2.491840 +v 4.245357 0.009999 2.491840 +v 4.245357 0.009999 2.399549 +v 4.153066 0.009999 2.399549 +v 4.337647 0.009999 2.491840 +v 4.429937 0.009999 2.491840 +v 4.429937 0.009999 2.399549 +v 4.337647 0.009999 2.399549 +v 3.414743 0.009999 2.307259 +v 3.507033 0.009999 2.307259 +v 3.507033 0.009999 2.214968 +v 3.414743 0.009999 2.214968 +v 3.414743 0.009999 2.491840 +v 3.507033 0.009999 2.491840 +v 3.507033 0.009999 2.399549 +v 3.414743 0.009999 2.399549 +v 3.599324 0.009999 2.491840 +v 3.691614 0.009999 2.491840 +v 3.691614 0.009999 2.399549 +v 3.599324 0.009999 2.399549 +v 3.414743 0.009999 1.568936 +v 3.507033 0.009999 1.568936 +v 3.507033 0.009999 1.476646 +v 3.414743 0.009999 1.476646 +v 3.414743 0.009999 1.753517 +v 3.507033 0.009999 1.753517 +v 3.507033 0.009999 1.661226 +v 3.414743 0.009999 1.661226 +v 3.599324 0.009999 1.753517 +v 3.691614 0.009999 1.753517 +v 3.691614 0.009999 1.661226 +v 3.599324 0.009999 1.661226 +v 5.629711 0.009999 2.307259 +v 5.722002 0.009999 2.307259 +v 5.722002 0.009999 2.214968 +v 5.629711 0.009999 2.214968 +v 5.629711 0.009999 2.491840 +v 5.722002 0.009999 2.491840 +v 5.722002 0.009999 2.399549 +v 5.629711 0.009999 2.399549 +v 5.814293 0.009999 2.491840 +v 5.906583 0.009999 2.491840 +v 5.906583 0.009999 2.399549 +v 5.814293 0.009999 2.399549 +v 4.891389 0.009999 2.307259 +v 4.983679 0.009999 2.307259 +v 4.983679 0.009999 2.214968 +v 4.891389 0.009999 2.214968 +v 4.891389 0.009999 2.491840 +v 4.983679 0.009999 2.491840 +v 4.983679 0.009999 2.399549 +v 4.891389 0.009999 2.399549 +v 5.075970 0.009999 2.491840 +v 5.168260 0.009999 2.491840 +v 5.168260 0.009999 2.399549 +v 5.075970 0.009999 2.399549 +v 4.891389 0.009999 1.568936 +v 4.983679 0.009999 1.568936 +v 4.983679 0.009999 1.476646 +v 4.891389 0.009999 1.476646 +v 4.891389 0.009999 1.753517 +v 4.983679 0.009999 1.753517 +v 4.983679 0.009999 1.661226 +v 4.891389 0.009999 1.661226 +v 5.075970 0.009999 1.753517 +v 5.168260 0.009999 1.753517 +v 5.168260 0.009999 1.661226 +v 5.075970 0.009999 1.661226 +v -1.753517 0.010000 0.830613 +v -1.661226 0.010000 0.830613 +v -1.661226 0.010000 0.738323 +v -1.753517 0.010000 0.738323 +v -1.753517 0.010000 1.015194 +v -1.661226 0.010000 1.015194 +v -1.661226 0.010000 0.922904 +v -1.753517 0.010000 0.922904 +v -1.568936 0.010000 1.015194 +v -1.476646 0.010000 1.015194 +v -1.476646 0.010000 0.922904 +v -1.568936 0.010000 0.922904 +v -2.491840 0.010000 0.830613 +v -2.399549 0.010000 0.830613 +v -2.399549 0.010000 0.738323 +v -2.491840 0.010000 0.738323 +v -2.491840 0.010000 1.015194 +v -2.399549 0.010000 1.015194 +v -2.399549 0.010000 0.922904 +v -2.491840 0.010000 0.922904 +v -2.307259 0.010000 1.015194 +v -2.214968 0.010000 1.015194 +v -2.214968 0.010000 0.922904 +v -2.307259 0.010000 0.922904 +v -2.491840 0.010000 0.092290 +v -2.399549 0.010000 0.092290 +v -2.399549 0.010000 -0.000000 +v -2.491840 0.010000 -0.000000 +v -2.491840 0.010000 0.276871 +v -2.399549 0.010000 0.276871 +v -2.399549 0.010000 0.184581 +v -2.491840 0.010000 0.184581 +v -2.307259 0.010000 0.276871 +v -2.214968 0.010000 0.276871 +v -2.214968 0.010000 0.184581 +v -2.307259 0.010000 0.184581 +v -1.753517 0.009999 2.307259 +v -1.661226 0.009999 2.307259 +v -1.661226 0.009999 2.214968 +v -1.753517 0.009999 2.214968 +v -1.753517 0.009999 2.491840 +v -1.661226 0.009999 2.491840 +v -1.661226 0.009999 2.399549 +v -1.753517 0.009999 2.399549 +v -1.568936 0.009999 2.491840 +v -1.476646 0.009999 2.491840 +v -1.476646 0.009999 2.399549 +v -1.568936 0.009999 2.399549 +v -2.491840 0.009999 2.307259 +v -2.399549 0.009999 2.307259 +v -2.399549 0.009999 2.214968 +v -2.491840 0.009999 2.214968 +v -2.491840 0.009999 2.491840 +v -2.399549 0.009999 2.491840 +v -2.399549 0.009999 2.399549 +v -2.491840 0.009999 2.399549 +v -2.307259 0.009999 2.491840 +v -2.214968 0.009999 2.491840 +v -2.214968 0.009999 2.399549 +v -2.307259 0.009999 2.399549 +v -2.491840 0.009999 1.568936 +v -2.399549 0.009999 1.568936 +v -2.399549 0.009999 1.476646 +v -2.491840 0.009999 1.476646 +v -2.491840 0.009999 1.753517 +v -2.399549 0.009999 1.753517 +v -2.399549 0.009999 1.661226 +v -2.491840 0.009999 1.661226 +v -2.307259 0.009999 1.753517 +v -2.214968 0.009999 1.753517 +v -2.214968 0.009999 1.661226 +v -2.307259 0.009999 1.661226 +v -0.276871 0.009999 2.307259 +v -0.184581 0.009999 2.307259 +v -0.184581 0.009999 2.214968 +v -0.276871 0.009999 2.214968 +v -0.276871 0.009999 2.491840 +v -0.184581 0.009999 2.491840 +v -0.184581 0.009999 2.399549 +v -0.276871 0.009999 2.399549 +v -0.092290 0.009999 2.491840 +v 0.000000 0.009999 2.491840 +v 0.000000 0.009999 2.399549 +v -0.092290 0.009999 2.399549 +v -1.015194 0.009999 2.307259 +v -0.922904 0.009999 2.307259 +v -0.922904 0.009999 2.214968 +v -1.015194 0.009999 2.214968 +v -1.015194 0.009999 2.491840 +v -0.922904 0.009999 2.491840 +v -0.922904 0.009999 2.399549 +v -1.015194 0.009999 2.399549 +v -0.830613 0.009999 2.491840 +v -0.738323 0.009999 2.491840 +v -0.738323 0.009999 2.399549 +v -0.830613 0.009999 2.399549 +v -1.015194 0.009999 1.568936 +v -0.922904 0.009999 1.568936 +v -0.922904 0.009999 1.476646 +v -1.015194 0.009999 1.476646 +v -1.015194 0.009999 1.753517 +v -0.922904 0.009999 1.753517 +v -0.922904 0.009999 1.661226 +v -1.015194 0.009999 1.661226 +v -0.830613 0.009999 1.753517 +v -0.738323 0.009999 1.753517 +v -0.738323 0.009999 1.661226 +v -0.830613 0.009999 1.661226 +v -1.753517 0.010002 -5.075970 +v -1.661226 0.010002 -5.075970 +v -1.661226 0.010002 -5.168260 +v -1.753517 0.010002 -5.168260 +v -1.753517 0.010002 -4.891389 +v -1.661226 0.010002 -4.891389 +v -1.661226 0.010002 -4.983679 +v -1.753517 0.010002 -4.983679 +v -1.568936 0.010002 -4.891389 +v -1.476646 0.010002 -4.891389 +v -1.476646 0.010002 -4.983679 +v -1.568936 0.010002 -4.983679 +v -2.491840 0.010002 -5.075970 +v -2.399549 0.010002 -5.075970 +v -2.399549 0.010002 -5.168260 +v -2.491840 0.010002 -5.168260 +v -2.491840 0.010002 -4.891389 +v -2.399549 0.010002 -4.891389 +v -2.399549 0.010002 -4.983679 +v -2.491840 0.010002 -4.983679 +v -2.307259 0.010002 -4.891389 +v -2.214968 0.010002 -4.891389 +v -2.214968 0.010002 -4.983679 +v -2.307259 0.010002 -4.983679 +v -2.491840 0.010002 -5.814293 +v -2.399549 0.010002 -5.814293 +v -2.399549 0.010002 -5.906583 +v -2.491840 0.010002 -5.906583 +v -2.491840 0.010002 -5.629711 +v -2.399549 0.010002 -5.629711 +v -2.399549 0.010002 -5.722002 +v -2.491840 0.010002 -5.722002 +v -2.307259 0.010002 -5.629711 +v -2.214968 0.010002 -5.629711 +v -2.214968 0.010002 -5.722002 +v -2.307259 0.010002 -5.722002 +v -1.753517 0.010001 -3.599324 +v -1.661226 0.010001 -3.599324 +v -1.661226 0.010002 -3.691614 +v -1.753517 0.010002 -3.691614 +v -1.753517 0.010001 -3.414743 +v -1.661226 0.010001 -3.414743 +v -1.661226 0.010001 -3.507033 +v -1.753517 0.010001 -3.507033 +v -1.568936 0.010001 -3.414743 +v -1.476646 0.010001 -3.414743 +v -1.476646 0.010001 -3.507033 +v -1.568936 0.010001 -3.507033 +v -2.491840 0.010001 -3.599324 +v -2.399549 0.010001 -3.599324 +v -2.399549 0.010002 -3.691614 +v -2.491840 0.010002 -3.691614 +v -2.491840 0.010001 -3.414743 +v -2.399549 0.010001 -3.414743 +v -2.399549 0.010001 -3.507033 +v -2.491840 0.010001 -3.507033 +v -2.307259 0.010001 -3.414743 +v -2.214968 0.010001 -3.414743 +v -2.214968 0.010001 -3.507033 +v -2.307259 0.010001 -3.507033 +v -2.491840 0.010002 -4.337647 +v -2.399549 0.010002 -4.337647 +v -2.399549 0.010002 -4.429937 +v -2.491840 0.010002 -4.429937 +v -2.491840 0.010002 -4.153066 +v -2.399549 0.010002 -4.153066 +v -2.399549 0.010002 -4.245357 +v -2.491840 0.010002 -4.245357 +v -2.307259 0.010002 -4.153066 +v -2.214968 0.010002 -4.153066 +v -2.214968 0.010002 -4.245357 +v -2.307259 0.010002 -4.245357 +v -0.276871 0.010001 -3.599324 +v -0.184581 0.010001 -3.599324 +v -0.184581 0.010002 -3.691614 +v -0.276871 0.010002 -3.691614 +v -0.276871 0.010001 -3.414743 +v -0.184581 0.010001 -3.414743 +v -0.184581 0.010001 -3.507033 +v -0.276871 0.010001 -3.507033 +v -0.092290 0.010001 -3.414743 +v 0.000000 0.010001 -3.414743 +v 0.000000 0.010001 -3.507033 +v -0.092290 0.010001 -3.507033 +v -1.015194 0.010001 -3.599324 +v -0.922904 0.010001 -3.599324 +v -0.922904 0.010002 -3.691614 +v -1.015194 0.010002 -3.691614 +v -1.015194 0.010001 -3.414743 +v -0.922904 0.010001 -3.414743 +v -0.922904 0.010001 -3.507033 +v -1.015194 0.010001 -3.507033 +v -0.830613 0.010001 -3.414743 +v -0.738323 0.010001 -3.414743 +v -0.738323 0.010001 -3.507033 +v -0.830613 0.010001 -3.507033 +v -1.015194 0.010002 -4.337647 +v -0.922904 0.010002 -4.337647 +v -0.922904 0.010002 -4.429937 +v -1.015194 0.010002 -4.429937 +v -1.015194 0.010002 -4.153066 +v -0.922904 0.010002 -4.153066 +v -0.922904 0.010002 -4.245357 +v -1.015194 0.010002 -4.245357 +v -0.830613 0.010002 -4.153066 +v -0.738323 0.010002 -4.153066 +v -0.738323 0.010002 -4.245357 +v -0.830613 0.010002 -4.245357 +v 4.153066 0.010002 -5.075970 +v 4.245357 0.010002 -5.075970 +v 4.245357 0.010002 -5.168260 +v 4.153066 0.010002 -5.168260 +v 4.153066 0.010002 -4.891389 +v 4.245357 0.010002 -4.891389 +v 4.245357 0.010002 -4.983679 +v 4.153066 0.010002 -4.983679 +v 4.337647 0.010002 -4.891389 +v 4.429937 0.010002 -4.891389 +v 4.429937 0.010002 -4.983679 +v 4.337647 0.010002 -4.983679 +v 3.414743 0.010002 -5.075970 +v 3.507033 0.010002 -5.075970 +v 3.507033 0.010002 -5.168260 +v 3.414743 0.010002 -5.168260 +v 3.414743 0.010002 -4.891389 +v 3.507033 0.010002 -4.891389 +v 3.507033 0.010002 -4.983679 +v 3.414743 0.010002 -4.983679 +v 3.599324 0.010002 -4.891389 +v 3.691614 0.010002 -4.891389 +v 3.691614 0.010002 -4.983679 +v 3.599324 0.010002 -4.983679 +v 3.414743 0.010002 -5.814293 +v 3.507033 0.010002 -5.814293 +v 3.507033 0.010002 -5.906583 +v 3.414743 0.010002 -5.906583 +v 3.414743 0.010002 -5.629711 +v 3.507033 0.010002 -5.629711 +v 3.507033 0.010002 -5.722002 +v 3.414743 0.010002 -5.722002 +v 3.599324 0.010002 -5.629711 +v 3.691614 0.010002 -5.629711 +v 3.691614 0.010002 -5.722002 +v 3.599324 0.010002 -5.722002 +v 4.153066 0.010001 -3.599324 +v 4.245357 0.010001 -3.599324 +v 4.245357 0.010002 -3.691614 +v 4.153066 0.010002 -3.691614 +v 4.153066 0.010001 -3.414743 +v 4.245357 0.010001 -3.414743 +v 4.245357 0.010001 -3.507033 +v 4.153066 0.010001 -3.507033 +v 4.337647 0.010001 -3.414743 +v 4.429937 0.010001 -3.414743 +v 4.429937 0.010001 -3.507033 +v 4.337647 0.010001 -3.507033 +v 3.414743 0.010001 -3.599324 +v 3.507033 0.010001 -3.599324 +v 3.507033 0.010002 -3.691614 +v 3.414743 0.010002 -3.691614 +v 3.414743 0.010001 -3.414743 +v 3.507033 0.010001 -3.414743 +v 3.507033 0.010001 -3.507033 +v 3.414743 0.010001 -3.507033 +v 3.599324 0.010001 -3.414743 +v 3.691614 0.010001 -3.414743 +v 3.691614 0.010001 -3.507033 +v 3.599324 0.010001 -3.507033 +v 3.414743 0.010002 -4.337647 +v 3.507033 0.010002 -4.337647 +v 3.507033 0.010002 -4.429937 +v 3.414743 0.010002 -4.429937 +v 3.414743 0.010002 -4.153066 +v 3.507033 0.010002 -4.153066 +v 3.507033 0.010002 -4.245357 +v 3.414743 0.010002 -4.245357 +v 3.599324 0.010002 -4.153066 +v 3.691614 0.010002 -4.153066 +v 3.691614 0.010002 -4.245357 +v 3.599324 0.010002 -4.245357 +v 5.629711 0.010001 -3.599324 +v 5.722002 0.010001 -3.599324 +v 5.722002 0.010002 -3.691614 +v 5.629711 0.010002 -3.691614 +v 5.629711 0.010001 -3.414743 +v 5.722002 0.010001 -3.414743 +v 5.722002 0.010001 -3.507033 +v 5.629711 0.010001 -3.507033 +v 5.814293 0.010001 -3.414743 +v 5.906583 0.010001 -3.414743 +v 5.906583 0.010001 -3.507033 +v 5.814293 0.010001 -3.507033 +v 4.891389 0.010001 -3.599324 +v 4.983679 0.010001 -3.599324 +v 4.983679 0.010002 -3.691614 +v 4.891389 0.010002 -3.691614 +v 4.891389 0.010001 -3.414743 +v 4.983679 0.010001 -3.414743 +v 4.983679 0.010001 -3.507033 +v 4.891389 0.010001 -3.507033 +v 5.075970 0.010001 -3.414743 +v 5.168260 0.010001 -3.414743 +v 5.168260 0.010001 -3.507033 +v 5.075970 0.010001 -3.507033 +v 4.891389 0.010002 -4.337647 +v 4.983679 0.010002 -4.337647 +v 4.983679 0.010002 -4.429937 +v 4.891389 0.010002 -4.429937 +v 4.891389 0.010002 -4.153066 +v 4.983679 0.010002 -4.153066 +v 4.983679 0.010002 -4.245357 +v 4.891389 0.010002 -4.245357 +v 5.075970 0.010002 -4.153066 +v 5.168260 0.010002 -4.153066 +v 5.168260 0.010002 -4.245357 +v 5.075970 0.010002 -4.245357 +v 5.629711 0.010002 -4.337647 +v 5.722002 0.010002 -4.337647 +v 5.722002 0.010002 -4.429937 +v 5.629711 0.010002 -4.429937 +v 5.629711 0.010002 -4.153066 +v 5.722002 0.010002 -4.153066 +v 5.722002 0.010002 -4.245357 +v 5.629711 0.010002 -4.245357 +v 5.814293 0.010002 -4.153066 +v 5.906583 0.010002 -4.153066 +v 5.906583 0.010002 -4.245357 +v 5.814293 0.010002 -4.245357 +v 4.153066 0.010002 -4.337647 +v 4.245357 0.010002 -4.337647 +v 4.245357 0.010002 -4.429937 +v 4.153066 0.010002 -4.429937 +v 4.153066 0.010002 -4.153066 +v 4.245357 0.010002 -4.153066 +v 4.245357 0.010002 -4.245357 +v 4.153066 0.010002 -4.245357 +v 4.337647 0.010002 -4.153066 +v 4.429937 0.010002 -4.153066 +v 4.429937 0.010002 -4.245357 +v 4.337647 0.010002 -4.245357 +v 4.153066 0.010002 -5.814293 +v 4.245357 0.010002 -5.814293 +v 4.245357 0.010002 -5.906583 +v 4.153066 0.010002 -5.906583 +v 4.153066 0.010002 -5.629711 +v 4.245357 0.010002 -5.629711 +v 4.245357 0.010002 -5.722002 +v 4.153066 0.010002 -5.722002 +v 4.337647 0.010002 -5.629711 +v 4.429937 0.010002 -5.629711 +v 4.429937 0.010002 -5.722002 +v 4.337647 0.010002 -5.722002 +v -0.276871 0.010002 -4.337647 +v -0.184581 0.010002 -4.337647 +v -0.184581 0.010002 -4.429937 +v -0.276871 0.010002 -4.429937 +v -0.276871 0.010002 -4.153066 +v -0.184581 0.010002 -4.153066 +v -0.184581 0.010002 -4.245357 +v -0.276871 0.010002 -4.245357 +v -0.092290 0.010002 -4.153066 +v 0.000000 0.010002 -4.153066 +v 0.000000 0.010002 -4.245357 +v -0.092290 0.010002 -4.245357 +v -1.753517 0.010002 -4.337647 +v -1.661226 0.010002 -4.337647 +v -1.661226 0.010002 -4.429937 +v -1.753517 0.010002 -4.429937 +v -1.753517 0.010002 -4.153066 +v -1.661226 0.010002 -4.153066 +v -1.661226 0.010002 -4.245357 +v -1.753517 0.010002 -4.245357 +v -1.568936 0.010002 -4.153066 +v -1.476646 0.010002 -4.153066 +v -1.476646 0.010002 -4.245357 +v -1.568936 0.010002 -4.245357 +v -1.753517 0.010002 -5.814293 +v -1.661226 0.010002 -5.814293 +v -1.661226 0.010002 -5.906583 +v -1.753517 0.010002 -5.906583 +v -1.753517 0.010002 -5.629711 +v -1.661226 0.010002 -5.629711 +v -1.661226 0.010002 -5.722002 +v -1.753517 0.010002 -5.722002 +v -1.568936 0.010002 -5.629711 +v -1.476646 0.010002 -5.629711 +v -1.476646 0.010002 -5.722002 +v -1.568936 0.010002 -5.722002 +v -0.276871 0.009999 1.568936 +v -0.184581 0.009999 1.568936 +v -0.184581 0.009999 1.476646 +v -0.276871 0.009999 1.476646 +v -0.276871 0.009999 1.753517 +v -0.184581 0.009999 1.753517 +v -0.184581 0.009999 1.661226 +v -0.276871 0.009999 1.661226 +v -0.092290 0.009999 1.753517 +v 0.000000 0.009999 1.753517 +v 0.000000 0.009999 1.661226 +v -0.092290 0.009999 1.661226 +v -1.753517 0.009999 1.568936 +v -1.661226 0.009999 1.568936 +v -1.661226 0.009999 1.476646 +v -1.753517 0.009999 1.476646 +v -1.753517 0.009999 1.753517 +v -1.661226 0.009999 1.753517 +v -1.661226 0.009999 1.661226 +v -1.753517 0.009999 1.661226 +v -1.568936 0.009999 1.753517 +v -1.476646 0.009999 1.753517 +v -1.476646 0.009999 1.661226 +v -1.568936 0.009999 1.661226 +v -1.753517 0.010000 0.092290 +v -1.661226 0.010000 0.092290 +v -1.661226 0.010000 -0.000000 +v -1.753517 0.010000 -0.000000 +v -1.753517 0.010000 0.276871 +v -1.661226 0.010000 0.276871 +v -1.661226 0.010000 0.184581 +v -1.753517 0.010000 0.184581 +v -1.568936 0.010000 0.276871 +v -1.476646 0.010000 0.276871 +v -1.476646 0.010000 0.184581 +v -1.568936 0.010000 0.184581 +v 5.629711 0.009999 1.568936 +v 5.722002 0.009999 1.568936 +v 5.722002 0.009999 1.476646 +v 5.629711 0.009999 1.476646 +v 5.629711 0.009999 1.753517 +v 5.722002 0.009999 1.753517 +v 5.722002 0.009999 1.661226 +v 5.629711 0.009999 1.661226 +v 5.814293 0.009999 1.753517 +v 5.906583 0.009999 1.753517 +v 5.906583 0.009999 1.661226 +v 5.814293 0.009999 1.661226 +v 4.153066 0.009999 1.568936 +v 4.245357 0.009999 1.568936 +v 4.245357 0.009999 1.476646 +v 4.153066 0.009999 1.476646 +v 4.153066 0.009999 1.753517 +v 4.245357 0.009999 1.753517 +v 4.245357 0.009999 1.661226 +v 4.153066 0.009999 1.661226 +v 4.337647 0.009999 1.753517 +v 4.429937 0.009999 1.753517 +v 4.429937 0.009999 1.661226 +v 4.337647 0.009999 1.661226 +v 4.153066 0.010000 0.092290 +v 4.245357 0.010000 0.092290 +v 4.245357 0.010000 -0.000000 +v 4.153066 0.010000 -0.000000 +v 4.153066 0.010000 0.276871 +v 4.245357 0.010000 0.276871 +v 4.245357 0.010000 0.184581 +v 4.153066 0.010000 0.184581 +v 4.337647 0.010000 0.276871 +v 4.429937 0.010000 0.276871 +v 4.429937 0.010000 0.184581 +v 4.337647 0.010000 0.184581 +v 2.676420 0.009999 1.568936 +v 2.768711 0.009999 1.568936 +v 2.768711 0.009999 1.476646 +v 2.676420 0.009999 1.476646 +v 2.676420 0.009999 1.753517 +v 2.768711 0.009999 1.753517 +v 2.768711 0.009999 1.661226 +v 2.676420 0.009999 1.661226 +v 2.861001 0.009999 1.753517 +v 2.953291 0.009999 1.753517 +v 2.953291 0.009999 1.661226 +v 2.861001 0.009999 1.661226 +v 1.199775 0.009999 1.568936 +v 1.292065 0.009999 1.568936 +v 1.292065 0.009999 1.476646 +v 1.199775 0.009999 1.476646 +v 1.199775 0.009999 1.753517 +v 1.292065 0.009999 1.753517 +v 1.292065 0.009999 1.661226 +v 1.199775 0.009999 1.661226 +v 1.384355 0.009999 1.753517 +v 1.476646 0.009999 1.753517 +v 1.476646 0.009999 1.661226 +v 1.384355 0.009999 1.661226 +v 1.199775 0.010000 0.092290 +v 1.292065 0.010000 0.092290 +v 1.292065 0.010000 -0.000000 +v 1.199775 0.010000 -0.000000 +v 1.199775 0.010000 0.276871 +v 1.292065 0.010000 0.276871 +v 1.292065 0.010000 0.184581 +v 1.199775 0.010000 0.184581 +v 1.384355 0.010000 0.276871 +v 1.476646 0.010000 0.276871 +v 1.476646 0.010000 0.184581 +v 1.384355 0.010000 0.184581 +v 2.676420 0.009998 4.522227 +v 2.768711 0.009998 4.522227 +v 2.768711 0.009998 4.429937 +v 2.676420 0.009998 4.429937 +v 2.676420 0.009998 4.706808 +v 2.768711 0.009998 4.706808 +v 2.768711 0.009998 4.614518 +v 2.676420 0.009998 4.614518 +v 2.861001 0.009998 4.706808 +v 2.953291 0.009998 4.706808 +v 2.953291 0.009998 4.614518 +v 2.861001 0.009998 4.614518 +v 1.199775 0.009998 4.522227 +v 1.292065 0.009998 4.522227 +v 1.292065 0.009998 4.429937 +v 1.199775 0.009998 4.429937 +v 1.199775 0.009998 4.706808 +v 1.292065 0.009998 4.706808 +v 1.292065 0.009998 4.614518 +v 1.199775 0.009998 4.614518 +v 1.384355 0.009998 4.706808 +v 1.476646 0.009998 4.706808 +v 1.476646 0.009998 4.614518 +v 1.384355 0.009998 4.614518 +v 1.199775 0.009999 3.045582 +v 1.292065 0.009999 3.045582 +v 1.292065 0.009999 2.953291 +v 1.199775 0.009999 2.953291 +v 1.199775 0.009999 3.230163 +v 1.292065 0.009999 3.230163 +v 1.292065 0.009999 3.137872 +v 1.199775 0.009999 3.137872 +v 1.384355 0.009999 3.230163 +v 1.476646 0.009999 3.230163 +v 1.476646 0.009999 3.137872 +v 1.384355 0.009999 3.137872 +v 5.629711 0.009998 4.522227 +v 5.722002 0.009998 4.522227 +v 5.722002 0.009998 4.429937 +v 5.629711 0.009998 4.429937 +v 5.629711 0.009998 4.706808 +v 5.722002 0.009998 4.706808 +v 5.722002 0.009998 4.614518 +v 5.629711 0.009998 4.614518 +v 5.814293 0.009998 4.706808 +v 5.906583 0.009998 4.706808 +v 5.906583 0.009998 4.614518 +v 5.814293 0.009998 4.614518 +v 4.153066 0.009998 4.522227 +v 4.245357 0.009998 4.522227 +v 4.245357 0.009998 4.429937 +v 4.153066 0.009998 4.429937 +v 4.153066 0.009998 4.706808 +v 4.245357 0.009998 4.706808 +v 4.245357 0.009998 4.614518 +v 4.153066 0.009998 4.614518 +v 4.337647 0.009998 4.706808 +v 4.429937 0.009998 4.706808 +v 4.429937 0.009998 4.614518 +v 4.337647 0.009998 4.614518 +v 4.153066 0.009999 3.045582 +v 4.245357 0.009999 3.045582 +v 4.245357 0.009999 2.953291 +v 4.153066 0.009999 2.953291 +v 4.153066 0.009999 3.230163 +v 4.245357 0.009999 3.230163 +v 4.245357 0.009999 3.137872 +v 4.153066 0.009999 3.137872 +v 4.337647 0.009999 3.230163 +v 4.429937 0.009999 3.230163 +v 4.429937 0.009999 3.137872 +v 4.337647 0.009999 3.137872 +v -3.230163 0.009999 1.568936 +v -3.137872 0.009999 1.568936 +v -3.137872 0.009999 1.476646 +v -3.230163 0.009999 1.476646 +v -3.230163 0.009999 1.753517 +v -3.137872 0.009999 1.753517 +v -3.137872 0.009999 1.661226 +v -3.230163 0.009999 1.661226 +v -3.045582 0.009999 1.753517 +v -2.953291 0.009999 1.753517 +v -2.953291 0.009999 1.661226 +v -3.045582 0.009999 1.661226 +v -4.706808 0.009999 1.568936 +v -4.614518 0.009999 1.568936 +v -4.614518 0.009999 1.476646 +v -4.706808 0.009999 1.476646 +v -4.706808 0.009999 1.753517 +v -4.614518 0.009999 1.753517 +v -4.614518 0.009999 1.661226 +v -4.706808 0.009999 1.661226 +v -4.522227 0.009999 1.753517 +v -4.429937 0.009999 1.753517 +v -4.429937 0.009999 1.661226 +v -4.522227 0.009999 1.661226 +v -4.706808 0.010000 0.092290 +v -4.614518 0.010000 0.092290 +v -4.614518 0.010000 -0.000000 +v -4.706808 0.010000 -0.000000 +v -4.706808 0.010000 0.276871 +v -4.614518 0.010000 0.276871 +v -4.614518 0.010000 0.184581 +v -4.706808 0.010000 0.184581 +v -4.522227 0.010000 0.276871 +v -4.429937 0.010000 0.276871 +v -4.429937 0.010000 0.184581 +v -4.522227 0.010000 0.184581 +v -3.230163 0.009998 4.522227 +v -3.137872 0.009998 4.522227 +v -3.137872 0.009998 4.429937 +v -3.230163 0.009998 4.429937 +v -3.230163 0.009998 4.706808 +v -3.137872 0.009998 4.706808 +v -3.137872 0.009998 4.614518 +v -3.230163 0.009998 4.614518 +v -3.045582 0.009998 4.706808 +v -2.953291 0.009998 4.706808 +v -2.953291 0.009998 4.614518 +v -3.045582 0.009998 4.614518 +v -4.706808 0.009998 4.522227 +v -4.614518 0.009998 4.522227 +v -4.614518 0.009998 4.429937 +v -4.706808 0.009998 4.429937 +v -4.706808 0.009998 4.706808 +v -4.614518 0.009998 4.706808 +v -4.614518 0.009998 4.614518 +v -4.706808 0.009998 4.614518 +v -4.522227 0.009998 4.706808 +v -4.429937 0.009998 4.706808 +v -4.429937 0.009998 4.614518 +v -4.522227 0.009998 4.614518 +v -4.706808 0.009999 3.045582 +v -4.614518 0.009999 3.045582 +v -4.614518 0.009999 2.953291 +v -4.706808 0.009999 2.953291 +v -4.706808 0.009999 3.230163 +v -4.614518 0.009999 3.230163 +v -4.614518 0.009999 3.137872 +v -4.706808 0.009999 3.137872 +v -4.522227 0.009999 3.230163 +v -4.429937 0.009999 3.230163 +v -4.429937 0.009999 3.137872 +v -4.522227 0.009999 3.137872 +v -0.276871 0.009998 4.522227 +v -0.184581 0.009998 4.522227 +v -0.184581 0.009998 4.429937 +v -0.276871 0.009998 4.429937 +v -0.276871 0.009998 4.706808 +v -0.184581 0.009998 4.706808 +v -0.184581 0.009998 4.614518 +v -0.276871 0.009998 4.614518 +v -0.092290 0.009998 4.706808 +v 0.000000 0.009998 4.706808 +v 0.000000 0.009998 4.614518 +v -0.092290 0.009998 4.614518 +v -1.753517 0.009998 4.522227 +v -1.661226 0.009998 4.522227 +v -1.661226 0.009998 4.429937 +v -1.753517 0.009998 4.429937 +v -1.753517 0.009998 4.706808 +v -1.661226 0.009998 4.706808 +v -1.661226 0.009998 4.614518 +v -1.753517 0.009998 4.614518 +v -1.568936 0.009998 4.706808 +v -1.476646 0.009998 4.706808 +v -1.476646 0.009998 4.614518 +v -1.568936 0.009998 4.614518 +v -1.753517 0.009999 3.045582 +v -1.661226 0.009999 3.045582 +v -1.661226 0.009999 2.953291 +v -1.753517 0.009999 2.953291 +v -1.753517 0.009999 3.230163 +v -1.661226 0.009999 3.230163 +v -1.661226 0.009999 3.137872 +v -1.753517 0.009999 3.137872 +v -1.568936 0.009999 3.230163 +v -1.476646 0.009999 3.230163 +v -1.476646 0.009999 3.137872 +v -1.568936 0.009999 3.137872 +v -3.230163 0.010002 -4.337647 +v -3.137872 0.010002 -4.337647 +v -3.137872 0.010002 -4.429937 +v -3.230163 0.010002 -4.429937 +v -3.230163 0.010002 -4.153066 +v -3.137872 0.010002 -4.153066 +v -3.137872 0.010002 -4.245357 +v -3.230163 0.010002 -4.245357 +v -3.045582 0.010002 -4.153066 +v -2.953291 0.010002 -4.153066 +v -2.953291 0.010002 -4.245357 +v -3.045582 0.010002 -4.245357 +v -4.706808 0.010002 -4.337647 +v -4.614518 0.010002 -4.337647 +v -4.614518 0.010002 -4.429937 +v -4.706808 0.010002 -4.429937 +v -4.706808 0.010002 -4.153066 +v -4.614518 0.010002 -4.153066 +v -4.614518 0.010002 -4.245357 +v -4.706808 0.010002 -4.245357 +v -4.522227 0.010002 -4.153066 +v -4.429937 0.010002 -4.153066 +v -4.429937 0.010002 -4.245357 +v -4.522227 0.010002 -4.245357 +v -4.706808 0.010002 -5.814293 +v -4.614518 0.010002 -5.814293 +v -4.614518 0.010002 -5.906583 +v -4.706808 0.010002 -5.906583 +v -4.706808 0.010002 -5.629711 +v -4.614518 0.010002 -5.629711 +v -4.614518 0.010002 -5.722002 +v -4.706808 0.010002 -5.722002 +v -4.522227 0.010002 -5.629711 +v -4.429937 0.010002 -5.629711 +v -4.429937 0.010002 -5.722002 +v -4.522227 0.010002 -5.722002 +v -3.230163 0.010001 -1.384355 +v -3.137872 0.010001 -1.384355 +v -3.137872 0.010001 -1.476646 +v -3.230163 0.010001 -1.476646 +v -3.230163 0.010000 -1.199775 +v -3.137872 0.010000 -1.199775 +v -3.137872 0.010001 -1.292065 +v -3.230163 0.010001 -1.292065 +v -3.045582 0.010000 -1.199775 +v -2.953291 0.010000 -1.199775 +v -2.953291 0.010001 -1.292065 +v -3.045582 0.010001 -1.292065 +v -4.706808 0.010001 -1.384355 +v -4.614518 0.010001 -1.384355 +v -4.614518 0.010001 -1.476646 +v -4.706808 0.010001 -1.476646 +v -4.706808 0.010000 -1.199775 +v -4.614518 0.010000 -1.199775 +v -4.614518 0.010001 -1.292065 +v -4.706808 0.010001 -1.292065 +v -4.522227 0.010000 -1.199775 +v -4.429937 0.010000 -1.199775 +v -4.429937 0.010001 -1.292065 +v -4.522227 0.010001 -1.292065 +v -4.706808 0.010001 -2.861001 +v -4.614518 0.010001 -2.861001 +v -4.614518 0.010001 -2.953291 +v -4.706808 0.010001 -2.953291 +v -4.706808 0.010001 -2.676420 +v -4.614518 0.010001 -2.676420 +v -4.614518 0.010001 -2.768711 +v -4.706808 0.010001 -2.768711 +v -4.522227 0.010001 -2.676420 +v -4.429937 0.010001 -2.676420 +v -4.429937 0.010001 -2.768711 +v -4.522227 0.010001 -2.768711 +v -0.276871 0.010001 -1.384355 +v -0.184581 0.010001 -1.384355 +v -0.184581 0.010001 -1.476646 +v -0.276871 0.010001 -1.476646 +v -0.276871 0.010000 -1.199775 +v -0.184581 0.010000 -1.199775 +v -0.184581 0.010001 -1.292065 +v -0.276871 0.010001 -1.292065 +v -0.092290 0.010000 -1.199775 +v 0.000000 0.010000 -1.199775 +v 0.000000 0.010001 -1.292065 +v -0.092290 0.010001 -1.292065 +v -1.753517 0.010001 -1.384355 +v -1.661226 0.010001 -1.384355 +v -1.661226 0.010001 -1.476646 +v -1.753517 0.010001 -1.476646 +v -1.753517 0.010000 -1.199775 +v -1.661226 0.010000 -1.199775 +v -1.661226 0.010001 -1.292065 +v -1.753517 0.010001 -1.292065 +v -1.568936 0.010000 -1.199775 +v -1.476646 0.010000 -1.199775 +v -1.476646 0.010001 -1.292065 +v -1.568936 0.010001 -1.292065 +v -1.753517 0.010001 -2.861001 +v -1.661226 0.010001 -2.861001 +v -1.661226 0.010001 -2.953291 +v -1.753517 0.010001 -2.953291 +v -1.753517 0.010001 -2.676420 +v -1.661226 0.010001 -2.676420 +v -1.661226 0.010001 -2.768711 +v -1.753517 0.010001 -2.768711 +v -1.568936 0.010001 -2.676420 +v -1.476646 0.010001 -2.676420 +v -1.476646 0.010001 -2.768711 +v -1.568936 0.010001 -2.768711 +v 2.676420 0.010002 -4.337647 +v 2.768711 0.010002 -4.337647 +v 2.768711 0.010002 -4.429937 +v 2.676420 0.010002 -4.429937 +v 2.676420 0.010002 -4.153066 +v 2.768711 0.010002 -4.153066 +v 2.768711 0.010002 -4.245357 +v 2.676420 0.010002 -4.245357 +v 2.861001 0.010002 -4.153066 +v 2.953291 0.010002 -4.153066 +v 2.953291 0.010002 -4.245357 +v 2.861001 0.010002 -4.245357 +v 1.199775 0.010002 -4.337647 +v 1.292065 0.010002 -4.337647 +v 1.292065 0.010002 -4.429937 +v 1.199775 0.010002 -4.429937 +v 1.199775 0.010002 -4.153066 +v 1.292065 0.010002 -4.153066 +v 1.292065 0.010002 -4.245357 +v 1.199775 0.010002 -4.245357 +v 1.384355 0.010002 -4.153066 +v 1.476646 0.010002 -4.153066 +v 1.476646 0.010002 -4.245357 +v 1.384355 0.010002 -4.245357 +v 1.199775 0.010002 -5.814293 +v 1.292065 0.010002 -5.814293 +v 1.292065 0.010002 -5.906583 +v 1.199775 0.010002 -5.906583 +v 1.199775 0.010002 -5.629711 +v 1.292065 0.010002 -5.629711 +v 1.292065 0.010002 -5.722002 +v 1.199775 0.010002 -5.722002 +v 1.384355 0.010002 -5.629711 +v 1.476646 0.010002 -5.629711 +v 1.476646 0.010002 -5.722002 +v 1.384355 0.010002 -5.722002 +v 2.676420 0.010001 -1.384355 +v 2.768711 0.010001 -1.384355 +v 2.768711 0.010001 -1.476646 +v 2.676420 0.010001 -1.476646 +v 2.676420 0.010000 -1.199775 +v 2.768711 0.010000 -1.199775 +v 2.768711 0.010001 -1.292065 +v 2.676420 0.010001 -1.292065 +v 2.861001 0.010000 -1.199775 +v 2.953291 0.010000 -1.199775 +v 2.953291 0.010001 -1.292065 +v 2.861001 0.010001 -1.292065 +v 1.199775 0.010001 -1.384355 +v 1.292065 0.010001 -1.384355 +v 1.292065 0.010001 -1.476646 +v 1.199775 0.010001 -1.476646 +v 1.199775 0.010000 -1.199775 +v 1.292065 0.010000 -1.199775 +v 1.292065 0.010001 -1.292065 +v 1.199775 0.010001 -1.292065 +v 1.384355 0.010000 -1.199775 +v 1.476646 0.010000 -1.199775 +v 1.476646 0.010001 -1.292065 +v 1.384355 0.010001 -1.292065 +v 1.199775 0.010001 -2.861001 +v 1.292065 0.010001 -2.861001 +v 1.292065 0.010001 -2.953291 +v 1.199775 0.010001 -2.953291 +v 1.199775 0.010001 -2.676420 +v 1.292065 0.010001 -2.676420 +v 1.292065 0.010001 -2.768711 +v 1.199775 0.010001 -2.768711 +v 1.384355 0.010001 -2.676420 +v 1.476646 0.010001 -2.676420 +v 1.476646 0.010001 -2.768711 +v 1.384355 0.010001 -2.768711 +v 5.629711 0.010001 -1.384355 +v 5.722002 0.010001 -1.384355 +v 5.722002 0.010001 -1.476646 +v 5.629711 0.010001 -1.476646 +v 5.629711 0.010000 -1.199775 +v 5.722002 0.010000 -1.199775 +v 5.722002 0.010001 -1.292065 +v 5.629711 0.010001 -1.292065 +v 5.814293 0.010000 -1.199775 +v 5.906583 0.010000 -1.199775 +v 5.906583 0.010001 -1.292065 +v 5.814293 0.010001 -1.292065 +v 4.153066 0.010001 -1.384355 +v 4.245357 0.010001 -1.384355 +v 4.245357 0.010001 -1.476646 +v 4.153066 0.010001 -1.476646 +v 4.153066 0.010000 -1.199775 +v 4.245357 0.010000 -1.199775 +v 4.245357 0.010001 -1.292065 +v 4.153066 0.010001 -1.292065 +v 4.337647 0.010000 -1.199775 +v 4.429937 0.010000 -1.199775 +v 4.429937 0.010001 -1.292065 +v 4.337647 0.010001 -1.292065 +v 4.153066 0.010001 -2.861001 +v 4.245357 0.010001 -2.861001 +v 4.245357 0.010001 -2.953291 +v 4.153066 0.010001 -2.953291 +v 4.153066 0.010001 -2.676420 +v 4.245357 0.010001 -2.676420 +v 4.245357 0.010001 -2.768711 +v 4.153066 0.010001 -2.768711 +v 4.337647 0.010001 -2.676420 +v 4.429937 0.010001 -2.676420 +v 4.429937 0.010001 -2.768711 +v 4.337647 0.010001 -2.768711 +v 5.629711 0.010001 -2.861001 +v 5.722002 0.010001 -2.861001 +v 5.722002 0.010001 -2.953291 +v 5.629711 0.010001 -2.953291 +v 5.629711 0.010001 -2.676420 +v 5.722002 0.010001 -2.676420 +v 5.722002 0.010001 -2.768711 +v 5.629711 0.010001 -2.768711 +v 5.814293 0.010001 -2.676420 +v 5.906583 0.010001 -2.676420 +v 5.906583 0.010001 -2.768711 +v 5.814293 0.010001 -2.768711 +v 2.676420 0.010001 -2.861001 +v 2.768711 0.010001 -2.861001 +v 2.768711 0.010001 -2.953291 +v 2.676420 0.010001 -2.953291 +v 2.676420 0.010001 -2.676420 +v 2.768711 0.010001 -2.676420 +v 2.768711 0.010001 -2.768711 +v 2.676420 0.010001 -2.768711 +v 2.861001 0.010001 -2.676420 +v 2.953291 0.010001 -2.676420 +v 2.953291 0.010001 -2.768711 +v 2.861001 0.010001 -2.768711 +v 2.676420 0.010002 -5.814293 +v 2.768711 0.010002 -5.814293 +v 2.768711 0.010002 -5.906583 +v 2.676420 0.010002 -5.906583 +v 2.676420 0.010002 -5.629711 +v 2.768711 0.010002 -5.629711 +v 2.768711 0.010002 -5.722002 +v 2.676420 0.010002 -5.722002 +v 2.861001 0.010002 -5.629711 +v 2.953291 0.010002 -5.629711 +v 2.953291 0.010002 -5.722002 +v 2.861001 0.010002 -5.722002 +v -0.276871 0.010001 -2.861001 +v -0.184581 0.010001 -2.861001 +v -0.184581 0.010001 -2.953291 +v -0.276871 0.010001 -2.953291 +v -0.276871 0.010001 -2.676420 +v -0.184581 0.010001 -2.676420 +v -0.184581 0.010001 -2.768711 +v -0.276871 0.010001 -2.768711 +v -0.092290 0.010001 -2.676420 +v 0.000000 0.010001 -2.676420 +v 0.000000 0.010001 -2.768711 +v -0.092290 0.010001 -2.768711 +v -3.230163 0.010001 -2.861001 +v -3.137872 0.010001 -2.861001 +v -3.137872 0.010001 -2.953291 +v -3.230163 0.010001 -2.953291 +v -3.230163 0.010001 -2.676420 +v -3.137872 0.010001 -2.676420 +v -3.137872 0.010001 -2.768711 +v -3.230163 0.010001 -2.768711 +v -3.045582 0.010001 -2.676420 +v -2.953291 0.010001 -2.676420 +v -2.953291 0.010001 -2.768711 +v -3.045582 0.010001 -2.768711 +v -3.230163 0.010002 -5.814293 +v -3.137872 0.010002 -5.814293 +v -3.137872 0.010002 -5.906583 +v -3.230163 0.010002 -5.906583 +v -3.230163 0.010002 -5.629711 +v -3.137872 0.010002 -5.629711 +v -3.137872 0.010002 -5.722002 +v -3.230163 0.010002 -5.722002 +v -3.045582 0.010002 -5.629711 +v -2.953291 0.010002 -5.629711 +v -2.953291 0.010002 -5.722002 +v -3.045582 0.010002 -5.722002 +v -0.276871 0.009999 3.045582 +v -0.184581 0.009999 3.045582 +v -0.184581 0.009999 2.953291 +v -0.276871 0.009999 2.953291 +v -0.276871 0.009999 3.230163 +v -0.184581 0.009999 3.230163 +v -0.184581 0.009999 3.137872 +v -0.276871 0.009999 3.137872 +v -0.092290 0.009999 3.230163 +v 0.000000 0.009999 3.230163 +v 0.000000 0.009999 3.137872 +v -0.092290 0.009999 3.137872 +v -3.230163 0.009999 3.045582 +v -3.137872 0.009999 3.045582 +v -3.137872 0.009999 2.953291 +v -3.230163 0.009999 2.953291 +v -3.230163 0.009999 3.230163 +v -3.137872 0.009999 3.230163 +v -3.137872 0.009999 3.137872 +v -3.230163 0.009999 3.137872 +v -3.045582 0.009999 3.230163 +v -2.953291 0.009999 3.230163 +v -2.953291 0.009999 3.137872 +v -3.045582 0.009999 3.137872 +v -3.230163 0.010000 0.092290 +v -3.137872 0.010000 0.092290 +v -3.137872 0.010000 -0.000000 +v -3.230163 0.010000 -0.000000 +v -3.230163 0.010000 0.276871 +v -3.137872 0.010000 0.276871 +v -3.137872 0.010000 0.184581 +v -3.230163 0.010000 0.184581 +v -3.045582 0.010000 0.276871 +v -2.953291 0.010000 0.276871 +v -2.953291 0.010000 0.184581 +v -3.045582 0.010000 0.184581 +v 5.629711 0.009999 3.045582 +v 5.722002 0.009999 3.045582 +v 5.722002 0.009999 2.953291 +v 5.629711 0.009999 2.953291 +v 5.629711 0.009999 3.230163 +v 5.722002 0.009999 3.230163 +v 5.722002 0.009999 3.137872 +v 5.629711 0.009999 3.137872 +v 5.814293 0.009999 3.230163 +v 5.906583 0.009999 3.230163 +v 5.906583 0.009999 3.137872 +v 5.814293 0.009999 3.137872 +v 2.676420 0.009999 3.045582 +v 2.768711 0.009999 3.045582 +v 2.768711 0.009999 2.953291 +v 2.676420 0.009999 2.953291 +v 2.676420 0.009999 3.230163 +v 2.768711 0.009999 3.230163 +v 2.768711 0.009999 3.137872 +v 2.676420 0.009999 3.137872 +v 2.861001 0.009999 3.230163 +v 2.953291 0.009999 3.230163 +v 2.953291 0.009999 3.137872 +v 2.861001 0.009999 3.137872 +v 2.676420 0.010000 0.092290 +v 2.768711 0.010000 0.092290 +v 2.768711 0.010000 -0.000000 +v 2.676420 0.010000 -0.000000 +v 2.676420 0.010000 0.276871 +v 2.768711 0.010000 0.276871 +v 2.768711 0.010000 0.184581 +v 2.676420 0.010000 0.184581 +v 2.861001 0.010000 0.276871 +v 2.953291 0.010000 0.276871 +v 2.953291 0.010000 0.184581 +v 2.861001 0.010000 0.184581 +v 5.629711 0.010000 0.092290 +v 5.722002 0.010000 0.092290 +v 5.722002 0.010000 -0.000000 +v 5.629711 0.010000 -0.000000 +v 5.629711 0.010000 0.276871 +v 5.722002 0.010000 0.276871 +v 5.722002 0.010000 0.184581 +v 5.629711 0.010000 0.184581 +v 5.814293 0.010000 0.276871 +v 5.906583 0.010000 0.276871 +v 5.906583 0.010000 0.184581 +v 5.814293 0.010000 0.184581 +v -0.276871 0.010000 0.092290 +v -0.184581 0.010000 0.092290 +v -0.184581 0.010000 -0.000000 +v -0.276871 0.010000 -0.000000 +v -0.276871 0.010000 0.276871 +v -0.184581 0.010000 0.276871 +v -0.184581 0.010000 0.184581 +v -0.276871 0.010000 0.184581 +v -0.092290 0.010000 0.276871 +v 0.000000 0.010000 0.276871 +v 0.000000 0.010000 0.184581 +v -0.092290 0.010000 0.184581 +v -0.276871 0.010002 -5.814293 +v -0.184581 0.010002 -5.814293 +v -0.184581 0.010002 -5.906583 +v -0.276871 0.010002 -5.906583 +v -0.276871 0.010002 -5.629711 +v -0.184581 0.010002 -5.629711 +v -0.184581 0.010002 -5.722002 +v -0.276871 0.010002 -5.722002 +v -0.092290 0.010002 -5.629711 +v 0.000000 0.010002 -5.629711 +v 0.000000 0.010002 -5.722002 +v -0.092290 0.010002 -5.722002 +v 5.629711 0.010002 -5.814293 +v 5.722002 0.010002 -5.814293 +v 5.722002 0.010002 -5.906583 +v 5.629711 0.010002 -5.906583 +v 5.629711 0.010002 -5.629711 +v 5.722002 0.010002 -5.629711 +v 5.722002 0.010002 -5.722002 +v 5.629711 0.010002 -5.722002 +v 5.814293 0.010002 -5.629711 +v 5.906583 0.010002 -5.629711 +v 5.906583 0.010002 -5.722002 +v 5.814293 0.010002 -5.722002 +v -5.906583 0.010001 -1.938097 +v -5.906583 0.010001 -2.030388 +v -5.906583 0.010001 -1.845807 +v -5.906583 0.010001 -2.122678 +v -5.906583 0.010001 -2.214968 +v -5.906583 0.010001 -1.568936 +v -5.906583 0.010001 -1.661226 +v -5.906583 0.010001 -1.476646 +v -5.906583 0.010001 -1.753517 +v -5.906583 0.010001 -2.676420 +v -5.906583 0.010001 -2.768711 +v -5.906583 0.010001 -2.584130 +v -5.906583 0.010001 -2.861001 +v -5.906583 0.010001 -2.953291 +v -5.906583 0.010001 -2.307259 +v -5.906583 0.010001 -2.399549 +v -5.906583 0.010001 -2.491840 +v -5.906583 0.010000 -0.461452 +v -5.906583 0.010000 -0.553742 +v -5.906583 0.010000 -0.369161 +v -5.906583 0.010000 -0.646033 +v -5.906583 0.010000 -0.738323 +v -5.906583 0.010000 -0.092290 +v -5.906583 0.010000 -0.184581 +v -5.906583 0.010000 -0.000000 +v -5.906583 0.010000 -0.276871 +v -5.906583 0.010000 -1.199775 +v -5.906583 0.010001 -1.292065 +v -5.906583 0.010000 -1.107484 +v -5.906583 0.010001 -1.384355 +v -5.906583 0.010000 -0.830613 +v -5.906583 0.010000 -0.922904 +v -5.906583 0.010000 -1.015194 +v -5.906583 0.010002 -4.891389 +v -5.906583 0.010002 -4.983679 +v -5.906583 0.010002 -4.799098 +v -5.906583 0.010002 -5.075970 +v -5.906583 0.010002 -5.168260 +v -5.906583 0.010002 -4.522227 +v -5.906583 0.010002 -4.614518 +v -5.906583 0.010002 -4.429937 +v -5.906583 0.010002 -4.706808 +v -5.906583 0.010002 -5.629711 +v -5.906583 0.010002 -5.722002 +v -5.906583 0.010002 -5.537421 +v -5.906583 0.010002 -5.814293 +v -5.906583 0.010002 -5.906583 +v -5.906583 0.010002 -5.260550 +v -5.906583 0.010002 -5.352840 +v -5.906583 0.010002 -5.445131 +v -5.906583 0.010001 -3.414743 +v -5.906583 0.010001 -3.507033 +v -5.906583 0.010001 -3.322453 +v -5.906583 0.010001 -3.599324 +v -5.906583 0.010002 -3.691614 +v -5.906583 0.010001 -3.045582 +v -5.906583 0.010001 -3.137872 +v -5.906583 0.010001 -3.230163 +v -5.906583 0.010002 -4.153066 +v -5.906583 0.010002 -4.245357 +v -5.906583 0.010002 -4.060776 +v -5.906583 0.010002 -4.337647 +v -5.906583 0.010002 -3.783905 +v -5.906583 0.010002 -3.876195 +v -5.906583 0.010002 -3.968485 +v -2.030388 0.009998 5.906583 +v -1.938097 0.009998 5.906583 +v -1.845807 0.009998 5.906583 +v -2.214968 0.009998 5.906583 +v -2.122678 0.009998 5.906583 +v -1.661226 0.009998 5.906583 +v -1.568936 0.009998 5.906583 +v -1.476646 0.009998 5.906583 +v -1.753517 0.009998 5.906583 +v -2.768711 0.009998 5.906583 +v -2.676420 0.009998 5.906583 +v -2.584130 0.009998 5.906583 +v -2.953291 0.009998 5.906583 +v -2.861001 0.009998 5.906583 +v -2.399549 0.009998 5.906583 +v -2.307259 0.009998 5.906583 +v -2.491840 0.009998 5.906583 +v -0.553742 0.009998 5.906583 +v -0.461452 0.009998 5.906583 +v -0.369161 0.009998 5.906583 +v -0.738323 0.009998 5.906583 +v -0.646033 0.009998 5.906583 +v -0.184581 0.009998 5.906583 +v -0.092290 0.009998 5.906583 +v 0.000000 0.009998 5.906583 +v -0.276871 0.009998 5.906583 +v -1.292065 0.009998 5.906583 +v -1.199775 0.009998 5.906583 +v -1.107484 0.009998 5.906583 +v -1.384355 0.009998 5.906583 +v -0.922904 0.009998 5.906583 +v -0.830613 0.009998 5.906583 +v -1.015194 0.009998 5.906583 +v -5.906583 0.009998 3.968485 +v -5.906583 0.009998 3.876195 +v -5.906583 0.009998 4.060776 +v -5.906583 0.009998 3.783905 +v -5.906583 0.009998 3.691614 +v -5.906583 0.009998 4.337647 +v -5.906583 0.009998 4.245357 +v -5.906583 0.009998 4.429937 +v -5.906583 0.009998 4.153066 +v -5.906583 0.009999 3.230163 +v -5.906583 0.009999 3.137872 +v -5.906583 0.009999 3.322453 +v -5.906583 0.009999 3.045582 +v -5.906583 0.009999 2.953291 +v -5.906583 0.009999 3.599324 +v -5.906583 0.009999 3.507033 +v -5.906583 0.009999 3.414743 +v -4.983679 0.009998 5.906583 +v -4.891389 0.009998 5.906583 +v -4.799098 0.009998 5.906583 +v -5.168260 0.009998 5.906583 +v -5.075970 0.009998 5.906583 +v -4.614518 0.009998 5.906583 +v -4.522227 0.009998 5.906583 +v -4.429937 0.009998 5.906583 +v -4.706808 0.009998 5.906583 +v -5.906583 0.009998 5.445131 +v -5.906583 0.009998 5.352840 +v -5.906583 0.009998 5.537421 +v -5.906583 0.009998 5.260550 +v -5.906583 0.009998 5.168260 +v -5.722002 0.009998 5.906583 +v -5.629711 0.009998 5.906583 +v -5.537421 0.009998 5.906583 +v -5.906583 0.009998 5.814293 +v -5.906583 0.009998 5.722002 +v -5.906583 0.009998 5.906583 +v -5.814293 0.009998 5.906583 +v -5.906583 0.009998 5.629711 +v -5.352840 0.009998 5.906583 +v -5.260550 0.009998 5.906583 +v -5.445131 0.009998 5.906583 +v -5.906583 0.009998 4.706808 +v -5.906583 0.009998 4.614518 +v -5.906583 0.009998 4.799098 +v -5.906583 0.009998 4.522227 +v -5.906583 0.009998 5.075970 +v -5.906583 0.009998 4.983679 +v -5.906583 0.009998 4.891389 +v -3.507033 0.009998 5.906583 +v -3.414743 0.009998 5.906583 +v -3.322453 0.009998 5.906583 +v -3.691614 0.009998 5.906583 +v -3.599324 0.009998 5.906583 +v -3.137872 0.009998 5.906583 +v -3.045582 0.009998 5.906583 +v -3.230163 0.009998 5.906583 +v -4.245357 0.009998 5.906583 +v -4.153066 0.009998 5.906583 +v -4.060776 0.009998 5.906583 +v -4.337647 0.009998 5.906583 +v -3.876195 0.009998 5.906583 +v -3.783905 0.009998 5.906583 +v -3.968485 0.009998 5.906583 +v -5.906583 0.010000 1.015194 +v -5.906583 0.010000 0.922904 +v -5.906583 0.010000 1.107484 +v -5.906583 0.010000 0.830613 +v -5.906583 0.010000 0.738323 +v -5.906583 0.009999 1.384355 +v -5.906583 0.009999 1.292065 +v -5.906583 0.009999 1.476646 +v -5.906583 0.010000 1.199775 +v -5.906583 0.010000 0.276871 +v -5.906583 0.010000 0.184581 +v -5.906583 0.010000 0.369161 +v -5.906583 0.010000 0.092290 +v -5.906583 0.010000 0.646033 +v -5.906583 0.010000 0.553742 +v -5.906583 0.010000 0.461452 +v -5.906583 0.009999 2.491840 +v -5.906583 0.009999 2.399549 +v -5.906583 0.009999 2.584130 +v -5.906583 0.009999 2.307259 +v -5.906583 0.009999 2.214968 +v -5.906583 0.009999 2.861001 +v -5.906583 0.009999 2.768711 +v -5.906583 0.009999 2.676420 +v -5.906583 0.009999 1.753517 +v -5.906583 0.009999 1.661226 +v -5.906583 0.009999 1.845807 +v -5.906583 0.009999 1.568936 +v -5.906583 0.009999 2.122678 +v -5.906583 0.009999 2.030388 +v -5.906583 0.009999 1.938097 +v 3.876195 0.009998 5.906583 +v 3.968485 0.009998 5.906583 +v 4.060776 0.009998 5.906583 +v 3.691614 0.009998 5.906583 +v 3.783905 0.009998 5.906583 +v 4.245357 0.009998 5.906583 +v 4.337647 0.009998 5.906583 +v 4.429937 0.009998 5.906583 +v 4.153066 0.009998 5.906583 +v 3.137872 0.009998 5.906583 +v 3.230163 0.009998 5.906583 +v 3.322453 0.009998 5.906583 +v 2.953291 0.009998 5.906583 +v 3.045582 0.009998 5.906583 +v 3.507033 0.009998 5.906583 +v 3.599324 0.009998 5.906583 +v 3.414743 0.009998 5.906583 +v 5.352840 0.009998 5.906583 +v 5.445131 0.009998 5.906583 +v 5.537421 0.009998 5.906583 +v 5.168260 0.009998 5.906583 +v 5.260550 0.009998 5.906583 +v 5.722002 0.009998 5.906583 +v 5.814293 0.009998 5.906583 +v 5.906583 0.009998 5.906583 +v 5.629711 0.009998 5.906583 +v 4.614518 0.009998 5.906583 +v 4.706808 0.009998 5.906583 +v 4.799098 0.009998 5.906583 +v 4.522227 0.009998 5.906583 +v 4.983679 0.009998 5.906583 +v 5.075970 0.009998 5.906583 +v 4.891389 0.009998 5.906583 +v 0.922904 0.009998 5.906583 +v 1.015194 0.009998 5.906583 +v 1.107484 0.009998 5.906583 +v 0.738323 0.009998 5.906583 +v 0.830613 0.009998 5.906583 +v 1.292065 0.009998 5.906583 +v 1.384355 0.009998 5.906583 +v 1.476646 0.009998 5.906583 +v 1.199775 0.009998 5.906583 +v 0.184581 0.009998 5.906583 +v 0.276871 0.009998 5.906583 +v 0.369161 0.009998 5.906583 +v 0.092290 0.009998 5.906583 +v 0.553742 0.009998 5.906583 +v 0.646033 0.009998 5.906583 +v 0.461452 0.009998 5.906583 +v 2.399549 0.009998 5.906583 +v 2.491840 0.009998 5.906583 +v 2.584130 0.009998 5.906583 +v 2.214968 0.009998 5.906583 +v 2.307259 0.009998 5.906583 +v 2.768711 0.009998 5.906583 +v 2.861001 0.009998 5.906583 +v 2.676420 0.009998 5.906583 +v 1.661226 0.009998 5.906583 +v 1.753517 0.009998 5.906583 +v 1.845807 0.009998 5.906583 +v 1.568936 0.009998 5.906583 +v 2.030388 0.009998 5.906583 +v 2.122678 0.009998 5.906583 +v 1.938097 0.009998 5.906583 +v 5.906583 -1.989998 -5.906583 +v -5.906583 -1.989998 -5.906583 +v 5.906583 -1.990002 5.906582 +v -5.906583 -1.990002 5.906582 +v 5.906583 0.010002 -5.906583 +v -5.906583 0.010002 -5.906583 +v 5.906583 0.009998 5.906583 +v -5.906583 0.009998 5.906583 +vt 0.0000 0.0000 +vt 0.0000 0.0000 +vt 0.0000 0.0000 +vt 0.0000 0.0000 +vt 793.9620 -385.0559 +vt 819.5174 -385.0559 +vt 819.5174 386.1091 +vt 793.9620 386.1091 +vt -1560.1830 -385.0559 +vt -1535.4172 -385.0559 +vt -1535.4172 386.1091 +vt -1560.1904 386.1091 +vt -23.5456 -385.0559 +vt 2.0099 -385.0559 +vt 2.0099 386.1091 +vt -23.5456 386.1091 +vt -2453.5078 -385.0559 +vt -2479.0557 -385.0559 +vt -2479.0557 386.1091 +vt -2453.5078 386.1091 +vt -2734.5286 -385.0559 +vt -2760.0693 -385.0559 +vt -2760.0693 386.1091 +vt -2734.5286 386.1091 +vt 2326.7847 -385.0559 +vt 2352.3401 -385.0559 +vt 2352.3254 386.1091 +vt 2326.7847 386.1091 +vt 198.7351 -385.0559 +vt 173.9544 -385.0559 +vt 173.9544 386.1091 +vt 198.7351 386.1091 +vt 1356.0040 -385.0559 +vt 1381.5447 -385.0559 +vt 1381.5447 386.1091 +vt 1356.0040 386.1091 +vt -384.1984 -385.0559 +vt -409.7538 -385.0559 +vt -409.7538 386.1091 +vt -384.1984 386.1091 +vt 283.0309 -385.0559 +vt 308.5715 -385.0559 +vt 308.5715 386.1091 +vt 283.0309 386.1091 +vt -2249.1309 -385.0559 +vt -2274.6787 -385.0559 +vt -2274.6787 386.1091 +vt -2249.1309 386.1091 +vt -2989.9941 -385.0559 +vt -3015.5422 -385.0559 +vt -3015.5498 386.1091 +vt -2989.9941 386.1091 +vt 248.2814 -385.0559 +vt 223.5008 -385.0559 +vt 223.5008 386.1091 +vt 248.2665 386.1091 +vt -2922.6560 -385.0559 +vt -2897.8901 -385.0559 +vt -2897.8755 386.1091 +vt -2922.6560 386.1091 +vt -1176.1653 -385.0559 +vt -1201.7058 -385.0559 +vt -1201.7058 386.1091 +vt -1176.1653 386.1091 +vt 461.8598 -385.0559 +vt 487.4004 -385.0559 +vt 487.4004 386.1091 +vt 461.8598 386.1091 +vt 273.0471 -385.0559 +vt 273.0471 386.1091 +vt -2938.9128 -385.0559 +vt -2964.4539 -385.0559 +vt -2964.4539 386.1091 +vt -2938.9128 386.1091 +vt 870.6136 -385.0559 +vt 896.1542 -385.0559 +vt 896.1542 386.1091 +vt 870.6136 386.1091 +vt -1380.5347 -385.0559 +vt -1406.0826 -385.0559 +vt -1406.0826 386.1091 +vt -1380.5347 386.1091 +vt 666.2292 -385.0559 +vt 691.7698 -385.0559 +vt 691.7698 386.1091 +vt 666.2292 386.1091 +vt 2849.3538 -385.0559 +vt 2824.5730 -385.0559 +vt 2824.5730 386.1091 +vt 2849.3538 386.1091 +vt -2253.8098 -385.0559 +vt -2229.0366 -385.0559 +vt -2229.0366 386.1091 +vt -2253.8098 386.1091 +vt -569.3005 -385.0559 +vt -544.5349 -385.0559 +vt -544.5349 386.1091 +vt -569.3005 386.1091 +vt -1907.0000 -385.0559 +vt -1882.2269 -385.0559 +vt -1882.2269 386.1091 +vt -1907.0000 386.1091 +vt -435.2944 -385.0559 +vt -460.8499 -385.0559 +vt -460.8499 386.1091 +vt -435.2944 386.1091 +vt 3093.1963 -385.0559 +vt 3118.7366 -385.0559 +vt 3118.7366 386.1091 +vt 3093.1963 386.1091 +vt -1510.6442 -385.0559 +vt -1510.6442 386.1091 +vt 1509.2773 -385.0559 +vt 1534.8328 -385.0559 +vt 1534.8328 386.1091 +vt 1509.2773 386.1091 +vt 3195.3882 -385.0559 +vt 3220.9290 -385.0559 +vt 3220.9290 386.1091 +vt 3195.3882 386.1091 +vt 2279.5930 -385.0559 +vt 2254.8123 -385.0559 +vt 2254.8123 386.1091 +vt 2279.5930 386.1091 +vt 1662.5656 -385.0559 +vt 1688.1061 -385.0559 +vt 1688.1061 386.1091 +vt 1662.5656 386.1091 +vt -1227.2465 -385.0559 +vt -1252.8019 -385.0559 +vt -1252.8019 386.1091 +vt -1227.2614 386.1091 +vt 2626.4023 -385.0559 +vt 2601.6218 -385.0559 +vt 2601.6218 386.1091 +vt 2626.4023 386.1091 +vt -895.1442 -385.0559 +vt -920.6848 -385.0559 +vt -920.6848 386.1091 +vt -895.1442 386.1091 +vt 2130.9536 -385.0559 +vt 2106.1880 -385.0559 +vt 2106.1880 386.1091 +vt 2130.9536 386.1091 +vt -3168.8381 -385.0559 +vt -3194.3784 -385.0559 +vt -3194.3784 386.1091 +vt -3168.8306 386.1091 +vt -2823.5632 -385.0559 +vt -2798.7974 -385.0559 +vt -2798.7974 386.1091 +vt -2823.5632 386.1091 +vt 257.4754 -385.0559 +vt 257.4754 386.1091 +vt -2095.8501 -385.0559 +vt -2121.3979 -385.0559 +vt -2121.3979 386.1091 +vt -2095.8501 386.1091 +vt -1840.3844 -385.0559 +vt -1865.9250 -385.0559 +vt -1865.9324 386.1091 +vt -1840.3844 386.1091 +vt 1734.5978 -385.0559 +vt 1709.8320 -385.0559 +vt 1709.8320 386.1091 +vt 1734.5978 386.1091 +vt -2377.6682 -385.0559 +vt -2352.8950 -385.0559 +vt -2352.8950 386.1091 +vt -2377.6682 386.1091 +vt -2328.1221 -385.0559 +vt -2328.1221 386.1091 +vt 2874.1191 -385.0559 +vt 2874.1191 386.1091 +vt -2657.8848 -385.0559 +vt -2683.4326 -385.0559 +vt -2683.4326 386.1091 +vt -2657.8848 386.1091 +vt 2576.8560 -385.0559 +vt 2552.0903 -385.0559 +vt 2552.0903 386.1091 +vt 2576.8560 386.1091 +vt 2837.7307 -385.0559 +vt 2863.2712 -385.0559 +vt 2863.2712 386.1091 +vt 2837.7307 386.1091 +vt -256.4656 -385.0559 +vt -282.0211 -385.0559 +vt -282.0211 386.1091 +vt -256.4656 386.1091 +vt 1660.2858 -385.0559 +vt 1635.5200 -385.0559 +vt 1635.5200 386.1091 +vt 1660.2858 386.1091 +vt -1238.1542 -385.0559 +vt -1213.3734 -385.0559 +vt -1213.3734 386.1091 +vt -1238.1542 386.1091 +vt 1253.8119 -385.0559 +vt 1279.3524 -385.0559 +vt 1279.3524 386.1091 +vt 1253.8119 386.1091 +vt 512.9410 -385.0559 +vt 538.4965 -385.0559 +vt 538.4965 386.1091 +vt 512.9410 386.1091 +vt 947.2502 -385.0559 +vt 972.7908 -385.0559 +vt 972.7908 386.1091 +vt 947.2502 386.1091 +vt -3117.7419 -385.0559 +vt -3143.2825 -385.0559 +vt -3143.2825 386.1091 +vt -3117.7419 386.1091 +vt 1511.6465 -385.0559 +vt 1486.8809 -385.0559 +vt 1486.8809 386.1091 +vt 1511.6465 386.1091 +vt 2965.4636 -385.0559 +vt 2991.0039 -385.0559 +vt 2991.0039 386.1091 +vt 2965.4636 386.1091 +vt 2096.8599 -385.0559 +vt 2122.4155 -385.0559 +vt 2122.4155 386.1091 +vt 2096.8599 386.1091 +vt 564.0370 -385.0559 +vt 564.0370 386.1091 +vt -1993.6652 -385.0559 +vt -2019.2131 -385.0559 +vt -2019.2131 386.1091 +vt -1993.6652 386.1091 +vt -2204.2634 -385.0559 +vt -2204.2634 386.1091 +vt -2811.1655 -385.0559 +vt -2836.7134 -385.0559 +vt -2836.7134 386.1091 +vt -2811.1655 386.1091 +vt 1304.9078 -385.0559 +vt 1304.9078 386.1091 +vt 793.2615 -385.0559 +vt 768.4958 -385.0559 +vt 768.4811 386.1091 +vt 793.2615 386.1091 +vt -767.4115 -385.0559 +vt -792.9521 -385.0559 +vt -792.9521 386.1091 +vt -767.4115 386.1091 +vt 24.5554 -385.0559 +vt -1.0001 -385.0559 +vt -1.0001 386.1091 +vt 24.5554 386.1091 +vt 2275.6885 -385.0559 +vt 2301.2441 -385.0559 +vt 2301.2441 386.1091 +vt 2275.6885 386.1091 +vt -2172.4941 -385.0559 +vt -2198.0422 -385.0559 +vt -2198.0422 386.1091 +vt -2172.4941 386.1091 +vt 2454.5176 -385.0559 +vt 2480.0730 -385.0559 +vt 2480.0730 386.1091 +vt 2454.5176 386.1091 +vt 446.4520 -385.0559 +vt 421.6862 -385.0559 +vt 421.6713 386.1091 +vt 446.4520 386.1091 +vt 1462.1151 -385.0559 +vt 1462.1151 386.1091 +vt -841.7981 -385.0559 +vt -817.0174 -385.0559 +vt -817.0174 386.1091 +vt -841.7981 386.1091 +vt 1713.6617 -385.0559 +vt 1713.6617 386.1091 +vt -792.2518 -385.0559 +vt -792.2518 386.1091 +vt -2376.8711 -385.0559 +vt -2402.4192 -385.0559 +vt -2402.4192 386.1091 +vt -2376.8711 386.1091 +vt -1981.3123 -385.0559 +vt -1956.5391 -385.0559 +vt -1956.5391 386.1091 +vt -1981.3123 386.1091 +vt -1125.0691 -385.0559 +vt -1150.6099 -385.0559 +vt -1150.6099 386.1091 +vt -1125.0691 386.1091 +vt -1968.1172 -385.0559 +vt -1968.1172 386.1091 +vt 1866.9351 -385.0559 +vt 1892.4905 -385.0559 +vt 1892.4905 386.1091 +vt 1866.9351 386.1091 +vt 1330.4484 -385.0559 +vt 1330.4484 386.1091 +vt -179.8289 -385.0559 +vt -205.3695 -385.0559 +vt -205.3695 386.1091 +vt -179.8289 386.1091 +vt -26.5407 -385.0559 +vt -52.0962 -385.0559 +vt -52.0962 386.1091 +vt -26.5407 386.1091 +vt 644.6226 -385.0559 +vt 619.8568 -385.0559 +vt 619.8568 386.1091 +vt 644.6226 386.1091 +vt -767.4711 -385.0559 +vt -767.4711 386.1091 +vt -77.6368 -385.0559 +vt -77.6368 386.1091 +vt -1814.8364 -385.0559 +vt -1814.8364 386.1091 +vt 1412.5688 -385.0559 +vt 1387.7881 -385.0559 +vt 1387.7881 386.1091 +vt 1412.5688 386.1091 +vt 2007.0953 -385.0559 +vt 1982.3296 -385.0559 +vt 1982.3296 386.1091 +vt 2007.0953 386.1091 +vt 2020.2231 -385.0559 +vt 2045.7640 -385.0559 +vt 2045.7640 386.1091 +vt 2020.2231 386.1091 +vt -1278.3499 -385.0559 +vt -1303.8981 -385.0559 +vt -1303.8981 386.1091 +vt -1278.3499 386.1091 +vt -1659.2758 -385.0559 +vt -1634.5026 -385.0559 +vt -1634.5026 386.1091 +vt -1659.2758 386.1091 +vt 180.8388 -385.0559 +vt 206.3794 -385.0559 +vt 206.3794 386.1091 +vt 180.8388 386.1091 +vt 396.9056 -385.0559 +vt 372.1399 -385.0559 +vt 372.1399 386.1091 +vt 396.9056 386.1091 +vt -321.5837 -385.0559 +vt -296.8030 -385.0559 +vt -296.8030 386.1091 +vt -321.5837 386.1091 +vt 1126.0791 -385.0559 +vt 1151.6198 -385.0559 +vt 1151.6198 386.1091 +vt 1126.0791 386.1091 +vt -2300.2271 -385.0559 +vt -2300.2271 386.1091 +vt 1338.2418 -385.0559 +vt 1313.4761 -385.0559 +vt 1313.4761 386.1091 +vt 1338.2418 386.1091 +vt 589.5926 -385.0559 +vt 615.1331 -385.0559 +vt 615.1331 386.1091 +vt 589.5926 386.1091 +vt 2651.1682 -385.0559 +vt 2651.1682 386.1091 +vt -2785.6248 -385.0559 +vt -2785.6248 386.1091 +vt 818.0273 -385.0559 +vt 818.0273 386.1091 +vt 231.9348 -385.0559 +vt 231.9348 386.1091 +vt -1099.5138 -385.0559 +vt -1099.5138 386.1091 +vt 2700.7146 -385.0559 +vt 2675.9487 -385.0559 +vt 2675.9487 386.1091 +vt 2700.7146 386.1091 +vt -717.9396 -385.0559 +vt -693.1589 -385.0559 +vt -693.1589 386.1091 +vt -717.9396 386.1091 +vt -2551.0732 -385.0559 +vt -2526.3000 -385.0559 +vt -2526.3000 386.1091 +vt -2551.0732 386.1091 +vt 1685.0515 -385.0559 +vt 1685.0515 386.1091 +vt -2451.9805 -385.0559 +vt -2427.2146 -385.0559 +vt -2427.2146 386.1091 +vt -2451.9878 386.1091 +vt -668.3933 -385.0559 +vt -668.3933 386.1091 +vt 1407.1000 -385.0559 +vt 1432.6406 -385.0559 +vt 1432.6406 386.1091 +vt 1407.1000 386.1091 +vt -2278.5754 -385.0559 +vt -2278.5833 386.1091 +vt 2230.0464 -385.0559 +vt 2205.2659 -385.0559 +vt 2205.2659 386.1091 +vt 2230.0464 386.1091 +vt -2351.3230 -385.0559 +vt -2351.3230 386.1091 +vt -371.1300 -385.0559 +vt -346.3494 -385.0559 +vt -346.3494 386.1091 +vt -371.1300 386.1091 +vt -358.6578 -385.0559 +vt -358.6578 386.1091 +vt -997.3364 -385.0559 +vt -1022.8770 -385.0559 +vt -1022.8770 386.1091 +vt -997.3364 386.1091 +vt 1239.1639 -385.0559 +vt 1214.3834 -385.0559 +vt 1214.3834 386.1091 +vt 1239.1639 386.1091 +vt -1917.0212 -385.0559 +vt -1942.5692 -385.0559 +vt -1942.5692 386.1091 +vt -1917.0212 386.1091 +vt -2774.0244 -385.0559 +vt -2774.0244 386.1091 +vt -1431.6309 -385.0559 +vt -1431.6309 386.1091 +vt 768.4214 -385.0559 +vt 768.4214 386.1091 +vt 2527.3098 -385.0559 +vt 2527.3098 386.1091 +vt -2632.3367 -385.0559 +vt -2632.3367 386.1091 +vt 2147.9558 -385.0559 +vt 2173.5115 -385.0559 +vt 2173.4966 386.1091 +vt 2147.9558 386.1091 +vt -618.8469 -385.0559 +vt -594.0663 -385.0559 +vt -594.0663 386.1091 +vt -618.8469 386.1091 +vt -1609.7295 -385.0559 +vt -1609.7295 386.1091 +vt -2996.9678 -385.0559 +vt -2972.2024 -385.0559 +vt -2972.2024 386.1091 +vt -2996.9678 386.1091 +vt 3042.1001 -385.0559 +vt 3067.6555 -385.0559 +vt 3067.6555 386.1091 +vt 3042.1001 386.1091 +vt -946.2403 -385.0559 +vt -971.7810 -385.0559 +vt -971.7810 386.1091 +vt -946.2403 386.1091 +vt -2600.6194 -385.0559 +vt -2575.8462 -385.0559 +vt -2575.8462 386.1091 +vt -2600.6194 386.1091 +vt -2749.2510 -385.0559 +vt -2749.2510 386.1091 +vt -1329.4386 -385.0559 +vt -1354.9867 -385.0559 +vt -1354.9867 386.1091 +vt -1329.4386 386.1091 +vt -307.5617 -385.0559 +vt -333.1023 -385.0559 +vt -333.1023 386.1091 +vt -307.5617 386.1091 +vt 1560.3733 -385.0559 +vt 1585.9290 -385.0559 +vt 1585.9290 386.1091 +vt 1560.3733 386.1091 +vt -2055.6318 -385.0559 +vt -2030.8585 -385.0559 +vt -2030.8585 386.1091 +vt -2055.6318 386.1091 +vt 1074.9829 -385.0559 +vt 1100.5236 -385.0559 +vt 1100.5236 386.1091 +vt 1074.9829 386.1091 +vt -1891.4730 -385.0559 +vt -1891.4730 386.1091 +vt -3021.7412 -385.0559 +vt -3021.7412 386.1091 +vt -1857.4537 -385.0559 +vt -1857.4537 386.1091 +vt 2786.6345 -385.0559 +vt 2812.1753 -385.0559 +vt 2812.1753 386.1091 +vt 2786.6345 386.1091 +vt -1508.2673 -385.0559 +vt -1533.8153 -385.0559 +vt -1533.8153 386.1091 +vt -1508.2673 386.1091 +vt 27.5505 -385.0559 +vt 27.5505 386.1091 +vt -272.0373 -385.0559 +vt -272.0373 386.1091 +vt 845.0580 -385.0559 +vt 845.0580 386.1091 +vt 1611.4695 -385.0559 +vt 1637.0101 -385.0559 +vt 1637.0101 386.1091 +vt 1611.4695 386.1091 +vt -2501.5266 -385.0559 +vt -2501.5266 386.1091 +vt -1411.5514 -385.0559 +vt -1386.7783 -385.0559 +vt -1386.7858 386.1091 +vt -1411.5514 386.1091 +vt 2888.8267 -385.0559 +vt 2914.3674 -385.0559 +vt 2914.3674 386.1091 +vt 2888.8267 386.1091 +vt -2080.4050 -385.0559 +vt -2080.4050 386.1091 +vt -197.7252 -385.0559 +vt -172.9446 -385.0559 +vt -172.9446 386.1091 +vt -197.7252 386.1091 +vt 1536.4272 -385.0559 +vt 1536.4272 386.1091 +vt -1636.0076 -385.0559 +vt -1661.5558 -385.0559 +vt -1661.5558 386.1091 +vt -1636.0076 386.1091 +vt 1957.5490 -385.0559 +vt 1957.5490 386.1091 +vt 1065.7592 -385.0559 +vt 1040.9785 -385.0559 +vt 1040.9785 386.1091 +vt 1065.7592 386.1091 +vt 1228.2712 -385.0559 +vt 1228.2712 386.1091 +vt 2452.9976 -385.0559 +vt 2428.2168 -385.0559 +vt 2428.2168 386.1091 +vt 2452.9976 386.1091 +vt 1739.2023 -385.0559 +vt 1739.2023 386.1091 +vt 640.6887 -385.0559 +vt 640.6887 386.1091 +vt -1610.4595 -385.0559 +vt -1610.4595 386.1091 +vt 991.4323 -385.0559 +vt 966.6665 -385.0559 +vt 966.6665 386.1091 +vt 991.4323 386.1091 +vt 941.9008 -385.0559 +vt 917.1200 -385.0559 +vt 917.1200 386.1091 +vt 941.9008 386.1091 +vt 3169.8328 -385.0559 +vt 3169.8328 386.1091 +vt -103.1923 -385.0559 +vt -103.1923 386.1091 +vt -2708.9807 -385.0559 +vt -2708.9807 386.1091 +vt -49.0862 -385.0559 +vt -49.0862 386.1091 +vt 1883.2369 -385.0559 +vt 1858.4712 -385.0559 +vt 1858.4562 386.1091 +vt 1883.2369 386.1091 +vt -2044.7614 -385.0559 +vt -2070.3020 -385.0559 +vt -2070.3020 386.1091 +vt -2044.7614 386.1091 +vt -2650.1584 -385.0559 +vt -2625.3926 -385.0559 +vt -2625.3926 386.1091 +vt -2650.1584 386.1091 +vt -148.1789 -385.0559 +vt -148.1789 386.1091 +vt -3219.9192 -385.0559 +vt -3195.1384 -385.0559 +vt -3195.1384 386.1091 +vt -3219.9192 386.1091 +vt -1188.6077 -385.0559 +vt -1188.6077 386.1091 +vt 1288.7104 -385.0559 +vt 1263.9297 -385.0559 +vt 1263.9297 386.1091 +vt 1288.7104 386.1091 +vt 2761.0791 -385.0559 +vt 2761.0791 386.1091 +vt 1140.0712 -385.0559 +vt 1115.3054 -385.0559 +vt 1115.3054 386.1091 +vt 1140.0712 386.1091 +vt 1994.6678 -385.0559 +vt 1994.6678 386.1091 +vt -2303.3486 -385.0559 +vt -2303.3486 386.1091 +vt -247.2567 -385.0559 +vt -247.2567 386.1091 +vt 347.3593 -385.0559 +vt 347.3593 386.1091 +vt -1312.4661 -385.0559 +vt -1287.6930 -385.0559 +vt -1287.6930 386.1091 +vt -1312.4661 386.1091 +vt -1064.7491 -385.0559 +vt -1039.9688 -385.0559 +vt -1039.9688 386.1091 +vt -1064.7491 386.1091 +vt 3097.0706 -385.0559 +vt 3072.3047 -385.0559 +vt 3072.3047 386.1091 +vt 3097.0706 386.1091 +vt -2581.2478 -385.0559 +vt -2606.7959 -385.0559 +vt -2606.7959 386.1091 +vt -2581.2478 386.1091 +vt -1584.9562 -385.0559 +vt -1584.9562 386.1091 +vt 1363.0223 -385.0559 +vt 1363.0223 386.1091 +vt -1073.9730 -385.0559 +vt -1073.9730 386.1091 +vt 2031.8761 -385.0559 +vt 2031.8611 386.1091 +vt -1262.9199 -385.0559 +vt -1262.9199 386.1091 +vt -2325.7749 -385.0559 +vt -2325.7749 386.1091 +vt -2402.4417 -385.0559 +vt -2402.4417 386.1091 +vt 2224.5925 -385.0559 +vt 2250.1482 -385.0559 +vt 2250.1482 386.1091 +vt 2224.5925 386.1091 +vt 1016.2127 -385.0559 +vt 1016.2127 386.1091 +vt -1362.0126 -385.0559 +vt -1362.0126 386.1091 +vt -1708.8223 -385.0559 +vt -1684.0488 -385.0559 +vt -1684.0488 386.1091 +vt -1708.8223 386.1091 +vt -2504.6040 -385.0559 +vt -2504.6040 386.1091 +vt -1485.8711 -385.0559 +vt -1485.8711 386.1091 +vt 2378.6853 -385.0559 +vt 2353.9048 -385.0559 +vt 2353.9048 386.1091 +vt 2378.6707 386.1091 +vt -818.5075 -385.0559 +vt -844.0482 -385.0559 +vt -844.0482 386.1091 +vt -818.5075 386.1091 +vt -1337.2393 -385.0559 +vt -1337.2393 386.1091 +vt -1163.8271 -385.0559 +vt -1163.8271 386.1091 +vt 2071.3193 -385.0559 +vt 2071.3193 386.1091 +vt 1943.5867 -385.0559 +vt 1969.1272 -385.0559 +vt 1969.1272 386.1091 +vt 1943.5867 386.1091 +vt 2329.1392 -385.0559 +vt 2304.3584 -385.0559 +vt 2304.3584 386.1091 +vt 2329.1392 386.1091 +vt 2997.9775 -385.0559 +vt 2973.2122 -385.0559 +vt 2973.2122 386.1091 +vt 2997.9775 386.1091 +vt 570.3104 -385.0559 +vt 545.5448 -385.0559 +vt 545.5448 386.1091 +vt 570.3104 386.1091 +vt -869.5887 -385.0559 +vt -869.5887 386.1091 +vt 3220.9290 -385.0559 +vt 3196.1631 -385.0559 +vt 3196.1631 386.1091 +vt 3220.9290 386.1091 +vt 1090.5249 -385.0559 +vt 1090.5249 386.1091 +vt -1089.5149 -385.0559 +vt -1089.5149 386.1091 +vt 1808.9247 -385.0559 +vt 1784.1442 -385.0559 +vt 1784.1442 386.1091 +vt 1808.9247 386.1091 +vt 1023.8870 -385.0559 +vt 1049.4424 -385.0559 +vt 1049.4424 386.1091 +vt 1023.8870 386.1091 +vt 2948.4314 -385.0559 +vt 2923.6658 -385.0559 +vt 2923.6658 386.1091 +vt 2948.4314 386.1091 +vt -2223.5906 -385.0559 +vt -2223.5906 386.1091 +vt 2377.8809 -385.0559 +vt 2377.8809 386.1091 +vt -1931.7657 -385.0559 +vt -1931.7657 386.1091 +vt -519.7542 -385.0559 +vt -494.9885 -385.0559 +vt -494.9885 386.1091 +vt -519.7542 386.1091 +vt -1461.0977 -385.0559 +vt -1461.0977 386.1091 +vt 53.1060 -385.0559 +vt 78.6466 -385.0559 +vt 78.6466 386.1091 +vt 53.1060 386.1091 +vt 2505.6138 -385.0559 +vt 2505.6138 386.1091 +vt 1815.8389 -385.0559 +vt 1841.3944 -385.0559 +vt 1841.3944 386.1091 +vt 1815.8389 386.1091 +vt 2403.4214 -385.0559 +vt 2403.4214 386.1091 +vt -470.2079 -385.0559 +vt -470.2079 386.1091 +vt -2873.1094 -385.0559 +vt -2873.1094 386.1091 +vt 471.2177 -385.0559 +vt 471.2177 386.1091 +vt -2129.9438 -385.0559 +vt -2105.1709 -385.0559 +vt -2105.1709 386.1091 +vt -2129.9438 386.1091 +vt 595.0911 -385.0559 +vt 595.0911 386.1091 +vt 3022.7583 -385.0559 +vt 3022.7583 386.1091 +vt 2155.7344 -385.0559 +vt 2155.7344 386.1091 +vt 2939.9080 -385.0559 +vt 2939.9080 386.1091 +vt -742.7054 -385.0559 +vt -742.7054 386.1091 +vt -1832.6807 -385.0559 +vt -1807.9073 -385.0559 +vt -1807.9073 386.1091 +vt -1832.6807 386.1091 +vt -2476.7537 -385.0559 +vt -2476.7537 386.1091 +vt -128.7328 -385.0559 +vt -154.2735 -385.0559 +vt -154.2735 386.1091 +vt -128.7328 386.1091 +vt 1189.6177 -385.0559 +vt 1189.6177 386.1091 +vt -486.3905 -385.0559 +vt -511.9312 -385.0559 +vt -511.9312 386.1091 +vt -486.3905 386.1091 +vt -2427.9597 -385.0559 +vt -2427.9597 386.1091 +vt 998.3464 -385.0559 +vt 998.3464 386.1091 +vt -639.6788 -385.0559 +vt -665.2194 -385.0559 +vt -665.2194 386.1091 +vt -639.6788 386.1091 +vt 1790.2982 -385.0559 +vt 1790.2982 386.1091 +vt -643.6127 -385.0559 +vt -643.6127 386.1091 +vt 2477.7634 -385.0559 +vt 2477.7634 386.1091 +vt 3016.5596 -385.0559 +vt 3016.5596 386.1091 +vt -2530.1519 -385.0559 +vt -2555.7000 -385.0559 +vt -2555.7000 386.1091 +vt -2530.1519 386.1091 +vt -3041.0903 -385.0559 +vt -3041.0903 386.1091 +vt -1789.2885 -385.0559 +vt -1789.2885 386.1091 +vt -614.1232 -385.0559 +vt -614.1232 386.1091 +vt -2146.9460 -385.0559 +vt -2146.9460 386.1091 +vt 2799.8071 -385.0559 +vt 2799.8071 386.1091 +vt 743.7153 -385.0559 +vt 743.7153 386.1091 +vt -3071.2800 -385.0559 +vt -3046.5144 -385.0559 +vt -3046.5144 386.1091 +vt -3071.2800 386.1091 +vt 1458.1812 -385.0559 +vt 1483.7368 -385.0559 +vt 1483.7368 386.1091 +vt 1458.1812 386.1091 +vt -230.9250 -385.0559 +vt -230.9250 386.1091 +vt -98.6325 -385.0559 +vt -73.8519 -385.0559 +vt -73.8519 386.1091 +vt -98.6325 386.1091 +vt 359.6676 -385.0559 +vt 385.2082 -385.0559 +vt 385.2082 386.1091 +vt 359.6676 386.1091 +vt -940.8759 -385.0559 +vt -916.1102 -385.0559 +vt -916.1102 386.1091 +vt -940.8908 386.1091 +vt -891.3444 -385.0559 +vt -891.3444 386.1091 +vt -2179.4902 -385.0559 +vt -2179.4902 386.1091 +vt 3171.3826 -385.0559 +vt 3146.6169 -385.0559 +vt 3146.6169 386.1091 +vt 3171.3826 386.1091 +vt 717.3254 -385.0559 +vt 742.8658 -385.0559 +vt 742.8658 386.1091 +vt 717.3254 386.1091 +vt 410.7637 -385.0559 +vt 410.7637 386.1091 +vt 1759.3784 -385.0559 +vt 1759.3784 386.1091 +vt 2735.5383 -385.0559 +vt 2735.5383 386.1091 +vt 694.1688 -385.0559 +vt 669.4033 -385.0559 +vt 669.4033 386.1091 +vt 694.1688 386.1091 +vt 3047.5242 -385.0559 +vt 3047.5242 386.1091 +vt 1177.1750 -385.0559 +vt 1177.1750 386.1091 +vt 892.3543 -385.0559 +vt 892.3543 386.1091 +vt -2848.3364 -385.0559 +vt -2848.3364 386.1091 +vt 2180.5000 -385.0559 +vt 2180.5000 386.1091 +vt -2674.9316 -385.0559 +vt -2674.9316 386.1091 +vt 1437.3346 -385.0559 +vt 1437.3346 386.1091 +vt -1738.1923 -385.0559 +vt -1763.7402 -385.0559 +vt -1763.7402 386.1091 +vt -1738.1923 386.1091 +vt -2154.7170 -385.0559 +vt -2154.7170 386.1091 +vt -222.4910 -385.0559 +vt -222.4910 386.1091 +vt 520.7641 -385.0559 +vt 495.9983 -385.0559 +vt 495.9983 386.1091 +vt 520.7641 386.1091 +vt -123.3982 -385.0559 +vt -123.3982 386.1091 +vt 1561.1930 -385.0559 +vt 1561.1930 386.1091 +vt -1783.1342 -385.0559 +vt -1758.3611 -385.0559 +vt -1758.3611 386.1091 +vt -1783.1342 386.1091 +vt 2725.4954 -385.0559 +vt 2725.4954 386.1091 +vt -2947.4290 -385.0559 +vt -2947.4290 386.1091 +vt 334.1121 -385.0559 +vt 334.1121 386.1091 +vt -1436.3246 -385.0559 +vt -1436.3246 386.1091 +vt 1932.7832 -385.0559 +vt 1932.7832 386.1091 +vt 322.5935 -385.0559 +vt 297.8129 -385.0559 +vt 297.8129 386.1091 +vt 322.5935 386.1091 +vt 1202.7157 -385.0559 +vt 1202.7157 386.1091 +vt 2199.0520 -385.0559 +vt 2199.0520 386.1091 +vt 2403.4514 -385.0559 +vt 2403.4514 386.1091 +vt -690.7599 -385.0559 +vt -716.3155 -385.0559 +vt -716.3155 386.1091 +vt -690.7599 386.1091 +vt 149.1887 -385.0559 +vt 124.4081 -385.0559 +vt 124.4081 386.1091 +vt 149.1887 386.1091 +vt 1764.7577 -385.0559 +vt 1764.7577 386.1091 +vt 867.5738 -385.0559 +vt 867.5738 386.1091 +vt 104.2021 -385.0559 +vt 129.7427 -385.0559 +vt 129.7427 386.1091 +vt 104.2021 386.1091 +vt 1908.0027 -385.0559 +vt 1908.0027 386.1091 +vt 1164.8369 -385.0559 +vt 1164.8369 386.1091 +vt -741.8560 -385.0559 +vt -741.8560 386.1091 +vt -1457.1788 -385.0559 +vt -1482.7268 -385.0559 +vt -1482.7268 386.1091 +vt -1457.1788 386.1091 +vt -445.4421 -385.0559 +vt -420.6615 -385.0559 +vt -420.6615 386.1091 +vt -445.4421 386.1091 +vt 2750.2607 -385.0559 +vt 2750.2607 386.1091 +vt 2556.7097 -385.0559 +vt 2582.2502 -385.0559 +vt 2582.2502 386.1091 +vt 2556.7097 386.1091 +vt -1048.4175 -385.0559 +vt -1048.4175 386.1091 +vt 1833.6904 -385.0559 +vt 1833.6904 386.1091 +vt 842.8080 -385.0559 +vt 842.8080 386.1091 +vt 2502.5439 -385.0559 +vt 2502.5439 386.1091 +vt 2531.1692 -385.0559 +vt 2531.1541 386.1091 +vt 2633.3464 -385.0559 +vt 2658.9019 -385.0559 +vt 2658.9019 386.1091 +vt 2633.3464 386.1091 +vt 2898.8999 -385.0559 +vt 2898.8999 386.1091 +vt 50.0960 -385.0559 +vt 50.0960 386.1091 +vt 99.6423 -385.0559 +vt 99.6423 386.1091 +vt 3121.8362 -385.0559 +vt 3121.8362 386.1091 +vt -1139.0613 -385.0559 +vt -1139.0613 386.1091 +vt -3066.6458 -385.0559 +vt -3092.1865 -385.0559 +vt -3092.1865 386.1091 +vt -3066.6458 386.1091 +vt 2775.0266 -385.0559 +vt 2775.0266 386.1091 +vt 2081.4075 -385.0559 +vt 2056.6416 -385.0559 +vt 2056.6416 386.1091 +vt 2081.4075 386.1091 +vt 2428.9768 -385.0559 +vt 2428.9768 386.1091 +vt -3219.9192 -385.0559 +vt -3219.9192 386.1091 +vt 2684.4424 -385.0559 +vt 2684.4424 386.1091 +vt -1114.2806 -385.0559 +vt -1114.2957 386.1091 +vt -1733.5879 -385.0559 +vt -1733.5953 386.1091 +vt 2709.9980 -385.0559 +vt 2709.9829 386.1091 +vt -3145.6072 -385.0559 +vt -3120.8340 -385.0559 +vt -3120.8340 386.1091 +vt -3145.6072 386.1091 +vt 1918.0310 -385.0559 +vt 1918.0310 386.1091 +vt -2724.4778 -385.0559 +vt -2699.7048 -385.0559 +vt -2699.7048 386.1091 +vt -2724.4778 386.1091 +vt 718.9495 -385.0559 +vt 718.9495 386.1091 +vt -1712.6443 -385.0559 +vt -1712.6443 386.1091 +vt -563.0272 -385.0559 +vt -588.5827 -385.0559 +vt -588.5827 386.1091 +vt -563.0272 386.1091 +vt -3170.3728 -385.0559 +vt -3170.3728 386.1091 +vt -3096.0608 -385.0559 +vt -3096.0608 386.1091 +vt 155.2833 -385.0559 +vt 155.2833 386.1091 +vt -2006.0853 -385.0559 +vt -2006.0853 386.1091 +vt 3144.2922 -385.0559 +vt 3144.2922 386.1091 +vt 1610.7393 -385.0559 +vt 1585.9735 -385.0559 +vt 1585.9735 386.1091 +vt 1610.7393 386.1091 +vt 2607.8057 -385.0559 +vt 2607.8057 386.1091 +vt -537.4866 -385.0559 +vt -537.4866 386.1091 +vt -2862.2615 -385.0559 +vt -2887.8096 -385.0559 +vt -2887.8096 386.1091 +vt -2862.2615 386.1091 +vt 74.8617 -385.0559 +vt 50.0960 -385.0559 +vt 50.0960 386.1091 +vt 74.8617 386.1091 +vt -1015.2028 -385.0559 +vt -990.4223 -385.0559 +vt -990.4223 386.1091 +vt -1015.2028 386.1091 +vt -965.6566 -385.0559 +vt -965.6566 386.1091 +vt -49.0862 -385.0559 +vt -49.0862 386.1091 +vt -1559.3635 -385.0559 +vt -1559.3635 386.1091 +vt -866.5638 -385.0559 +vt -866.5638 386.1091 +vt -2913.3577 -385.0559 +vt -2913.3577 386.1091 +vt -1687.0963 -385.0559 +vt -1687.0963 386.1091 +vt -395.8958 -385.0559 +vt -395.8958 386.1091 +vt 436.3043 -385.0559 +vt 436.3043 386.1091 +vt -1584.9115 -385.0559 +vt -1584.9115 386.1091 +vt 921.6948 -385.0559 +vt 921.6948 386.1091 +vt 0.9918 0.9921 +vt 0.9996 0.9921 +vt 0.9996 0.9999 +vt 0.9918 0.9999 +vt 0.4920 0.9919 +vt 0.4999 0.9919 +vt 0.4998 0.9997 +vt 0.4920 0.9997 +vt 0.4922 0.4922 +vt 0.5000 0.4922 +vt 0.5000 0.5000 +vt 0.4922 0.5000 +vt 0.9919 0.4923 +vt 0.9997 0.4923 +vt 0.9997 0.5001 +vt 0.9919 0.5001 +vt 0.7421 0.4923 +vt 0.7499 0.4923 +vt 0.7499 0.5001 +vt 0.7421 0.5001 +vt 0.7421 0.2424 +vt 0.7500 0.2424 +vt 0.7499 0.2502 +vt 0.7421 0.2502 +vt 0.9920 0.2425 +vt 0.9998 0.2425 +vt 0.9998 0.2503 +vt 0.9920 0.2503 +vt 0.2423 0.4921 +vt 0.2501 0.4921 +vt 0.2501 0.4999 +vt 0.2423 0.4999 +vt 0.2424 0.2422 +vt 0.2502 0.2422 +vt 0.2502 0.2500 +vt 0.2424 0.2500 +vt 0.4923 0.2423 +vt 0.5001 0.2423 +vt 0.5001 0.2501 +vt 0.4923 0.2501 +vt 0.2422 0.9918 +vt 0.2500 0.9918 +vt 0.2500 0.9997 +vt 0.2422 0.9996 +vt 0.2422 0.7420 +vt 0.2501 0.7420 +vt 0.2501 0.7498 +vt 0.2422 0.7498 +vt 0.4921 0.7420 +vt 0.4999 0.7420 +vt 0.4999 0.7499 +vt 0.4921 0.7499 +vt 0.7419 0.9920 +vt 0.7497 0.9920 +vt 0.7497 0.9998 +vt 0.7419 0.9998 +vt 0.7420 0.7421 +vt 0.7498 0.7421 +vt 0.7498 0.7499 +vt 0.7420 0.7499 +vt 0.9919 0.7422 +vt 0.9997 0.7422 +vt 0.9997 0.7500 +vt 0.9918 0.7500 +vt 0.8669 0.7422 +vt 0.8747 0.7422 +vt 0.8747 0.7500 +vt 0.8669 0.7500 +vt 0.8670 0.6172 +vt 0.8748 0.6172 +vt 0.8748 0.6250 +vt 0.8670 0.6250 +vt 0.9919 0.6173 +vt 0.9997 0.6173 +vt 0.9997 0.6251 +vt 0.9919 0.6251 +vt 0.6171 0.7421 +vt 0.6249 0.7421 +vt 0.6249 0.7499 +vt 0.6170 0.7499 +vt 0.6171 0.6171 +vt 0.6249 0.6172 +vt 0.6249 0.6250 +vt 0.6171 0.6250 +vt 0.7420 0.6172 +vt 0.7498 0.6172 +vt 0.7498 0.6250 +vt 0.7420 0.6250 +vt 0.6170 0.9919 +vt 0.6248 0.9920 +vt 0.6248 0.9998 +vt 0.6170 0.9998 +vt 0.6170 0.8670 +vt 0.6248 0.8670 +vt 0.6248 0.8748 +vt 0.6170 0.8748 +vt 0.7419 0.8671 +vt 0.7498 0.8671 +vt 0.7498 0.8749 +vt 0.7419 0.8749 +vt 0.3672 0.7420 +vt 0.3750 0.7420 +vt 0.3750 0.7498 +vt 0.3672 0.7498 +vt 0.3672 0.6171 +vt 0.3750 0.6171 +vt 0.3750 0.6249 +vt 0.3672 0.6249 +vt 0.4922 0.6171 +vt 0.5000 0.6171 +vt 0.5000 0.6249 +vt 0.4922 0.6249 +vt 0.1173 0.7419 +vt 0.1251 0.7419 +vt 0.1251 0.7497 +vt 0.1173 0.7497 +vt 0.1174 0.6170 +vt 0.1252 0.6170 +vt 0.1252 0.6248 +vt 0.1173 0.6248 +vt 0.2423 0.6170 +vt 0.2501 0.6170 +vt 0.2501 0.6248 +vt 0.2423 0.6248 +vt 0.1172 0.9918 +vt 0.1250 0.9918 +vt 0.1250 0.9996 +vt 0.1172 0.9996 +vt 0.1173 0.8669 +vt 0.1251 0.8669 +vt 0.1251 0.8747 +vt 0.1173 0.8747 +vt 0.2422 0.8669 +vt 0.2500 0.8669 +vt 0.2500 0.8747 +vt 0.2422 0.8747 +vt 0.3673 0.2423 +vt 0.3751 0.2423 +vt 0.3751 0.2501 +vt 0.3673 0.2501 +vt 0.3674 0.1173 +vt 0.3752 0.1173 +vt 0.3752 0.1251 +vt 0.3674 0.1251 +vt 0.4923 0.1174 +vt 0.5001 0.1174 +vt 0.5001 0.1252 +vt 0.4923 0.1252 +vt 0.1175 0.2422 +vt 0.1253 0.2422 +vt 0.1253 0.2500 +vt 0.1175 0.2500 +vt 0.1175 0.1173 +vt 0.1253 0.1173 +vt 0.1253 0.1251 +vt 0.1175 0.1251 +vt 0.2424 0.1173 +vt 0.2503 0.1173 +vt 0.2503 0.1251 +vt 0.2424 0.1251 +vt 0.1174 0.4921 +vt 0.1252 0.4921 +vt 0.1252 0.4999 +vt 0.1174 0.4999 +vt 0.1174 0.3671 +vt 0.1252 0.3671 +vt 0.1252 0.3749 +vt 0.1174 0.3749 +vt 0.2424 0.3672 +vt 0.2502 0.3672 +vt 0.2502 0.3750 +vt 0.2424 0.3750 +vt 0.8671 0.2424 +vt 0.8749 0.2424 +vt 0.8749 0.2502 +vt 0.8671 0.2502 +vt 0.8671 0.1175 +vt 0.8749 0.1175 +vt 0.8749 0.1253 +vt 0.8671 0.1253 +vt 0.9921 0.1175 +vt 0.9999 0.1175 +vt 0.9999 0.1253 +vt 0.9921 0.1253 +vt 0.6172 0.2423 +vt 0.6250 0.2423 +vt 0.6250 0.2502 +vt 0.6172 0.2502 +vt 0.6172 0.1174 +vt 0.6251 0.1174 +vt 0.6251 0.1252 +vt 0.6172 0.1252 +vt 0.7422 0.1174 +vt 0.7500 0.1175 +vt 0.7500 0.1253 +vt 0.7422 0.1253 +vt 0.6171 0.4922 +vt 0.6249 0.4922 +vt 0.6249 0.5000 +vt 0.6171 0.5000 +vt 0.6172 0.3673 +vt 0.6250 0.3673 +vt 0.6250 0.3751 +vt 0.6172 0.3751 +vt 0.7421 0.3673 +vt 0.7499 0.3673 +vt 0.7499 0.3751 +vt 0.7421 0.3751 +vt 0.8670 0.4923 +vt 0.8748 0.4923 +vt 0.8748 0.5001 +vt 0.8670 0.5001 +vt 0.8670 0.3674 +vt 0.8748 0.3674 +vt 0.8748 0.3752 +vt 0.8670 0.3752 +vt 0.9920 0.3674 +vt 0.9998 0.3674 +vt 0.9998 0.3752 +vt 0.9920 0.3752 +vt 0.3673 0.4921 +vt 0.3751 0.4921 +vt 0.3751 0.4999 +vt 0.3673 0.4999 +vt 0.3673 0.3672 +vt 0.3751 0.3672 +vt 0.3751 0.3750 +vt 0.3673 0.3750 +vt 0.4922 0.3672 +vt 0.5000 0.3672 +vt 0.5000 0.3751 +vt 0.4922 0.3750 +vt 0.3671 0.9919 +vt 0.3749 0.9919 +vt 0.3749 0.9997 +vt 0.3671 0.9997 +vt 0.3671 0.8669 +vt 0.3750 0.8669 +vt 0.3750 0.8748 +vt 0.3671 0.8747 +vt 0.4921 0.8670 +vt 0.4999 0.8670 +vt 0.4999 0.8748 +vt 0.4921 0.8748 +vt 0.8668 0.9920 +vt 0.8746 0.9920 +vt 0.8746 0.9998 +vt 0.8668 0.9998 +vt 0.8669 0.8671 +vt 0.8747 0.8671 +vt 0.8747 0.8749 +vt 0.8669 0.8749 +vt 0.9918 0.8671 +vt 0.9996 0.8671 +vt 0.9996 0.8749 +vt 0.9918 0.8749 +vt 0.9293 0.8671 +vt 0.9372 0.8671 +vt 0.9372 0.8749 +vt 0.9293 0.8749 +vt 0.9294 0.8046 +vt 0.9372 0.8046 +vt 0.9372 0.8125 +vt 0.9294 0.8125 +vt 0.9918 0.8047 +vt 0.9996 0.8047 +vt 0.9996 0.8125 +vt 0.9918 0.8125 +vt 0.8044 0.8671 +vt 0.8122 0.8671 +vt 0.8122 0.8749 +vt 0.8044 0.8749 +vt 0.8044 0.8046 +vt 0.8122 0.8046 +vt 0.8122 0.8124 +vt 0.8044 0.8124 +vt 0.8669 0.8046 +vt 0.8747 0.8046 +vt 0.8747 0.8124 +vt 0.8669 0.8124 +vt 0.8044 0.9920 +vt 0.8122 0.9920 +vt 0.8122 0.9998 +vt 0.8044 0.9998 +vt 0.8044 0.9295 +vt 0.8122 0.9295 +vt 0.8122 0.9373 +vt 0.8044 0.9373 +vt 0.8669 0.9296 +vt 0.8747 0.9296 +vt 0.8747 0.9374 +vt 0.8669 0.9374 +vt 0.4296 0.8670 +vt 0.4374 0.8670 +vt 0.4374 0.8748 +vt 0.4296 0.8748 +vt 0.4296 0.8045 +vt 0.4374 0.8045 +vt 0.4374 0.8123 +vt 0.4296 0.8123 +vt 0.4921 0.8045 +vt 0.4999 0.8045 +vt 0.4999 0.8123 +vt 0.4921 0.8123 +vt 0.3047 0.8669 +vt 0.3125 0.8669 +vt 0.3125 0.8747 +vt 0.3047 0.8747 +vt 0.3047 0.8045 +vt 0.3125 0.8045 +vt 0.3125 0.8123 +vt 0.3047 0.8123 +vt 0.3672 0.8045 +vt 0.3750 0.8045 +vt 0.3750 0.8123 +vt 0.3672 0.8123 +vt 0.3046 0.9919 +vt 0.3124 0.9919 +vt 0.3124 0.9997 +vt 0.3046 0.9997 +vt 0.3047 0.9294 +vt 0.3125 0.9294 +vt 0.3125 0.9372 +vt 0.3047 0.9372 +vt 0.3671 0.9294 +vt 0.3749 0.9294 +vt 0.3749 0.9372 +vt 0.3671 0.9372 +vt 0.4298 0.3672 +vt 0.4376 0.3672 +vt 0.4376 0.3750 +vt 0.4298 0.3750 +vt 0.4298 0.3048 +vt 0.4376 0.3048 +vt 0.4376 0.3126 +vt 0.4298 0.3126 +vt 0.4923 0.3048 +vt 0.5001 0.3048 +vt 0.5001 0.3126 +vt 0.4923 0.3126 +vt 0.3048 0.3672 +vt 0.3126 0.3672 +vt 0.3126 0.3750 +vt 0.3048 0.3750 +vt 0.3049 0.3047 +vt 0.3127 0.3047 +vt 0.3127 0.3125 +vt 0.3049 0.3125 +vt 0.3673 0.3047 +vt 0.3751 0.3047 +vt 0.3751 0.3125 +vt 0.3673 0.3125 +vt 0.3048 0.4921 +vt 0.3126 0.4921 +vt 0.3126 0.4999 +vt 0.3048 0.4999 +vt 0.3048 0.4296 +vt 0.3126 0.4297 +vt 0.3126 0.4375 +vt 0.3048 0.4375 +vt 0.3673 0.4297 +vt 0.3751 0.4297 +vt 0.3751 0.4375 +vt 0.3673 0.4375 +vt 0.9295 0.3674 +vt 0.9373 0.3674 +vt 0.9373 0.3752 +vt 0.9295 0.3752 +vt 0.9295 0.3049 +vt 0.9373 0.3049 +vt 0.9373 0.3127 +vt 0.9295 0.3127 +vt 0.9920 0.3049 +vt 0.9998 0.3049 +vt 0.9998 0.3127 +vt 0.9920 0.3127 +vt 0.8046 0.3673 +vt 0.8124 0.3673 +vt 0.8124 0.3752 +vt 0.8046 0.3751 +vt 0.8046 0.3049 +vt 0.8124 0.3049 +vt 0.8124 0.3127 +vt 0.8046 0.3127 +vt 0.8671 0.3049 +vt 0.8749 0.3049 +vt 0.8749 0.3127 +vt 0.8671 0.3127 +vt 0.8045 0.4923 +vt 0.8123 0.4923 +vt 0.8123 0.5001 +vt 0.8045 0.5001 +vt 0.8046 0.4298 +vt 0.8124 0.4298 +vt 0.8124 0.4376 +vt 0.8045 0.4376 +vt 0.8670 0.4298 +vt 0.8748 0.4298 +vt 0.8748 0.4376 +vt 0.8670 0.4376 +vt 0.6796 0.3673 +vt 0.6874 0.3673 +vt 0.6874 0.3751 +vt 0.6796 0.3751 +vt 0.6797 0.3048 +vt 0.6875 0.3048 +vt 0.6875 0.3126 +vt 0.6797 0.3126 +vt 0.7421 0.3049 +vt 0.7499 0.3049 +vt 0.7499 0.3127 +vt 0.7421 0.3127 +vt 0.5547 0.3673 +vt 0.5625 0.3673 +vt 0.5625 0.3751 +vt 0.5547 0.3751 +vt 0.5547 0.3048 +vt 0.5625 0.3048 +vt 0.5625 0.3126 +vt 0.5547 0.3126 +vt 0.6172 0.3048 +vt 0.6250 0.3048 +vt 0.6250 0.3126 +vt 0.6172 0.3126 +vt 0.5547 0.4922 +vt 0.5625 0.4922 +vt 0.5625 0.5000 +vt 0.5547 0.5000 +vt 0.5547 0.4297 +vt 0.5625 0.4297 +vt 0.5625 0.4375 +vt 0.5547 0.4375 +vt 0.6171 0.4297 +vt 0.6250 0.4297 +vt 0.6250 0.4376 +vt 0.6171 0.4376 +vt 0.6797 0.1174 +vt 0.6875 0.1174 +vt 0.6875 0.1252 +vt 0.6797 0.1252 +vt 0.6797 0.0550 +vt 0.6875 0.0550 +vt 0.6875 0.0628 +vt 0.6797 0.0628 +vt 0.7422 0.0550 +vt 0.7500 0.0550 +vt 0.7500 0.0628 +vt 0.7422 0.0628 +vt 0.5548 0.1174 +vt 0.5626 0.1174 +vt 0.5626 0.1252 +vt 0.5548 0.1252 +vt 0.5548 0.0549 +vt 0.5626 0.0549 +vt 0.5626 0.0627 +vt 0.5548 0.0627 +vt 0.6173 0.0549 +vt 0.6251 0.0549 +vt 0.6251 0.0628 +vt 0.6173 0.0628 +vt 0.5547 0.2423 +vt 0.5625 0.2423 +vt 0.5625 0.2501 +vt 0.5547 0.2501 +vt 0.5548 0.1799 +vt 0.5626 0.1799 +vt 0.5626 0.1877 +vt 0.5548 0.1877 +vt 0.6172 0.1799 +vt 0.6250 0.1799 +vt 0.6250 0.1877 +vt 0.6172 0.1877 +vt 0.9296 0.1175 +vt 0.9374 0.1175 +vt 0.9374 0.1253 +vt 0.9296 0.1253 +vt 0.9296 0.0550 +vt 0.9374 0.0550 +vt 0.9374 0.0628 +vt 0.9296 0.0628 +vt 0.9921 0.0551 +vt 0.9999 0.0551 +vt 0.9999 0.0629 +vt 0.9921 0.0629 +vt 0.8046 0.1175 +vt 0.8125 0.1175 +vt 0.8125 0.1253 +vt 0.8046 0.1253 +vt 0.8047 0.0550 +vt 0.8125 0.0550 +vt 0.8125 0.0628 +vt 0.8047 0.0628 +vt 0.8671 0.0550 +vt 0.8749 0.0550 +vt 0.8749 0.0628 +vt 0.8671 0.0628 +vt 0.8046 0.2424 +vt 0.8124 0.2424 +vt 0.8124 0.2502 +vt 0.8046 0.2502 +vt 0.8046 0.1799 +vt 0.8124 0.1799 +vt 0.8124 0.1877 +vt 0.8046 0.1877 +vt 0.8671 0.1800 +vt 0.8749 0.1800 +vt 0.8749 0.1878 +vt 0.8671 0.1878 +vt 0.1799 0.3671 +vt 0.1877 0.3671 +vt 0.1877 0.3750 +vt 0.1799 0.3750 +vt 0.1799 0.3047 +vt 0.1877 0.3047 +vt 0.1877 0.3125 +vt 0.1799 0.3125 +vt 0.2424 0.3047 +vt 0.2502 0.3047 +vt 0.2502 0.3125 +vt 0.2424 0.3125 +vt 0.0550 0.3671 +vt 0.0628 0.3671 +vt 0.0628 0.3749 +vt 0.0550 0.3749 +vt 0.0550 0.3046 +vt 0.0628 0.3046 +vt 0.0628 0.3124 +vt 0.0550 0.3124 +vt 0.1175 0.3047 +vt 0.1253 0.3047 +vt 0.1253 0.3125 +vt 0.1175 0.3125 +vt 0.0549 0.4920 +vt 0.0627 0.4920 +vt 0.0627 0.4998 +vt 0.0549 0.4998 +vt 0.0549 0.4296 +vt 0.0628 0.4296 +vt 0.0628 0.4374 +vt 0.0549 0.4374 +vt 0.1174 0.4296 +vt 0.1252 0.4296 +vt 0.1252 0.4374 +vt 0.1174 0.4374 +vt 0.1800 0.1173 +vt 0.1878 0.1173 +vt 0.1878 0.1251 +vt 0.1800 0.1251 +vt 0.1800 0.0548 +vt 0.1878 0.0548 +vt 0.1878 0.0626 +vt 0.1800 0.0626 +vt 0.2425 0.0548 +vt 0.2503 0.0548 +vt 0.2503 0.0626 +vt 0.2425 0.0626 +vt 0.0550 0.1172 +vt 0.0629 0.1172 +vt 0.0629 0.1250 +vt 0.0550 0.1250 +vt 0.0551 0.0548 +vt 0.0629 0.0548 +vt 0.0629 0.0626 +vt 0.0551 0.0626 +vt 0.1175 0.0548 +vt 0.1253 0.0548 +vt 0.1253 0.0626 +vt 0.1175 0.0626 +vt 0.0550 0.2422 +vt 0.0628 0.2422 +vt 0.0628 0.2500 +vt 0.0550 0.2500 +vt 0.0550 0.1797 +vt 0.0628 0.1797 +vt 0.0628 0.1875 +vt 0.0550 0.1875 +vt 0.1175 0.1797 +vt 0.1253 0.1797 +vt 0.1253 0.1875 +vt 0.1175 0.1875 +vt 0.4298 0.1174 +vt 0.4377 0.1174 +vt 0.4377 0.1252 +vt 0.4298 0.1252 +vt 0.4299 0.0549 +vt 0.4377 0.0549 +vt 0.4377 0.0627 +vt 0.4299 0.0627 +vt 0.4923 0.0549 +vt 0.5001 0.0549 +vt 0.5001 0.0627 +vt 0.4923 0.0627 +vt 0.3049 0.1173 +vt 0.3127 0.1173 +vt 0.3127 0.1251 +vt 0.3049 0.1251 +vt 0.3049 0.0549 +vt 0.3127 0.0549 +vt 0.3127 0.0627 +vt 0.3049 0.0627 +vt 0.3674 0.0549 +vt 0.3752 0.0549 +vt 0.3752 0.0627 +vt 0.3674 0.0627 +vt 0.3049 0.2422 +vt 0.3127 0.2423 +vt 0.3127 0.2501 +vt 0.3049 0.2501 +vt 0.3049 0.1798 +vt 0.3127 0.1798 +vt 0.3127 0.1876 +vt 0.3049 0.1876 +vt 0.3674 0.1798 +vt 0.3752 0.1798 +vt 0.3752 0.1876 +vt 0.3674 0.1876 +vt 0.1797 0.8669 +vt 0.1875 0.8669 +vt 0.1875 0.8747 +vt 0.1797 0.8747 +vt 0.1798 0.8044 +vt 0.1876 0.8044 +vt 0.1876 0.8122 +vt 0.1798 0.8122 +vt 0.2422 0.8044 +vt 0.2500 0.8044 +vt 0.2500 0.8122 +vt 0.2422 0.8122 +vt 0.0548 0.8668 +vt 0.0626 0.8668 +vt 0.0626 0.8747 +vt 0.0548 0.8747 +vt 0.0548 0.8044 +vt 0.0626 0.8044 +vt 0.0626 0.8122 +vt 0.0548 0.8122 +vt 0.1173 0.8044 +vt 0.1251 0.8044 +vt 0.1251 0.8122 +vt 0.1173 0.8122 +vt 0.0548 0.9918 +vt 0.0626 0.9918 +vt 0.0626 0.9996 +vt 0.0548 0.9996 +vt 0.0548 0.9293 +vt 0.0626 0.9293 +vt 0.0626 0.9371 +vt 0.0548 0.9371 +vt 0.1173 0.9293 +vt 0.1251 0.9293 +vt 0.1251 0.9371 +vt 0.1172 0.9371 +vt 0.1798 0.6170 +vt 0.1876 0.6170 +vt 0.1876 0.6248 +vt 0.1798 0.6248 +vt 0.1798 0.5545 +vt 0.1876 0.5545 +vt 0.1876 0.5624 +vt 0.1798 0.5624 +vt 0.2423 0.5546 +vt 0.2501 0.5546 +vt 0.2501 0.5624 +vt 0.2423 0.5624 +vt 0.0549 0.6170 +vt 0.0627 0.6170 +vt 0.0627 0.6248 +vt 0.0549 0.6248 +vt 0.0549 0.5545 +vt 0.0627 0.5545 +vt 0.0627 0.5623 +vt 0.0549 0.5623 +vt 0.1174 0.5545 +vt 0.1252 0.5545 +vt 0.1252 0.5623 +vt 0.1174 0.5623 +vt 0.0548 0.7419 +vt 0.0627 0.7419 +vt 0.0626 0.7497 +vt 0.0548 0.7497 +vt 0.0549 0.6794 +vt 0.0627 0.6794 +vt 0.0627 0.6872 +vt 0.0549 0.6872 +vt 0.1173 0.6795 +vt 0.1251 0.6795 +vt 0.1251 0.6873 +vt 0.1173 0.6873 +vt 0.4297 0.6171 +vt 0.4375 0.6171 +vt 0.4375 0.6249 +vt 0.4297 0.6249 +vt 0.4297 0.5546 +vt 0.4375 0.5546 +vt 0.4375 0.5624 +vt 0.4297 0.5624 +vt 0.4922 0.5546 +vt 0.5000 0.5546 +vt 0.5000 0.5625 +vt 0.4922 0.5625 +vt 0.3048 0.6171 +vt 0.3126 0.6171 +vt 0.3126 0.6249 +vt 0.3048 0.6249 +vt 0.3048 0.5546 +vt 0.3126 0.5546 +vt 0.3126 0.5624 +vt 0.3048 0.5624 +vt 0.3672 0.5546 +vt 0.3751 0.5546 +vt 0.3750 0.5624 +vt 0.3672 0.5624 +vt 0.3047 0.7420 +vt 0.3125 0.7420 +vt 0.3125 0.7498 +vt 0.3047 0.7498 +vt 0.3047 0.6795 +vt 0.3125 0.6795 +vt 0.3125 0.6873 +vt 0.3047 0.6873 +vt 0.3672 0.6795 +vt 0.3750 0.6795 +vt 0.3750 0.6873 +vt 0.3672 0.6873 +vt 0.6795 0.8670 +vt 0.6873 0.8670 +vt 0.6873 0.8748 +vt 0.6795 0.8748 +vt 0.6795 0.8046 +vt 0.6873 0.8046 +vt 0.6873 0.8124 +vt 0.6795 0.8124 +vt 0.7420 0.8046 +vt 0.7498 0.8046 +vt 0.7498 0.8124 +vt 0.7420 0.8124 +vt 0.5545 0.8670 +vt 0.5624 0.8670 +vt 0.5624 0.8748 +vt 0.5545 0.8748 +vt 0.5546 0.8045 +vt 0.5624 0.8045 +vt 0.5624 0.8123 +vt 0.5546 0.8123 +vt 0.6170 0.8045 +vt 0.6248 0.8046 +vt 0.6248 0.8124 +vt 0.6170 0.8124 +vt 0.5545 0.9919 +vt 0.5623 0.9919 +vt 0.5623 0.9997 +vt 0.5545 0.9997 +vt 0.5545 0.9295 +vt 0.5623 0.9295 +vt 0.5623 0.9373 +vt 0.5545 0.9373 +vt 0.6170 0.9295 +vt 0.6248 0.9295 +vt 0.6248 0.9373 +vt 0.6170 0.9373 +vt 0.6796 0.6172 +vt 0.6874 0.6172 +vt 0.6874 0.6250 +vt 0.6796 0.6250 +vt 0.6796 0.5547 +vt 0.6874 0.5547 +vt 0.6874 0.5625 +vt 0.6796 0.5625 +vt 0.7420 0.5547 +vt 0.7499 0.5547 +vt 0.7499 0.5625 +vt 0.7420 0.5625 +vt 0.5546 0.6171 +vt 0.5624 0.6171 +vt 0.5624 0.6249 +vt 0.5546 0.6249 +vt 0.5546 0.5547 +vt 0.5625 0.5547 +vt 0.5624 0.5625 +vt 0.5546 0.5625 +vt 0.6171 0.5547 +vt 0.6249 0.5547 +vt 0.6249 0.5625 +vt 0.6171 0.5625 +vt 0.5546 0.7421 +vt 0.5624 0.7421 +vt 0.5624 0.7499 +vt 0.5546 0.7499 +vt 0.5546 0.6796 +vt 0.5624 0.6796 +vt 0.5624 0.6874 +vt 0.5546 0.6874 +vt 0.6171 0.6796 +vt 0.6249 0.6796 +vt 0.6249 0.6874 +vt 0.6171 0.6874 +vt 0.9294 0.6172 +vt 0.9372 0.6172 +vt 0.9372 0.6251 +vt 0.9294 0.6251 +vt 0.9294 0.5548 +vt 0.9373 0.5548 +vt 0.9373 0.5626 +vt 0.9294 0.5626 +vt 0.9919 0.5548 +vt 0.9997 0.5548 +vt 0.9997 0.5626 +vt 0.9919 0.5626 +vt 0.8045 0.6172 +vt 0.8123 0.6172 +vt 0.8123 0.6250 +vt 0.8045 0.6250 +vt 0.8045 0.5547 +vt 0.8123 0.5547 +vt 0.8123 0.5626 +vt 0.8045 0.5625 +vt 0.8670 0.5548 +vt 0.8748 0.5548 +vt 0.8748 0.5626 +vt 0.8670 0.5626 +vt 0.8045 0.7421 +vt 0.8123 0.7421 +vt 0.8123 0.7500 +vt 0.8044 0.7499 +vt 0.8045 0.6797 +vt 0.8123 0.6797 +vt 0.8123 0.6875 +vt 0.8045 0.6875 +vt 0.8669 0.6797 +vt 0.8747 0.6797 +vt 0.8747 0.6875 +vt 0.8669 0.6875 +vt 0.9294 0.7422 +vt 0.9372 0.7422 +vt 0.9372 0.7500 +vt 0.9294 0.7500 +vt 0.9294 0.6797 +vt 0.9372 0.6797 +vt 0.9372 0.6875 +vt 0.9294 0.6875 +vt 0.9919 0.6797 +vt 0.9997 0.6797 +vt 0.9997 0.6875 +vt 0.9919 0.6875 +vt 0.6795 0.7421 +vt 0.6873 0.7421 +vt 0.6873 0.7499 +vt 0.6795 0.7499 +vt 0.6795 0.6796 +vt 0.6873 0.6796 +vt 0.6873 0.6874 +vt 0.6795 0.6874 +vt 0.7420 0.6797 +vt 0.7498 0.6797 +vt 0.7498 0.6875 +vt 0.7420 0.6875 +vt 0.6794 0.9920 +vt 0.6873 0.9920 +vt 0.6872 0.9998 +vt 0.6794 0.9998 +vt 0.6795 0.9295 +vt 0.6873 0.9295 +vt 0.6873 0.9373 +vt 0.6795 0.9373 +vt 0.7419 0.9295 +vt 0.7497 0.9295 +vt 0.7497 0.9373 +vt 0.7419 0.9373 +vt 0.4297 0.7420 +vt 0.4375 0.7420 +vt 0.4375 0.7498 +vt 0.4296 0.7498 +vt 0.4297 0.6796 +vt 0.4375 0.6796 +vt 0.4375 0.6874 +vt 0.4297 0.6874 +vt 0.4921 0.6796 +vt 0.4999 0.6796 +vt 0.4999 0.6874 +vt 0.4921 0.6874 +vt 0.1798 0.7419 +vt 0.1876 0.7419 +vt 0.1876 0.7498 +vt 0.1798 0.7498 +vt 0.1798 0.6795 +vt 0.1876 0.6795 +vt 0.1876 0.6873 +vt 0.1798 0.6873 +vt 0.2423 0.6795 +vt 0.2501 0.6795 +vt 0.2501 0.6873 +vt 0.2423 0.6873 +vt 0.1797 0.9918 +vt 0.1875 0.9918 +vt 0.1875 0.9996 +vt 0.1797 0.9996 +vt 0.1797 0.9294 +vt 0.1875 0.9294 +vt 0.1875 0.9372 +vt 0.1797 0.9372 +vt 0.2422 0.9294 +vt 0.2500 0.9294 +vt 0.2500 0.9372 +vt 0.2422 0.9372 +vt 0.4298 0.2423 +vt 0.4376 0.2423 +vt 0.4376 0.2501 +vt 0.4298 0.2501 +vt 0.4298 0.1798 +vt 0.4376 0.1798 +vt 0.4376 0.1876 +vt 0.4298 0.1876 +vt 0.4923 0.1798 +vt 0.5001 0.1798 +vt 0.5001 0.1877 +vt 0.4923 0.1876 +vt 0.1799 0.2422 +vt 0.1877 0.2422 +vt 0.1877 0.2500 +vt 0.1799 0.2500 +vt 0.1800 0.1797 +vt 0.1878 0.1797 +vt 0.1878 0.1876 +vt 0.1800 0.1876 +vt 0.2424 0.1798 +vt 0.2502 0.1798 +vt 0.2502 0.1876 +vt 0.2424 0.1876 +vt 0.1799 0.4921 +vt 0.1877 0.4921 +vt 0.1877 0.4999 +vt 0.1799 0.4999 +vt 0.1799 0.4296 +vt 0.1877 0.4296 +vt 0.1877 0.4374 +vt 0.1799 0.4374 +vt 0.2423 0.4296 +vt 0.2502 0.4296 +vt 0.2502 0.4374 +vt 0.2423 0.4374 +vt 0.9295 0.2424 +vt 0.9374 0.2424 +vt 0.9374 0.2503 +vt 0.9295 0.2503 +vt 0.9296 0.1800 +vt 0.9374 0.1800 +vt 0.9374 0.1878 +vt 0.9296 0.1878 +vt 0.9920 0.1800 +vt 0.9998 0.1800 +vt 0.9998 0.1878 +vt 0.9920 0.1878 +vt 0.6797 0.2424 +vt 0.6875 0.2424 +vt 0.6875 0.2502 +vt 0.6797 0.2502 +vt 0.6797 0.1799 +vt 0.6875 0.1799 +vt 0.6875 0.1877 +vt 0.6797 0.1877 +vt 0.7422 0.1799 +vt 0.7500 0.1799 +vt 0.7500 0.1877 +vt 0.7422 0.1877 +vt 0.6796 0.4922 +vt 0.6874 0.4922 +vt 0.6874 0.5000 +vt 0.6796 0.5000 +vt 0.6796 0.4298 +vt 0.6874 0.4298 +vt 0.6874 0.4376 +vt 0.6796 0.4376 +vt 0.7421 0.4298 +vt 0.7499 0.4298 +vt 0.7499 0.4376 +vt 0.7421 0.4376 +vt 0.9295 0.4923 +vt 0.9373 0.4923 +vt 0.9373 0.5001 +vt 0.9295 0.5001 +vt 0.9295 0.4298 +vt 0.9373 0.4298 +vt 0.9373 0.4377 +vt 0.9295 0.4377 +vt 0.9920 0.4299 +vt 0.9998 0.4299 +vt 0.9998 0.4377 +vt 0.9920 0.4377 +vt 0.4297 0.4922 +vt 0.4375 0.4922 +vt 0.4375 0.5000 +vt 0.4297 0.5000 +vt 0.4297 0.4297 +vt 0.4376 0.4297 +vt 0.4376 0.4375 +vt 0.4297 0.4375 +vt 0.4922 0.4297 +vt 0.5000 0.4297 +vt 0.5000 0.4375 +vt 0.4922 0.4375 +vt 0.4296 0.9919 +vt 0.4374 0.9919 +vt 0.4374 0.9997 +vt 0.4296 0.9997 +vt 0.4296 0.9294 +vt 0.4374 0.9294 +vt 0.4374 0.9372 +vt 0.4296 0.9372 +vt 0.4921 0.9294 +vt 0.4999 0.9294 +vt 0.4999 0.9373 +vt 0.4921 0.9373 +vt 0.9293 0.9920 +vt 0.9371 0.9920 +vt 0.9371 0.9999 +vt 0.9293 0.9999 +vt 0.9293 0.9296 +vt 0.9371 0.9296 +vt 0.9371 0.9374 +vt 0.9293 0.9374 +vt 0.9918 0.9296 +vt 0.9996 0.9296 +vt 0.9996 0.9374 +vt 0.9918 0.9374 +vt 0.9606 0.9296 +vt 0.9684 0.9296 +vt 0.9684 0.9374 +vt 0.9606 0.9374 +vt 0.9606 0.8984 +vt 0.9684 0.8984 +vt 0.9684 0.9062 +vt 0.9606 0.9062 +vt 0.9918 0.8984 +vt 0.9996 0.8984 +vt 0.9996 0.9062 +vt 0.9918 0.9062 +vt 0.8981 0.9296 +vt 0.9059 0.9296 +vt 0.9059 0.9374 +vt 0.8981 0.9374 +vt 0.8981 0.8983 +vt 0.9059 0.8983 +vt 0.9059 0.9061 +vt 0.8981 0.9061 +vt 0.9293 0.8983 +vt 0.9371 0.8983 +vt 0.9371 0.9062 +vt 0.9293 0.9062 +vt 0.8981 0.9920 +vt 0.9059 0.9920 +vt 0.9059 0.9998 +vt 0.8981 0.9998 +vt 0.8981 0.9608 +vt 0.9059 0.9608 +vt 0.9059 0.9686 +vt 0.8981 0.9686 +vt 0.9293 0.9608 +vt 0.9371 0.9608 +vt 0.9371 0.9686 +vt 0.9293 0.9686 +vt 0.4608 0.9294 +vt 0.4686 0.9294 +vt 0.4686 0.9372 +vt 0.4608 0.9372 +vt 0.4608 0.8982 +vt 0.4686 0.8982 +vt 0.4686 0.9060 +vt 0.4608 0.9060 +vt 0.4921 0.8982 +vt 0.4999 0.8982 +vt 0.4999 0.9060 +vt 0.4921 0.9060 +vt 0.3984 0.9294 +vt 0.4062 0.9294 +vt 0.4062 0.9372 +vt 0.3984 0.9372 +vt 0.3984 0.8982 +vt 0.4062 0.8982 +vt 0.4062 0.9060 +vt 0.3984 0.9060 +vt 0.4296 0.8982 +vt 0.4374 0.8982 +vt 0.4374 0.9060 +vt 0.4296 0.9060 +vt 0.3983 0.9919 +vt 0.4061 0.9919 +vt 0.4061 0.9997 +vt 0.3983 0.9997 +vt 0.3984 0.9607 +vt 0.4062 0.9607 +vt 0.4062 0.9685 +vt 0.3983 0.9685 +vt 0.4296 0.9607 +vt 0.4374 0.9607 +vt 0.4374 0.9685 +vt 0.4296 0.9685 +vt 0.4610 0.4297 +vt 0.4688 0.4297 +vt 0.4688 0.4375 +vt 0.4610 0.4375 +vt 0.4610 0.3985 +vt 0.4688 0.3985 +vt 0.4688 0.4063 +vt 0.4610 0.4063 +vt 0.4922 0.3985 +vt 0.5000 0.3985 +vt 0.5000 0.4063 +vt 0.4922 0.4063 +vt 0.3985 0.4297 +vt 0.4063 0.4297 +vt 0.4063 0.4375 +vt 0.3985 0.4375 +vt 0.3985 0.3984 +vt 0.4063 0.3984 +vt 0.4063 0.4063 +vt 0.3985 0.4063 +vt 0.4298 0.3985 +vt 0.4376 0.3985 +vt 0.4376 0.4063 +vt 0.4298 0.4063 +vt 0.3985 0.4921 +vt 0.4063 0.4921 +vt 0.4063 0.5000 +vt 0.3985 0.5000 +vt 0.3985 0.4609 +vt 0.4063 0.4609 +vt 0.4063 0.4687 +vt 0.3985 0.4687 +vt 0.4297 0.4609 +vt 0.4375 0.4609 +vt 0.4375 0.4687 +vt 0.4297 0.4687 +vt 0.9607 0.4299 +vt 0.9685 0.4299 +vt 0.9685 0.4377 +vt 0.9607 0.4377 +vt 0.9607 0.3986 +vt 0.9685 0.3986 +vt 0.9685 0.4064 +vt 0.9607 0.4064 +vt 0.9920 0.3986 +vt 0.9998 0.3986 +vt 0.9998 0.4064 +vt 0.9920 0.4064 +vt 0.8983 0.4298 +vt 0.9061 0.4298 +vt 0.9061 0.4376 +vt 0.8982 0.4376 +vt 0.8983 0.3986 +vt 0.9061 0.3986 +vt 0.9061 0.4064 +vt 0.8983 0.4064 +vt 0.9295 0.3986 +vt 0.9373 0.3986 +vt 0.9373 0.4064 +vt 0.9295 0.4064 +vt 0.8982 0.4923 +vt 0.9060 0.4923 +vt 0.9060 0.5001 +vt 0.8982 0.5001 +vt 0.8982 0.4611 +vt 0.9061 0.4611 +vt 0.9060 0.4689 +vt 0.8982 0.4689 +vt 0.9295 0.4611 +vt 0.9373 0.4611 +vt 0.9373 0.4689 +vt 0.9295 0.4689 +vt 0.7109 0.4298 +vt 0.7187 0.4298 +vt 0.7187 0.4376 +vt 0.7108 0.4376 +vt 0.7109 0.3985 +vt 0.7187 0.3985 +vt 0.7187 0.4064 +vt 0.7109 0.4064 +vt 0.7421 0.3986 +vt 0.7499 0.3986 +vt 0.7499 0.4064 +vt 0.7421 0.4064 +vt 0.6484 0.4298 +vt 0.6562 0.4298 +vt 0.6562 0.4376 +vt 0.6484 0.4376 +vt 0.6484 0.3985 +vt 0.6562 0.3985 +vt 0.6562 0.4063 +vt 0.6484 0.4063 +vt 0.6796 0.3985 +vt 0.6874 0.3985 +vt 0.6874 0.4063 +vt 0.6796 0.4063 +vt 0.6484 0.4922 +vt 0.6562 0.4922 +vt 0.6562 0.5000 +vt 0.6484 0.5000 +vt 0.6484 0.4610 +vt 0.6562 0.4610 +vt 0.6562 0.4688 +vt 0.6484 0.4688 +vt 0.6796 0.4610 +vt 0.6874 0.4610 +vt 0.6874 0.4688 +vt 0.6796 0.4688 +vt 0.7109 0.1799 +vt 0.7187 0.1799 +vt 0.7187 0.1877 +vt 0.7109 0.1877 +vt 0.7109 0.1487 +vt 0.7187 0.1487 +vt 0.7187 0.1565 +vt 0.7109 0.1565 +vt 0.7422 0.1487 +vt 0.7500 0.1487 +vt 0.7500 0.1565 +vt 0.7422 0.1565 +vt 0.6485 0.1799 +vt 0.6563 0.1799 +vt 0.6563 0.1877 +vt 0.6485 0.1877 +vt 0.6485 0.1487 +vt 0.6563 0.1487 +vt 0.6563 0.1565 +vt 0.6485 0.1565 +vt 0.6797 0.1487 +vt 0.6875 0.1487 +vt 0.6875 0.1565 +vt 0.6797 0.1565 +vt 0.6484 0.2424 +vt 0.6562 0.2424 +vt 0.6562 0.2502 +vt 0.6484 0.2502 +vt 0.6485 0.2111 +vt 0.6563 0.2111 +vt 0.6563 0.2189 +vt 0.6484 0.2189 +vt 0.6797 0.2111 +vt 0.6875 0.2111 +vt 0.6875 0.2189 +vt 0.6797 0.2189 +vt 0.9608 0.1800 +vt 0.9686 0.1800 +vt 0.9686 0.1878 +vt 0.9608 0.1878 +vt 0.9608 0.1488 +vt 0.9686 0.1488 +vt 0.9686 0.1566 +vt 0.9608 0.1566 +vt 0.9920 0.1488 +vt 0.9999 0.1488 +vt 0.9999 0.1566 +vt 0.9920 0.1566 +vt 0.8983 0.1800 +vt 0.9061 0.1800 +vt 0.9061 0.1878 +vt 0.8983 0.1878 +vt 0.8983 0.1487 +vt 0.9062 0.1487 +vt 0.9061 0.1565 +vt 0.8983 0.1565 +vt 0.9296 0.1487 +vt 0.9374 0.1487 +vt 0.9374 0.1566 +vt 0.9296 0.1565 +vt 0.8983 0.2424 +vt 0.9061 0.2424 +vt 0.9061 0.2502 +vt 0.8983 0.2502 +vt 0.8983 0.2112 +vt 0.9061 0.2112 +vt 0.9061 0.2190 +vt 0.8983 0.2190 +vt 0.9296 0.2112 +vt 0.9374 0.2112 +vt 0.9374 0.2190 +vt 0.9296 0.2190 +vt 0.2111 0.4296 +vt 0.2189 0.4296 +vt 0.2189 0.4374 +vt 0.2111 0.4374 +vt 0.2111 0.3984 +vt 0.2189 0.3984 +vt 0.2189 0.4062 +vt 0.2111 0.4062 +vt 0.2424 0.3984 +vt 0.2502 0.3984 +vt 0.2502 0.4062 +vt 0.2424 0.4062 +vt 0.1486 0.4296 +vt 0.1565 0.4296 +vt 0.1565 0.4374 +vt 0.1486 0.4374 +vt 0.1487 0.3984 +vt 0.1565 0.3984 +vt 0.1565 0.4062 +vt 0.1487 0.4062 +vt 0.1799 0.3984 +vt 0.1877 0.3984 +vt 0.1877 0.4062 +vt 0.1799 0.4062 +vt 0.1486 0.4921 +vt 0.1564 0.4921 +vt 0.1564 0.4999 +vt 0.1486 0.4999 +vt 0.1486 0.4608 +vt 0.1564 0.4608 +vt 0.1564 0.4686 +vt 0.1486 0.4686 +vt 0.1799 0.4608 +vt 0.1877 0.4608 +vt 0.1877 0.4687 +vt 0.1799 0.4687 +vt 0.2112 0.1798 +vt 0.2190 0.1798 +vt 0.2190 0.1876 +vt 0.2112 0.1876 +vt 0.2112 0.1485 +vt 0.2190 0.1485 +vt 0.2190 0.1563 +vt 0.2112 0.1563 +vt 0.2424 0.1485 +vt 0.2502 0.1485 +vt 0.2502 0.1563 +vt 0.2424 0.1563 +vt 0.1487 0.1797 +vt 0.1565 0.1797 +vt 0.1565 0.1875 +vt 0.1487 0.1875 +vt 0.1487 0.1485 +vt 0.1565 0.1485 +vt 0.1565 0.1563 +vt 0.1487 0.1563 +vt 0.1800 0.1485 +vt 0.1878 0.1485 +vt 0.1878 0.1563 +vt 0.1800 0.1563 +vt 0.1487 0.2422 +vt 0.1565 0.2422 +vt 0.1565 0.2500 +vt 0.1487 0.2500 +vt 0.1487 0.2110 +vt 0.1565 0.2110 +vt 0.1565 0.2188 +vt 0.1487 0.2188 +vt 0.1800 0.2110 +vt 0.1878 0.2110 +vt 0.1878 0.2188 +vt 0.1799 0.2188 +vt 0.4611 0.1798 +vt 0.4689 0.1798 +vt 0.4689 0.1876 +vt 0.4611 0.1876 +vt 0.4611 0.1486 +vt 0.4689 0.1486 +vt 0.4689 0.1564 +vt 0.4611 0.1564 +vt 0.4923 0.1486 +vt 0.5001 0.1486 +vt 0.5001 0.1564 +vt 0.4923 0.1564 +vt 0.3986 0.1798 +vt 0.4064 0.1798 +vt 0.4064 0.1876 +vt 0.3986 0.1876 +vt 0.3986 0.1486 +vt 0.4064 0.1486 +vt 0.4064 0.1564 +vt 0.3986 0.1564 +vt 0.4298 0.1486 +vt 0.4376 0.1486 +vt 0.4376 0.1564 +vt 0.4298 0.1564 +vt 0.3986 0.2423 +vt 0.4064 0.2423 +vt 0.4064 0.2501 +vt 0.3986 0.2501 +vt 0.3986 0.2110 +vt 0.4064 0.2110 +vt 0.4064 0.2189 +vt 0.3986 0.2189 +vt 0.4298 0.2111 +vt 0.4376 0.2111 +vt 0.4376 0.2189 +vt 0.4298 0.2189 +vt 0.2110 0.9294 +vt 0.2188 0.9294 +vt 0.2188 0.9372 +vt 0.2110 0.9372 +vt 0.2110 0.8981 +vt 0.2188 0.8981 +vt 0.2188 0.9059 +vt 0.2110 0.9059 +vt 0.2422 0.8981 +vt 0.2500 0.8981 +vt 0.2500 0.9059 +vt 0.2422 0.9059 +vt 0.1485 0.9293 +vt 0.1563 0.9293 +vt 0.1563 0.9372 +vt 0.1485 0.9372 +vt 0.1485 0.8981 +vt 0.1563 0.8981 +vt 0.1563 0.9059 +vt 0.1485 0.9059 +vt 0.1797 0.8981 +vt 0.1875 0.8981 +vt 0.1875 0.9059 +vt 0.1797 0.9059 +vt 0.1485 0.9918 +vt 0.1563 0.9918 +vt 0.1563 0.9996 +vt 0.1485 0.9996 +vt 0.1485 0.9606 +vt 0.1563 0.9606 +vt 0.1563 0.9684 +vt 0.1485 0.9684 +vt 0.1797 0.9606 +vt 0.1875 0.9606 +vt 0.1875 0.9684 +vt 0.1797 0.9684 +vt 0.2110 0.6795 +vt 0.2188 0.6795 +vt 0.2188 0.6873 +vt 0.2110 0.6873 +vt 0.2110 0.6483 +vt 0.2189 0.6483 +vt 0.2188 0.6561 +vt 0.2110 0.6561 +vt 0.2423 0.6483 +vt 0.2501 0.6483 +vt 0.2501 0.6561 +vt 0.2423 0.6561 +vt 0.1486 0.6795 +vt 0.1564 0.6795 +vt 0.1564 0.6873 +vt 0.1486 0.6873 +vt 0.1486 0.6482 +vt 0.1564 0.6482 +vt 0.1564 0.6560 +vt 0.1486 0.6560 +vt 0.1798 0.6482 +vt 0.1876 0.6482 +vt 0.1876 0.6561 +vt 0.1798 0.6561 +vt 0.1485 0.7419 +vt 0.1564 0.7419 +vt 0.1564 0.7497 +vt 0.1485 0.7497 +vt 0.1486 0.7107 +vt 0.1564 0.7107 +vt 0.1564 0.7185 +vt 0.1486 0.7185 +vt 0.1798 0.7107 +vt 0.1876 0.7107 +vt 0.1876 0.7185 +vt 0.1798 0.7185 +vt 0.4609 0.6796 +vt 0.4687 0.6796 +vt 0.4687 0.6874 +vt 0.4609 0.6874 +vt 0.4609 0.6483 +vt 0.4687 0.6483 +vt 0.4687 0.6561 +vt 0.4609 0.6561 +vt 0.4921 0.6483 +vt 0.5000 0.6483 +vt 0.5000 0.6562 +vt 0.4921 0.6562 +vt 0.3984 0.6795 +vt 0.4062 0.6796 +vt 0.4062 0.6874 +vt 0.3984 0.6874 +vt 0.3984 0.6483 +vt 0.4063 0.6483 +vt 0.4063 0.6561 +vt 0.3984 0.6561 +vt 0.4297 0.6483 +vt 0.4375 0.6483 +vt 0.4375 0.6561 +vt 0.4297 0.6561 +vt 0.3984 0.7420 +vt 0.4062 0.7420 +vt 0.4062 0.7498 +vt 0.3984 0.7498 +vt 0.3984 0.7108 +vt 0.4062 0.7108 +vt 0.4062 0.7186 +vt 0.3984 0.7186 +vt 0.4297 0.7108 +vt 0.4375 0.7108 +vt 0.4375 0.7186 +vt 0.4297 0.7186 +vt 0.7107 0.9295 +vt 0.7185 0.9295 +vt 0.7185 0.9373 +vt 0.7107 0.9373 +vt 0.7107 0.8983 +vt 0.7185 0.8983 +vt 0.7185 0.9061 +vt 0.7107 0.9061 +vt 0.7419 0.8983 +vt 0.7497 0.8983 +vt 0.7497 0.9061 +vt 0.7419 0.9061 +vt 0.6482 0.9295 +vt 0.6560 0.9295 +vt 0.6560 0.9373 +vt 0.6482 0.9373 +vt 0.6482 0.8983 +vt 0.6560 0.8983 +vt 0.6560 0.9061 +vt 0.6482 0.9061 +vt 0.6795 0.8983 +vt 0.6873 0.8983 +vt 0.6873 0.9061 +vt 0.6795 0.9061 +vt 0.6482 0.9920 +vt 0.6560 0.9920 +vt 0.6560 0.9998 +vt 0.6482 0.9998 +vt 0.6482 0.9607 +vt 0.6560 0.9607 +vt 0.6560 0.9685 +vt 0.6482 0.9685 +vt 0.6795 0.9607 +vt 0.6873 0.9607 +vt 0.6873 0.9685 +vt 0.6795 0.9685 +vt 0.7108 0.6796 +vt 0.7186 0.6796 +vt 0.7186 0.6875 +vt 0.7108 0.6875 +vt 0.7108 0.6484 +vt 0.7186 0.6484 +vt 0.7186 0.6562 +vt 0.7108 0.6562 +vt 0.7420 0.6484 +vt 0.7498 0.6484 +vt 0.7498 0.6562 +vt 0.7420 0.6562 +vt 0.6483 0.6796 +vt 0.6561 0.6796 +vt 0.6561 0.6874 +vt 0.6483 0.6874 +vt 0.6483 0.6484 +vt 0.6561 0.6484 +vt 0.6561 0.6562 +vt 0.6483 0.6562 +vt 0.6795 0.6484 +vt 0.6874 0.6484 +vt 0.6874 0.6562 +vt 0.6795 0.6562 +vt 0.6483 0.7421 +vt 0.6561 0.7421 +vt 0.6561 0.7499 +vt 0.6483 0.7499 +vt 0.6483 0.7109 +vt 0.6561 0.7109 +vt 0.6561 0.7187 +vt 0.6483 0.7187 +vt 0.6795 0.7109 +vt 0.6873 0.7109 +vt 0.6873 0.7187 +vt 0.6795 0.7187 +vt 0.9606 0.6797 +vt 0.9684 0.6797 +vt 0.9684 0.6875 +vt 0.9606 0.6875 +vt 0.9606 0.6485 +vt 0.9685 0.6485 +vt 0.9685 0.6563 +vt 0.9606 0.6563 +vt 0.9919 0.6485 +vt 0.9997 0.6485 +vt 0.9997 0.6563 +vt 0.9919 0.6563 +vt 0.8982 0.6797 +vt 0.9060 0.6797 +vt 0.9060 0.6875 +vt 0.8982 0.6875 +vt 0.8982 0.6485 +vt 0.9060 0.6485 +vt 0.9060 0.6563 +vt 0.8982 0.6563 +vt 0.9294 0.6485 +vt 0.9372 0.6485 +vt 0.9372 0.6563 +vt 0.9294 0.6563 +vt 0.8982 0.7422 +vt 0.9060 0.7422 +vt 0.9060 0.7500 +vt 0.8981 0.7500 +vt 0.8982 0.7109 +vt 0.9060 0.7109 +vt 0.9060 0.7187 +vt 0.8982 0.7187 +vt 0.9294 0.7109 +vt 0.9372 0.7109 +vt 0.9372 0.7188 +vt 0.9294 0.7188 +vt 0.8357 0.6797 +vt 0.8435 0.6797 +vt 0.8435 0.6875 +vt 0.8357 0.6875 +vt 0.8357 0.6485 +vt 0.8435 0.6485 +vt 0.8435 0.6563 +vt 0.8357 0.6563 +vt 0.8669 0.6485 +vt 0.8748 0.6485 +vt 0.8748 0.6563 +vt 0.8669 0.6563 +vt 0.7732 0.6797 +vt 0.7810 0.6797 +vt 0.7810 0.6875 +vt 0.7732 0.6875 +vt 0.7732 0.6484 +vt 0.7811 0.6484 +vt 0.7811 0.6562 +vt 0.7732 0.6562 +vt 0.8045 0.6484 +vt 0.8123 0.6484 +vt 0.8123 0.6563 +vt 0.8045 0.6562 +vt 0.7732 0.7421 +vt 0.7810 0.7421 +vt 0.7810 0.7499 +vt 0.7732 0.7499 +vt 0.7732 0.7109 +vt 0.7810 0.7109 +vt 0.7810 0.7187 +vt 0.7732 0.7187 +vt 0.8045 0.7109 +vt 0.8123 0.7109 +vt 0.8123 0.7187 +vt 0.8045 0.7187 +vt 0.8357 0.5548 +vt 0.8436 0.5548 +vt 0.8436 0.5626 +vt 0.8357 0.5626 +vt 0.8358 0.5235 +vt 0.8436 0.5235 +vt 0.8436 0.5313 +vt 0.8358 0.5313 +vt 0.8670 0.5235 +vt 0.8748 0.5235 +vt 0.8748 0.5313 +vt 0.8670 0.5313 +vt 0.7733 0.5547 +vt 0.7811 0.5547 +vt 0.7811 0.5625 +vt 0.7733 0.5625 +vt 0.7733 0.5235 +vt 0.7811 0.5235 +vt 0.7811 0.5313 +vt 0.7733 0.5313 +vt 0.8045 0.5235 +vt 0.8123 0.5235 +vt 0.8123 0.5313 +vt 0.8045 0.5313 +vt 0.7733 0.6172 +vt 0.7811 0.6172 +vt 0.7811 0.6250 +vt 0.7733 0.6250 +vt 0.7733 0.5860 +vt 0.7811 0.5860 +vt 0.7811 0.5938 +vt 0.7733 0.5938 +vt 0.8045 0.5860 +vt 0.8123 0.5860 +vt 0.8123 0.5938 +vt 0.8045 0.5938 +vt 0.9607 0.5548 +vt 0.9685 0.5548 +vt 0.9685 0.5626 +vt 0.9607 0.5626 +vt 0.9607 0.5236 +vt 0.9685 0.5236 +vt 0.9685 0.5314 +vt 0.9607 0.5314 +vt 0.9919 0.5236 +vt 0.9997 0.5236 +vt 0.9997 0.5314 +vt 0.9919 0.5314 +vt 0.8982 0.5548 +vt 0.9060 0.5548 +vt 0.9060 0.5626 +vt 0.8982 0.5626 +vt 0.8982 0.5235 +vt 0.9060 0.5235 +vt 0.9060 0.5313 +vt 0.8982 0.5313 +vt 0.9295 0.5235 +vt 0.9373 0.5235 +vt 0.9373 0.5314 +vt 0.9295 0.5314 +vt 0.8982 0.6172 +vt 0.9060 0.6172 +vt 0.9060 0.6250 +vt 0.8982 0.6250 +vt 0.8982 0.5860 +vt 0.9060 0.5860 +vt 0.9060 0.5938 +vt 0.8982 0.5938 +vt 0.9294 0.5860 +vt 0.9372 0.5860 +vt 0.9372 0.5938 +vt 0.9294 0.5938 +vt 0.5858 0.6796 +vt 0.5936 0.6796 +vt 0.5936 0.6874 +vt 0.5858 0.6874 +vt 0.5858 0.6484 +vt 0.5937 0.6484 +vt 0.5937 0.6562 +vt 0.5858 0.6562 +vt 0.6171 0.6484 +vt 0.6249 0.6484 +vt 0.6249 0.6562 +vt 0.6171 0.6562 +vt 0.5234 0.6796 +vt 0.5312 0.6796 +vt 0.5312 0.6874 +vt 0.5234 0.6874 +vt 0.5234 0.6484 +vt 0.5312 0.6484 +vt 0.5312 0.6562 +vt 0.5234 0.6562 +vt 0.5546 0.6484 +vt 0.5624 0.6484 +vt 0.5624 0.6562 +vt 0.5546 0.6562 +vt 0.5234 0.7421 +vt 0.5312 0.7421 +vt 0.5312 0.7499 +vt 0.5233 0.7499 +vt 0.5234 0.7108 +vt 0.5312 0.7108 +vt 0.5312 0.7186 +vt 0.5234 0.7186 +vt 0.5546 0.7108 +vt 0.5624 0.7108 +vt 0.5624 0.7186 +vt 0.5546 0.7186 +vt 0.5859 0.5547 +vt 0.5937 0.5547 +vt 0.5937 0.5625 +vt 0.5859 0.5625 +vt 0.5859 0.5234 +vt 0.5937 0.5234 +vt 0.5937 0.5312 +vt 0.5859 0.5312 +vt 0.6171 0.5234 +vt 0.6249 0.5235 +vt 0.6249 0.5313 +vt 0.6171 0.5313 +vt 0.5234 0.5547 +vt 0.5312 0.5547 +vt 0.5312 0.5625 +vt 0.5234 0.5625 +vt 0.5234 0.5234 +vt 0.5312 0.5234 +vt 0.5312 0.5312 +vt 0.5234 0.5312 +vt 0.5547 0.5234 +vt 0.5625 0.5234 +vt 0.5625 0.5312 +vt 0.5547 0.5312 +vt 0.5234 0.6171 +vt 0.5312 0.6171 +vt 0.5312 0.6249 +vt 0.5234 0.6249 +vt 0.5234 0.5859 +vt 0.5312 0.5859 +vt 0.5312 0.5937 +vt 0.5234 0.5937 +vt 0.5546 0.5859 +vt 0.5624 0.5859 +vt 0.5624 0.5937 +vt 0.5546 0.5937 +vt 0.7108 0.5547 +vt 0.7186 0.5547 +vt 0.7186 0.5625 +vt 0.7108 0.5625 +vt 0.7108 0.5235 +vt 0.7186 0.5235 +vt 0.7186 0.5313 +vt 0.7108 0.5313 +vt 0.7421 0.5235 +vt 0.7499 0.5235 +vt 0.7499 0.5313 +vt 0.7421 0.5313 +vt 0.6483 0.5547 +vt 0.6562 0.5547 +vt 0.6561 0.5625 +vt 0.6483 0.5625 +vt 0.6484 0.5235 +vt 0.6562 0.5235 +vt 0.6562 0.5313 +vt 0.6484 0.5313 +vt 0.6796 0.5235 +vt 0.6874 0.5235 +vt 0.6874 0.5313 +vt 0.6796 0.5313 +vt 0.6483 0.6172 +vt 0.6561 0.6172 +vt 0.6561 0.6250 +vt 0.6483 0.6250 +vt 0.6483 0.5859 +vt 0.6561 0.5859 +vt 0.6561 0.5937 +vt 0.6483 0.5937 +vt 0.6796 0.5859 +vt 0.6874 0.5859 +vt 0.6874 0.5937 +vt 0.6796 0.5937 +vt 0.5858 0.9295 +vt 0.5936 0.9295 +vt 0.5936 0.9373 +vt 0.5858 0.9373 +vt 0.5858 0.8982 +vt 0.5936 0.8982 +vt 0.5936 0.9061 +vt 0.5858 0.9060 +vt 0.6170 0.8982 +vt 0.6248 0.8983 +vt 0.6248 0.9061 +vt 0.6170 0.9061 +vt 0.5233 0.9295 +vt 0.5311 0.9295 +vt 0.5311 0.9373 +vt 0.5233 0.9373 +vt 0.5233 0.8982 +vt 0.5311 0.8982 +vt 0.5311 0.9060 +vt 0.5233 0.9060 +vt 0.5545 0.8982 +vt 0.5623 0.8982 +vt 0.5623 0.9060 +vt 0.5545 0.9060 +vt 0.5233 0.9919 +vt 0.5311 0.9919 +vt 0.5311 0.9997 +vt 0.5233 0.9997 +vt 0.5233 0.9607 +vt 0.5311 0.9607 +vt 0.5311 0.9685 +vt 0.5233 0.9685 +vt 0.5545 0.9607 +vt 0.5623 0.9607 +vt 0.5623 0.9685 +vt 0.5545 0.9685 +vt 0.5858 0.8045 +vt 0.5936 0.8045 +vt 0.5936 0.8124 +vt 0.5858 0.8123 +vt 0.5858 0.7733 +vt 0.5936 0.7733 +vt 0.5936 0.7811 +vt 0.5858 0.7811 +vt 0.6170 0.7733 +vt 0.6249 0.7733 +vt 0.6248 0.7811 +vt 0.6170 0.7811 +vt 0.5233 0.8045 +vt 0.5311 0.8045 +vt 0.5311 0.8123 +vt 0.5233 0.8123 +vt 0.5233 0.7733 +vt 0.5312 0.7733 +vt 0.5311 0.7811 +vt 0.5233 0.7811 +vt 0.5546 0.7733 +vt 0.5624 0.7733 +vt 0.5624 0.7811 +vt 0.5546 0.7811 +vt 0.5233 0.8670 +vt 0.5311 0.8670 +vt 0.5311 0.8748 +vt 0.5233 0.8748 +vt 0.5233 0.8358 +vt 0.5311 0.8358 +vt 0.5311 0.8436 +vt 0.5233 0.8436 +vt 0.5546 0.8358 +vt 0.5624 0.8358 +vt 0.5624 0.8436 +vt 0.5546 0.8436 +vt 0.7107 0.8046 +vt 0.7185 0.8046 +vt 0.7185 0.8124 +vt 0.7107 0.8124 +vt 0.7107 0.7733 +vt 0.7186 0.7733 +vt 0.7185 0.7812 +vt 0.7107 0.7812 +vt 0.7420 0.7734 +vt 0.7498 0.7734 +vt 0.7498 0.7812 +vt 0.7420 0.7812 +vt 0.6483 0.8046 +vt 0.6561 0.8046 +vt 0.6561 0.8124 +vt 0.6483 0.8124 +vt 0.6483 0.7733 +vt 0.6561 0.7733 +vt 0.6561 0.7811 +vt 0.6483 0.7811 +vt 0.6795 0.7733 +vt 0.6873 0.7733 +vt 0.6873 0.7811 +vt 0.6795 0.7811 +vt 0.6482 0.8670 +vt 0.6561 0.8670 +vt 0.6561 0.8748 +vt 0.6482 0.8748 +vt 0.6483 0.8358 +vt 0.6561 0.8358 +vt 0.6561 0.8436 +vt 0.6483 0.8436 +vt 0.6795 0.8358 +vt 0.6873 0.8358 +vt 0.6873 0.8436 +vt 0.6795 0.8436 +vt 0.3360 0.6795 +vt 0.3438 0.6795 +vt 0.3438 0.6873 +vt 0.3360 0.6873 +vt 0.3360 0.6483 +vt 0.3438 0.6483 +vt 0.3438 0.6561 +vt 0.3360 0.6561 +vt 0.3672 0.6483 +vt 0.3750 0.6483 +vt 0.3750 0.6561 +vt 0.3672 0.6561 +vt 0.2735 0.6795 +vt 0.2813 0.6795 +vt 0.2813 0.6873 +vt 0.2735 0.6873 +vt 0.2735 0.6483 +vt 0.2813 0.6483 +vt 0.2813 0.6561 +vt 0.2735 0.6561 +vt 0.3047 0.6483 +vt 0.3126 0.6483 +vt 0.3126 0.6561 +vt 0.3047 0.6561 +vt 0.2735 0.7420 +vt 0.2813 0.7420 +vt 0.2813 0.7498 +vt 0.2735 0.7498 +vt 0.2735 0.7107 +vt 0.2813 0.7107 +vt 0.2813 0.7186 +vt 0.2735 0.7186 +vt 0.3047 0.7108 +vt 0.3125 0.7108 +vt 0.3125 0.7186 +vt 0.3047 0.7186 +vt 0.3360 0.5546 +vt 0.3438 0.5546 +vt 0.3438 0.5624 +vt 0.3360 0.5624 +vt 0.3360 0.5234 +vt 0.3438 0.5234 +vt 0.3438 0.5312 +vt 0.3360 0.5312 +vt 0.3673 0.5234 +vt 0.3751 0.5234 +vt 0.3751 0.5312 +vt 0.3672 0.5312 +vt 0.2735 0.5546 +vt 0.2813 0.5546 +vt 0.2813 0.5624 +vt 0.2735 0.5624 +vt 0.2736 0.5233 +vt 0.2814 0.5233 +vt 0.2814 0.5312 +vt 0.2735 0.5311 +vt 0.3048 0.5233 +vt 0.3126 0.5234 +vt 0.3126 0.5312 +vt 0.3048 0.5312 +vt 0.2735 0.6170 +vt 0.2813 0.6170 +vt 0.2813 0.6249 +vt 0.2735 0.6248 +vt 0.2735 0.5858 +vt 0.2813 0.5858 +vt 0.2813 0.5936 +vt 0.2735 0.5936 +vt 0.3048 0.5858 +vt 0.3126 0.5858 +vt 0.3126 0.5936 +vt 0.3048 0.5936 +vt 0.4609 0.5546 +vt 0.4688 0.5546 +vt 0.4687 0.5624 +vt 0.4609 0.5624 +vt 0.4610 0.5234 +vt 0.4688 0.5234 +vt 0.4688 0.5312 +vt 0.4609 0.5312 +vt 0.4922 0.5234 +vt 0.5000 0.5234 +vt 0.5000 0.5312 +vt 0.4922 0.5312 +vt 0.3985 0.5546 +vt 0.4063 0.5546 +vt 0.4063 0.5624 +vt 0.3985 0.5624 +vt 0.3985 0.5234 +vt 0.4063 0.5234 +vt 0.4063 0.5312 +vt 0.3985 0.5312 +vt 0.4297 0.5234 +vt 0.4375 0.5234 +vt 0.4375 0.5312 +vt 0.4297 0.5312 +vt 0.3985 0.6171 +vt 0.4063 0.6171 +vt 0.4063 0.6249 +vt 0.3985 0.6249 +vt 0.3985 0.5858 +vt 0.4063 0.5858 +vt 0.4063 0.5937 +vt 0.3985 0.5937 +vt 0.4297 0.5859 +vt 0.4375 0.5859 +vt 0.4375 0.5937 +vt 0.4297 0.5937 +vt 0.0861 0.6794 +vt 0.0939 0.6795 +vt 0.0939 0.6873 +vt 0.0861 0.6873 +vt 0.0861 0.6482 +vt 0.0939 0.6482 +vt 0.0939 0.6560 +vt 0.0861 0.6560 +vt 0.1173 0.6482 +vt 0.1252 0.6482 +vt 0.1251 0.6560 +vt 0.1173 0.6560 +vt 0.0236 0.6794 +vt 0.0314 0.6794 +vt 0.0314 0.6872 +vt 0.0236 0.6872 +vt 0.0236 0.6482 +vt 0.0314 0.6482 +vt 0.0314 0.6560 +vt 0.0236 0.6560 +vt 0.0549 0.6482 +vt 0.0627 0.6482 +vt 0.0627 0.6560 +vt 0.0549 0.6560 +vt 0.0236 0.7419 +vt 0.0314 0.7419 +vt 0.0314 0.7497 +vt 0.0236 0.7497 +vt 0.0236 0.7107 +vt 0.0314 0.7107 +vt 0.0314 0.7185 +vt 0.0236 0.7185 +vt 0.0549 0.7107 +vt 0.0627 0.7107 +vt 0.0627 0.7185 +vt 0.0549 0.7185 +vt 0.0861 0.5545 +vt 0.0939 0.5545 +vt 0.0939 0.5623 +vt 0.0861 0.5623 +vt 0.0861 0.5233 +vt 0.0940 0.5233 +vt 0.0940 0.5311 +vt 0.0861 0.5311 +vt 0.1174 0.5233 +vt 0.1252 0.5233 +vt 0.1252 0.5311 +vt 0.1174 0.5311 +vt 0.0237 0.5545 +vt 0.0315 0.5545 +vt 0.0315 0.5623 +vt 0.0237 0.5623 +vt 0.0237 0.5233 +vt 0.0315 0.5233 +vt 0.0315 0.5311 +vt 0.0237 0.5311 +vt 0.0549 0.5233 +vt 0.0627 0.5233 +vt 0.0627 0.5311 +vt 0.0549 0.5311 +vt 0.0237 0.6170 +vt 0.0315 0.6170 +vt 0.0315 0.6248 +vt 0.0236 0.6248 +vt 0.0237 0.5857 +vt 0.0315 0.5857 +vt 0.0315 0.5935 +vt 0.0237 0.5935 +vt 0.0549 0.5857 +vt 0.0627 0.5857 +vt 0.0627 0.5935 +vt 0.0549 0.5935 +vt 0.2111 0.5546 +vt 0.2189 0.5546 +vt 0.2189 0.5624 +vt 0.2111 0.5624 +vt 0.2111 0.5233 +vt 0.2189 0.5233 +vt 0.2189 0.5311 +vt 0.2111 0.5311 +vt 0.2423 0.5233 +vt 0.2501 0.5233 +vt 0.2501 0.5311 +vt 0.2423 0.5311 +vt 0.1486 0.5545 +vt 0.1564 0.5545 +vt 0.1564 0.5623 +vt 0.1486 0.5623 +vt 0.1486 0.5233 +vt 0.1564 0.5233 +vt 0.1564 0.5311 +vt 0.1486 0.5311 +vt 0.1798 0.5233 +vt 0.1877 0.5233 +vt 0.1877 0.5311 +vt 0.1798 0.5311 +vt 0.1486 0.6170 +vt 0.1564 0.6170 +vt 0.1564 0.6248 +vt 0.1486 0.6248 +vt 0.1486 0.5858 +vt 0.1564 0.5858 +vt 0.1564 0.5936 +vt 0.1486 0.5936 +vt 0.1798 0.5858 +vt 0.1876 0.5858 +vt 0.1876 0.5936 +vt 0.1798 0.5936 +vt 0.0860 0.9293 +vt 0.0938 0.9293 +vt 0.0938 0.9371 +vt 0.0860 0.9371 +vt 0.0860 0.8981 +vt 0.0938 0.8981 +vt 0.0938 0.9059 +vt 0.0860 0.9059 +vt 0.1173 0.8981 +vt 0.1251 0.8981 +vt 0.1251 0.9059 +vt 0.1173 0.9059 +vt 0.0235 0.9293 +vt 0.0314 0.9293 +vt 0.0314 0.9371 +vt 0.0235 0.9371 +vt 0.0236 0.8981 +vt 0.0314 0.8981 +vt 0.0314 0.9059 +vt 0.0236 0.9059 +vt 0.0548 0.8981 +vt 0.0626 0.8981 +vt 0.0626 0.9059 +vt 0.0548 0.9059 +vt 0.0235 0.9918 +vt 0.0313 0.9918 +vt 0.0313 0.9996 +vt 0.0235 0.9996 +vt 0.0235 0.9605 +vt 0.0313 0.9605 +vt 0.0313 0.9683 +vt 0.0235 0.9683 +vt 0.0548 0.9605 +vt 0.0626 0.9605 +vt 0.0626 0.9684 +vt 0.0548 0.9684 +vt 0.0861 0.8044 +vt 0.0939 0.8044 +vt 0.0939 0.8122 +vt 0.0861 0.8122 +vt 0.0861 0.7732 +vt 0.0939 0.7732 +vt 0.0939 0.7810 +vt 0.0861 0.7810 +vt 0.1173 0.7732 +vt 0.1251 0.7732 +vt 0.1251 0.7810 +vt 0.1173 0.7810 +vt 0.0236 0.8044 +vt 0.0314 0.8044 +vt 0.0314 0.8122 +vt 0.0236 0.8122 +vt 0.0236 0.7731 +vt 0.0314 0.7731 +vt 0.0314 0.7809 +vt 0.0236 0.7809 +vt 0.0548 0.7731 +vt 0.0626 0.7731 +vt 0.0626 0.7810 +vt 0.0548 0.7809 +vt 0.0236 0.8668 +vt 0.0314 0.8668 +vt 0.0314 0.8746 +vt 0.0236 0.8746 +vt 0.0236 0.8356 +vt 0.0314 0.8356 +vt 0.0314 0.8434 +vt 0.0236 0.8434 +vt 0.0548 0.8356 +vt 0.0626 0.8356 +vt 0.0626 0.8434 +vt 0.0548 0.8434 +vt 0.2110 0.8044 +vt 0.2188 0.8044 +vt 0.2188 0.8122 +vt 0.2110 0.8122 +vt 0.2110 0.7732 +vt 0.2188 0.7732 +vt 0.2188 0.7810 +vt 0.2110 0.7810 +vt 0.2422 0.7732 +vt 0.2500 0.7732 +vt 0.2500 0.7810 +vt 0.2422 0.7810 +vt 0.1485 0.8044 +vt 0.1563 0.8044 +vt 0.1563 0.8122 +vt 0.1485 0.8122 +vt 0.1485 0.7732 +vt 0.1563 0.7732 +vt 0.1563 0.7810 +vt 0.1485 0.7810 +vt 0.1798 0.7732 +vt 0.1876 0.7732 +vt 0.1876 0.7810 +vt 0.1798 0.7810 +vt 0.1485 0.8669 +vt 0.1563 0.8669 +vt 0.1563 0.8747 +vt 0.1485 0.8747 +vt 0.1485 0.8356 +vt 0.1563 0.8356 +vt 0.1563 0.8434 +vt 0.1485 0.8434 +vt 0.1797 0.8356 +vt 0.1876 0.8357 +vt 0.1876 0.8435 +vt 0.1797 0.8435 +vt 0.3361 0.1798 +vt 0.3439 0.1798 +vt 0.3439 0.1876 +vt 0.3361 0.1876 +vt 0.3361 0.1486 +vt 0.3439 0.1486 +vt 0.3439 0.1564 +vt 0.3361 0.1564 +vt 0.3674 0.1486 +vt 0.3752 0.1486 +vt 0.3752 0.1564 +vt 0.3674 0.1564 +vt 0.2737 0.1798 +vt 0.2815 0.1798 +vt 0.2815 0.1876 +vt 0.2737 0.1876 +vt 0.2737 0.1485 +vt 0.2815 0.1485 +vt 0.2815 0.1564 +vt 0.2737 0.1563 +vt 0.3049 0.1485 +vt 0.3127 0.1486 +vt 0.3127 0.1564 +vt 0.3049 0.1564 +vt 0.2736 0.2422 +vt 0.2814 0.2422 +vt 0.2814 0.2501 +vt 0.2736 0.2500 +vt 0.2736 0.2110 +vt 0.2815 0.2110 +vt 0.2815 0.2188 +vt 0.2736 0.2188 +vt 0.3049 0.2110 +vt 0.3127 0.2110 +vt 0.3127 0.2188 +vt 0.3049 0.2188 +vt 0.3362 0.0549 +vt 0.3440 0.0549 +vt 0.3440 0.0627 +vt 0.3362 0.0627 +vt 0.3362 0.0236 +vt 0.3440 0.0236 +vt 0.3440 0.0314 +vt 0.3362 0.0314 +vt 0.3674 0.0236 +vt 0.3752 0.0236 +vt 0.3752 0.0314 +vt 0.3674 0.0314 +vt 0.2737 0.0548 +vt 0.2815 0.0548 +vt 0.2815 0.0627 +vt 0.2737 0.0626 +vt 0.2737 0.0236 +vt 0.2815 0.0236 +vt 0.2815 0.0314 +vt 0.2737 0.0314 +vt 0.3049 0.0236 +vt 0.3127 0.0236 +vt 0.3127 0.0314 +vt 0.3049 0.0314 +vt 0.2737 0.1173 +vt 0.2815 0.1173 +vt 0.2815 0.1251 +vt 0.2737 0.1251 +vt 0.2737 0.0861 +vt 0.2815 0.0861 +vt 0.2815 0.0939 +vt 0.2737 0.0939 +vt 0.3049 0.0861 +vt 0.3127 0.0861 +vt 0.3127 0.0939 +vt 0.3049 0.0939 +vt 0.4611 0.0549 +vt 0.4689 0.0549 +vt 0.4689 0.0627 +vt 0.4611 0.0627 +vt 0.4611 0.0237 +vt 0.4689 0.0237 +vt 0.4689 0.0315 +vt 0.4611 0.0315 +vt 0.4923 0.0237 +vt 0.5001 0.0237 +vt 0.5001 0.0315 +vt 0.4923 0.0315 +vt 0.3986 0.0549 +vt 0.4064 0.0549 +vt 0.4064 0.0627 +vt 0.3986 0.0627 +vt 0.3986 0.0236 +vt 0.4064 0.0236 +vt 0.4064 0.0315 +vt 0.3986 0.0315 +vt 0.4299 0.0237 +vt 0.4377 0.0237 +vt 0.4377 0.0315 +vt 0.4299 0.0315 +vt 0.3986 0.1173 +vt 0.4064 0.1173 +vt 0.4064 0.1252 +vt 0.3986 0.1252 +vt 0.3986 0.0861 +vt 0.4064 0.0861 +vt 0.4064 0.0939 +vt 0.3986 0.0939 +vt 0.4299 0.0861 +vt 0.4377 0.0861 +vt 0.4377 0.0939 +vt 0.4299 0.0939 +vt 0.0863 0.1797 +vt 0.0941 0.1797 +vt 0.0941 0.1875 +vt 0.0863 0.1875 +vt 0.0863 0.1485 +vt 0.0941 0.1485 +vt 0.0941 0.1563 +vt 0.0863 0.1563 +vt 0.1175 0.1485 +vt 0.1253 0.1485 +vt 0.1253 0.1563 +vt 0.1175 0.1563 +vt 0.0238 0.1797 +vt 0.0316 0.1797 +vt 0.0316 0.1875 +vt 0.0238 0.1875 +vt 0.0238 0.1485 +vt 0.0316 0.1485 +vt 0.0316 0.1563 +vt 0.0238 0.1563 +vt 0.0550 0.1485 +vt 0.0628 0.1485 +vt 0.0628 0.1563 +vt 0.0550 0.1563 +vt 0.0238 0.2422 +vt 0.0316 0.2422 +vt 0.0316 0.2500 +vt 0.0238 0.2500 +vt 0.0238 0.2109 +vt 0.0316 0.2109 +vt 0.0316 0.2187 +vt 0.0238 0.2187 +vt 0.0550 0.2109 +vt 0.0628 0.2109 +vt 0.0628 0.2187 +vt 0.0550 0.2187 +vt 0.0863 0.0548 +vt 0.0941 0.0548 +vt 0.0941 0.0626 +vt 0.0863 0.0626 +vt 0.0863 0.0236 +vt 0.0941 0.0236 +vt 0.0941 0.0314 +vt 0.0863 0.0314 +vt 0.1175 0.0236 +vt 0.1254 0.0236 +vt 0.1253 0.0314 +vt 0.1175 0.0314 +vt 0.0238 0.0548 +vt 0.0316 0.0548 +vt 0.0316 0.0626 +vt 0.0238 0.0626 +vt 0.0238 0.0235 +vt 0.0317 0.0235 +vt 0.0317 0.0313 +vt 0.0238 0.0313 +vt 0.0551 0.0235 +vt 0.0629 0.0235 +vt 0.0629 0.0314 +vt 0.0551 0.0313 +vt 0.0238 0.1172 +vt 0.0316 0.1172 +vt 0.0316 0.1250 +vt 0.0238 0.1250 +vt 0.0238 0.0860 +vt 0.0316 0.0860 +vt 0.0316 0.0938 +vt 0.0238 0.0938 +vt 0.0551 0.0860 +vt 0.0629 0.0860 +vt 0.0629 0.0938 +vt 0.0551 0.0938 +vt 0.2112 0.0548 +vt 0.2190 0.0548 +vt 0.2190 0.0626 +vt 0.2112 0.0626 +vt 0.2112 0.0236 +vt 0.2190 0.0236 +vt 0.2190 0.0314 +vt 0.2112 0.0314 +vt 0.2425 0.0236 +vt 0.2503 0.0236 +vt 0.2503 0.0314 +vt 0.2425 0.0314 +vt 0.1488 0.0548 +vt 0.1566 0.0548 +vt 0.1566 0.0626 +vt 0.1488 0.0626 +vt 0.1488 0.0236 +vt 0.1566 0.0236 +vt 0.1566 0.0314 +vt 0.1488 0.0314 +vt 0.1800 0.0236 +vt 0.1878 0.0236 +vt 0.1878 0.0314 +vt 0.1800 0.0314 +vt 0.1487 0.1173 +vt 0.1566 0.1173 +vt 0.1566 0.1251 +vt 0.1487 0.1251 +vt 0.1488 0.0860 +vt 0.1566 0.0860 +vt 0.1566 0.0938 +vt 0.1488 0.0938 +vt 0.1800 0.0860 +vt 0.1878 0.0860 +vt 0.1878 0.0939 +vt 0.1800 0.0939 +vt 0.0862 0.4296 +vt 0.0940 0.4296 +vt 0.0940 0.4374 +vt 0.0862 0.4374 +vt 0.0862 0.3983 +vt 0.0940 0.3983 +vt 0.0940 0.4062 +vt 0.0862 0.4062 +vt 0.1174 0.3984 +vt 0.1252 0.3984 +vt 0.1252 0.4062 +vt 0.1174 0.4062 +vt 0.0237 0.4296 +vt 0.0315 0.4296 +vt 0.0315 0.4374 +vt 0.0237 0.4374 +vt 0.0237 0.3983 +vt 0.0315 0.3983 +vt 0.0315 0.4061 +vt 0.0237 0.4061 +vt 0.0550 0.3983 +vt 0.0628 0.3983 +vt 0.0628 0.4061 +vt 0.0550 0.4061 +vt 0.0237 0.4920 +vt 0.0315 0.4920 +vt 0.0315 0.4998 +vt 0.0237 0.4998 +vt 0.0237 0.4608 +vt 0.0315 0.4608 +vt 0.0315 0.4686 +vt 0.0237 0.4686 +vt 0.0549 0.4608 +vt 0.0627 0.4608 +vt 0.0627 0.4686 +vt 0.0549 0.4686 +vt 0.0862 0.3046 +vt 0.0940 0.3046 +vt 0.0940 0.3125 +vt 0.0862 0.3125 +vt 0.0862 0.2734 +vt 0.0940 0.2734 +vt 0.0940 0.2812 +vt 0.0862 0.2812 +vt 0.1175 0.2734 +vt 0.1253 0.2734 +vt 0.1253 0.2812 +vt 0.1175 0.2812 +vt 0.0238 0.3046 +vt 0.0316 0.3046 +vt 0.0316 0.3124 +vt 0.0238 0.3124 +vt 0.0238 0.2734 +vt 0.0316 0.2734 +vt 0.0316 0.2812 +vt 0.0238 0.2812 +vt 0.0550 0.2734 +vt 0.0628 0.2734 +vt 0.0628 0.2812 +vt 0.0550 0.2812 +vt 0.0237 0.3671 +vt 0.0315 0.3671 +vt 0.0315 0.3749 +vt 0.0237 0.3749 +vt 0.0237 0.3359 +vt 0.0316 0.3359 +vt 0.0316 0.3437 +vt 0.0237 0.3437 +vt 0.0550 0.3359 +vt 0.0628 0.3359 +vt 0.0628 0.3437 +vt 0.0550 0.3437 +vt 0.2112 0.3047 +vt 0.2190 0.3047 +vt 0.2190 0.3125 +vt 0.2112 0.3125 +vt 0.2112 0.2735 +vt 0.2190 0.2735 +vt 0.2190 0.2813 +vt 0.2112 0.2813 +vt 0.2424 0.2735 +vt 0.2502 0.2735 +vt 0.2502 0.2813 +vt 0.2424 0.2813 +vt 0.1487 0.3047 +vt 0.1565 0.3047 +vt 0.1565 0.3125 +vt 0.1487 0.3125 +vt 0.1487 0.2734 +vt 0.1565 0.2734 +vt 0.1565 0.2812 +vt 0.1487 0.2812 +vt 0.1799 0.2734 +vt 0.1877 0.2734 +vt 0.1877 0.2813 +vt 0.1799 0.2813 +vt 0.1487 0.3671 +vt 0.1565 0.3671 +vt 0.1565 0.3749 +vt 0.1487 0.3749 +vt 0.1487 0.3359 +vt 0.1565 0.3359 +vt 0.1565 0.3437 +vt 0.1487 0.3437 +vt 0.1799 0.3359 +vt 0.1877 0.3359 +vt 0.1877 0.3437 +vt 0.1799 0.3437 +vt 0.8359 0.1799 +vt 0.8437 0.1799 +vt 0.8437 0.1878 +vt 0.8359 0.1878 +vt 0.8359 0.1487 +vt 0.8437 0.1487 +vt 0.8437 0.1565 +vt 0.8359 0.1565 +vt 0.8671 0.1487 +vt 0.8749 0.1487 +vt 0.8749 0.1565 +vt 0.8671 0.1565 +vt 0.7734 0.1799 +vt 0.7812 0.1799 +vt 0.7812 0.1877 +vt 0.7734 0.1877 +vt 0.7734 0.1487 +vt 0.7812 0.1487 +vt 0.7812 0.1565 +vt 0.7734 0.1565 +vt 0.8046 0.1487 +vt 0.8124 0.1487 +vt 0.8124 0.1565 +vt 0.8046 0.1565 +vt 0.7734 0.2424 +vt 0.7812 0.2424 +vt 0.7812 0.2502 +vt 0.7734 0.2502 +vt 0.7734 0.2112 +vt 0.7812 0.2112 +vt 0.7812 0.2190 +vt 0.7734 0.2190 +vt 0.8046 0.2112 +vt 0.8124 0.2112 +vt 0.8124 0.2190 +vt 0.8046 0.2190 +vt 0.8359 0.0550 +vt 0.8437 0.0550 +vt 0.8437 0.0628 +vt 0.8359 0.0628 +vt 0.8359 0.0238 +vt 0.8437 0.0238 +vt 0.8437 0.0316 +vt 0.8359 0.0316 +vt 0.8671 0.0238 +vt 0.8750 0.0238 +vt 0.8750 0.0316 +vt 0.8671 0.0316 +vt 0.7734 0.0550 +vt 0.7812 0.0550 +vt 0.7812 0.0628 +vt 0.7734 0.0628 +vt 0.7734 0.0238 +vt 0.7813 0.0238 +vt 0.7812 0.0316 +vt 0.7734 0.0316 +vt 0.8047 0.0238 +vt 0.8125 0.0238 +vt 0.8125 0.0316 +vt 0.8047 0.0316 +vt 0.7734 0.1175 +vt 0.7812 0.1175 +vt 0.7812 0.1253 +vt 0.7734 0.1253 +vt 0.7734 0.0862 +vt 0.7812 0.0862 +vt 0.7812 0.0940 +vt 0.7734 0.0940 +vt 0.8047 0.0862 +vt 0.8125 0.0862 +vt 0.8125 0.0940 +vt 0.8047 0.0940 +vt 0.9608 0.0550 +vt 0.9686 0.0551 +vt 0.9686 0.0629 +vt 0.9608 0.0629 +vt 0.9608 0.0238 +vt 0.9687 0.0238 +vt 0.9687 0.0316 +vt 0.9608 0.0316 +vt 0.9921 0.0238 +vt 0.9999 0.0238 +vt 0.9999 0.0316 +vt 0.9921 0.0316 +vt 0.8984 0.0550 +vt 0.9062 0.0550 +vt 0.9062 0.0628 +vt 0.8984 0.0628 +vt 0.8984 0.0238 +vt 0.9062 0.0238 +vt 0.9062 0.0316 +vt 0.8984 0.0316 +vt 0.9296 0.0238 +vt 0.9374 0.0238 +vt 0.9374 0.0316 +vt 0.9296 0.0316 +vt 0.8984 0.1175 +vt 0.9062 0.1175 +vt 0.9062 0.1253 +vt 0.8983 0.1253 +vt 0.8984 0.0863 +vt 0.9062 0.0863 +vt 0.9062 0.0941 +vt 0.8984 0.0941 +vt 0.9296 0.0863 +vt 0.9374 0.0863 +vt 0.9374 0.0941 +vt 0.9296 0.0941 +vt 0.5860 0.1799 +vt 0.5938 0.1799 +vt 0.5938 0.1877 +vt 0.5860 0.1877 +vt 0.5860 0.1486 +vt 0.5938 0.1486 +vt 0.5938 0.1564 +vt 0.5860 0.1564 +vt 0.6172 0.1486 +vt 0.6250 0.1486 +vt 0.6250 0.1565 +vt 0.6172 0.1565 +vt 0.5235 0.1798 +vt 0.5313 0.1799 +vt 0.5313 0.1877 +vt 0.5235 0.1877 +vt 0.5235 0.1486 +vt 0.5313 0.1486 +vt 0.5313 0.1564 +vt 0.5235 0.1564 +vt 0.5548 0.1486 +vt 0.5626 0.1486 +vt 0.5626 0.1564 +vt 0.5548 0.1564 +vt 0.5235 0.2423 +vt 0.5313 0.2423 +vt 0.5313 0.2501 +vt 0.5235 0.2501 +vt 0.5235 0.2111 +vt 0.5313 0.2111 +vt 0.5313 0.2189 +vt 0.5235 0.2189 +vt 0.5548 0.2111 +vt 0.5626 0.2111 +vt 0.5626 0.2189 +vt 0.5547 0.2189 +vt 0.5860 0.0549 +vt 0.5938 0.0549 +vt 0.5938 0.0627 +vt 0.5860 0.0627 +vt 0.5860 0.0237 +vt 0.5938 0.0237 +vt 0.5938 0.0315 +vt 0.5860 0.0315 +vt 0.6173 0.0237 +vt 0.6251 0.0237 +vt 0.6251 0.0315 +vt 0.6173 0.0315 +vt 0.5236 0.0549 +vt 0.5314 0.0549 +vt 0.5314 0.0627 +vt 0.5236 0.0627 +vt 0.5236 0.0237 +vt 0.5314 0.0237 +vt 0.5314 0.0315 +vt 0.5236 0.0315 +vt 0.5548 0.0237 +vt 0.5626 0.0237 +vt 0.5626 0.0315 +vt 0.5548 0.0315 +vt 0.5235 0.1174 +vt 0.5314 0.1174 +vt 0.5314 0.1252 +vt 0.5235 0.1252 +vt 0.5236 0.0861 +vt 0.5314 0.0862 +vt 0.5314 0.0940 +vt 0.5236 0.0940 +vt 0.5548 0.0862 +vt 0.5626 0.0862 +vt 0.5626 0.0940 +vt 0.5548 0.0940 +vt 0.7110 0.0550 +vt 0.7188 0.0550 +vt 0.7188 0.0628 +vt 0.7110 0.0628 +vt 0.7110 0.0237 +vt 0.7188 0.0237 +vt 0.7188 0.0315 +vt 0.7110 0.0315 +vt 0.7422 0.0237 +vt 0.7500 0.0237 +vt 0.7500 0.0316 +vt 0.7422 0.0316 +vt 0.6485 0.0550 +vt 0.6563 0.0550 +vt 0.6563 0.0628 +vt 0.6485 0.0628 +vt 0.6485 0.0237 +vt 0.6563 0.0237 +vt 0.6563 0.0315 +vt 0.6485 0.0315 +vt 0.6797 0.0237 +vt 0.6876 0.0237 +vt 0.6875 0.0315 +vt 0.6797 0.0315 +vt 0.6485 0.1174 +vt 0.6563 0.1174 +vt 0.6563 0.1252 +vt 0.6485 0.1252 +vt 0.6485 0.0862 +vt 0.6563 0.0862 +vt 0.6563 0.0940 +vt 0.6485 0.0940 +vt 0.6797 0.0862 +vt 0.6875 0.0862 +vt 0.6875 0.0940 +vt 0.6797 0.0940 +vt 0.5859 0.4297 +vt 0.5937 0.4297 +vt 0.5937 0.4375 +vt 0.5859 0.4375 +vt 0.5859 0.3985 +vt 0.5937 0.3985 +vt 0.5937 0.4063 +vt 0.5859 0.4063 +vt 0.6172 0.3985 +vt 0.6250 0.3985 +vt 0.6250 0.4063 +vt 0.6172 0.4063 +vt 0.5234 0.4297 +vt 0.5313 0.4297 +vt 0.5313 0.4375 +vt 0.5234 0.4375 +vt 0.5235 0.3985 +vt 0.5313 0.3985 +vt 0.5313 0.4063 +vt 0.5235 0.4063 +vt 0.5547 0.3985 +vt 0.5625 0.3985 +vt 0.5625 0.4063 +vt 0.5547 0.4063 +vt 0.5234 0.4922 +vt 0.5312 0.4922 +vt 0.5312 0.5000 +vt 0.5234 0.5000 +vt 0.5234 0.4610 +vt 0.5312 0.4610 +vt 0.5312 0.4688 +vt 0.5234 0.4688 +vt 0.5547 0.4610 +vt 0.5625 0.4610 +vt 0.5625 0.4688 +vt 0.5547 0.4688 +vt 0.5860 0.3048 +vt 0.5938 0.3048 +vt 0.5938 0.3126 +vt 0.5860 0.3126 +vt 0.5860 0.2736 +vt 0.5938 0.2736 +vt 0.5938 0.2814 +vt 0.5860 0.2814 +vt 0.6172 0.2736 +vt 0.6250 0.2736 +vt 0.6250 0.2814 +vt 0.6172 0.2814 +vt 0.5235 0.3048 +vt 0.5313 0.3048 +vt 0.5313 0.3126 +vt 0.5235 0.3126 +vt 0.5235 0.2736 +vt 0.5313 0.2736 +vt 0.5313 0.2814 +vt 0.5235 0.2814 +vt 0.5547 0.2736 +vt 0.5625 0.2736 +vt 0.5625 0.2814 +vt 0.5547 0.2814 +vt 0.5235 0.3673 +vt 0.5313 0.3673 +vt 0.5313 0.3751 +vt 0.5235 0.3751 +vt 0.5235 0.3360 +vt 0.5313 0.3360 +vt 0.5313 0.3438 +vt 0.5235 0.3438 +vt 0.5547 0.3360 +vt 0.5625 0.3360 +vt 0.5625 0.3438 +vt 0.5547 0.3438 +vt 0.7109 0.3048 +vt 0.7187 0.3048 +vt 0.7187 0.3127 +vt 0.7109 0.3127 +vt 0.7109 0.2736 +vt 0.7187 0.2736 +vt 0.7187 0.2814 +vt 0.7109 0.2814 +vt 0.7421 0.2736 +vt 0.7499 0.2736 +vt 0.7499 0.2814 +vt 0.7421 0.2814 +vt 0.6484 0.3048 +vt 0.6562 0.3048 +vt 0.6562 0.3126 +vt 0.6484 0.3126 +vt 0.6484 0.2736 +vt 0.6562 0.2736 +vt 0.6562 0.2814 +vt 0.6484 0.2814 +vt 0.6797 0.2736 +vt 0.6875 0.2736 +vt 0.6875 0.2814 +vt 0.6797 0.2814 +vt 0.6484 0.3673 +vt 0.6562 0.3673 +vt 0.6562 0.3751 +vt 0.6484 0.3751 +vt 0.6484 0.3361 +vt 0.6562 0.3361 +vt 0.6562 0.3439 +vt 0.6484 0.3439 +vt 0.6796 0.3361 +vt 0.6875 0.3361 +vt 0.6875 0.3439 +vt 0.6796 0.3439 +vt 0.8358 0.4298 +vt 0.8436 0.4298 +vt 0.8436 0.4376 +vt 0.8358 0.4376 +vt 0.8358 0.3986 +vt 0.8436 0.3986 +vt 0.8436 0.4064 +vt 0.8358 0.4064 +vt 0.8670 0.3986 +vt 0.8748 0.3986 +vt 0.8748 0.4064 +vt 0.8670 0.4064 +vt 0.7733 0.4298 +vt 0.7811 0.4298 +vt 0.7811 0.4376 +vt 0.7733 0.4376 +vt 0.7733 0.3986 +vt 0.7811 0.3986 +vt 0.7811 0.4064 +vt 0.7733 0.4064 +vt 0.8046 0.3986 +vt 0.8124 0.3986 +vt 0.8124 0.4064 +vt 0.8046 0.4064 +vt 0.7733 0.4923 +vt 0.7811 0.4923 +vt 0.7811 0.5001 +vt 0.7733 0.5001 +vt 0.7733 0.4610 +vt 0.7811 0.4610 +vt 0.7811 0.4688 +vt 0.7733 0.4688 +vt 0.8045 0.4610 +vt 0.8123 0.4610 +vt 0.8123 0.4689 +vt 0.8045 0.4688 +vt 0.8358 0.3049 +vt 0.8436 0.3049 +vt 0.8436 0.3127 +vt 0.8358 0.3127 +vt 0.8358 0.2736 +vt 0.8436 0.2737 +vt 0.8436 0.2815 +vt 0.8358 0.2815 +vt 0.8671 0.2737 +vt 0.8749 0.2737 +vt 0.8749 0.2815 +vt 0.8671 0.2815 +vt 0.7734 0.3049 +vt 0.7812 0.3049 +vt 0.7812 0.3127 +vt 0.7734 0.3127 +vt 0.7734 0.2736 +vt 0.7812 0.2736 +vt 0.7812 0.2814 +vt 0.7734 0.2814 +vt 0.8046 0.2736 +vt 0.8124 0.2736 +vt 0.8124 0.2814 +vt 0.8046 0.2814 +vt 0.7733 0.3673 +vt 0.7811 0.3673 +vt 0.7811 0.3751 +vt 0.7733 0.3751 +vt 0.7733 0.3361 +vt 0.7812 0.3361 +vt 0.7812 0.3439 +vt 0.7733 0.3439 +vt 0.8046 0.3361 +vt 0.8124 0.3361 +vt 0.8124 0.3439 +vt 0.8046 0.3439 +vt 0.9608 0.3049 +vt 0.9686 0.3049 +vt 0.9686 0.3127 +vt 0.9608 0.3127 +vt 0.9608 0.2737 +vt 0.9686 0.2737 +vt 0.9686 0.2815 +vt 0.9608 0.2815 +vt 0.9920 0.2737 +vt 0.9998 0.2737 +vt 0.9998 0.2815 +vt 0.9920 0.2815 +vt 0.8983 0.3049 +vt 0.9061 0.3049 +vt 0.9061 0.3127 +vt 0.8983 0.3127 +vt 0.8983 0.2737 +vt 0.9061 0.2737 +vt 0.9061 0.2815 +vt 0.8983 0.2815 +vt 0.9295 0.2737 +vt 0.9373 0.2737 +vt 0.9373 0.2815 +vt 0.9295 0.2815 +vt 0.8983 0.3674 +vt 0.9061 0.3674 +vt 0.9061 0.3752 +vt 0.8983 0.3752 +vt 0.8983 0.3361 +vt 0.9061 0.3361 +vt 0.9061 0.3439 +vt 0.8983 0.3439 +vt 0.9295 0.3361 +vt 0.9373 0.3361 +vt 0.9373 0.3440 +vt 0.9295 0.3440 +vt 0.3360 0.4297 +vt 0.3439 0.4297 +vt 0.3439 0.4375 +vt 0.3360 0.4375 +vt 0.3361 0.3984 +vt 0.3439 0.3984 +vt 0.3439 0.4062 +vt 0.3361 0.4062 +vt 0.3673 0.3984 +vt 0.3751 0.3984 +vt 0.3751 0.4062 +vt 0.3673 0.4062 +vt 0.2736 0.4296 +vt 0.2814 0.4296 +vt 0.2814 0.4375 +vt 0.2736 0.4374 +vt 0.2736 0.3984 +vt 0.2814 0.3984 +vt 0.2814 0.4062 +vt 0.2736 0.4062 +vt 0.3048 0.3984 +vt 0.3126 0.3984 +vt 0.3126 0.4062 +vt 0.3048 0.4062 +vt 0.2736 0.4921 +vt 0.2814 0.4921 +vt 0.2814 0.4999 +vt 0.2736 0.4999 +vt 0.2736 0.4609 +vt 0.2814 0.4609 +vt 0.2814 0.4687 +vt 0.2736 0.4687 +vt 0.3048 0.4609 +vt 0.3126 0.4609 +vt 0.3126 0.4687 +vt 0.3048 0.4687 +vt 0.3361 0.3047 +vt 0.3439 0.3047 +vt 0.3439 0.3125 +vt 0.3361 0.3125 +vt 0.3361 0.2735 +vt 0.3439 0.2735 +vt 0.3439 0.2813 +vt 0.3361 0.2813 +vt 0.3673 0.2735 +vt 0.3751 0.2735 +vt 0.3751 0.2813 +vt 0.3673 0.2813 +vt 0.2736 0.3047 +vt 0.2814 0.3047 +vt 0.2814 0.3125 +vt 0.2736 0.3125 +vt 0.2736 0.2735 +vt 0.2814 0.2735 +vt 0.2814 0.2813 +vt 0.2736 0.2813 +vt 0.3049 0.2735 +vt 0.3127 0.2735 +vt 0.3127 0.2813 +vt 0.3049 0.2813 +vt 0.2736 0.3672 +vt 0.2814 0.3672 +vt 0.2814 0.3750 +vt 0.2736 0.3750 +vt 0.2736 0.3359 +vt 0.2814 0.3359 +vt 0.2814 0.3437 +vt 0.2736 0.3437 +vt 0.3048 0.3359 +vt 0.3127 0.3360 +vt 0.3126 0.3438 +vt 0.3048 0.3438 +vt 0.4610 0.3048 +vt 0.4688 0.3048 +vt 0.4688 0.3126 +vt 0.4610 0.3126 +vt 0.4610 0.2735 +vt 0.4688 0.2735 +vt 0.4688 0.2813 +vt 0.4610 0.2813 +vt 0.4923 0.2735 +vt 0.5001 0.2735 +vt 0.5001 0.2814 +vt 0.4923 0.2813 +vt 0.3986 0.3047 +vt 0.4064 0.3047 +vt 0.4064 0.3126 +vt 0.3986 0.3126 +vt 0.3986 0.2735 +vt 0.4064 0.2735 +vt 0.4064 0.2813 +vt 0.3986 0.2813 +vt 0.4298 0.2735 +vt 0.4376 0.2735 +vt 0.4376 0.2813 +vt 0.4298 0.2813 +vt 0.3985 0.3672 +vt 0.4063 0.3672 +vt 0.4063 0.3750 +vt 0.3985 0.3750 +vt 0.3985 0.3360 +vt 0.4064 0.3360 +vt 0.4063 0.3438 +vt 0.3985 0.3438 +vt 0.4298 0.3360 +vt 0.4376 0.3360 +vt 0.4376 0.3438 +vt 0.4298 0.3438 +vt 0.3359 0.9294 +vt 0.3437 0.9294 +vt 0.3437 0.9372 +vt 0.3359 0.9372 +vt 0.3359 0.8982 +vt 0.3437 0.8982 +vt 0.3437 0.9060 +vt 0.3359 0.9060 +vt 0.3671 0.8982 +vt 0.3749 0.8982 +vt 0.3749 0.9060 +vt 0.3671 0.9060 +vt 0.2734 0.9294 +vt 0.2812 0.9294 +vt 0.2812 0.9372 +vt 0.2734 0.9372 +vt 0.2734 0.8981 +vt 0.2812 0.8981 +vt 0.2812 0.9060 +vt 0.2734 0.9060 +vt 0.3047 0.8982 +vt 0.3125 0.8982 +vt 0.3125 0.9060 +vt 0.3047 0.9060 +vt 0.2734 0.9918 +vt 0.2812 0.9919 +vt 0.2812 0.9997 +vt 0.2734 0.9997 +vt 0.2734 0.9606 +vt 0.2812 0.9606 +vt 0.2812 0.9684 +vt 0.2734 0.9684 +vt 0.3046 0.9606 +vt 0.3125 0.9606 +vt 0.3125 0.9684 +vt 0.3046 0.9684 +vt 0.3359 0.8045 +vt 0.3437 0.8045 +vt 0.3437 0.8123 +vt 0.3359 0.8123 +vt 0.3359 0.7732 +vt 0.3437 0.7732 +vt 0.3437 0.7810 +vt 0.3359 0.7810 +vt 0.3672 0.7732 +vt 0.3750 0.7732 +vt 0.3750 0.7811 +vt 0.3672 0.7810 +vt 0.2735 0.8044 +vt 0.2813 0.8044 +vt 0.2813 0.8123 +vt 0.2735 0.8123 +vt 0.2735 0.7732 +vt 0.2813 0.7732 +vt 0.2813 0.7810 +vt 0.2735 0.7810 +vt 0.3047 0.7732 +vt 0.3125 0.7732 +vt 0.3125 0.7810 +vt 0.3047 0.7810 +vt 0.2734 0.8669 +vt 0.2813 0.8669 +vt 0.2812 0.8747 +vt 0.2734 0.8747 +vt 0.2735 0.8357 +vt 0.2813 0.8357 +vt 0.2813 0.8435 +vt 0.2734 0.8435 +vt 0.3047 0.8357 +vt 0.3125 0.8357 +vt 0.3125 0.8435 +vt 0.3047 0.8435 +vt 0.4609 0.8045 +vt 0.4687 0.8045 +vt 0.4687 0.8123 +vt 0.4609 0.8123 +vt 0.4609 0.7733 +vt 0.4687 0.7733 +vt 0.4687 0.7811 +vt 0.4609 0.7811 +vt 0.4921 0.7733 +vt 0.4999 0.7733 +vt 0.4999 0.7811 +vt 0.4921 0.7811 +vt 0.3984 0.8045 +vt 0.4062 0.8045 +vt 0.4062 0.8123 +vt 0.3984 0.8123 +vt 0.3984 0.7732 +vt 0.4062 0.7733 +vt 0.4062 0.7811 +vt 0.3984 0.7811 +vt 0.4296 0.7733 +vt 0.4374 0.7733 +vt 0.4374 0.7811 +vt 0.4296 0.7811 +vt 0.3984 0.8670 +vt 0.4062 0.8670 +vt 0.4062 0.8748 +vt 0.3984 0.8748 +vt 0.3984 0.8357 +vt 0.4062 0.8357 +vt 0.4062 0.8435 +vt 0.3984 0.8435 +vt 0.4296 0.8357 +vt 0.4374 0.8357 +vt 0.4374 0.8435 +vt 0.4296 0.8435 +vt 0.8356 0.9295 +vt 0.8434 0.9296 +vt 0.8434 0.9374 +vt 0.8356 0.9374 +vt 0.8356 0.8983 +vt 0.8434 0.8983 +vt 0.8434 0.9061 +vt 0.8356 0.9061 +vt 0.8669 0.8983 +vt 0.8747 0.8983 +vt 0.8747 0.9061 +vt 0.8669 0.9061 +vt 0.7732 0.9295 +vt 0.7810 0.9295 +vt 0.7810 0.9373 +vt 0.7732 0.9373 +vt 0.7732 0.8983 +vt 0.7810 0.8983 +vt 0.7810 0.9061 +vt 0.7732 0.9061 +vt 0.8044 0.8983 +vt 0.8122 0.8983 +vt 0.8122 0.9061 +vt 0.8044 0.9061 +vt 0.7731 0.9920 +vt 0.7810 0.9920 +vt 0.7809 0.9998 +vt 0.7731 0.9998 +vt 0.7732 0.9608 +vt 0.7810 0.9608 +vt 0.7810 0.9686 +vt 0.7731 0.9686 +vt 0.8044 0.9608 +vt 0.8122 0.9608 +vt 0.8122 0.9686 +vt 0.8044 0.9686 +vt 0.8357 0.8046 +vt 0.8435 0.8046 +vt 0.8435 0.8124 +vt 0.8357 0.8124 +vt 0.8357 0.7734 +vt 0.8435 0.7734 +vt 0.8435 0.7812 +vt 0.8357 0.7812 +vt 0.8669 0.7734 +vt 0.8747 0.7734 +vt 0.8747 0.7812 +vt 0.8669 0.7812 +vt 0.7732 0.8046 +vt 0.7810 0.8046 +vt 0.7810 0.8124 +vt 0.7732 0.8124 +vt 0.7732 0.7734 +vt 0.7810 0.7734 +vt 0.7810 0.7812 +vt 0.7732 0.7812 +vt 0.8044 0.7734 +vt 0.8123 0.7734 +vt 0.8122 0.7812 +vt 0.8044 0.7812 +vt 0.7732 0.8671 +vt 0.7810 0.8671 +vt 0.7810 0.8749 +vt 0.7732 0.8749 +vt 0.7732 0.8358 +vt 0.7810 0.8358 +vt 0.7810 0.8436 +vt 0.7732 0.8436 +vt 0.8044 0.8358 +vt 0.8122 0.8358 +vt 0.8122 0.8437 +vt 0.8044 0.8436 +vt 0.9606 0.8047 +vt 0.9684 0.8047 +vt 0.9684 0.8125 +vt 0.9606 0.8125 +vt 0.9606 0.7734 +vt 0.9684 0.7734 +vt 0.9684 0.7812 +vt 0.9606 0.7812 +vt 0.9918 0.7734 +vt 0.9996 0.7734 +vt 0.9996 0.7812 +vt 0.9918 0.7812 +vt 0.8981 0.8046 +vt 0.9059 0.8046 +vt 0.9059 0.8124 +vt 0.8981 0.8124 +vt 0.8981 0.7734 +vt 0.9059 0.7734 +vt 0.9059 0.7812 +vt 0.8981 0.7812 +vt 0.9294 0.7734 +vt 0.9372 0.7734 +vt 0.9372 0.7812 +vt 0.9294 0.7812 +vt 0.8981 0.8671 +vt 0.9059 0.8671 +vt 0.9059 0.8749 +vt 0.8981 0.8749 +vt 0.8981 0.8359 +vt 0.9059 0.8359 +vt 0.9059 0.8437 +vt 0.8981 0.8437 +vt 0.9294 0.8359 +vt 0.9372 0.8359 +vt 0.9372 0.8437 +vt 0.9294 0.8437 +vt 0.9606 0.8671 +vt 0.9684 0.8671 +vt 0.9684 0.8749 +vt 0.9606 0.8749 +vt 0.9606 0.8359 +vt 0.9684 0.8359 +vt 0.9684 0.8437 +vt 0.9606 0.8437 +vt 0.9918 0.8359 +vt 0.9996 0.8359 +vt 0.9996 0.8437 +vt 0.9918 0.8437 +vt 0.8356 0.8671 +vt 0.8435 0.8671 +vt 0.8435 0.8749 +vt 0.8356 0.8749 +vt 0.8357 0.8358 +vt 0.8435 0.8359 +vt 0.8435 0.8437 +vt 0.8357 0.8437 +vt 0.8669 0.8359 +vt 0.8747 0.8359 +vt 0.8747 0.8437 +vt 0.8669 0.8437 +vt 0.8356 0.9920 +vt 0.8434 0.9920 +vt 0.8434 0.9998 +vt 0.8356 0.9998 +vt 0.8356 0.9608 +vt 0.8434 0.9608 +vt 0.8434 0.9686 +vt 0.8356 0.9686 +vt 0.8669 0.9608 +vt 0.8747 0.9608 +vt 0.8747 0.9686 +vt 0.8668 0.9686 +vt 0.4608 0.8670 +vt 0.4687 0.8670 +vt 0.4687 0.8748 +vt 0.4608 0.8748 +vt 0.4609 0.8357 +vt 0.4687 0.8357 +vt 0.4687 0.8435 +vt 0.4609 0.8435 +vt 0.4921 0.8357 +vt 0.4999 0.8357 +vt 0.4999 0.8436 +vt 0.4921 0.8436 +vt 0.3359 0.8669 +vt 0.3437 0.8669 +vt 0.3437 0.8747 +vt 0.3359 0.8747 +vt 0.3359 0.8357 +vt 0.3437 0.8357 +vt 0.3437 0.8435 +vt 0.3359 0.8435 +vt 0.3672 0.8357 +vt 0.3750 0.8357 +vt 0.3750 0.8435 +vt 0.3672 0.8435 +vt 0.3359 0.9919 +vt 0.3437 0.9919 +vt 0.3437 0.9997 +vt 0.3359 0.9997 +vt 0.3359 0.9606 +vt 0.3437 0.9606 +vt 0.3437 0.9684 +vt 0.3359 0.9684 +vt 0.3671 0.9606 +vt 0.3749 0.9606 +vt 0.3749 0.9685 +vt 0.3671 0.9685 +vt 0.4610 0.3672 +vt 0.4688 0.3672 +vt 0.4688 0.3750 +vt 0.4610 0.3750 +vt 0.4610 0.3360 +vt 0.4688 0.3360 +vt 0.4688 0.3438 +vt 0.4610 0.3438 +vt 0.4922 0.3360 +vt 0.5001 0.3360 +vt 0.5001 0.3438 +vt 0.4922 0.3438 +vt 0.3361 0.3672 +vt 0.3439 0.3672 +vt 0.3439 0.3750 +vt 0.3361 0.3750 +vt 0.3361 0.3360 +vt 0.3439 0.3360 +vt 0.3439 0.3438 +vt 0.3361 0.3438 +vt 0.3673 0.3360 +vt 0.3751 0.3360 +vt 0.3751 0.3438 +vt 0.3673 0.3438 +vt 0.3360 0.4921 +vt 0.3438 0.4921 +vt 0.3438 0.4999 +vt 0.3360 0.4999 +vt 0.3360 0.4609 +vt 0.3438 0.4609 +vt 0.3438 0.4687 +vt 0.3360 0.4687 +vt 0.3673 0.4609 +vt 0.3751 0.4609 +vt 0.3751 0.4687 +vt 0.3673 0.4687 +vt 0.9607 0.3674 +vt 0.9685 0.3674 +vt 0.9685 0.3752 +vt 0.9607 0.3752 +vt 0.9607 0.3362 +vt 0.9686 0.3362 +vt 0.9686 0.3440 +vt 0.9607 0.3440 +vt 0.9920 0.3362 +vt 0.9998 0.3362 +vt 0.9998 0.3440 +vt 0.9920 0.3440 +vt 0.8358 0.3673 +vt 0.8436 0.3674 +vt 0.8436 0.3752 +vt 0.8358 0.3752 +vt 0.8358 0.3361 +vt 0.8436 0.3361 +vt 0.8436 0.3439 +vt 0.8358 0.3439 +vt 0.8670 0.3361 +vt 0.8749 0.3361 +vt 0.8749 0.3439 +vt 0.8670 0.3439 +vt 0.8358 0.4923 +vt 0.8436 0.4923 +vt 0.8436 0.5001 +vt 0.8358 0.5001 +vt 0.8358 0.4611 +vt 0.8436 0.4611 +vt 0.8436 0.4689 +vt 0.8358 0.4689 +vt 0.8670 0.4611 +vt 0.8748 0.4611 +vt 0.8748 0.4689 +vt 0.8670 0.4689 +vt 0.7109 0.3673 +vt 0.7187 0.3673 +vt 0.7187 0.3751 +vt 0.7109 0.3751 +vt 0.7109 0.3361 +vt 0.7187 0.3361 +vt 0.7187 0.3439 +vt 0.7109 0.3439 +vt 0.7421 0.3361 +vt 0.7499 0.3361 +vt 0.7499 0.3439 +vt 0.7421 0.3439 +vt 0.5859 0.3673 +vt 0.5937 0.3673 +vt 0.5937 0.3751 +vt 0.5859 0.3751 +vt 0.5859 0.3360 +vt 0.5938 0.3360 +vt 0.5938 0.3438 +vt 0.5859 0.3438 +vt 0.6172 0.3360 +vt 0.6250 0.3360 +vt 0.6250 0.3439 +vt 0.6172 0.3439 +vt 0.5859 0.4922 +vt 0.5937 0.4922 +vt 0.5937 0.5000 +vt 0.5859 0.5000 +vt 0.5859 0.4610 +vt 0.5937 0.4610 +vt 0.5937 0.4688 +vt 0.5859 0.4688 +vt 0.6171 0.4610 +vt 0.6249 0.4610 +vt 0.6249 0.4688 +vt 0.6171 0.4688 +vt 0.7109 0.1174 +vt 0.7188 0.1174 +vt 0.7188 0.1253 +vt 0.7109 0.1252 +vt 0.7110 0.0862 +vt 0.7188 0.0862 +vt 0.7188 0.0940 +vt 0.7110 0.0940 +vt 0.7422 0.0862 +vt 0.7500 0.0862 +vt 0.7500 0.0940 +vt 0.7422 0.0940 +vt 0.5860 0.1174 +vt 0.5938 0.1174 +vt 0.5938 0.1252 +vt 0.5860 0.1252 +vt 0.5860 0.0862 +vt 0.5938 0.0862 +vt 0.5938 0.0940 +vt 0.5860 0.0940 +vt 0.6173 0.0862 +vt 0.6251 0.0862 +vt 0.6251 0.0940 +vt 0.6173 0.0940 +vt 0.5860 0.2423 +vt 0.5938 0.2423 +vt 0.5938 0.2501 +vt 0.5860 0.2501 +vt 0.5860 0.2111 +vt 0.5938 0.2111 +vt 0.5938 0.2189 +vt 0.5860 0.2189 +vt 0.6172 0.2111 +vt 0.6250 0.2111 +vt 0.6250 0.2189 +vt 0.6172 0.2189 +vt 0.9608 0.1175 +vt 0.9686 0.1175 +vt 0.9686 0.1253 +vt 0.9608 0.1253 +vt 0.9608 0.0863 +vt 0.9686 0.0863 +vt 0.9686 0.0941 +vt 0.9608 0.0941 +vt 0.9921 0.0863 +vt 0.9999 0.0863 +vt 0.9999 0.0941 +vt 0.9921 0.0941 +vt 0.8359 0.1175 +vt 0.8437 0.1175 +vt 0.8437 0.1253 +vt 0.8359 0.1253 +vt 0.8359 0.0862 +vt 0.8437 0.0862 +vt 0.8437 0.0941 +vt 0.8359 0.0941 +vt 0.8671 0.0863 +vt 0.8749 0.0863 +vt 0.8749 0.0941 +vt 0.8671 0.0941 +vt 0.8358 0.2424 +vt 0.8437 0.2424 +vt 0.8437 0.2502 +vt 0.8358 0.2502 +vt 0.8359 0.2112 +vt 0.8437 0.2112 +vt 0.8437 0.2190 +vt 0.8359 0.2190 +vt 0.8671 0.2112 +vt 0.8749 0.2112 +vt 0.8749 0.2190 +vt 0.8671 0.2190 +vt 0.2111 0.3672 +vt 0.2189 0.3672 +vt 0.2189 0.3750 +vt 0.2111 0.3750 +vt 0.2111 0.3359 +vt 0.2190 0.3359 +vt 0.2189 0.3437 +vt 0.2111 0.3437 +vt 0.2424 0.3359 +vt 0.2502 0.3359 +vt 0.2502 0.3437 +vt 0.2424 0.3437 +vt 0.0862 0.3671 +vt 0.0940 0.3671 +vt 0.0940 0.3749 +vt 0.0862 0.3749 +vt 0.0862 0.3359 +vt 0.0940 0.3359 +vt 0.0940 0.3437 +vt 0.0862 0.3437 +vt 0.1174 0.3359 +vt 0.1253 0.3359 +vt 0.1252 0.3437 +vt 0.1174 0.3437 +vt 0.0862 0.4920 +vt 0.0940 0.4920 +vt 0.0940 0.4999 +vt 0.0862 0.4999 +vt 0.0862 0.4608 +vt 0.0940 0.4608 +vt 0.0940 0.4686 +vt 0.0862 0.4686 +vt 0.1174 0.4608 +vt 0.1252 0.4608 +vt 0.1252 0.4686 +vt 0.1174 0.4686 +vt 0.2112 0.1173 +vt 0.2190 0.1173 +vt 0.2190 0.1251 +vt 0.2112 0.1251 +vt 0.2112 0.0861 +vt 0.2190 0.0861 +vt 0.2190 0.0939 +vt 0.2112 0.0939 +vt 0.2425 0.0861 +vt 0.2503 0.0861 +vt 0.2503 0.0939 +vt 0.2425 0.0939 +vt 0.0863 0.1172 +vt 0.0941 0.1173 +vt 0.0941 0.1251 +vt 0.0863 0.1251 +vt 0.0863 0.0860 +vt 0.0941 0.0860 +vt 0.0941 0.0938 +vt 0.0863 0.0938 +vt 0.1175 0.0860 +vt 0.1253 0.0860 +vt 0.1253 0.0938 +vt 0.1175 0.0938 +vt 0.0862 0.2422 +vt 0.0940 0.2422 +vt 0.0940 0.2500 +vt 0.0862 0.2500 +vt 0.0863 0.2109 +vt 0.0941 0.2109 +vt 0.0941 0.2188 +vt 0.0862 0.2188 +vt 0.1175 0.2110 +vt 0.1253 0.2110 +vt 0.1253 0.2188 +vt 0.1175 0.2188 +vt 0.4611 0.1174 +vt 0.4689 0.1174 +vt 0.4689 0.1252 +vt 0.4611 0.1252 +vt 0.4611 0.0861 +vt 0.4689 0.0861 +vt 0.4689 0.0939 +vt 0.4611 0.0939 +vt 0.4923 0.0861 +vt 0.5001 0.0861 +vt 0.5001 0.0940 +vt 0.4923 0.0939 +vt 0.3361 0.1173 +vt 0.3440 0.1173 +vt 0.3440 0.1251 +vt 0.3361 0.1251 +vt 0.3362 0.0861 +vt 0.3440 0.0861 +vt 0.3440 0.0939 +vt 0.3362 0.0939 +vt 0.3674 0.0861 +vt 0.3752 0.0861 +vt 0.3752 0.0939 +vt 0.3674 0.0939 +vt 0.3361 0.2423 +vt 0.3439 0.2423 +vt 0.3439 0.2501 +vt 0.3361 0.2501 +vt 0.3361 0.2110 +vt 0.3439 0.2110 +vt 0.3439 0.2188 +vt 0.3361 0.2188 +vt 0.3673 0.2110 +vt 0.3752 0.2110 +vt 0.3752 0.2188 +vt 0.3673 0.2188 +vt 0.2110 0.8669 +vt 0.2188 0.8669 +vt 0.2188 0.8747 +vt 0.2110 0.8747 +vt 0.2110 0.8357 +vt 0.2188 0.8357 +vt 0.2188 0.8435 +vt 0.2110 0.8435 +vt 0.2422 0.8357 +vt 0.2500 0.8357 +vt 0.2500 0.8435 +vt 0.2422 0.8435 +vt 0.0860 0.8669 +vt 0.0938 0.8669 +vt 0.0938 0.8747 +vt 0.0860 0.8747 +vt 0.0860 0.8356 +vt 0.0939 0.8356 +vt 0.0939 0.8434 +vt 0.0860 0.8434 +vt 0.1173 0.8356 +vt 0.1251 0.8356 +vt 0.1251 0.8434 +vt 0.1173 0.8434 +vt 0.0860 0.9918 +vt 0.0938 0.9918 +vt 0.0938 0.9996 +vt 0.0860 0.9996 +vt 0.0860 0.9606 +vt 0.0938 0.9606 +vt 0.0938 0.9684 +vt 0.0860 0.9684 +vt 0.1172 0.9606 +vt 0.1251 0.9606 +vt 0.1250 0.9684 +vt 0.1172 0.9684 +vt 0.2111 0.6170 +vt 0.2189 0.6170 +vt 0.2189 0.6248 +vt 0.2111 0.6248 +vt 0.2111 0.5858 +vt 0.2189 0.5858 +vt 0.2189 0.5936 +vt 0.2111 0.5936 +vt 0.2423 0.5858 +vt 0.2501 0.5858 +vt 0.2501 0.5936 +vt 0.2423 0.5936 +vt 0.0861 0.6170 +vt 0.0939 0.6170 +vt 0.0939 0.6248 +vt 0.0861 0.6248 +vt 0.0861 0.5857 +vt 0.0939 0.5857 +vt 0.0939 0.5936 +vt 0.0861 0.5936 +vt 0.1174 0.5858 +vt 0.1252 0.5858 +vt 0.1252 0.5936 +vt 0.1174 0.5936 +vt 0.0861 0.7419 +vt 0.0939 0.7419 +vt 0.0939 0.7497 +vt 0.0861 0.7497 +vt 0.0861 0.7107 +vt 0.0939 0.7107 +vt 0.0939 0.7185 +vt 0.0861 0.7185 +vt 0.1173 0.7107 +vt 0.1251 0.7107 +vt 0.1251 0.7185 +vt 0.1173 0.7185 +vt 0.4609 0.6171 +vt 0.4687 0.6171 +vt 0.4687 0.6249 +vt 0.4609 0.6249 +vt 0.4609 0.5859 +vt 0.4687 0.5859 +vt 0.4687 0.5937 +vt 0.4609 0.5937 +vt 0.4922 0.5859 +vt 0.5000 0.5859 +vt 0.5000 0.5937 +vt 0.4922 0.5937 +vt 0.3360 0.6171 +vt 0.3438 0.6171 +vt 0.3438 0.6249 +vt 0.3360 0.6249 +vt 0.3360 0.5858 +vt 0.3438 0.5858 +vt 0.3438 0.5936 +vt 0.3360 0.5936 +vt 0.3672 0.5858 +vt 0.3750 0.5858 +vt 0.3750 0.5936 +vt 0.3672 0.5936 +vt 0.3359 0.7420 +vt 0.3438 0.7420 +vt 0.3438 0.7498 +vt 0.3359 0.7498 +vt 0.3360 0.7108 +vt 0.3438 0.7108 +vt 0.3438 0.7186 +vt 0.3360 0.7186 +vt 0.3672 0.7108 +vt 0.3750 0.7108 +vt 0.3750 0.7186 +vt 0.3672 0.7186 +vt 0.7107 0.8670 +vt 0.7185 0.8670 +vt 0.7185 0.8749 +vt 0.7107 0.8749 +vt 0.7107 0.8358 +vt 0.7185 0.8358 +vt 0.7185 0.8436 +vt 0.7107 0.8436 +vt 0.7420 0.8358 +vt 0.7498 0.8358 +vt 0.7498 0.8436 +vt 0.7420 0.8436 +vt 0.5858 0.8670 +vt 0.5936 0.8670 +vt 0.5936 0.8748 +vt 0.5858 0.8748 +vt 0.5858 0.8358 +vt 0.5936 0.8358 +vt 0.5936 0.8436 +vt 0.5858 0.8436 +vt 0.6170 0.8358 +vt 0.6248 0.8358 +vt 0.6248 0.8436 +vt 0.6170 0.8436 +vt 0.5857 0.9919 +vt 0.5936 0.9919 +vt 0.5935 0.9998 +vt 0.5857 0.9997 +vt 0.5858 0.9607 +vt 0.5936 0.9607 +vt 0.5936 0.9685 +vt 0.5858 0.9685 +vt 0.6170 0.9607 +vt 0.6248 0.9607 +vt 0.6248 0.9685 +vt 0.6170 0.9685 +vt 0.7108 0.6172 +vt 0.7186 0.6172 +vt 0.7186 0.6250 +vt 0.7108 0.6250 +vt 0.7108 0.5859 +vt 0.7186 0.5859 +vt 0.7186 0.5938 +vt 0.7108 0.5938 +vt 0.7420 0.5860 +vt 0.7498 0.5860 +vt 0.7498 0.5938 +vt 0.7420 0.5938 +vt 0.5859 0.6171 +vt 0.5937 0.6171 +vt 0.5937 0.6249 +vt 0.5859 0.6249 +vt 0.5859 0.5859 +vt 0.5937 0.5859 +vt 0.5937 0.5937 +vt 0.5859 0.5937 +vt 0.6171 0.5859 +vt 0.6249 0.5859 +vt 0.6249 0.5937 +vt 0.6171 0.5937 +vt 0.5858 0.7421 +vt 0.5936 0.7421 +vt 0.5936 0.7499 +vt 0.5858 0.7499 +vt 0.5858 0.7108 +vt 0.5936 0.7108 +vt 0.5936 0.7187 +vt 0.5858 0.7186 +vt 0.6171 0.7108 +vt 0.6249 0.7109 +vt 0.6249 0.7187 +vt 0.6171 0.7187 +vt 0.9607 0.6173 +vt 0.9685 0.6173 +vt 0.9685 0.6251 +vt 0.9607 0.6251 +vt 0.9607 0.5860 +vt 0.9685 0.5860 +vt 0.9685 0.5938 +vt 0.9607 0.5938 +vt 0.9919 0.5860 +vt 0.9997 0.5860 +vt 0.9997 0.5938 +vt 0.9919 0.5938 +vt 0.8357 0.6172 +vt 0.8435 0.6172 +vt 0.8435 0.6250 +vt 0.8357 0.6250 +vt 0.8357 0.5860 +vt 0.8435 0.5860 +vt 0.8435 0.5938 +vt 0.8357 0.5938 +vt 0.8670 0.5860 +vt 0.8748 0.5860 +vt 0.8748 0.5938 +vt 0.8670 0.5938 +vt 0.8357 0.7422 +vt 0.8435 0.7422 +vt 0.8435 0.7500 +vt 0.8357 0.7500 +vt 0.8357 0.7109 +vt 0.8435 0.7109 +vt 0.8435 0.7187 +vt 0.8357 0.7187 +vt 0.8669 0.7109 +vt 0.8747 0.7109 +vt 0.8747 0.7187 +vt 0.8669 0.7187 +vt 0.9606 0.7422 +vt 0.9684 0.7422 +vt 0.9684 0.7500 +vt 0.9606 0.7500 +vt 0.9606 0.7110 +vt 0.9684 0.7110 +vt 0.9684 0.7188 +vt 0.9606 0.7188 +vt 0.9919 0.7110 +vt 0.9997 0.7110 +vt 0.9997 0.7188 +vt 0.9919 0.7188 +vt 0.7108 0.7421 +vt 0.7186 0.7421 +vt 0.7186 0.7499 +vt 0.7107 0.7499 +vt 0.7108 0.7109 +vt 0.7186 0.7109 +vt 0.7186 0.7187 +vt 0.7108 0.7187 +vt 0.7420 0.7109 +vt 0.7498 0.7109 +vt 0.7498 0.7187 +vt 0.7420 0.7187 +vt 0.7107 0.9920 +vt 0.7185 0.9920 +vt 0.7185 0.9998 +vt 0.7107 0.9998 +vt 0.7107 0.9607 +vt 0.7185 0.9607 +vt 0.7185 0.9686 +vt 0.7107 0.9686 +vt 0.7419 0.9608 +vt 0.7497 0.9608 +vt 0.7497 0.9686 +vt 0.7419 0.9686 +vt 0.4609 0.7420 +vt 0.4687 0.7420 +vt 0.4687 0.7498 +vt 0.4609 0.7498 +vt 0.4609 0.7108 +vt 0.4687 0.7108 +vt 0.4687 0.7186 +vt 0.4609 0.7186 +vt 0.4921 0.7108 +vt 0.4999 0.7108 +vt 0.4999 0.7186 +vt 0.4921 0.7186 +vt 0.2110 0.7420 +vt 0.2188 0.7420 +vt 0.2188 0.7498 +vt 0.2110 0.7498 +vt 0.2110 0.7107 +vt 0.2188 0.7107 +vt 0.2188 0.7185 +vt 0.2110 0.7185 +vt 0.2423 0.7107 +vt 0.2501 0.7107 +vt 0.2501 0.7185 +vt 0.2423 0.7185 +vt 0.2109 0.9918 +vt 0.2187 0.9918 +vt 0.2187 0.9996 +vt 0.2109 0.9996 +vt 0.2109 0.9606 +vt 0.2188 0.9606 +vt 0.2188 0.9684 +vt 0.2109 0.9684 +vt 0.2422 0.9606 +vt 0.2500 0.9606 +vt 0.2500 0.9684 +vt 0.2422 0.9684 +vt 0.4610 0.2423 +vt 0.4688 0.2423 +vt 0.4688 0.2501 +vt 0.4610 0.2501 +vt 0.4610 0.2111 +vt 0.4689 0.2111 +vt 0.4689 0.2189 +vt 0.4610 0.2189 +vt 0.4923 0.2111 +vt 0.5001 0.2111 +vt 0.5001 0.2189 +vt 0.4923 0.2189 +vt 0.2112 0.2422 +vt 0.2190 0.2422 +vt 0.2190 0.2500 +vt 0.2112 0.2500 +vt 0.2112 0.2110 +vt 0.2190 0.2110 +vt 0.2190 0.2188 +vt 0.2112 0.2188 +vt 0.2424 0.2110 +vt 0.2502 0.2110 +vt 0.2502 0.2188 +vt 0.2424 0.2188 +vt 0.2111 0.4921 +vt 0.2189 0.4921 +vt 0.2189 0.4999 +vt 0.2111 0.4999 +vt 0.2111 0.4609 +vt 0.2189 0.4609 +vt 0.2189 0.4687 +vt 0.2111 0.4687 +vt 0.2423 0.4609 +vt 0.2501 0.4609 +vt 0.2501 0.4687 +vt 0.2423 0.4687 +vt 0.9608 0.2425 +vt 0.9686 0.2425 +vt 0.9686 0.2503 +vt 0.9608 0.2503 +vt 0.9608 0.2112 +vt 0.9686 0.2112 +vt 0.9686 0.2190 +vt 0.9608 0.2190 +vt 0.9920 0.2112 +vt 0.9998 0.2112 +vt 0.9998 0.2190 +vt 0.9920 0.2190 +vt 0.7109 0.2424 +vt 0.7187 0.2424 +vt 0.7187 0.2502 +vt 0.7109 0.2502 +vt 0.7109 0.2111 +vt 0.7187 0.2111 +vt 0.7187 0.2190 +vt 0.7109 0.2189 +vt 0.7422 0.2112 +vt 0.7500 0.2112 +vt 0.7500 0.2190 +vt 0.7421 0.2190 +vt 0.7108 0.4922 +vt 0.7186 0.4922 +vt 0.7186 0.5001 +vt 0.7108 0.5001 +vt 0.7108 0.4610 +vt 0.7186 0.4610 +vt 0.7186 0.4688 +vt 0.7108 0.4688 +vt 0.7421 0.4610 +vt 0.7499 0.4610 +vt 0.7499 0.4688 +vt 0.7421 0.4688 +vt 0.9607 0.4923 +vt 0.9685 0.4923 +vt 0.9685 0.5001 +vt 0.9607 0.5001 +vt 0.9607 0.4611 +vt 0.9685 0.4611 +vt 0.9685 0.4689 +vt 0.9607 0.4689 +vt 0.9919 0.4611 +vt 0.9998 0.4611 +vt 0.9997 0.4689 +vt 0.9919 0.4689 +vt 0.4610 0.4922 +vt 0.4688 0.4922 +vt 0.4688 0.5000 +vt 0.4610 0.5000 +vt 0.4610 0.4609 +vt 0.4688 0.4609 +vt 0.4688 0.4687 +vt 0.4610 0.4687 +vt 0.4922 0.4609 +vt 0.5000 0.4609 +vt 0.5000 0.4688 +vt 0.4922 0.4688 +vt 0.4608 0.9919 +vt 0.4686 0.9919 +vt 0.4686 0.9997 +vt 0.4608 0.9997 +vt 0.4608 0.9607 +vt 0.4686 0.9607 +vt 0.4686 0.9685 +vt 0.4608 0.9685 +vt 0.4921 0.9607 +vt 0.4999 0.9607 +vt 0.4999 0.9685 +vt 0.4920 0.9685 +vt 0.9605 0.9921 +vt 0.9683 0.9921 +vt 0.9683 0.9999 +vt 0.9605 0.9999 +vt 0.9605 0.9608 +vt 0.9684 0.9608 +vt 0.9684 0.9686 +vt 0.9605 0.9686 +vt 0.9918 0.9608 +vt 0.9996 0.9608 +vt 0.9996 0.9686 +vt 0.9918 0.9686 +vt 0.9762 0.9608 +vt 0.9840 0.9608 +vt 0.9840 0.9686 +vt 0.9762 0.9686 +vt 0.9762 0.9452 +vt 0.9840 0.9452 +vt 0.9840 0.9530 +vt 0.9762 0.9530 +vt 0.9918 0.9452 +vt 0.9996 0.9452 +vt 0.9996 0.9530 +vt 0.9918 0.9530 +vt 0.9449 0.9608 +vt 0.9527 0.9608 +vt 0.9527 0.9686 +vt 0.9449 0.9686 +vt 0.9449 0.9452 +vt 0.9527 0.9452 +vt 0.9527 0.9530 +vt 0.9449 0.9530 +vt 0.9606 0.9452 +vt 0.9684 0.9452 +vt 0.9684 0.9530 +vt 0.9606 0.9530 +vt 0.9449 0.9920 +vt 0.9527 0.9920 +vt 0.9527 0.9999 +vt 0.9449 0.9999 +vt 0.9449 0.9764 +vt 0.9527 0.9764 +vt 0.9527 0.9842 +vt 0.9449 0.9842 +vt 0.9605 0.9764 +vt 0.9684 0.9764 +vt 0.9683 0.9842 +vt 0.9605 0.9842 +vt 0.4764 0.9607 +vt 0.4842 0.9607 +vt 0.4842 0.9685 +vt 0.4764 0.9685 +vt 0.4764 0.9451 +vt 0.4842 0.9451 +vt 0.4842 0.9529 +vt 0.4764 0.9529 +vt 0.4921 0.9451 +vt 0.4999 0.9451 +vt 0.4999 0.9529 +vt 0.4921 0.9529 +vt 0.4452 0.9607 +vt 0.4530 0.9607 +vt 0.4530 0.9685 +vt 0.4452 0.9685 +vt 0.4452 0.9450 +vt 0.4530 0.9451 +vt 0.4530 0.9529 +vt 0.4452 0.9529 +vt 0.4608 0.9451 +vt 0.4686 0.9451 +vt 0.4686 0.9529 +vt 0.4608 0.9529 +vt 0.4452 0.9919 +vt 0.4530 0.9919 +vt 0.4530 0.9997 +vt 0.4452 0.9997 +vt 0.4452 0.9763 +vt 0.4530 0.9763 +vt 0.4530 0.9841 +vt 0.4452 0.9841 +vt 0.4608 0.9763 +vt 0.4686 0.9763 +vt 0.4686 0.9841 +vt 0.4608 0.9841 +vt 0.4766 0.4609 +vt 0.4844 0.4609 +vt 0.4844 0.4687 +vt 0.4766 0.4687 +vt 0.4766 0.4453 +vt 0.4844 0.4453 +vt 0.4844 0.4531 +vt 0.4766 0.4531 +vt 0.4922 0.4453 +vt 0.5000 0.4453 +vt 0.5000 0.4531 +vt 0.4922 0.4531 +vt 0.4454 0.4609 +vt 0.4532 0.4609 +vt 0.4532 0.4687 +vt 0.4454 0.4687 +vt 0.4454 0.4453 +vt 0.4532 0.4453 +vt 0.4532 0.4531 +vt 0.4454 0.4531 +vt 0.4610 0.4453 +vt 0.4688 0.4453 +vt 0.4688 0.4531 +vt 0.4610 0.4531 +vt 0.4453 0.4922 +vt 0.4532 0.4922 +vt 0.4532 0.5000 +vt 0.4453 0.5000 +vt 0.4454 0.4765 +vt 0.4532 0.4765 +vt 0.4532 0.4844 +vt 0.4453 0.4844 +vt 0.4610 0.4765 +vt 0.4688 0.4766 +vt 0.4688 0.4844 +vt 0.4610 0.4844 +vt 0.9763 0.4611 +vt 0.9841 0.4611 +vt 0.9841 0.4689 +vt 0.9763 0.4689 +vt 0.9763 0.4455 +vt 0.9841 0.4455 +vt 0.9841 0.4533 +vt 0.9763 0.4533 +vt 0.9919 0.4455 +vt 0.9998 0.4455 +vt 0.9998 0.4533 +vt 0.9919 0.4533 +vt 0.9451 0.4611 +vt 0.9529 0.4611 +vt 0.9529 0.4689 +vt 0.9451 0.4689 +vt 0.9451 0.4455 +vt 0.9529 0.4455 +vt 0.9529 0.4533 +vt 0.9451 0.4533 +vt 0.9607 0.4455 +vt 0.9685 0.4455 +vt 0.9685 0.4533 +vt 0.9607 0.4533 +vt 0.9451 0.4923 +vt 0.9529 0.4923 +vt 0.9529 0.5001 +vt 0.9451 0.5001 +vt 0.9451 0.4767 +vt 0.9529 0.4767 +vt 0.9529 0.4845 +vt 0.9451 0.4845 +vt 0.9607 0.4767 +vt 0.9685 0.4767 +vt 0.9685 0.4845 +vt 0.9607 0.4845 +vt 0.7265 0.4610 +vt 0.7343 0.4610 +vt 0.7343 0.4688 +vt 0.7265 0.4688 +vt 0.7265 0.4454 +vt 0.7343 0.4454 +vt 0.7343 0.4532 +vt 0.7265 0.4532 +vt 0.7421 0.4454 +vt 0.7499 0.4454 +vt 0.7499 0.4532 +vt 0.7421 0.4532 +vt 0.6952 0.4610 +vt 0.7030 0.4610 +vt 0.7030 0.4688 +vt 0.6952 0.4688 +vt 0.6952 0.4454 +vt 0.7030 0.4454 +vt 0.7030 0.4532 +vt 0.6952 0.4532 +vt 0.7108 0.4454 +vt 0.7187 0.4454 +vt 0.7187 0.4532 +vt 0.7108 0.4532 +vt 0.6952 0.4922 +vt 0.7030 0.4922 +vt 0.7030 0.5000 +vt 0.6952 0.5000 +vt 0.6952 0.4766 +vt 0.7030 0.4766 +vt 0.7030 0.4844 +vt 0.6952 0.4844 +vt 0.7108 0.4766 +vt 0.7186 0.4766 +vt 0.7186 0.4844 +vt 0.7108 0.4844 +vt 0.7265 0.2111 +vt 0.7343 0.2111 +vt 0.7343 0.2190 +vt 0.7265 0.2190 +vt 0.7265 0.1955 +vt 0.7343 0.1955 +vt 0.7343 0.2033 +vt 0.7265 0.2033 +vt 0.7422 0.1955 +vt 0.7500 0.1955 +vt 0.7500 0.2033 +vt 0.7422 0.2033 +vt 0.6953 0.2111 +vt 0.7031 0.2111 +vt 0.7031 0.2189 +vt 0.6953 0.2189 +vt 0.6953 0.1955 +vt 0.7031 0.1955 +vt 0.7031 0.2033 +vt 0.6953 0.2033 +vt 0.7109 0.1955 +vt 0.7187 0.1955 +vt 0.7187 0.2033 +vt 0.7109 0.2033 +vt 0.6953 0.2424 +vt 0.7031 0.2424 +vt 0.7031 0.2502 +vt 0.6953 0.2502 +vt 0.6953 0.2268 +vt 0.7031 0.2268 +vt 0.7031 0.2346 +vt 0.6953 0.2346 +vt 0.7109 0.2268 +vt 0.7187 0.2268 +vt 0.7187 0.2346 +vt 0.7109 0.2346 +vt 0.9764 0.2112 +vt 0.9842 0.2112 +vt 0.9842 0.2190 +vt 0.9764 0.2190 +vt 0.9764 0.1956 +vt 0.9842 0.1956 +vt 0.9842 0.2034 +vt 0.9764 0.2034 +vt 0.9920 0.1956 +vt 0.9998 0.1956 +vt 0.9998 0.2034 +vt 0.9920 0.2034 +vt 0.9452 0.2112 +vt 0.9530 0.2112 +vt 0.9530 0.2190 +vt 0.9452 0.2190 +vt 0.9452 0.1956 +vt 0.9530 0.1956 +vt 0.9530 0.2034 +vt 0.9452 0.2034 +vt 0.9608 0.1956 +vt 0.9686 0.1956 +vt 0.9686 0.2034 +vt 0.9608 0.2034 +vt 0.9452 0.2424 +vt 0.9530 0.2425 +vt 0.9530 0.2503 +vt 0.9452 0.2503 +vt 0.9452 0.2268 +vt 0.9530 0.2268 +vt 0.9530 0.2346 +vt 0.9452 0.2346 +vt 0.9608 0.2268 +vt 0.9686 0.2268 +vt 0.9686 0.2346 +vt 0.9608 0.2346 +vt 0.2267 0.4609 +vt 0.2345 0.4609 +vt 0.2345 0.4687 +vt 0.2267 0.4687 +vt 0.2267 0.4452 +vt 0.2345 0.4452 +vt 0.2345 0.4531 +vt 0.2267 0.4530 +vt 0.2423 0.4452 +vt 0.2502 0.4452 +vt 0.2501 0.4531 +vt 0.2423 0.4531 +vt 0.1955 0.4608 +vt 0.2033 0.4609 +vt 0.2033 0.4687 +vt 0.1955 0.4687 +vt 0.1955 0.4452 +vt 0.2033 0.4452 +vt 0.2033 0.4530 +vt 0.1955 0.4530 +vt 0.2111 0.4452 +vt 0.2189 0.4452 +vt 0.2189 0.4530 +vt 0.2111 0.4530 +vt 0.1955 0.4921 +vt 0.2033 0.4921 +vt 0.2033 0.4999 +vt 0.1955 0.4999 +vt 0.1955 0.4765 +vt 0.2033 0.4765 +vt 0.2033 0.4843 +vt 0.1955 0.4843 +vt 0.2111 0.4765 +vt 0.2189 0.4765 +vt 0.2189 0.4843 +vt 0.2111 0.4843 +vt 0.2268 0.2110 +vt 0.2346 0.2110 +vt 0.2346 0.2188 +vt 0.2268 0.2188 +vt 0.2268 0.1954 +vt 0.2346 0.1954 +vt 0.2346 0.2032 +vt 0.2268 0.2032 +vt 0.2424 0.1954 +vt 0.2502 0.1954 +vt 0.2502 0.2032 +vt 0.2424 0.2032 +vt 0.1956 0.2110 +vt 0.2034 0.2110 +vt 0.2034 0.2188 +vt 0.1956 0.2188 +vt 0.1956 0.1954 +vt 0.2034 0.1954 +vt 0.2034 0.2032 +vt 0.1956 0.2032 +vt 0.2112 0.1954 +vt 0.2190 0.1954 +vt 0.2190 0.2032 +vt 0.2112 0.2032 +vt 0.1956 0.2422 +vt 0.2034 0.2422 +vt 0.2034 0.2500 +vt 0.1956 0.2500 +vt 0.1956 0.2266 +vt 0.2034 0.2266 +vt 0.2034 0.2344 +vt 0.1956 0.2344 +vt 0.2112 0.2266 +vt 0.2190 0.2266 +vt 0.2190 0.2344 +vt 0.2112 0.2344 +vt 0.4767 0.2111 +vt 0.4845 0.2111 +vt 0.4845 0.2189 +vt 0.4767 0.2189 +vt 0.4767 0.1955 +vt 0.4845 0.1955 +vt 0.4845 0.2033 +vt 0.4767 0.2033 +vt 0.4923 0.1955 +vt 0.5001 0.1955 +vt 0.5001 0.2033 +vt 0.4923 0.2033 +vt 0.4454 0.2111 +vt 0.4532 0.2111 +vt 0.4532 0.2189 +vt 0.4454 0.2189 +vt 0.4454 0.1954 +vt 0.4532 0.1954 +vt 0.4532 0.2033 +vt 0.4454 0.2033 +vt 0.4611 0.1954 +vt 0.4689 0.1954 +vt 0.4689 0.2033 +vt 0.4611 0.2033 +vt 0.4454 0.2423 +vt 0.4532 0.2423 +vt 0.4532 0.2501 +vt 0.4454 0.2501 +vt 0.4454 0.2267 +vt 0.4532 0.2267 +vt 0.4532 0.2345 +vt 0.4454 0.2345 +vt 0.4610 0.2267 +vt 0.4689 0.2267 +vt 0.4689 0.2345 +vt 0.4610 0.2345 +vt 0.2266 0.9606 +vt 0.2344 0.9606 +vt 0.2344 0.9684 +vt 0.2266 0.9684 +vt 0.2266 0.9450 +vt 0.2344 0.9450 +vt 0.2344 0.9528 +vt 0.2266 0.9528 +vt 0.2422 0.9450 +vt 0.2500 0.9450 +vt 0.2500 0.9528 +vt 0.2422 0.9528 +vt 0.1953 0.9606 +vt 0.2031 0.9606 +vt 0.2031 0.9684 +vt 0.1953 0.9684 +vt 0.1953 0.9450 +vt 0.2031 0.9450 +vt 0.2031 0.9528 +vt 0.1953 0.9528 +vt 0.2110 0.9450 +vt 0.2188 0.9450 +vt 0.2188 0.9528 +vt 0.2109 0.9528 +vt 0.1953 0.9918 +vt 0.2031 0.9918 +vt 0.2031 0.9996 +vt 0.1953 0.9996 +vt 0.1953 0.9762 +vt 0.2031 0.9762 +vt 0.2031 0.9840 +vt 0.1953 0.9840 +vt 0.2109 0.9762 +vt 0.2187 0.9762 +vt 0.2187 0.9840 +vt 0.2109 0.9840 +vt 0.2266 0.7107 +vt 0.2344 0.7107 +vt 0.2344 0.7185 +vt 0.2266 0.7185 +vt 0.2266 0.6951 +vt 0.2345 0.6951 +vt 0.2345 0.7029 +vt 0.2266 0.7029 +vt 0.2423 0.6951 +vt 0.2501 0.6951 +vt 0.2501 0.7029 +vt 0.2423 0.7029 +vt 0.1954 0.7107 +vt 0.2032 0.7107 +vt 0.2032 0.7185 +vt 0.1954 0.7185 +vt 0.1954 0.6951 +vt 0.2032 0.6951 +vt 0.2032 0.7029 +vt 0.1954 0.7029 +vt 0.2110 0.6951 +vt 0.2188 0.6951 +vt 0.2188 0.7029 +vt 0.2110 0.7029 +vt 0.1954 0.7420 +vt 0.2032 0.7420 +vt 0.2032 0.7498 +vt 0.1954 0.7498 +vt 0.1954 0.7263 +vt 0.2032 0.7263 +vt 0.2032 0.7341 +vt 0.1954 0.7341 +vt 0.2110 0.7263 +vt 0.2188 0.7263 +vt 0.2188 0.7342 +vt 0.2110 0.7341 +vt 0.4765 0.7108 +vt 0.4843 0.7108 +vt 0.4843 0.7186 +vt 0.4765 0.7186 +vt 0.4765 0.6952 +vt 0.4843 0.6952 +vt 0.4843 0.7030 +vt 0.4765 0.7030 +vt 0.4921 0.6952 +vt 0.4999 0.6952 +vt 0.4999 0.7030 +vt 0.4921 0.7030 +vt 0.4453 0.7108 +vt 0.4531 0.7108 +vt 0.4531 0.7186 +vt 0.4453 0.7186 +vt 0.4453 0.6952 +vt 0.4531 0.6952 +vt 0.4531 0.7030 +vt 0.4453 0.7030 +vt 0.4609 0.6952 +vt 0.4687 0.6952 +vt 0.4687 0.7030 +vt 0.4609 0.7030 +vt 0.4453 0.7420 +vt 0.4531 0.7420 +vt 0.4531 0.7498 +vt 0.4453 0.7498 +vt 0.4453 0.7264 +vt 0.4531 0.7264 +vt 0.4531 0.7342 +vt 0.4453 0.7342 +vt 0.4609 0.7264 +vt 0.4687 0.7264 +vt 0.4687 0.7342 +vt 0.4609 0.7342 +vt 0.7263 0.9607 +vt 0.7341 0.9608 +vt 0.7341 0.9686 +vt 0.7263 0.9686 +vt 0.7263 0.9451 +vt 0.7341 0.9451 +vt 0.7341 0.9529 +vt 0.7263 0.9529 +vt 0.7419 0.9451 +vt 0.7497 0.9451 +vt 0.7497 0.9529 +vt 0.7419 0.9529 +vt 0.6951 0.9607 +vt 0.7029 0.9607 +vt 0.7029 0.9686 +vt 0.6951 0.9685 +vt 0.6951 0.9451 +vt 0.7029 0.9451 +vt 0.7029 0.9529 +vt 0.6951 0.9529 +vt 0.7107 0.9451 +vt 0.7185 0.9451 +vt 0.7185 0.9529 +vt 0.7107 0.9529 +vt 0.6951 0.9920 +vt 0.7029 0.9920 +vt 0.7029 0.9998 +vt 0.6951 0.9998 +vt 0.6951 0.9764 +vt 0.7029 0.9764 +vt 0.7029 0.9842 +vt 0.6951 0.9842 +vt 0.7107 0.9764 +vt 0.7185 0.9764 +vt 0.7185 0.9842 +vt 0.7107 0.9842 +vt 0.7264 0.7109 +vt 0.7342 0.7109 +vt 0.7342 0.7187 +vt 0.7264 0.7187 +vt 0.7264 0.6953 +vt 0.7342 0.6953 +vt 0.7342 0.7031 +vt 0.7264 0.7031 +vt 0.7420 0.6953 +vt 0.7498 0.6953 +vt 0.7498 0.7031 +vt 0.7420 0.7031 +vt 0.6951 0.7109 +vt 0.7030 0.7109 +vt 0.7030 0.7187 +vt 0.6951 0.7187 +vt 0.6951 0.6953 +vt 0.7030 0.6953 +vt 0.7030 0.7031 +vt 0.6951 0.7031 +vt 0.7108 0.6953 +vt 0.7186 0.6953 +vt 0.7186 0.7031 +vt 0.7108 0.7031 +vt 0.6951 0.7421 +vt 0.7029 0.7421 +vt 0.7029 0.7499 +vt 0.6951 0.7499 +vt 0.6951 0.7265 +vt 0.7029 0.7265 +vt 0.7029 0.7343 +vt 0.6951 0.7343 +vt 0.7108 0.7265 +vt 0.7186 0.7265 +vt 0.7186 0.7343 +vt 0.7108 0.7343 +vt 0.9762 0.7110 +vt 0.9841 0.7110 +vt 0.9840 0.7188 +vt 0.9762 0.7188 +vt 0.9762 0.6953 +vt 0.9841 0.6953 +vt 0.9841 0.7032 +vt 0.9762 0.7032 +vt 0.9919 0.6954 +vt 0.9997 0.6954 +vt 0.9997 0.7032 +vt 0.9919 0.7032 +vt 0.9450 0.7110 +vt 0.9528 0.7110 +vt 0.9528 0.7188 +vt 0.9450 0.7188 +vt 0.9450 0.6953 +vt 0.9528 0.6953 +vt 0.9528 0.7031 +vt 0.9450 0.7031 +vt 0.9606 0.6953 +vt 0.9684 0.6953 +vt 0.9684 0.7032 +vt 0.9606 0.7031 +vt 0.9450 0.7422 +vt 0.9528 0.7422 +vt 0.9528 0.7500 +vt 0.9450 0.7500 +vt 0.9450 0.7266 +vt 0.9528 0.7266 +vt 0.9528 0.7344 +vt 0.9450 0.7344 +vt 0.9606 0.7266 +vt 0.9684 0.7266 +vt 0.9684 0.7344 +vt 0.9606 0.7344 +vt 0.8513 0.7109 +vt 0.8591 0.7109 +vt 0.8591 0.7187 +vt 0.8513 0.7187 +vt 0.8513 0.6953 +vt 0.8591 0.6953 +vt 0.8591 0.7031 +vt 0.8513 0.7031 +vt 0.8669 0.6953 +vt 0.8747 0.6953 +vt 0.8747 0.7031 +vt 0.8669 0.7031 +vt 0.8201 0.7109 +vt 0.8279 0.7109 +vt 0.8279 0.7187 +vt 0.8201 0.7187 +vt 0.8201 0.6953 +vt 0.8279 0.6953 +vt 0.8279 0.7031 +vt 0.8201 0.7031 +vt 0.8357 0.6953 +vt 0.8435 0.6953 +vt 0.8435 0.7031 +vt 0.8357 0.7031 +vt 0.8201 0.7421 +vt 0.8279 0.7421 +vt 0.8279 0.7500 +vt 0.8201 0.7500 +vt 0.8201 0.7265 +vt 0.8279 0.7265 +vt 0.8279 0.7343 +vt 0.8201 0.7343 +vt 0.8357 0.7265 +vt 0.8435 0.7265 +vt 0.8435 0.7343 +vt 0.8357 0.7343 +vt 0.8514 0.5860 +vt 0.8592 0.5860 +vt 0.8592 0.5938 +vt 0.8513 0.5938 +vt 0.8514 0.5704 +vt 0.8592 0.5704 +vt 0.8592 0.5782 +vt 0.8514 0.5782 +vt 0.8670 0.5704 +vt 0.8748 0.5704 +vt 0.8748 0.5782 +vt 0.8670 0.5782 +vt 0.8201 0.5860 +vt 0.8279 0.5860 +vt 0.8279 0.5938 +vt 0.8201 0.5938 +vt 0.8201 0.5704 +vt 0.8279 0.5704 +vt 0.8279 0.5782 +vt 0.8201 0.5782 +vt 0.8357 0.5704 +vt 0.8435 0.5704 +vt 0.8435 0.5782 +vt 0.8357 0.5782 +vt 0.8201 0.6172 +vt 0.8279 0.6172 +vt 0.8279 0.6250 +vt 0.8201 0.6250 +vt 0.8201 0.6016 +vt 0.8279 0.6016 +vt 0.8279 0.6094 +vt 0.8201 0.6094 +vt 0.8357 0.6016 +vt 0.8435 0.6016 +vt 0.8435 0.6094 +vt 0.8357 0.6094 +vt 0.9763 0.5860 +vt 0.9841 0.5860 +vt 0.9841 0.5938 +vt 0.9763 0.5938 +vt 0.9763 0.5704 +vt 0.9841 0.5704 +vt 0.9841 0.5782 +vt 0.9763 0.5782 +vt 0.9919 0.5704 +vt 0.9997 0.5704 +vt 0.9997 0.5782 +vt 0.9919 0.5782 +vt 0.9451 0.5860 +vt 0.9529 0.5860 +vt 0.9529 0.5938 +vt 0.9450 0.5938 +vt 0.9451 0.5704 +vt 0.9529 0.5704 +vt 0.9529 0.5782 +vt 0.9451 0.5782 +vt 0.9607 0.5704 +vt 0.9685 0.5704 +vt 0.9685 0.5782 +vt 0.9607 0.5782 +vt 0.9450 0.6173 +vt 0.9528 0.6173 +vt 0.9528 0.6251 +vt 0.9450 0.6251 +vt 0.9450 0.6016 +vt 0.9529 0.6016 +vt 0.9529 0.6094 +vt 0.9450 0.6094 +vt 0.9607 0.6016 +vt 0.9685 0.6016 +vt 0.9685 0.6095 +vt 0.9607 0.6094 +vt 0.6014 0.7108 +vt 0.6093 0.7108 +vt 0.6093 0.7187 +vt 0.6014 0.7187 +vt 0.6014 0.6952 +vt 0.6093 0.6952 +vt 0.6093 0.7030 +vt 0.6014 0.7030 +vt 0.6171 0.6952 +vt 0.6249 0.6952 +vt 0.6249 0.7030 +vt 0.6171 0.7030 +vt 0.5702 0.7108 +vt 0.5780 0.7108 +vt 0.5780 0.7186 +vt 0.5702 0.7186 +vt 0.5702 0.6952 +vt 0.5780 0.6952 +vt 0.5780 0.7030 +vt 0.5702 0.7030 +vt 0.5858 0.6952 +vt 0.5936 0.6952 +vt 0.5936 0.7030 +vt 0.5858 0.7030 +vt 0.5702 0.7421 +vt 0.5780 0.7421 +vt 0.5780 0.7499 +vt 0.5702 0.7499 +vt 0.5702 0.7265 +vt 0.5780 0.7265 +vt 0.5780 0.7343 +vt 0.5702 0.7343 +vt 0.5858 0.7265 +vt 0.5936 0.7265 +vt 0.5936 0.7343 +vt 0.5858 0.7343 +vt 0.6015 0.5859 +vt 0.6093 0.5859 +vt 0.6093 0.5937 +vt 0.6015 0.5937 +vt 0.6015 0.5703 +vt 0.6093 0.5703 +vt 0.6093 0.5781 +vt 0.6015 0.5781 +vt 0.6171 0.5703 +vt 0.6249 0.5703 +vt 0.6249 0.5781 +vt 0.6171 0.5781 +vt 0.5703 0.5859 +vt 0.5781 0.5859 +vt 0.5781 0.5937 +vt 0.5702 0.5937 +vt 0.5703 0.5703 +vt 0.5781 0.5703 +vt 0.5781 0.5781 +vt 0.5703 0.5781 +vt 0.5859 0.5703 +vt 0.5937 0.5703 +vt 0.5937 0.5781 +vt 0.5859 0.5781 +vt 0.5702 0.6171 +vt 0.5780 0.6171 +vt 0.5780 0.6249 +vt 0.5702 0.6249 +vt 0.5702 0.6015 +vt 0.5781 0.6015 +vt 0.5781 0.6093 +vt 0.5702 0.6093 +vt 0.5859 0.6015 +vt 0.5937 0.6015 +vt 0.5937 0.6093 +vt 0.5859 0.6093 +vt 0.7264 0.5859 +vt 0.7342 0.5860 +vt 0.7342 0.5938 +vt 0.7264 0.5938 +vt 0.7264 0.5703 +vt 0.7342 0.5703 +vt 0.7342 0.5781 +vt 0.7264 0.5781 +vt 0.7420 0.5703 +vt 0.7498 0.5703 +vt 0.7498 0.5781 +vt 0.7420 0.5781 +vt 0.6952 0.5859 +vt 0.7030 0.5859 +vt 0.7030 0.5938 +vt 0.6952 0.5937 +vt 0.6952 0.5703 +vt 0.7030 0.5703 +vt 0.7030 0.5781 +vt 0.6952 0.5781 +vt 0.7108 0.5703 +vt 0.7186 0.5703 +vt 0.7186 0.5781 +vt 0.7108 0.5781 +vt 0.6952 0.6172 +vt 0.7030 0.6172 +vt 0.7030 0.6250 +vt 0.6952 0.6250 +vt 0.6952 0.6016 +vt 0.7030 0.6016 +vt 0.7030 0.6094 +vt 0.6952 0.6094 +vt 0.7108 0.6016 +vt 0.7186 0.6016 +vt 0.7186 0.6094 +vt 0.7108 0.6094 +vt 0.6014 0.9607 +vt 0.6092 0.9607 +vt 0.6092 0.9685 +vt 0.6014 0.9685 +vt 0.6014 0.9451 +vt 0.6092 0.9451 +vt 0.6092 0.9529 +vt 0.6014 0.9529 +vt 0.6170 0.9451 +vt 0.6248 0.9451 +vt 0.6248 0.9529 +vt 0.6170 0.9529 +vt 0.5701 0.9607 +vt 0.5779 0.9607 +vt 0.5779 0.9685 +vt 0.5701 0.9685 +vt 0.5701 0.9451 +vt 0.5779 0.9451 +vt 0.5779 0.9529 +vt 0.5701 0.9529 +vt 0.5858 0.9451 +vt 0.5936 0.9451 +vt 0.5936 0.9529 +vt 0.5858 0.9529 +vt 0.5701 0.9919 +vt 0.5779 0.9919 +vt 0.5779 0.9997 +vt 0.5701 0.9997 +vt 0.5701 0.9763 +vt 0.5779 0.9763 +vt 0.5779 0.9841 +vt 0.5701 0.9841 +vt 0.5857 0.9763 +vt 0.5936 0.9763 +vt 0.5936 0.9841 +vt 0.5857 0.9841 +vt 0.6014 0.8358 +vt 0.6092 0.8358 +vt 0.6092 0.8436 +vt 0.6014 0.8436 +vt 0.6014 0.8202 +vt 0.6092 0.8202 +vt 0.6092 0.8280 +vt 0.6014 0.8280 +vt 0.6170 0.8202 +vt 0.6248 0.8202 +vt 0.6248 0.8280 +vt 0.6170 0.8280 +vt 0.5702 0.8358 +vt 0.5780 0.8358 +vt 0.5780 0.8436 +vt 0.5702 0.8436 +vt 0.5702 0.8202 +vt 0.5780 0.8202 +vt 0.5780 0.8280 +vt 0.5702 0.8280 +vt 0.5858 0.8202 +vt 0.5936 0.8202 +vt 0.5936 0.8280 +vt 0.5858 0.8280 +vt 0.5702 0.8670 +vt 0.5780 0.8670 +vt 0.5780 0.8748 +vt 0.5702 0.8748 +vt 0.5702 0.8514 +vt 0.5780 0.8514 +vt 0.5780 0.8592 +vt 0.5702 0.8592 +vt 0.5858 0.8514 +vt 0.5936 0.8514 +vt 0.5936 0.8592 +vt 0.5858 0.8592 +vt 0.7263 0.8358 +vt 0.7341 0.8358 +vt 0.7341 0.8436 +vt 0.7263 0.8436 +vt 0.7263 0.8202 +vt 0.7342 0.8202 +vt 0.7342 0.8280 +vt 0.7263 0.8280 +vt 0.7420 0.8202 +vt 0.7498 0.8202 +vt 0.7498 0.8280 +vt 0.7420 0.8280 +vt 0.6951 0.8358 +vt 0.7029 0.8358 +vt 0.7029 0.8436 +vt 0.6951 0.8436 +vt 0.6951 0.8202 +vt 0.7029 0.8202 +vt 0.7029 0.8280 +vt 0.6951 0.8280 +vt 0.7107 0.8202 +vt 0.7185 0.8202 +vt 0.7185 0.8280 +vt 0.7107 0.8280 +vt 0.6951 0.8670 +vt 0.7029 0.8670 +vt 0.7029 0.8749 +vt 0.6951 0.8748 +vt 0.6951 0.8514 +vt 0.7029 0.8514 +vt 0.7029 0.8592 +vt 0.6951 0.8592 +vt 0.7107 0.8514 +vt 0.7185 0.8514 +vt 0.7185 0.8592 +vt 0.7107 0.8592 +vt 0.3516 0.7108 +vt 0.3594 0.7108 +vt 0.3594 0.7186 +vt 0.3516 0.7186 +vt 0.3516 0.6951 +vt 0.3594 0.6952 +vt 0.3594 0.7030 +vt 0.3516 0.7030 +vt 0.3672 0.6952 +vt 0.3750 0.6952 +vt 0.3750 0.7030 +vt 0.3672 0.7030 +vt 0.3203 0.7108 +vt 0.3282 0.7108 +vt 0.3281 0.7186 +vt 0.3203 0.7186 +vt 0.3203 0.6951 +vt 0.3282 0.6951 +vt 0.3282 0.7030 +vt 0.3203 0.7029 +vt 0.3360 0.6951 +vt 0.3438 0.6951 +vt 0.3438 0.7030 +vt 0.3360 0.7030 +vt 0.3203 0.7420 +vt 0.3281 0.7420 +vt 0.3281 0.7498 +vt 0.3203 0.7498 +vt 0.3203 0.7264 +vt 0.3281 0.7264 +vt 0.3281 0.7342 +vt 0.3203 0.7342 +vt 0.3360 0.7264 +vt 0.3438 0.7264 +vt 0.3438 0.7342 +vt 0.3360 0.7342 +vt 0.3516 0.5858 +vt 0.3594 0.5858 +vt 0.3594 0.5936 +vt 0.3516 0.5936 +vt 0.3516 0.5702 +vt 0.3594 0.5702 +vt 0.3594 0.5780 +vt 0.3516 0.5780 +vt 0.3672 0.5702 +vt 0.3750 0.5702 +vt 0.3750 0.5780 +vt 0.3672 0.5780 +vt 0.3204 0.5858 +vt 0.3282 0.5858 +vt 0.3282 0.5936 +vt 0.3204 0.5936 +vt 0.3204 0.5702 +vt 0.3282 0.5702 +vt 0.3282 0.5780 +vt 0.3204 0.5780 +vt 0.3360 0.5702 +vt 0.3438 0.5702 +vt 0.3438 0.5780 +vt 0.3360 0.5780 +vt 0.3204 0.6171 +vt 0.3282 0.6171 +vt 0.3282 0.6249 +vt 0.3204 0.6249 +vt 0.3204 0.6014 +vt 0.3282 0.6014 +vt 0.3282 0.6092 +vt 0.3204 0.6092 +vt 0.3360 0.6014 +vt 0.3438 0.6014 +vt 0.3438 0.6093 +vt 0.3360 0.6093 +vt 0.4765 0.5859 +vt 0.4844 0.5859 +vt 0.4844 0.5937 +vt 0.4765 0.5937 +vt 0.4766 0.5703 +vt 0.4844 0.5703 +vt 0.4844 0.5781 +vt 0.4766 0.5781 +vt 0.4922 0.5703 +vt 0.5000 0.5703 +vt 0.5000 0.5781 +vt 0.4922 0.5781 +vt 0.4453 0.5859 +vt 0.4531 0.5859 +vt 0.4531 0.5937 +vt 0.4453 0.5937 +vt 0.4453 0.5702 +vt 0.4531 0.5702 +vt 0.4531 0.5781 +vt 0.4453 0.5781 +vt 0.4609 0.5702 +vt 0.4687 0.5703 +vt 0.4687 0.5781 +vt 0.4609 0.5781 +vt 0.4453 0.6171 +vt 0.4531 0.6171 +vt 0.4531 0.6249 +vt 0.4453 0.6249 +vt 0.4453 0.6015 +vt 0.4531 0.6015 +vt 0.4531 0.6093 +vt 0.4453 0.6093 +vt 0.4609 0.6015 +vt 0.4687 0.6015 +vt 0.4687 0.6093 +vt 0.4609 0.6093 +vt 0.1017 0.7107 +vt 0.1095 0.7107 +vt 0.1095 0.7185 +vt 0.1017 0.7185 +vt 0.1017 0.6951 +vt 0.1095 0.6951 +vt 0.1095 0.7029 +vt 0.1017 0.7029 +vt 0.1173 0.6951 +vt 0.1251 0.6951 +vt 0.1251 0.7029 +vt 0.1173 0.7029 +vt 0.0705 0.7107 +vt 0.0783 0.7107 +vt 0.0783 0.7185 +vt 0.0705 0.7185 +vt 0.0705 0.6951 +vt 0.0783 0.6951 +vt 0.0783 0.7029 +vt 0.0705 0.7029 +vt 0.0861 0.6951 +vt 0.0939 0.6951 +vt 0.0939 0.7029 +vt 0.0861 0.7029 +vt 0.0705 0.7419 +vt 0.0783 0.7419 +vt 0.0783 0.7497 +vt 0.0705 0.7497 +vt 0.0705 0.7263 +vt 0.0783 0.7263 +vt 0.0783 0.7341 +vt 0.0705 0.7341 +vt 0.0861 0.7263 +vt 0.0939 0.7263 +vt 0.0939 0.7341 +vt 0.0861 0.7341 +vt 0.1017 0.5858 +vt 0.1096 0.5858 +vt 0.1096 0.5936 +vt 0.1017 0.5936 +vt 0.1018 0.5701 +vt 0.1096 0.5701 +vt 0.1096 0.5779 +vt 0.1017 0.5779 +vt 0.1174 0.5701 +vt 0.1252 0.5701 +vt 0.1252 0.5780 +vt 0.1174 0.5779 +vt 0.0705 0.5857 +vt 0.0783 0.5857 +vt 0.0783 0.5936 +vt 0.0705 0.5935 +vt 0.0705 0.5701 +vt 0.0783 0.5701 +vt 0.0783 0.5779 +vt 0.0705 0.5779 +vt 0.0861 0.5701 +vt 0.0939 0.5701 +vt 0.0939 0.5779 +vt 0.0861 0.5779 +vt 0.0705 0.6170 +vt 0.0783 0.6170 +vt 0.0783 0.6248 +vt 0.0705 0.6248 +vt 0.0705 0.6014 +vt 0.0783 0.6014 +vt 0.0783 0.6092 +vt 0.0705 0.6092 +vt 0.0861 0.6014 +vt 0.0939 0.6014 +vt 0.0939 0.6092 +vt 0.0861 0.6092 +vt 0.2267 0.5858 +vt 0.2345 0.5858 +vt 0.2345 0.5936 +vt 0.2267 0.5936 +vt 0.2267 0.5702 +vt 0.2345 0.5702 +vt 0.2345 0.5780 +vt 0.2267 0.5780 +vt 0.2423 0.5702 +vt 0.2501 0.5702 +vt 0.2501 0.5780 +vt 0.2423 0.5780 +vt 0.1954 0.5858 +vt 0.2033 0.5858 +vt 0.2033 0.5936 +vt 0.1954 0.5936 +vt 0.1955 0.5702 +vt 0.2033 0.5702 +vt 0.2033 0.5780 +vt 0.1954 0.5780 +vt 0.2111 0.5702 +vt 0.2189 0.5702 +vt 0.2189 0.5780 +vt 0.2111 0.5780 +vt 0.1954 0.6170 +vt 0.2032 0.6170 +vt 0.2032 0.6248 +vt 0.1954 0.6248 +vt 0.1954 0.6014 +vt 0.2033 0.6014 +vt 0.2032 0.6092 +vt 0.1954 0.6092 +vt 0.2111 0.6014 +vt 0.2189 0.6014 +vt 0.2189 0.6092 +vt 0.2111 0.6092 +vt 0.1016 0.9606 +vt 0.1094 0.9606 +vt 0.1094 0.9684 +vt 0.1016 0.9684 +vt 0.1016 0.9449 +vt 0.1094 0.9449 +vt 0.1094 0.9528 +vt 0.1016 0.9528 +vt 0.1172 0.9449 +vt 0.1251 0.9450 +vt 0.1251 0.9528 +vt 0.1172 0.9528 +vt 0.0704 0.9606 +vt 0.0782 0.9606 +vt 0.0782 0.9684 +vt 0.0704 0.9684 +vt 0.0704 0.9449 +vt 0.0782 0.9449 +vt 0.0782 0.9527 +vt 0.0704 0.9527 +vt 0.0860 0.9449 +vt 0.0938 0.9449 +vt 0.0938 0.9528 +vt 0.0860 0.9527 +vt 0.0704 0.9918 +vt 0.0782 0.9918 +vt 0.0782 0.9996 +vt 0.0704 0.9996 +vt 0.0704 0.9762 +vt 0.0782 0.9762 +vt 0.0782 0.9840 +vt 0.0704 0.9840 +vt 0.0860 0.9762 +vt 0.0938 0.9762 +vt 0.0938 0.9840 +vt 0.0860 0.9840 +vt 0.1017 0.8356 +vt 0.1095 0.8356 +vt 0.1095 0.8434 +vt 0.1017 0.8434 +vt 0.1017 0.8200 +vt 0.1095 0.8200 +vt 0.1095 0.8278 +vt 0.1017 0.8278 +vt 0.1173 0.8200 +vt 0.1251 0.8200 +vt 0.1251 0.8278 +vt 0.1173 0.8278 +vt 0.0704 0.8356 +vt 0.0782 0.8356 +vt 0.0782 0.8434 +vt 0.0704 0.8434 +vt 0.0704 0.8200 +vt 0.0782 0.8200 +vt 0.0782 0.8278 +vt 0.0704 0.8278 +vt 0.0861 0.8200 +vt 0.0939 0.8200 +vt 0.0939 0.8278 +vt 0.0860 0.8278 +vt 0.0704 0.8668 +vt 0.0782 0.8669 +vt 0.0782 0.8747 +vt 0.0704 0.8747 +vt 0.0704 0.8512 +vt 0.0782 0.8512 +vt 0.0782 0.8590 +vt 0.0704 0.8590 +vt 0.0860 0.8512 +vt 0.0939 0.8512 +vt 0.0938 0.8590 +vt 0.0860 0.8590 +vt 0.2266 0.8357 +vt 0.2344 0.8357 +vt 0.2344 0.8435 +vt 0.2266 0.8435 +vt 0.2266 0.8200 +vt 0.2344 0.8200 +vt 0.2344 0.8279 +vt 0.2266 0.8279 +vt 0.2422 0.8201 +vt 0.2500 0.8201 +vt 0.2500 0.8279 +vt 0.2422 0.8279 +vt 0.1954 0.8357 +vt 0.2032 0.8357 +vt 0.2032 0.8435 +vt 0.1954 0.8435 +vt 0.1954 0.8200 +vt 0.2032 0.8200 +vt 0.2032 0.8278 +vt 0.1954 0.8278 +vt 0.2110 0.8200 +vt 0.2188 0.8200 +vt 0.2188 0.8279 +vt 0.2110 0.8279 +vt 0.1954 0.8669 +vt 0.2032 0.8669 +vt 0.2032 0.8747 +vt 0.1954 0.8747 +vt 0.1954 0.8513 +vt 0.2032 0.8513 +vt 0.2032 0.8591 +vt 0.1954 0.8591 +vt 0.2110 0.8513 +vt 0.2188 0.8513 +vt 0.2188 0.8591 +vt 0.2110 0.8591 +vt 0.3517 0.2110 +vt 0.3595 0.2110 +vt 0.3595 0.2188 +vt 0.3517 0.2188 +vt 0.3517 0.1954 +vt 0.3595 0.1954 +vt 0.3595 0.2032 +vt 0.3517 0.2032 +vt 0.3674 0.1954 +vt 0.3752 0.1954 +vt 0.3752 0.2032 +vt 0.3674 0.2032 +vt 0.3205 0.2110 +vt 0.3283 0.2110 +vt 0.3283 0.2188 +vt 0.3205 0.2188 +vt 0.3205 0.1954 +vt 0.3283 0.1954 +vt 0.3283 0.2032 +vt 0.3205 0.2032 +vt 0.3361 0.1954 +vt 0.3439 0.1954 +vt 0.3439 0.2032 +vt 0.3361 0.2032 +vt 0.3205 0.2423 +vt 0.3283 0.2423 +vt 0.3283 0.2501 +vt 0.3205 0.2501 +vt 0.3205 0.2266 +vt 0.3283 0.2266 +vt 0.3283 0.2344 +vt 0.3205 0.2344 +vt 0.3361 0.2266 +vt 0.3439 0.2266 +vt 0.3439 0.2345 +vt 0.3361 0.2345 +vt 0.3518 0.0861 +vt 0.3596 0.0861 +vt 0.3596 0.0939 +vt 0.3518 0.0939 +vt 0.3518 0.0705 +vt 0.3596 0.0705 +vt 0.3596 0.0783 +vt 0.3518 0.0783 +vt 0.3674 0.0705 +vt 0.3752 0.0705 +vt 0.3752 0.0783 +vt 0.3674 0.0783 +vt 0.3205 0.0861 +vt 0.3283 0.0861 +vt 0.3283 0.0939 +vt 0.3205 0.0939 +vt 0.3205 0.0705 +vt 0.3284 0.0705 +vt 0.3283 0.0783 +vt 0.3205 0.0783 +vt 0.3362 0.0705 +vt 0.3440 0.0705 +vt 0.3440 0.0783 +vt 0.3362 0.0783 +vt 0.3205 0.1173 +vt 0.3283 0.1173 +vt 0.3283 0.1251 +vt 0.3205 0.1251 +vt 0.3205 0.1017 +vt 0.3283 0.1017 +vt 0.3283 0.1095 +vt 0.3205 0.1095 +vt 0.3361 0.1017 +vt 0.3440 0.1017 +vt 0.3440 0.1095 +vt 0.3361 0.1095 +vt 0.4767 0.0861 +vt 0.4845 0.0861 +vt 0.4845 0.0939 +vt 0.4767 0.0939 +vt 0.4767 0.0705 +vt 0.4845 0.0705 +vt 0.4845 0.0783 +vt 0.4767 0.0783 +vt 0.4923 0.0705 +vt 0.5001 0.0705 +vt 0.5001 0.0783 +vt 0.4923 0.0783 +vt 0.4455 0.0861 +vt 0.4533 0.0861 +vt 0.4533 0.0939 +vt 0.4455 0.0939 +vt 0.4455 0.0705 +vt 0.4533 0.0705 +vt 0.4533 0.0783 +vt 0.4455 0.0783 +vt 0.4611 0.0705 +vt 0.4689 0.0705 +vt 0.4689 0.0783 +vt 0.4611 0.0783 +vt 0.4455 0.1174 +vt 0.4533 0.1174 +vt 0.4533 0.1252 +vt 0.4455 0.1252 +vt 0.4455 0.1017 +vt 0.4533 0.1017 +vt 0.4533 0.1096 +vt 0.4455 0.1096 +vt 0.4611 0.1017 +vt 0.4689 0.1017 +vt 0.4689 0.1096 +vt 0.4611 0.1096 +vt 0.1019 0.2110 +vt 0.1097 0.2110 +vt 0.1097 0.2188 +vt 0.1019 0.2188 +vt 0.1019 0.1953 +vt 0.1097 0.1953 +vt 0.1097 0.2031 +vt 0.1019 0.2031 +vt 0.1175 0.1953 +vt 0.1253 0.1953 +vt 0.1253 0.2032 +vt 0.1175 0.2031 +vt 0.0706 0.2109 +vt 0.0784 0.2109 +vt 0.0784 0.2188 +vt 0.0706 0.2187 +vt 0.0706 0.1953 +vt 0.0784 0.1953 +vt 0.0784 0.2031 +vt 0.0706 0.2031 +vt 0.0863 0.1953 +vt 0.0941 0.1953 +vt 0.0941 0.2031 +vt 0.0863 0.2031 +vt 0.0706 0.2422 +vt 0.0784 0.2422 +vt 0.0784 0.2500 +vt 0.0706 0.2500 +vt 0.0706 0.2266 +vt 0.0784 0.2266 +vt 0.0784 0.2344 +vt 0.0706 0.2344 +vt 0.0862 0.2266 +vt 0.0941 0.2266 +vt 0.0941 0.2344 +vt 0.0862 0.2344 +vt 0.1019 0.0860 +vt 0.1097 0.0860 +vt 0.1097 0.0938 +vt 0.1019 0.0938 +vt 0.1019 0.0704 +vt 0.1097 0.0704 +vt 0.1097 0.0782 +vt 0.1019 0.0782 +vt 0.1175 0.0704 +vt 0.1253 0.0704 +vt 0.1253 0.0782 +vt 0.1175 0.0782 +vt 0.0707 0.0860 +vt 0.0785 0.0860 +vt 0.0785 0.0938 +vt 0.0707 0.0938 +vt 0.0707 0.0704 +vt 0.0785 0.0704 +vt 0.0785 0.0782 +vt 0.0707 0.0782 +vt 0.0863 0.0704 +vt 0.0941 0.0704 +vt 0.0941 0.0782 +vt 0.0863 0.0782 +vt 0.0707 0.1172 +vt 0.0785 0.1172 +vt 0.0785 0.1251 +vt 0.0707 0.1251 +vt 0.0707 0.1016 +vt 0.0785 0.1016 +vt 0.0785 0.1094 +vt 0.0707 0.1094 +vt 0.0863 0.1016 +vt 0.0941 0.1016 +vt 0.0941 0.1094 +vt 0.0863 0.1094 +vt 0.2268 0.0861 +vt 0.2346 0.0861 +vt 0.2346 0.0939 +vt 0.2268 0.0939 +vt 0.2268 0.0704 +vt 0.2347 0.0704 +vt 0.2346 0.0783 +vt 0.2268 0.0783 +vt 0.2425 0.0704 +vt 0.2503 0.0705 +vt 0.2503 0.0783 +vt 0.2425 0.0783 +vt 0.1956 0.0861 +vt 0.2034 0.0861 +vt 0.2034 0.0939 +vt 0.1956 0.0939 +vt 0.1956 0.0704 +vt 0.2034 0.0704 +vt 0.2034 0.0782 +vt 0.1956 0.0782 +vt 0.2112 0.0704 +vt 0.2190 0.0704 +vt 0.2190 0.0782 +vt 0.2112 0.0782 +vt 0.1956 0.1173 +vt 0.2034 0.1173 +vt 0.2034 0.1251 +vt 0.1956 0.1251 +vt 0.1956 0.1017 +vt 0.2034 0.1017 +vt 0.2034 0.1095 +vt 0.1956 0.1095 +vt 0.2112 0.1017 +vt 0.2190 0.1017 +vt 0.2190 0.1095 +vt 0.2112 0.1095 +vt 0.1018 0.4608 +vt 0.1096 0.4608 +vt 0.1096 0.4686 +vt 0.1018 0.4686 +vt 0.1018 0.4452 +vt 0.1096 0.4452 +vt 0.1096 0.4530 +vt 0.1018 0.4530 +vt 0.1174 0.4452 +vt 0.1252 0.4452 +vt 0.1252 0.4530 +vt 0.1174 0.4530 +vt 0.0706 0.4608 +vt 0.0784 0.4608 +vt 0.0784 0.4686 +vt 0.0706 0.4686 +vt 0.0706 0.4452 +vt 0.0784 0.4452 +vt 0.0784 0.4530 +vt 0.0706 0.4530 +vt 0.0862 0.4452 +vt 0.0940 0.4452 +vt 0.0940 0.4530 +vt 0.0862 0.4530 +vt 0.0705 0.4920 +vt 0.0784 0.4920 +vt 0.0783 0.4999 +vt 0.0705 0.4998 +vt 0.0705 0.4764 +vt 0.0784 0.4764 +vt 0.0784 0.4842 +vt 0.0705 0.4842 +vt 0.0862 0.4764 +vt 0.0940 0.4764 +vt 0.0940 0.4842 +vt 0.0862 0.4842 +vt 0.1018 0.3359 +vt 0.1096 0.3359 +vt 0.1096 0.3437 +vt 0.1018 0.3437 +vt 0.1018 0.3203 +vt 0.1096 0.3203 +vt 0.1096 0.3281 +vt 0.1018 0.3281 +vt 0.1174 0.3203 +vt 0.1253 0.3203 +vt 0.1253 0.3281 +vt 0.1174 0.3281 +vt 0.0706 0.3359 +vt 0.0784 0.3359 +vt 0.0784 0.3437 +vt 0.0706 0.3437 +vt 0.0706 0.3203 +vt 0.0784 0.3203 +vt 0.0784 0.3281 +vt 0.0706 0.3281 +vt 0.0862 0.3203 +vt 0.0940 0.3203 +vt 0.0940 0.3281 +vt 0.0862 0.3281 +vt 0.0706 0.3671 +vt 0.0784 0.3671 +vt 0.0784 0.3749 +vt 0.0706 0.3749 +vt 0.0706 0.3515 +vt 0.0784 0.3515 +vt 0.0784 0.3593 +vt 0.0706 0.3593 +vt 0.0862 0.3515 +vt 0.0940 0.3515 +vt 0.0940 0.3593 +vt 0.0862 0.3593 +vt 0.2268 0.3359 +vt 0.2346 0.3359 +vt 0.2346 0.3437 +vt 0.2268 0.3437 +vt 0.2268 0.3203 +vt 0.2346 0.3203 +vt 0.2346 0.3281 +vt 0.2268 0.3281 +vt 0.2424 0.3203 +vt 0.2502 0.3203 +vt 0.2502 0.3281 +vt 0.2424 0.3281 +vt 0.1955 0.3359 +vt 0.2033 0.3359 +vt 0.2033 0.3437 +vt 0.1955 0.3437 +vt 0.1955 0.3203 +vt 0.2033 0.3203 +vt 0.2033 0.3281 +vt 0.1955 0.3281 +vt 0.2111 0.3203 +vt 0.2190 0.3203 +vt 0.2190 0.3281 +vt 0.2111 0.3281 +vt 0.1955 0.3671 +vt 0.2033 0.3672 +vt 0.2033 0.3750 +vt 0.1955 0.3750 +vt 0.1955 0.3515 +vt 0.2033 0.3515 +vt 0.2033 0.3593 +vt 0.1955 0.3593 +vt 0.2111 0.3515 +vt 0.2189 0.3515 +vt 0.2189 0.3593 +vt 0.2111 0.3593 +vt 0.8515 0.2112 +vt 0.8593 0.2112 +vt 0.8593 0.2190 +vt 0.8515 0.2190 +vt 0.8515 0.1956 +vt 0.8593 0.1956 +vt 0.8593 0.2034 +vt 0.8515 0.2034 +vt 0.8671 0.1956 +vt 0.8749 0.1956 +vt 0.8749 0.2034 +vt 0.8671 0.2034 +vt 0.8202 0.2112 +vt 0.8280 0.2112 +vt 0.8280 0.2190 +vt 0.8202 0.2190 +vt 0.8202 0.1956 +vt 0.8281 0.1956 +vt 0.8280 0.2034 +vt 0.8202 0.2034 +vt 0.8359 0.1956 +vt 0.8437 0.1956 +vt 0.8437 0.2034 +vt 0.8359 0.2034 +vt 0.8202 0.2424 +vt 0.8280 0.2424 +vt 0.8280 0.2502 +vt 0.8202 0.2502 +vt 0.8202 0.2268 +vt 0.8280 0.2268 +vt 0.8280 0.2346 +vt 0.8202 0.2346 +vt 0.8358 0.2268 +vt 0.8437 0.2268 +vt 0.8437 0.2346 +vt 0.8358 0.2346 +vt 0.8515 0.0862 +vt 0.8593 0.0863 +vt 0.8593 0.0941 +vt 0.8515 0.0941 +vt 0.8515 0.0706 +vt 0.8593 0.0706 +vt 0.8593 0.0784 +vt 0.8515 0.0784 +vt 0.8671 0.0706 +vt 0.8749 0.0706 +vt 0.8749 0.0784 +vt 0.8671 0.0784 +vt 0.8203 0.0862 +vt 0.8281 0.0862 +vt 0.8281 0.0940 +vt 0.8203 0.0940 +vt 0.8203 0.0706 +vt 0.8281 0.0706 +vt 0.8281 0.0784 +vt 0.8203 0.0784 +vt 0.8359 0.0706 +vt 0.8437 0.0706 +vt 0.8437 0.0784 +vt 0.8359 0.0784 +vt 0.8203 0.1175 +vt 0.8281 0.1175 +vt 0.8281 0.1253 +vt 0.8203 0.1253 +vt 0.8203 0.1019 +vt 0.8281 0.1019 +vt 0.8281 0.1097 +vt 0.8203 0.1097 +vt 0.8359 0.1019 +vt 0.8437 0.1019 +vt 0.8437 0.1097 +vt 0.8359 0.1097 +vt 0.9764 0.0863 +vt 0.9843 0.0863 +vt 0.9843 0.0941 +vt 0.9764 0.0941 +vt 0.9765 0.0707 +vt 0.9843 0.0707 +vt 0.9843 0.0785 +vt 0.9764 0.0785 +vt 0.9921 0.0707 +vt 0.9999 0.0707 +vt 0.9999 0.0785 +vt 0.9921 0.0785 +vt 0.9452 0.0863 +vt 0.9530 0.0863 +vt 0.9530 0.0941 +vt 0.9452 0.0941 +vt 0.9452 0.0707 +vt 0.9530 0.0707 +vt 0.9530 0.0785 +vt 0.9452 0.0785 +vt 0.9608 0.0707 +vt 0.9686 0.0707 +vt 0.9686 0.0785 +vt 0.9608 0.0785 +vt 0.9452 0.1175 +vt 0.9530 0.1175 +vt 0.9530 0.1253 +vt 0.9452 0.1253 +vt 0.9452 0.1019 +vt 0.9530 0.1019 +vt 0.9530 0.1097 +vt 0.9452 0.1097 +vt 0.9608 0.1019 +vt 0.9686 0.1019 +vt 0.9686 0.1097 +vt 0.9608 0.1097 +vt 0.6016 0.2111 +vt 0.6094 0.2111 +vt 0.6094 0.2189 +vt 0.6016 0.2189 +vt 0.6016 0.1955 +vt 0.6094 0.1955 +vt 0.6094 0.2033 +vt 0.6016 0.2033 +vt 0.6172 0.1955 +vt 0.6250 0.1955 +vt 0.6250 0.2033 +vt 0.6172 0.2033 +vt 0.5704 0.2111 +vt 0.5782 0.2111 +vt 0.5782 0.2189 +vt 0.5704 0.2189 +vt 0.5704 0.1955 +vt 0.5782 0.1955 +vt 0.5782 0.2033 +vt 0.5704 0.2033 +vt 0.5860 0.1955 +vt 0.5938 0.1955 +vt 0.5938 0.2033 +vt 0.5860 0.2033 +vt 0.5704 0.2423 +vt 0.5782 0.2423 +vt 0.5782 0.2501 +vt 0.5704 0.2501 +vt 0.5704 0.2267 +vt 0.5782 0.2267 +vt 0.5782 0.2345 +vt 0.5704 0.2345 +vt 0.5860 0.2267 +vt 0.5938 0.2267 +vt 0.5938 0.2345 +vt 0.5860 0.2345 +vt 0.6016 0.0862 +vt 0.6094 0.0862 +vt 0.6094 0.0940 +vt 0.6016 0.0940 +vt 0.6016 0.0706 +vt 0.6095 0.0706 +vt 0.6094 0.0784 +vt 0.6016 0.0784 +vt 0.6173 0.0706 +vt 0.6251 0.0706 +vt 0.6251 0.0784 +vt 0.6173 0.0784 +vt 0.5704 0.0862 +vt 0.5782 0.0862 +vt 0.5782 0.0940 +vt 0.5704 0.0940 +vt 0.5704 0.0705 +vt 0.5782 0.0705 +vt 0.5782 0.0784 +vt 0.5704 0.0784 +vt 0.5860 0.0706 +vt 0.5938 0.0706 +vt 0.5938 0.0784 +vt 0.5860 0.0784 +vt 0.5704 0.1174 +vt 0.5782 0.1174 +vt 0.5782 0.1252 +vt 0.5704 0.1252 +vt 0.5704 0.1018 +vt 0.5782 0.1018 +vt 0.5782 0.1096 +vt 0.5704 0.1096 +vt 0.5860 0.1018 +vt 0.5938 0.1018 +vt 0.5938 0.1096 +vt 0.5860 0.1096 +vt 0.7266 0.0862 +vt 0.7344 0.0862 +vt 0.7344 0.0940 +vt 0.7266 0.0940 +vt 0.7266 0.0706 +vt 0.7344 0.0706 +vt 0.7344 0.0784 +vt 0.7266 0.0784 +vt 0.7422 0.0706 +vt 0.7500 0.0706 +vt 0.7500 0.0784 +vt 0.7422 0.0784 +vt 0.6953 0.0862 +vt 0.7031 0.0862 +vt 0.7031 0.0940 +vt 0.6953 0.0940 +vt 0.6953 0.0706 +vt 0.7032 0.0706 +vt 0.7032 0.0784 +vt 0.6953 0.0784 +vt 0.7110 0.0706 +vt 0.7188 0.0706 +vt 0.7188 0.0784 +vt 0.7110 0.0784 +vt 0.6953 0.1174 +vt 0.7031 0.1174 +vt 0.7031 0.1252 +vt 0.6953 0.1252 +vt 0.6953 0.1018 +vt 0.7031 0.1018 +vt 0.7031 0.1096 +vt 0.6953 0.1096 +vt 0.7110 0.1018 +vt 0.7188 0.1018 +vt 0.7188 0.1096 +vt 0.7109 0.1096 +vt 0.6015 0.4610 +vt 0.6093 0.4610 +vt 0.6093 0.4688 +vt 0.6015 0.4688 +vt 0.6015 0.4454 +vt 0.6093 0.4454 +vt 0.6093 0.4532 +vt 0.6015 0.4532 +vt 0.6171 0.4454 +vt 0.6250 0.4454 +vt 0.6250 0.4532 +vt 0.6171 0.4532 +vt 0.5703 0.4610 +vt 0.5781 0.4610 +vt 0.5781 0.4688 +vt 0.5703 0.4688 +vt 0.5703 0.4453 +vt 0.5781 0.4454 +vt 0.5781 0.4532 +vt 0.5703 0.4532 +vt 0.5859 0.4454 +vt 0.5937 0.4454 +vt 0.5937 0.4532 +vt 0.5859 0.4532 +vt 0.5703 0.4922 +vt 0.5781 0.4922 +vt 0.5781 0.5000 +vt 0.5703 0.5000 +vt 0.5703 0.4766 +vt 0.5781 0.4766 +vt 0.5781 0.4844 +vt 0.5703 0.4844 +vt 0.5859 0.4766 +vt 0.5937 0.4766 +vt 0.5937 0.4844 +vt 0.5859 0.4844 +vt 0.6016 0.3360 +vt 0.6094 0.3360 +vt 0.6094 0.3439 +vt 0.6016 0.3439 +vt 0.6016 0.3204 +vt 0.6094 0.3204 +vt 0.6094 0.3282 +vt 0.6016 0.3282 +vt 0.6172 0.3204 +vt 0.6250 0.3204 +vt 0.6250 0.3282 +vt 0.6172 0.3282 +vt 0.5703 0.3360 +vt 0.5781 0.3360 +vt 0.5781 0.3438 +vt 0.5703 0.3438 +vt 0.5703 0.3204 +vt 0.5781 0.3204 +vt 0.5781 0.3282 +vt 0.5703 0.3282 +vt 0.5859 0.3204 +vt 0.5938 0.3204 +vt 0.5938 0.3282 +vt 0.5859 0.3282 +vt 0.5703 0.3673 +vt 0.5781 0.3673 +vt 0.5781 0.3751 +vt 0.5703 0.3751 +vt 0.5703 0.3516 +vt 0.5781 0.3517 +vt 0.5781 0.3595 +vt 0.5703 0.3595 +vt 0.5859 0.3517 +vt 0.5937 0.3517 +vt 0.5937 0.3595 +vt 0.5859 0.3595 +vt 0.7265 0.3361 +vt 0.7343 0.3361 +vt 0.7343 0.3439 +vt 0.7265 0.3439 +vt 0.7265 0.3205 +vt 0.7343 0.3205 +vt 0.7343 0.3283 +vt 0.7265 0.3283 +vt 0.7421 0.3205 +vt 0.7499 0.3205 +vt 0.7499 0.3283 +vt 0.7421 0.3283 +vt 0.6953 0.3361 +vt 0.7031 0.3361 +vt 0.7031 0.3439 +vt 0.6953 0.3439 +vt 0.6953 0.3205 +vt 0.7031 0.3205 +vt 0.7031 0.3283 +vt 0.6953 0.3283 +vt 0.7109 0.3205 +vt 0.7187 0.3205 +vt 0.7187 0.3283 +vt 0.7109 0.3283 +vt 0.6953 0.3673 +vt 0.7031 0.3673 +vt 0.7031 0.3751 +vt 0.6953 0.3751 +vt 0.6953 0.3517 +vt 0.7031 0.3517 +vt 0.7031 0.3595 +vt 0.6953 0.3595 +vt 0.7109 0.3517 +vt 0.7187 0.3517 +vt 0.7187 0.3595 +vt 0.7109 0.3595 +vt 0.8514 0.4611 +vt 0.8592 0.4611 +vt 0.8592 0.4689 +vt 0.8514 0.4689 +vt 0.8514 0.4454 +vt 0.8592 0.4454 +vt 0.8592 0.4532 +vt 0.8514 0.4532 +vt 0.8670 0.4454 +vt 0.8748 0.4454 +vt 0.8748 0.4533 +vt 0.8670 0.4533 +vt 0.8202 0.4610 +vt 0.8280 0.4610 +vt 0.8280 0.4689 +vt 0.8202 0.4689 +vt 0.8202 0.4454 +vt 0.8280 0.4454 +vt 0.8280 0.4532 +vt 0.8202 0.4532 +vt 0.8358 0.4454 +vt 0.8436 0.4454 +vt 0.8436 0.4532 +vt 0.8358 0.4532 +vt 0.8201 0.4923 +vt 0.8280 0.4923 +vt 0.8280 0.5001 +vt 0.8201 0.5001 +vt 0.8202 0.4767 +vt 0.8280 0.4767 +vt 0.8280 0.4845 +vt 0.8202 0.4845 +vt 0.8358 0.4767 +vt 0.8436 0.4767 +vt 0.8436 0.4845 +vt 0.8358 0.4845 +vt 0.8514 0.3361 +vt 0.8592 0.3361 +vt 0.8592 0.3439 +vt 0.8514 0.3439 +vt 0.8514 0.3205 +vt 0.8592 0.3205 +vt 0.8592 0.3283 +vt 0.8514 0.3283 +vt 0.8671 0.3205 +vt 0.8749 0.3205 +vt 0.8749 0.3283 +vt 0.8671 0.3283 +vt 0.8202 0.3361 +vt 0.8280 0.3361 +vt 0.8280 0.3439 +vt 0.8202 0.3439 +vt 0.8202 0.3205 +vt 0.8280 0.3205 +vt 0.8280 0.3283 +vt 0.8202 0.3283 +vt 0.8358 0.3205 +vt 0.8436 0.3205 +vt 0.8436 0.3283 +vt 0.8358 0.3283 +vt 0.8202 0.3673 +vt 0.8280 0.3673 +vt 0.8280 0.3752 +vt 0.8202 0.3752 +vt 0.8202 0.3517 +vt 0.8280 0.3517 +vt 0.8280 0.3595 +vt 0.8202 0.3595 +vt 0.8358 0.3517 +vt 0.8436 0.3517 +vt 0.8436 0.3595 +vt 0.8358 0.3595 +vt 0.9764 0.3362 +vt 0.9842 0.3362 +vt 0.9842 0.3440 +vt 0.9764 0.3440 +vt 0.9764 0.3205 +vt 0.9842 0.3205 +vt 0.9842 0.3284 +vt 0.9764 0.3284 +vt 0.9920 0.3205 +vt 0.9998 0.3206 +vt 0.9998 0.3284 +vt 0.9920 0.3284 +vt 0.9451 0.3362 +vt 0.9529 0.3362 +vt 0.9529 0.3440 +vt 0.9451 0.3440 +vt 0.9451 0.3205 +vt 0.9529 0.3205 +vt 0.9529 0.3283 +vt 0.9451 0.3283 +vt 0.9608 0.3205 +vt 0.9686 0.3205 +vt 0.9686 0.3283 +vt 0.9608 0.3283 +vt 0.9451 0.3674 +vt 0.9529 0.3674 +vt 0.9529 0.3752 +vt 0.9451 0.3752 +vt 0.9451 0.3518 +vt 0.9529 0.3518 +vt 0.9529 0.3596 +vt 0.9451 0.3596 +vt 0.9607 0.3518 +vt 0.9686 0.3518 +vt 0.9686 0.3596 +vt 0.9607 0.3596 +vt 0.3517 0.4609 +vt 0.3595 0.4609 +vt 0.3595 0.4687 +vt 0.3517 0.4687 +vt 0.3517 0.4453 +vt 0.3595 0.4453 +vt 0.3595 0.4531 +vt 0.3517 0.4531 +vt 0.3673 0.4453 +vt 0.3751 0.4453 +vt 0.3751 0.4531 +vt 0.3673 0.4531 +vt 0.3204 0.4609 +vt 0.3282 0.4609 +vt 0.3282 0.4687 +vt 0.3204 0.4687 +vt 0.3204 0.4453 +vt 0.3282 0.4453 +vt 0.3282 0.4531 +vt 0.3204 0.4531 +vt 0.3360 0.4453 +vt 0.3439 0.4453 +vt 0.3438 0.4531 +vt 0.3360 0.4531 +vt 0.3204 0.4921 +vt 0.3282 0.4921 +vt 0.3282 0.4999 +vt 0.3204 0.4999 +vt 0.3204 0.4765 +vt 0.3282 0.4765 +vt 0.3282 0.4843 +vt 0.3204 0.4843 +vt 0.3360 0.4765 +vt 0.3438 0.4765 +vt 0.3438 0.4843 +vt 0.3360 0.4843 +vt 0.3517 0.3360 +vt 0.3595 0.3360 +vt 0.3595 0.3438 +vt 0.3517 0.3438 +vt 0.3517 0.3203 +vt 0.3595 0.3203 +vt 0.3595 0.3282 +vt 0.3517 0.3282 +vt 0.3673 0.3204 +vt 0.3751 0.3204 +vt 0.3751 0.3282 +vt 0.3673 0.3282 +vt 0.3205 0.3360 +vt 0.3283 0.3360 +vt 0.3283 0.3438 +vt 0.3205 0.3438 +vt 0.3205 0.3203 +vt 0.3283 0.3203 +vt 0.3283 0.3281 +vt 0.3205 0.3281 +vt 0.3361 0.3203 +vt 0.3439 0.3203 +vt 0.3439 0.3282 +vt 0.3361 0.3282 +vt 0.3205 0.3672 +vt 0.3283 0.3672 +vt 0.3283 0.3750 +vt 0.3204 0.3750 +vt 0.3205 0.3516 +vt 0.3283 0.3516 +vt 0.3283 0.3594 +vt 0.3205 0.3594 +vt 0.3361 0.3516 +vt 0.3439 0.3516 +vt 0.3439 0.3594 +vt 0.3361 0.3594 +vt 0.4766 0.3360 +vt 0.4844 0.3360 +vt 0.4844 0.3438 +vt 0.4766 0.3438 +vt 0.4766 0.3204 +vt 0.4844 0.3204 +vt 0.4844 0.3282 +vt 0.4766 0.3282 +vt 0.4922 0.3204 +vt 0.5001 0.3204 +vt 0.5001 0.3282 +vt 0.4922 0.3282 +vt 0.4454 0.3360 +vt 0.4532 0.3360 +vt 0.4532 0.3438 +vt 0.4454 0.3438 +vt 0.4454 0.3204 +vt 0.4532 0.3204 +vt 0.4532 0.3282 +vt 0.4454 0.3282 +vt 0.4610 0.3204 +vt 0.4688 0.3204 +vt 0.4688 0.3282 +vt 0.4610 0.3282 +vt 0.4454 0.3672 +vt 0.4532 0.3672 +vt 0.4532 0.3750 +vt 0.4454 0.3750 +vt 0.4454 0.3516 +vt 0.4532 0.3516 +vt 0.4532 0.3594 +vt 0.4454 0.3594 +vt 0.4610 0.3516 +vt 0.4688 0.3516 +vt 0.4688 0.3594 +vt 0.4610 0.3594 +vt 0.3515 0.9606 +vt 0.3593 0.9606 +vt 0.3593 0.9684 +vt 0.3515 0.9684 +vt 0.3515 0.9450 +vt 0.3593 0.9450 +vt 0.3593 0.9528 +vt 0.3515 0.9528 +vt 0.3671 0.9450 +vt 0.3749 0.9450 +vt 0.3749 0.9528 +vt 0.3671 0.9528 +vt 0.3203 0.9606 +vt 0.3281 0.9606 +vt 0.3281 0.9684 +vt 0.3203 0.9684 +vt 0.3203 0.9450 +vt 0.3281 0.9450 +vt 0.3281 0.9528 +vt 0.3203 0.9528 +vt 0.3359 0.9450 +vt 0.3437 0.9450 +vt 0.3437 0.9528 +vt 0.3359 0.9528 +vt 0.3203 0.9919 +vt 0.3281 0.9919 +vt 0.3281 0.9997 +vt 0.3203 0.9997 +vt 0.3203 0.9762 +vt 0.3281 0.9762 +vt 0.3281 0.9841 +vt 0.3203 0.9841 +vt 0.3359 0.9763 +vt 0.3437 0.9763 +vt 0.3437 0.9841 +vt 0.3359 0.9841 +vt 0.3515 0.8357 +vt 0.3593 0.8357 +vt 0.3593 0.8435 +vt 0.3515 0.8435 +vt 0.3515 0.8201 +vt 0.3594 0.8201 +vt 0.3593 0.8279 +vt 0.3515 0.8279 +vt 0.3672 0.8201 +vt 0.3750 0.8201 +vt 0.3750 0.8279 +vt 0.3672 0.8279 +vt 0.3203 0.8357 +vt 0.3281 0.8357 +vt 0.3281 0.8435 +vt 0.3203 0.8435 +vt 0.3203 0.8201 +vt 0.3281 0.8201 +vt 0.3281 0.8279 +vt 0.3203 0.8279 +vt 0.3359 0.8201 +vt 0.3437 0.8201 +vt 0.3437 0.8279 +vt 0.3359 0.8279 +vt 0.3203 0.8669 +vt 0.3281 0.8669 +vt 0.3281 0.8747 +vt 0.3203 0.8747 +vt 0.3203 0.8513 +vt 0.3281 0.8513 +vt 0.3281 0.8591 +vt 0.3203 0.8591 +vt 0.3359 0.8513 +vt 0.3437 0.8513 +vt 0.3437 0.8591 +vt 0.3359 0.8591 +vt 0.4765 0.8357 +vt 0.4843 0.8357 +vt 0.4843 0.8436 +vt 0.4765 0.8435 +vt 0.4765 0.8201 +vt 0.4843 0.8201 +vt 0.4843 0.8279 +vt 0.4765 0.8279 +vt 0.4921 0.8201 +vt 0.4999 0.8201 +vt 0.4999 0.8279 +vt 0.4921 0.8279 +vt 0.4452 0.8357 +vt 0.4530 0.8357 +vt 0.4530 0.8435 +vt 0.4452 0.8435 +vt 0.4452 0.8201 +vt 0.4531 0.8201 +vt 0.4530 0.8279 +vt 0.4452 0.8279 +vt 0.4609 0.8201 +vt 0.4687 0.8201 +vt 0.4687 0.8279 +vt 0.4609 0.8279 +vt 0.4452 0.8670 +vt 0.4530 0.8670 +vt 0.4530 0.8748 +vt 0.4452 0.8748 +vt 0.4452 0.8513 +vt 0.4530 0.8513 +vt 0.4530 0.8592 +vt 0.4452 0.8592 +vt 0.4609 0.8514 +vt 0.4687 0.8514 +vt 0.4687 0.8592 +vt 0.4608 0.8592 +vt 0.8512 0.9608 +vt 0.8590 0.9608 +vt 0.8590 0.9686 +vt 0.8512 0.9686 +vt 0.8512 0.9452 +vt 0.8590 0.9452 +vt 0.8590 0.9530 +vt 0.8512 0.9530 +vt 0.8669 0.9452 +vt 0.8747 0.9452 +vt 0.8747 0.9530 +vt 0.8669 0.9530 +vt 0.8200 0.9608 +vt 0.8278 0.9608 +vt 0.8278 0.9686 +vt 0.8200 0.9686 +vt 0.8200 0.9452 +vt 0.8278 0.9452 +vt 0.8278 0.9530 +vt 0.8200 0.9530 +vt 0.8356 0.9452 +vt 0.8434 0.9452 +vt 0.8434 0.9530 +vt 0.8356 0.9530 +vt 0.8200 0.9920 +vt 0.8278 0.9920 +vt 0.8278 0.9998 +vt 0.8200 0.9998 +vt 0.8200 0.9764 +vt 0.8278 0.9764 +vt 0.8278 0.9842 +vt 0.8200 0.9842 +vt 0.8356 0.9764 +vt 0.8434 0.9764 +vt 0.8434 0.9842 +vt 0.8356 0.9842 +vt 0.8513 0.8359 +vt 0.8591 0.8359 +vt 0.8591 0.8437 +vt 0.8513 0.8437 +vt 0.8513 0.8202 +vt 0.8591 0.8202 +vt 0.8591 0.8280 +vt 0.8513 0.8280 +vt 0.8669 0.8202 +vt 0.8747 0.8202 +vt 0.8747 0.8281 +vt 0.8669 0.8281 +vt 0.8200 0.8358 +vt 0.8278 0.8358 +vt 0.8278 0.8437 +vt 0.8200 0.8437 +vt 0.8200 0.8202 +vt 0.8279 0.8202 +vt 0.8278 0.8280 +vt 0.8200 0.8280 +vt 0.8357 0.8202 +vt 0.8435 0.8202 +vt 0.8435 0.8280 +vt 0.8357 0.8280 +vt 0.8200 0.8671 +vt 0.8278 0.8671 +vt 0.8278 0.8749 +vt 0.8200 0.8749 +vt 0.8200 0.8515 +vt 0.8278 0.8515 +vt 0.8278 0.8593 +vt 0.8200 0.8593 +vt 0.8357 0.8515 +vt 0.8435 0.8515 +vt 0.8435 0.8593 +vt 0.8356 0.8593 +vt 0.9762 0.8359 +vt 0.9840 0.8359 +vt 0.9840 0.8437 +vt 0.9762 0.8437 +vt 0.9762 0.8203 +vt 0.9840 0.8203 +vt 0.9840 0.8281 +vt 0.9762 0.8281 +vt 0.9918 0.8203 +vt 0.9996 0.8203 +vt 0.9996 0.8281 +vt 0.9918 0.8281 +vt 0.9450 0.8359 +vt 0.9528 0.8359 +vt 0.9528 0.8437 +vt 0.9450 0.8437 +vt 0.9450 0.8203 +vt 0.9528 0.8203 +vt 0.9528 0.8281 +vt 0.9450 0.8281 +vt 0.9606 0.8203 +vt 0.9684 0.8203 +vt 0.9684 0.8281 +vt 0.9606 0.8281 +vt 0.9450 0.8671 +vt 0.9528 0.8671 +vt 0.9528 0.8749 +vt 0.9450 0.8749 +vt 0.9450 0.8515 +vt 0.9528 0.8515 +vt 0.9528 0.8593 +vt 0.9450 0.8593 +vt 0.9606 0.8515 +vt 0.9684 0.8515 +vt 0.9684 0.8593 +vt 0.9606 0.8593 +vt 0.9137 0.8359 +vt 0.9215 0.8359 +vt 0.9215 0.8437 +vt 0.9137 0.8437 +vt 0.9137 0.8203 +vt 0.9216 0.8203 +vt 0.9215 0.8281 +vt 0.9137 0.8281 +vt 0.9294 0.8203 +vt 0.9372 0.8203 +vt 0.9372 0.8281 +vt 0.9294 0.8281 +vt 0.8825 0.8359 +vt 0.8903 0.8359 +vt 0.8903 0.8437 +vt 0.8825 0.8437 +vt 0.8825 0.8202 +vt 0.8903 0.8203 +vt 0.8903 0.8281 +vt 0.8825 0.8281 +vt 0.8981 0.8203 +vt 0.9059 0.8203 +vt 0.9059 0.8281 +vt 0.8981 0.8281 +vt 0.8825 0.8671 +vt 0.8903 0.8671 +vt 0.8903 0.8749 +vt 0.8825 0.8749 +vt 0.8825 0.8515 +vt 0.8903 0.8515 +vt 0.8903 0.8593 +vt 0.8825 0.8593 +vt 0.8981 0.8515 +vt 0.9059 0.8515 +vt 0.9059 0.8593 +vt 0.8981 0.8593 +vt 0.9138 0.7734 +vt 0.9216 0.7734 +vt 0.9216 0.7812 +vt 0.9138 0.7812 +vt 0.9138 0.7578 +vt 0.9216 0.7578 +vt 0.9216 0.7656 +vt 0.9138 0.7656 +vt 0.9294 0.7578 +vt 0.9372 0.7578 +vt 0.9372 0.7656 +vt 0.9294 0.7656 +vt 0.8825 0.7734 +vt 0.8903 0.7734 +vt 0.8903 0.7812 +vt 0.8825 0.7812 +vt 0.8825 0.7578 +vt 0.8903 0.7578 +vt 0.8903 0.7656 +vt 0.8825 0.7656 +vt 0.8981 0.7578 +vt 0.9060 0.7578 +vt 0.9060 0.7656 +vt 0.8981 0.7656 +vt 0.8825 0.8046 +vt 0.8903 0.8046 +vt 0.8903 0.8124 +vt 0.8825 0.8124 +vt 0.8825 0.7890 +vt 0.8903 0.7890 +vt 0.8903 0.7968 +vt 0.8825 0.7968 +vt 0.8981 0.7890 +vt 0.9059 0.7890 +vt 0.9059 0.7968 +vt 0.8981 0.7968 +vt 0.9762 0.7734 +vt 0.9840 0.7734 +vt 0.9840 0.7812 +vt 0.9762 0.7812 +vt 0.9762 0.7578 +vt 0.9840 0.7578 +vt 0.9840 0.7656 +vt 0.9762 0.7656 +vt 0.9918 0.7578 +vt 0.9997 0.7578 +vt 0.9997 0.7656 +vt 0.9918 0.7656 +vt 0.9450 0.7734 +vt 0.9528 0.7734 +vt 0.9528 0.7812 +vt 0.9450 0.7812 +vt 0.9450 0.7578 +vt 0.9528 0.7578 +vt 0.9528 0.7656 +vt 0.9450 0.7656 +vt 0.9606 0.7578 +vt 0.9684 0.7578 +vt 0.9684 0.7656 +vt 0.9606 0.7656 +vt 0.9450 0.8047 +vt 0.9528 0.8047 +vt 0.9528 0.8125 +vt 0.9450 0.8125 +vt 0.9450 0.7890 +vt 0.9528 0.7890 +vt 0.9528 0.7968 +vt 0.9450 0.7968 +vt 0.9606 0.7890 +vt 0.9684 0.7890 +vt 0.9684 0.7969 +vt 0.9606 0.7968 +vt 0.7888 0.8358 +vt 0.7966 0.8358 +vt 0.7966 0.8436 +vt 0.7888 0.8436 +vt 0.7888 0.8202 +vt 0.7966 0.8202 +vt 0.7966 0.8280 +vt 0.7888 0.8280 +vt 0.8044 0.8202 +vt 0.8122 0.8202 +vt 0.8122 0.8280 +vt 0.8044 0.8280 +vt 0.7576 0.8358 +vt 0.7654 0.8358 +vt 0.7654 0.8436 +vt 0.7576 0.8436 +vt 0.7576 0.8202 +vt 0.7654 0.8202 +vt 0.7654 0.8280 +vt 0.7576 0.8280 +vt 0.7732 0.8202 +vt 0.7810 0.8202 +vt 0.7810 0.8280 +vt 0.7732 0.8280 +vt 0.7576 0.8671 +vt 0.7654 0.8671 +vt 0.7654 0.8749 +vt 0.7576 0.8749 +vt 0.7576 0.8514 +vt 0.7654 0.8514 +vt 0.7654 0.8593 +vt 0.7576 0.8593 +vt 0.7732 0.8514 +vt 0.7810 0.8514 +vt 0.7810 0.8593 +vt 0.7732 0.8593 +vt 0.7888 0.7734 +vt 0.7966 0.7734 +vt 0.7966 0.7812 +vt 0.7888 0.7812 +vt 0.7888 0.7578 +vt 0.7966 0.7578 +vt 0.7966 0.7656 +vt 0.7888 0.7656 +vt 0.8044 0.7578 +vt 0.8123 0.7578 +vt 0.8123 0.7656 +vt 0.8044 0.7656 +vt 0.7576 0.7734 +vt 0.7654 0.7734 +vt 0.7654 0.7812 +vt 0.7576 0.7812 +vt 0.7576 0.7577 +vt 0.7654 0.7577 +vt 0.7654 0.7656 +vt 0.7576 0.7656 +vt 0.7732 0.7577 +vt 0.7810 0.7577 +vt 0.7810 0.7656 +vt 0.7732 0.7656 +vt 0.7576 0.8046 +vt 0.7654 0.8046 +vt 0.7654 0.8124 +vt 0.7576 0.8124 +vt 0.7576 0.7890 +vt 0.7654 0.7890 +vt 0.7654 0.7968 +vt 0.7576 0.7968 +vt 0.7732 0.7890 +vt 0.7810 0.7890 +vt 0.7810 0.7968 +vt 0.7732 0.7968 +vt 0.8513 0.7734 +vt 0.8591 0.7734 +vt 0.8591 0.7812 +vt 0.8513 0.7812 +vt 0.8513 0.7578 +vt 0.8591 0.7578 +vt 0.8591 0.7656 +vt 0.8513 0.7656 +vt 0.8669 0.7578 +vt 0.8747 0.7578 +vt 0.8747 0.7656 +vt 0.8669 0.7656 +vt 0.8201 0.7734 +vt 0.8279 0.7734 +vt 0.8279 0.7812 +vt 0.8201 0.7812 +vt 0.8201 0.7578 +vt 0.8279 0.7578 +vt 0.8279 0.7656 +vt 0.8201 0.7656 +vt 0.8357 0.7578 +vt 0.8435 0.7578 +vt 0.8435 0.7656 +vt 0.8357 0.7656 +vt 0.8200 0.8046 +vt 0.8279 0.8046 +vt 0.8279 0.8124 +vt 0.8200 0.8124 +vt 0.8201 0.7890 +vt 0.8279 0.7890 +vt 0.8279 0.7968 +vt 0.8201 0.7968 +vt 0.8357 0.7890 +vt 0.8435 0.7890 +vt 0.8435 0.7968 +vt 0.8357 0.7968 +vt 0.7888 0.9608 +vt 0.7966 0.9608 +vt 0.7966 0.9686 +vt 0.7888 0.9686 +vt 0.7888 0.9452 +vt 0.7966 0.9452 +vt 0.7966 0.9530 +vt 0.7888 0.9530 +vt 0.8044 0.9452 +vt 0.8122 0.9452 +vt 0.8122 0.9530 +vt 0.8044 0.9530 +vt 0.7575 0.9608 +vt 0.7653 0.9608 +vt 0.7653 0.9686 +vt 0.7575 0.9686 +vt 0.7575 0.9451 +vt 0.7653 0.9451 +vt 0.7653 0.9530 +vt 0.7575 0.9529 +vt 0.7732 0.9451 +vt 0.7810 0.9451 +vt 0.7810 0.9530 +vt 0.7732 0.9530 +vt 0.7575 0.9920 +vt 0.7653 0.9920 +vt 0.7653 0.9998 +vt 0.7575 0.9998 +vt 0.7575 0.9764 +vt 0.7653 0.9764 +vt 0.7653 0.9842 +vt 0.7575 0.9842 +vt 0.7731 0.9764 +vt 0.7810 0.9764 +vt 0.7810 0.9842 +vt 0.7731 0.9842 +vt 0.7888 0.8983 +vt 0.7966 0.8983 +vt 0.7966 0.9061 +vt 0.7888 0.9061 +vt 0.7888 0.8827 +vt 0.7966 0.8827 +vt 0.7966 0.8905 +vt 0.7888 0.8905 +vt 0.8044 0.8827 +vt 0.8122 0.8827 +vt 0.8122 0.8905 +vt 0.8044 0.8905 +vt 0.7576 0.8983 +vt 0.7654 0.8983 +vt 0.7654 0.9061 +vt 0.7576 0.9061 +vt 0.7576 0.8827 +vt 0.7654 0.8827 +vt 0.7654 0.8905 +vt 0.7576 0.8905 +vt 0.7732 0.8827 +vt 0.7810 0.8827 +vt 0.7810 0.8905 +vt 0.7732 0.8905 +vt 0.7575 0.9295 +vt 0.7654 0.9295 +vt 0.7654 0.9373 +vt 0.7575 0.9373 +vt 0.7575 0.9139 +vt 0.7654 0.9139 +vt 0.7654 0.9217 +vt 0.7575 0.9217 +vt 0.7732 0.9139 +vt 0.7810 0.9139 +vt 0.7810 0.9217 +vt 0.7732 0.9217 +vt 0.8513 0.8983 +vt 0.8591 0.8983 +vt 0.8591 0.9061 +vt 0.8513 0.9061 +vt 0.8513 0.8827 +vt 0.8591 0.8827 +vt 0.8591 0.8905 +vt 0.8513 0.8905 +vt 0.8669 0.8827 +vt 0.8747 0.8827 +vt 0.8747 0.8905 +vt 0.8669 0.8905 +vt 0.8200 0.8983 +vt 0.8278 0.8983 +vt 0.8278 0.9061 +vt 0.8200 0.9061 +vt 0.8200 0.8827 +vt 0.8278 0.8827 +vt 0.8278 0.8905 +vt 0.8200 0.8905 +vt 0.8356 0.8827 +vt 0.8434 0.8827 +vt 0.8434 0.8905 +vt 0.8356 0.8905 +vt 0.8200 0.9295 +vt 0.8278 0.9295 +vt 0.8278 0.9374 +vt 0.8200 0.9374 +vt 0.8200 0.9139 +vt 0.8278 0.9139 +vt 0.8278 0.9217 +vt 0.8200 0.9217 +vt 0.8356 0.9139 +vt 0.8434 0.9139 +vt 0.8434 0.9217 +vt 0.8356 0.9217 +vt 0.4140 0.8357 +vt 0.4218 0.8357 +vt 0.4218 0.8435 +vt 0.4140 0.8435 +vt 0.4140 0.8201 +vt 0.4218 0.8201 +vt 0.4218 0.8279 +vt 0.4140 0.8279 +vt 0.4296 0.8201 +vt 0.4374 0.8201 +vt 0.4374 0.8279 +vt 0.4296 0.8279 +vt 0.3828 0.8357 +vt 0.3906 0.8357 +vt 0.3906 0.8435 +vt 0.3828 0.8435 +vt 0.3828 0.8201 +vt 0.3906 0.8201 +vt 0.3906 0.8279 +vt 0.3828 0.8279 +vt 0.3984 0.8201 +vt 0.4062 0.8201 +vt 0.4062 0.8279 +vt 0.3984 0.8279 +vt 0.3828 0.8669 +vt 0.3906 0.8669 +vt 0.3906 0.8748 +vt 0.3828 0.8748 +vt 0.3828 0.8513 +vt 0.3906 0.8513 +vt 0.3906 0.8591 +vt 0.3828 0.8591 +vt 0.3984 0.8513 +vt 0.4062 0.8513 +vt 0.4062 0.8591 +vt 0.3984 0.8591 +vt 0.4140 0.7733 +vt 0.4218 0.7733 +vt 0.4218 0.7811 +vt 0.4140 0.7811 +vt 0.4140 0.7576 +vt 0.4218 0.7576 +vt 0.4218 0.7654 +vt 0.4140 0.7654 +vt 0.4296 0.7576 +vt 0.4375 0.7576 +vt 0.4375 0.7655 +vt 0.4296 0.7655 +vt 0.3828 0.7732 +vt 0.3906 0.7732 +vt 0.3906 0.7811 +vt 0.3828 0.7811 +vt 0.3828 0.7576 +vt 0.3906 0.7576 +vt 0.3906 0.7654 +vt 0.3828 0.7654 +vt 0.3984 0.7576 +vt 0.4062 0.7576 +vt 0.4062 0.7654 +vt 0.3984 0.7654 +vt 0.3828 0.8045 +vt 0.3906 0.8045 +vt 0.3906 0.8123 +vt 0.3828 0.8123 +vt 0.3828 0.7889 +vt 0.3906 0.7889 +vt 0.3906 0.7967 +vt 0.3828 0.7967 +vt 0.3984 0.7889 +vt 0.4062 0.7889 +vt 0.4062 0.7967 +vt 0.3984 0.7967 +vt 0.4765 0.7733 +vt 0.4843 0.7733 +vt 0.4843 0.7811 +vt 0.4765 0.7811 +vt 0.4765 0.7577 +vt 0.4843 0.7577 +vt 0.4843 0.7655 +vt 0.4765 0.7655 +vt 0.4921 0.7577 +vt 0.4999 0.7577 +vt 0.4999 0.7655 +vt 0.4921 0.7655 +vt 0.4453 0.7733 +vt 0.4531 0.7733 +vt 0.4531 0.7811 +vt 0.4453 0.7811 +vt 0.4453 0.7576 +vt 0.4531 0.7576 +vt 0.4531 0.7655 +vt 0.4453 0.7655 +vt 0.4609 0.7577 +vt 0.4687 0.7577 +vt 0.4687 0.7655 +vt 0.4609 0.7655 +vt 0.4452 0.8045 +vt 0.4531 0.8045 +vt 0.4531 0.8123 +vt 0.4452 0.8123 +vt 0.4453 0.7889 +vt 0.4531 0.7889 +vt 0.4531 0.7967 +vt 0.4453 0.7967 +vt 0.4609 0.7889 +vt 0.4687 0.7889 +vt 0.4687 0.7967 +vt 0.4609 0.7967 +vt 0.2891 0.8357 +vt 0.2969 0.8357 +vt 0.2969 0.8435 +vt 0.2891 0.8435 +vt 0.2891 0.8201 +vt 0.2969 0.8201 +vt 0.2969 0.8279 +vt 0.2891 0.8279 +vt 0.3047 0.8201 +vt 0.3125 0.8201 +vt 0.3125 0.8279 +vt 0.3047 0.8279 +vt 0.2578 0.8357 +vt 0.2656 0.8357 +vt 0.2656 0.8435 +vt 0.2578 0.8435 +vt 0.2578 0.8201 +vt 0.2656 0.8201 +vt 0.2656 0.8279 +vt 0.2578 0.8279 +vt 0.2735 0.8201 +vt 0.2813 0.8201 +vt 0.2813 0.8279 +vt 0.2735 0.8279 +vt 0.2578 0.8669 +vt 0.2656 0.8669 +vt 0.2656 0.8747 +vt 0.2578 0.8747 +vt 0.2578 0.8513 +vt 0.2656 0.8513 +vt 0.2656 0.8591 +vt 0.2578 0.8591 +vt 0.2734 0.8513 +vt 0.2813 0.8513 +vt 0.2813 0.8591 +vt 0.2734 0.8591 +vt 0.2891 0.7732 +vt 0.2969 0.7732 +vt 0.2969 0.7810 +vt 0.2891 0.7810 +vt 0.2891 0.7576 +vt 0.2969 0.7576 +vt 0.2969 0.7654 +vt 0.2891 0.7654 +vt 0.3047 0.7576 +vt 0.3125 0.7576 +vt 0.3125 0.7654 +vt 0.3047 0.7654 +vt 0.2579 0.7732 +vt 0.2657 0.7732 +vt 0.2657 0.7810 +vt 0.2579 0.7810 +vt 0.2579 0.7576 +vt 0.2657 0.7576 +vt 0.2657 0.7654 +vt 0.2579 0.7654 +vt 0.2735 0.7576 +vt 0.2813 0.7576 +vt 0.2813 0.7654 +vt 0.2735 0.7654 +vt 0.2578 0.8044 +vt 0.2657 0.8044 +vt 0.2657 0.8123 +vt 0.2578 0.8122 +vt 0.2578 0.7888 +vt 0.2657 0.7888 +vt 0.2657 0.7966 +vt 0.2578 0.7966 +vt 0.2735 0.7888 +vt 0.2813 0.7888 +vt 0.2813 0.7966 +vt 0.2735 0.7966 +vt 0.3516 0.7732 +vt 0.3594 0.7732 +vt 0.3594 0.7810 +vt 0.3516 0.7810 +vt 0.3516 0.7576 +vt 0.3594 0.7576 +vt 0.3594 0.7654 +vt 0.3516 0.7654 +vt 0.3672 0.7576 +vt 0.3750 0.7576 +vt 0.3750 0.7654 +vt 0.3672 0.7654 +vt 0.3203 0.7732 +vt 0.3281 0.7732 +vt 0.3281 0.7810 +vt 0.3203 0.7810 +vt 0.3203 0.7576 +vt 0.3281 0.7576 +vt 0.3281 0.7654 +vt 0.3203 0.7654 +vt 0.3359 0.7576 +vt 0.3438 0.7576 +vt 0.3438 0.7654 +vt 0.3359 0.7654 +vt 0.3203 0.8045 +vt 0.3281 0.8045 +vt 0.3281 0.8123 +vt 0.3203 0.8123 +vt 0.3203 0.7888 +vt 0.3281 0.7888 +vt 0.3281 0.7967 +vt 0.3203 0.7967 +vt 0.3359 0.7888 +vt 0.3437 0.7888 +vt 0.3437 0.7967 +vt 0.3359 0.7967 +vt 0.2890 0.9606 +vt 0.2968 0.9606 +vt 0.2968 0.9684 +vt 0.2890 0.9684 +vt 0.2890 0.9450 +vt 0.2968 0.9450 +vt 0.2968 0.9528 +vt 0.2890 0.9528 +vt 0.3047 0.9450 +vt 0.3125 0.9450 +vt 0.3125 0.9528 +vt 0.3047 0.9528 +vt 0.2578 0.9606 +vt 0.2656 0.9606 +vt 0.2656 0.9684 +vt 0.2578 0.9684 +vt 0.2578 0.9450 +vt 0.2656 0.9450 +vt 0.2656 0.9528 +vt 0.2578 0.9528 +vt 0.2734 0.9450 +vt 0.2812 0.9450 +vt 0.2812 0.9528 +vt 0.2734 0.9528 +vt 0.2578 0.9918 +vt 0.2656 0.9918 +vt 0.2656 0.9997 +vt 0.2578 0.9997 +vt 0.2578 0.9762 +vt 0.2656 0.9762 +vt 0.2656 0.9840 +vt 0.2578 0.9840 +vt 0.2734 0.9762 +vt 0.2812 0.9762 +vt 0.2812 0.9840 +vt 0.2734 0.9840 +vt 0.2891 0.8982 +vt 0.2969 0.8982 +vt 0.2969 0.9060 +vt 0.2890 0.9060 +vt 0.2891 0.8825 +vt 0.2969 0.8825 +vt 0.2969 0.8903 +vt 0.2891 0.8903 +vt 0.3047 0.8825 +vt 0.3125 0.8825 +vt 0.3125 0.8903 +vt 0.3047 0.8903 +vt 0.2578 0.8981 +vt 0.2656 0.8981 +vt 0.2656 0.9060 +vt 0.2578 0.9059 +vt 0.2578 0.8825 +vt 0.2656 0.8825 +vt 0.2656 0.8903 +vt 0.2578 0.8903 +vt 0.2734 0.8825 +vt 0.2812 0.8825 +vt 0.2812 0.8903 +vt 0.2734 0.8903 +vt 0.2578 0.9294 +vt 0.2656 0.9294 +vt 0.2656 0.9372 +vt 0.2578 0.9372 +vt 0.2578 0.9138 +vt 0.2656 0.9138 +vt 0.2656 0.9216 +vt 0.2578 0.9216 +vt 0.2734 0.9138 +vt 0.2812 0.9138 +vt 0.2812 0.9216 +vt 0.2734 0.9216 +vt 0.3515 0.8982 +vt 0.3593 0.8982 +vt 0.3593 0.9060 +vt 0.3515 0.9060 +vt 0.3515 0.8826 +vt 0.3593 0.8826 +vt 0.3593 0.8904 +vt 0.3515 0.8904 +vt 0.3671 0.8826 +vt 0.3749 0.8826 +vt 0.3749 0.8904 +vt 0.3671 0.8904 +vt 0.3203 0.8982 +vt 0.3281 0.8982 +vt 0.3281 0.9060 +vt 0.3203 0.9060 +vt 0.3203 0.8825 +vt 0.3281 0.8825 +vt 0.3281 0.8904 +vt 0.3203 0.8904 +vt 0.3359 0.8825 +vt 0.3437 0.8826 +vt 0.3437 0.8904 +vt 0.3359 0.8904 +vt 0.3203 0.9294 +vt 0.3281 0.9294 +vt 0.3281 0.9372 +vt 0.3203 0.9372 +vt 0.3203 0.9138 +vt 0.3281 0.9138 +vt 0.3281 0.9216 +vt 0.3203 0.9216 +vt 0.3359 0.9138 +vt 0.3437 0.9138 +vt 0.3437 0.9216 +vt 0.3359 0.9216 +vt 0.4142 0.3360 +vt 0.4220 0.3360 +vt 0.4220 0.3438 +vt 0.4142 0.3438 +vt 0.4142 0.3204 +vt 0.4220 0.3204 +vt 0.4220 0.3282 +vt 0.4142 0.3282 +vt 0.4298 0.3204 +vt 0.4376 0.3204 +vt 0.4376 0.3282 +vt 0.4298 0.3282 +vt 0.3829 0.3360 +vt 0.3907 0.3360 +vt 0.3907 0.3438 +vt 0.3829 0.3438 +vt 0.3829 0.3204 +vt 0.3907 0.3204 +vt 0.3907 0.3282 +vt 0.3829 0.3282 +vt 0.3985 0.3204 +vt 0.4064 0.3204 +vt 0.4064 0.3282 +vt 0.3985 0.3282 +vt 0.3829 0.3672 +vt 0.3907 0.3672 +vt 0.3907 0.3750 +vt 0.3829 0.3750 +vt 0.3829 0.3516 +vt 0.3907 0.3516 +vt 0.3907 0.3594 +vt 0.3829 0.3594 +vt 0.3985 0.3516 +vt 0.4063 0.3516 +vt 0.4063 0.3594 +vt 0.3985 0.3594 +vt 0.4142 0.2735 +vt 0.4220 0.2735 +vt 0.4220 0.2813 +vt 0.4142 0.2813 +vt 0.4142 0.2579 +vt 0.4220 0.2579 +vt 0.4220 0.2657 +vt 0.4142 0.2657 +vt 0.4298 0.2579 +vt 0.4376 0.2579 +vt 0.4376 0.2657 +vt 0.4298 0.2657 +vt 0.3829 0.2735 +vt 0.3908 0.2735 +vt 0.3908 0.2813 +vt 0.3829 0.2813 +vt 0.3830 0.2579 +vt 0.3908 0.2579 +vt 0.3908 0.2657 +vt 0.3829 0.2657 +vt 0.3986 0.2579 +vt 0.4064 0.2579 +vt 0.4064 0.2657 +vt 0.3986 0.2657 +vt 0.3829 0.3047 +vt 0.3907 0.3047 +vt 0.3907 0.3126 +vt 0.3829 0.3125 +vt 0.3829 0.2891 +vt 0.3908 0.2891 +vt 0.3907 0.2969 +vt 0.3829 0.2969 +vt 0.3986 0.2891 +vt 0.4064 0.2891 +vt 0.4064 0.2969 +vt 0.3986 0.2969 +vt 0.4766 0.2735 +vt 0.4845 0.2735 +vt 0.4845 0.2813 +vt 0.4766 0.2813 +vt 0.4767 0.2579 +vt 0.4845 0.2579 +vt 0.4845 0.2657 +vt 0.4766 0.2657 +vt 0.4923 0.2579 +vt 0.5001 0.2579 +vt 0.5001 0.2657 +vt 0.4923 0.2657 +vt 0.4454 0.2735 +vt 0.4532 0.2735 +vt 0.4532 0.2813 +vt 0.4454 0.2813 +vt 0.4454 0.2579 +vt 0.4532 0.2579 +vt 0.4532 0.2657 +vt 0.4454 0.2657 +vt 0.4610 0.2579 +vt 0.4688 0.2579 +vt 0.4688 0.2657 +vt 0.4610 0.2657 +vt 0.4454 0.3048 +vt 0.4532 0.3048 +vt 0.4532 0.3126 +vt 0.4454 0.3126 +vt 0.4454 0.2891 +vt 0.4532 0.2891 +vt 0.4532 0.2970 +vt 0.4454 0.2970 +vt 0.4610 0.2891 +vt 0.4688 0.2892 +vt 0.4688 0.2970 +vt 0.4610 0.2970 +vt 0.2892 0.3359 +vt 0.2970 0.3359 +vt 0.2970 0.3438 +vt 0.2892 0.3438 +vt 0.2892 0.3203 +vt 0.2970 0.3203 +vt 0.2970 0.3281 +vt 0.2892 0.3281 +vt 0.3048 0.3203 +vt 0.3127 0.3203 +vt 0.3127 0.3281 +vt 0.3048 0.3281 +vt 0.2580 0.3359 +vt 0.2658 0.3359 +vt 0.2658 0.3437 +vt 0.2580 0.3437 +vt 0.2580 0.3203 +vt 0.2658 0.3203 +vt 0.2658 0.3281 +vt 0.2580 0.3281 +vt 0.2736 0.3203 +vt 0.2814 0.3203 +vt 0.2814 0.3281 +vt 0.2736 0.3281 +vt 0.2580 0.3672 +vt 0.2658 0.3672 +vt 0.2658 0.3750 +vt 0.2580 0.3750 +vt 0.2580 0.3516 +vt 0.2658 0.3516 +vt 0.2658 0.3594 +vt 0.2580 0.3594 +vt 0.2736 0.3516 +vt 0.2814 0.3516 +vt 0.2814 0.3594 +vt 0.2736 0.3594 +vt 0.2892 0.2735 +vt 0.2971 0.2735 +vt 0.2971 0.2813 +vt 0.2892 0.2813 +vt 0.2893 0.2579 +vt 0.2971 0.2579 +vt 0.2971 0.2657 +vt 0.2892 0.2657 +vt 0.3049 0.2579 +vt 0.3127 0.2579 +vt 0.3127 0.2657 +vt 0.3049 0.2657 +vt 0.2580 0.2735 +vt 0.2658 0.2735 +vt 0.2658 0.2813 +vt 0.2580 0.2813 +vt 0.2580 0.2579 +vt 0.2658 0.2579 +vt 0.2658 0.2657 +vt 0.2580 0.2657 +vt 0.2736 0.2579 +vt 0.2814 0.2579 +vt 0.2814 0.2657 +vt 0.2736 0.2657 +vt 0.2580 0.3047 +vt 0.2658 0.3047 +vt 0.2658 0.3125 +vt 0.2580 0.3125 +vt 0.2580 0.2891 +vt 0.2658 0.2891 +vt 0.2658 0.2969 +vt 0.2580 0.2969 +vt 0.2736 0.2891 +vt 0.2814 0.2891 +vt 0.2814 0.2969 +vt 0.2736 0.2969 +vt 0.3517 0.2735 +vt 0.3595 0.2735 +vt 0.3595 0.2813 +vt 0.3517 0.2813 +vt 0.3517 0.2579 +vt 0.3595 0.2579 +vt 0.3595 0.2657 +vt 0.3517 0.2657 +vt 0.3673 0.2579 +vt 0.3751 0.2579 +vt 0.3751 0.2657 +vt 0.3673 0.2657 +vt 0.3205 0.2735 +vt 0.3283 0.2735 +vt 0.3283 0.2813 +vt 0.3205 0.2813 +vt 0.3205 0.2579 +vt 0.3283 0.2579 +vt 0.3283 0.2657 +vt 0.3205 0.2657 +vt 0.3361 0.2579 +vt 0.3439 0.2579 +vt 0.3439 0.2657 +vt 0.3361 0.2657 +vt 0.3205 0.3047 +vt 0.3283 0.3047 +vt 0.3283 0.3125 +vt 0.3205 0.3125 +vt 0.3205 0.2891 +vt 0.3283 0.2891 +vt 0.3283 0.2969 +vt 0.3205 0.2969 +vt 0.3361 0.2891 +vt 0.3439 0.2891 +vt 0.3439 0.2969 +vt 0.3361 0.2969 +vt 0.2892 0.4609 +vt 0.2970 0.4609 +vt 0.2970 0.4687 +vt 0.2892 0.4687 +vt 0.2892 0.4453 +vt 0.2970 0.4453 +vt 0.2970 0.4531 +vt 0.2892 0.4531 +vt 0.3048 0.4453 +vt 0.3126 0.4453 +vt 0.3126 0.4531 +vt 0.3048 0.4531 +vt 0.2580 0.4609 +vt 0.2658 0.4609 +vt 0.2658 0.4687 +vt 0.2580 0.4687 +vt 0.2580 0.4453 +vt 0.2658 0.4453 +vt 0.2658 0.4531 +vt 0.2580 0.4531 +vt 0.2736 0.4453 +vt 0.2814 0.4453 +vt 0.2814 0.4531 +vt 0.2736 0.4531 +vt 0.2579 0.4921 +vt 0.2658 0.4921 +vt 0.2657 0.4999 +vt 0.2579 0.4999 +vt 0.2579 0.4765 +vt 0.2658 0.4765 +vt 0.2658 0.4843 +vt 0.2579 0.4843 +vt 0.2736 0.4765 +vt 0.2814 0.4765 +vt 0.2814 0.4843 +vt 0.2736 0.4843 +vt 0.2892 0.3984 +vt 0.2970 0.3984 +vt 0.2970 0.4062 +vt 0.2892 0.4062 +vt 0.2892 0.3828 +vt 0.2970 0.3828 +vt 0.2970 0.3906 +vt 0.2892 0.3906 +vt 0.3048 0.3828 +vt 0.3126 0.3828 +vt 0.3126 0.3906 +vt 0.3048 0.3906 +vt 0.2580 0.3984 +vt 0.2658 0.3984 +vt 0.2658 0.4062 +vt 0.2580 0.4062 +vt 0.2580 0.3828 +vt 0.2658 0.3828 +vt 0.2658 0.3906 +vt 0.2580 0.3906 +vt 0.2736 0.3828 +vt 0.2814 0.3828 +vt 0.2814 0.3906 +vt 0.2736 0.3906 +vt 0.2580 0.4296 +vt 0.2658 0.4296 +vt 0.2658 0.4374 +vt 0.2580 0.4374 +vt 0.2580 0.4140 +vt 0.2658 0.4140 +vt 0.2658 0.4218 +vt 0.2580 0.4218 +vt 0.2736 0.4140 +vt 0.2814 0.4140 +vt 0.2814 0.4218 +vt 0.2736 0.4218 +vt 0.3517 0.3984 +vt 0.3595 0.3984 +vt 0.3595 0.4062 +vt 0.3517 0.4062 +vt 0.3517 0.3828 +vt 0.3595 0.3828 +vt 0.3595 0.3906 +vt 0.3517 0.3906 +vt 0.3673 0.3828 +vt 0.3751 0.3828 +vt 0.3751 0.3906 +vt 0.3673 0.3906 +vt 0.3204 0.3984 +vt 0.3282 0.3984 +vt 0.3282 0.4062 +vt 0.3204 0.4062 +vt 0.3204 0.3828 +vt 0.3283 0.3828 +vt 0.3283 0.3906 +vt 0.3204 0.3906 +vt 0.3361 0.3828 +vt 0.3439 0.3828 +vt 0.3439 0.3906 +vt 0.3361 0.3906 +vt 0.3204 0.4297 +vt 0.3282 0.4297 +vt 0.3282 0.4375 +vt 0.3204 0.4375 +vt 0.3204 0.4140 +vt 0.3282 0.4140 +vt 0.3282 0.4218 +vt 0.3204 0.4218 +vt 0.3361 0.4140 +vt 0.3439 0.4140 +vt 0.3439 0.4219 +vt 0.3361 0.4219 +vt 0.9139 0.3361 +vt 0.9217 0.3361 +vt 0.9217 0.3440 +vt 0.9139 0.3439 +vt 0.9139 0.3205 +vt 0.9217 0.3205 +vt 0.9217 0.3283 +vt 0.9139 0.3283 +vt 0.9295 0.3205 +vt 0.9373 0.3205 +vt 0.9373 0.3283 +vt 0.9295 0.3283 +vt 0.8827 0.3361 +vt 0.8905 0.3361 +vt 0.8905 0.3439 +vt 0.8827 0.3439 +vt 0.8827 0.3205 +vt 0.8905 0.3205 +vt 0.8905 0.3283 +vt 0.8827 0.3283 +vt 0.8983 0.3205 +vt 0.9061 0.3205 +vt 0.9061 0.3283 +vt 0.8983 0.3283 +vt 0.8827 0.3674 +vt 0.8905 0.3674 +vt 0.8905 0.3752 +vt 0.8827 0.3752 +vt 0.8827 0.3517 +vt 0.8905 0.3517 +vt 0.8905 0.3596 +vt 0.8827 0.3596 +vt 0.8983 0.3518 +vt 0.9061 0.3518 +vt 0.9061 0.3596 +vt 0.8983 0.3596 +vt 0.9139 0.2737 +vt 0.9217 0.2737 +vt 0.9217 0.2815 +vt 0.9139 0.2815 +vt 0.9139 0.2581 +vt 0.9217 0.2581 +vt 0.9217 0.2659 +vt 0.9139 0.2659 +vt 0.9295 0.2581 +vt 0.9373 0.2581 +vt 0.9373 0.2659 +vt 0.9295 0.2659 +vt 0.8827 0.2737 +vt 0.8905 0.2737 +vt 0.8905 0.2815 +vt 0.8827 0.2815 +vt 0.8827 0.2580 +vt 0.8905 0.2580 +vt 0.8905 0.2659 +vt 0.8827 0.2659 +vt 0.8983 0.2581 +vt 0.9061 0.2581 +vt 0.9061 0.2659 +vt 0.8983 0.2659 +vt 0.8827 0.3049 +vt 0.8905 0.3049 +vt 0.8905 0.3127 +vt 0.8827 0.3127 +vt 0.8827 0.2893 +vt 0.8905 0.2893 +vt 0.8905 0.2971 +vt 0.8827 0.2971 +vt 0.8983 0.2893 +vt 0.9061 0.2893 +vt 0.9061 0.2971 +vt 0.8983 0.2971 +vt 0.9764 0.2737 +vt 0.9842 0.2737 +vt 0.9842 0.2815 +vt 0.9764 0.2815 +vt 0.9764 0.2581 +vt 0.9842 0.2581 +vt 0.9842 0.2659 +vt 0.9764 0.2659 +vt 0.9920 0.2581 +vt 0.9998 0.2581 +vt 0.9998 0.2659 +vt 0.9920 0.2659 +vt 0.9452 0.2737 +vt 0.9530 0.2737 +vt 0.9530 0.2815 +vt 0.9452 0.2815 +vt 0.9452 0.2581 +vt 0.9530 0.2581 +vt 0.9530 0.2659 +vt 0.9452 0.2659 +vt 0.9608 0.2581 +vt 0.9686 0.2581 +vt 0.9686 0.2659 +vt 0.9608 0.2659 +vt 0.9451 0.3049 +vt 0.9530 0.3049 +vt 0.9529 0.3127 +vt 0.9451 0.3127 +vt 0.9451 0.2893 +vt 0.9530 0.2893 +vt 0.9530 0.2971 +vt 0.9451 0.2971 +vt 0.9608 0.2893 +vt 0.9686 0.2893 +vt 0.9686 0.2971 +vt 0.9608 0.2971 +vt 0.7890 0.3361 +vt 0.7968 0.3361 +vt 0.7968 0.3439 +vt 0.7890 0.3439 +vt 0.7890 0.3205 +vt 0.7968 0.3205 +vt 0.7968 0.3283 +vt 0.7890 0.3283 +vt 0.8046 0.3205 +vt 0.8124 0.3205 +vt 0.8124 0.3283 +vt 0.8046 0.3283 +vt 0.7577 0.3361 +vt 0.7655 0.3361 +vt 0.7655 0.3439 +vt 0.7577 0.3439 +vt 0.7577 0.3205 +vt 0.7655 0.3205 +vt 0.7655 0.3283 +vt 0.7577 0.3283 +vt 0.7734 0.3205 +vt 0.7812 0.3205 +vt 0.7812 0.3283 +vt 0.7733 0.3283 +vt 0.7577 0.3673 +vt 0.7655 0.3673 +vt 0.7655 0.3751 +vt 0.7577 0.3751 +vt 0.7577 0.3517 +vt 0.7655 0.3517 +vt 0.7655 0.3595 +vt 0.7577 0.3595 +vt 0.7733 0.3517 +vt 0.7812 0.3517 +vt 0.7811 0.3595 +vt 0.7733 0.3595 +vt 0.7890 0.2736 +vt 0.7968 0.2736 +vt 0.7968 0.2814 +vt 0.7890 0.2814 +vt 0.7890 0.2580 +vt 0.7968 0.2580 +vt 0.7968 0.2658 +vt 0.7890 0.2658 +vt 0.8046 0.2580 +vt 0.8124 0.2580 +vt 0.8124 0.2658 +vt 0.8046 0.2658 +vt 0.7577 0.2736 +vt 0.7656 0.2736 +vt 0.7656 0.2814 +vt 0.7577 0.2814 +vt 0.7578 0.2580 +vt 0.7656 0.2580 +vt 0.7656 0.2658 +vt 0.7578 0.2658 +vt 0.7734 0.2580 +vt 0.7812 0.2580 +vt 0.7812 0.2658 +vt 0.7734 0.2658 +vt 0.7577 0.3049 +vt 0.7655 0.3049 +vt 0.7655 0.3127 +vt 0.7577 0.3127 +vt 0.7577 0.2892 +vt 0.7656 0.2892 +vt 0.7656 0.2971 +vt 0.7577 0.2970 +vt 0.7734 0.2892 +vt 0.7812 0.2892 +vt 0.7812 0.2971 +vt 0.7734 0.2971 +vt 0.8515 0.2737 +vt 0.8593 0.2737 +vt 0.8593 0.2815 +vt 0.8514 0.2815 +vt 0.8515 0.2580 +vt 0.8593 0.2580 +vt 0.8593 0.2658 +vt 0.8515 0.2658 +vt 0.8671 0.2580 +vt 0.8749 0.2580 +vt 0.8749 0.2659 +vt 0.8671 0.2658 +vt 0.8202 0.2736 +vt 0.8280 0.2736 +vt 0.8280 0.2815 +vt 0.8202 0.2815 +vt 0.8202 0.2580 +vt 0.8280 0.2580 +vt 0.8280 0.2658 +vt 0.8202 0.2658 +vt 0.8358 0.2580 +vt 0.8436 0.2580 +vt 0.8436 0.2658 +vt 0.8358 0.2658 +vt 0.8202 0.3049 +vt 0.8280 0.3049 +vt 0.8280 0.3127 +vt 0.8202 0.3127 +vt 0.8202 0.2893 +vt 0.8280 0.2893 +vt 0.8280 0.2971 +vt 0.8202 0.2971 +vt 0.8358 0.2893 +vt 0.8436 0.2893 +vt 0.8436 0.2971 +vt 0.8358 0.2971 +vt 0.7889 0.4610 +vt 0.7967 0.4610 +vt 0.7967 0.4688 +vt 0.7889 0.4688 +vt 0.7889 0.4454 +vt 0.7967 0.4454 +vt 0.7967 0.4532 +vt 0.7889 0.4532 +vt 0.8045 0.4454 +vt 0.8124 0.4454 +vt 0.8124 0.4532 +vt 0.8045 0.4532 +vt 0.7577 0.4610 +vt 0.7655 0.4610 +vt 0.7655 0.4688 +vt 0.7577 0.4688 +vt 0.7577 0.4454 +vt 0.7655 0.4454 +vt 0.7655 0.4532 +vt 0.7577 0.4532 +vt 0.7733 0.4454 +vt 0.7811 0.4454 +vt 0.7811 0.4532 +vt 0.7733 0.4532 +vt 0.7577 0.4923 +vt 0.7655 0.4923 +vt 0.7655 0.5001 +vt 0.7577 0.5001 +vt 0.7577 0.4766 +vt 0.7655 0.4766 +vt 0.7655 0.4845 +vt 0.7577 0.4845 +vt 0.7733 0.4766 +vt 0.7811 0.4766 +vt 0.7811 0.4845 +vt 0.7733 0.4845 +vt 0.7889 0.3986 +vt 0.7968 0.3986 +vt 0.7968 0.4064 +vt 0.7889 0.4064 +vt 0.7889 0.3830 +vt 0.7968 0.3830 +vt 0.7968 0.3908 +vt 0.7889 0.3908 +vt 0.8046 0.3830 +vt 0.8124 0.3830 +vt 0.8124 0.3908 +vt 0.8046 0.3908 +vt 0.7577 0.3986 +vt 0.7655 0.3986 +vt 0.7655 0.4064 +vt 0.7577 0.4064 +vt 0.7577 0.3829 +vt 0.7655 0.3829 +vt 0.7655 0.3908 +vt 0.7577 0.3907 +vt 0.7733 0.3829 +vt 0.7811 0.3829 +vt 0.7811 0.3908 +vt 0.7733 0.3908 +vt 0.7577 0.4298 +vt 0.7655 0.4298 +vt 0.7655 0.4376 +vt 0.7577 0.4376 +vt 0.7577 0.4142 +vt 0.7655 0.4142 +vt 0.7655 0.4220 +vt 0.7577 0.4220 +vt 0.7733 0.4142 +vt 0.7811 0.4142 +vt 0.7811 0.4220 +vt 0.7733 0.4220 +vt 0.8514 0.3986 +vt 0.8592 0.3986 +vt 0.8592 0.4064 +vt 0.8514 0.4064 +vt 0.8514 0.3830 +vt 0.8592 0.3830 +vt 0.8592 0.3908 +vt 0.8514 0.3908 +vt 0.8670 0.3830 +vt 0.8748 0.3830 +vt 0.8748 0.3908 +vt 0.8670 0.3908 +vt 0.8202 0.3986 +vt 0.8280 0.3986 +vt 0.8280 0.4064 +vt 0.8202 0.4064 +vt 0.8202 0.3830 +vt 0.8280 0.3830 +vt 0.8280 0.3908 +vt 0.8202 0.3908 +vt 0.8358 0.3830 +vt 0.8436 0.3830 +vt 0.8436 0.3908 +vt 0.8358 0.3908 +vt 0.8202 0.4298 +vt 0.8280 0.4298 +vt 0.8280 0.4376 +vt 0.8202 0.4376 +vt 0.8202 0.4142 +vt 0.8280 0.4142 +vt 0.8280 0.4220 +vt 0.8202 0.4220 +vt 0.8358 0.4142 +vt 0.8436 0.4142 +vt 0.8436 0.4220 +vt 0.8358 0.4220 +vt 0.6640 0.3361 +vt 0.6718 0.3361 +vt 0.6718 0.3439 +vt 0.6640 0.3439 +vt 0.6640 0.3204 +vt 0.6718 0.3204 +vt 0.6718 0.3283 +vt 0.6640 0.3283 +vt 0.6797 0.3204 +vt 0.6875 0.3205 +vt 0.6875 0.3283 +vt 0.6796 0.3283 +vt 0.6328 0.3361 +vt 0.6406 0.3361 +vt 0.6406 0.3439 +vt 0.6328 0.3439 +vt 0.6328 0.3204 +vt 0.6406 0.3204 +vt 0.6406 0.3282 +vt 0.6328 0.3282 +vt 0.6484 0.3204 +vt 0.6562 0.3204 +vt 0.6562 0.3283 +vt 0.6484 0.3282 +vt 0.6328 0.3673 +vt 0.6406 0.3673 +vt 0.6406 0.3751 +vt 0.6328 0.3751 +vt 0.6328 0.3517 +vt 0.6406 0.3517 +vt 0.6406 0.3595 +vt 0.6328 0.3595 +vt 0.6484 0.3517 +vt 0.6562 0.3517 +vt 0.6562 0.3595 +vt 0.6484 0.3595 +vt 0.6640 0.2736 +vt 0.6719 0.2736 +vt 0.6719 0.2814 +vt 0.6640 0.2814 +vt 0.6641 0.2580 +vt 0.6719 0.2580 +vt 0.6719 0.2658 +vt 0.6641 0.2658 +vt 0.6797 0.2580 +vt 0.6875 0.2580 +vt 0.6875 0.2658 +vt 0.6797 0.2658 +vt 0.6328 0.2736 +vt 0.6406 0.2736 +vt 0.6406 0.2814 +vt 0.6328 0.2814 +vt 0.6328 0.2580 +vt 0.6406 0.2580 +vt 0.6406 0.2658 +vt 0.6328 0.2658 +vt 0.6484 0.2580 +vt 0.6562 0.2580 +vt 0.6562 0.2658 +vt 0.6484 0.2658 +vt 0.6328 0.3048 +vt 0.6406 0.3048 +vt 0.6406 0.3126 +vt 0.6328 0.3126 +vt 0.6328 0.2892 +vt 0.6406 0.2892 +vt 0.6406 0.2970 +vt 0.6328 0.2970 +vt 0.6484 0.2892 +vt 0.6562 0.2892 +vt 0.6562 0.2970 +vt 0.6484 0.2970 +vt 0.7265 0.2736 +vt 0.7343 0.2736 +vt 0.7343 0.2814 +vt 0.7265 0.2814 +vt 0.7265 0.2580 +vt 0.7343 0.2580 +vt 0.7343 0.2658 +vt 0.7265 0.2658 +vt 0.7421 0.2580 +vt 0.7499 0.2580 +vt 0.7499 0.2658 +vt 0.7421 0.2658 +vt 0.6953 0.2736 +vt 0.7031 0.2736 +vt 0.7031 0.2814 +vt 0.6953 0.2814 +vt 0.6953 0.2580 +vt 0.7031 0.2580 +vt 0.7031 0.2658 +vt 0.6953 0.2658 +vt 0.7109 0.2580 +vt 0.7187 0.2580 +vt 0.7187 0.2658 +vt 0.7109 0.2658 +vt 0.6953 0.3048 +vt 0.7031 0.3048 +vt 0.7031 0.3126 +vt 0.6953 0.3126 +vt 0.6953 0.2892 +vt 0.7031 0.2892 +vt 0.7031 0.2970 +vt 0.6953 0.2970 +vt 0.7109 0.2892 +vt 0.7187 0.2892 +vt 0.7187 0.2970 +vt 0.7109 0.2970 +vt 0.5391 0.3360 +vt 0.5469 0.3360 +vt 0.5469 0.3438 +vt 0.5391 0.3438 +vt 0.5391 0.3204 +vt 0.5469 0.3204 +vt 0.5469 0.3282 +vt 0.5391 0.3282 +vt 0.5547 0.3204 +vt 0.5625 0.3204 +vt 0.5625 0.3282 +vt 0.5547 0.3282 +vt 0.5079 0.3360 +vt 0.5157 0.3360 +vt 0.5157 0.3438 +vt 0.5079 0.3438 +vt 0.5079 0.3204 +vt 0.5157 0.3204 +vt 0.5157 0.3282 +vt 0.5079 0.3282 +vt 0.5235 0.3204 +vt 0.5313 0.3204 +vt 0.5313 0.3282 +vt 0.5235 0.3282 +vt 0.5079 0.3672 +vt 0.5157 0.3672 +vt 0.5157 0.3751 +vt 0.5078 0.3751 +vt 0.5079 0.3516 +vt 0.5157 0.3516 +vt 0.5157 0.3594 +vt 0.5079 0.3594 +vt 0.5235 0.3516 +vt 0.5313 0.3516 +vt 0.5313 0.3594 +vt 0.5235 0.3594 +vt 0.5391 0.2736 +vt 0.5469 0.2736 +vt 0.5469 0.2814 +vt 0.5391 0.2814 +vt 0.5391 0.2579 +vt 0.5469 0.2579 +vt 0.5469 0.2657 +vt 0.5391 0.2657 +vt 0.5547 0.2579 +vt 0.5625 0.2579 +vt 0.5625 0.2658 +vt 0.5547 0.2658 +vt 0.5079 0.2735 +vt 0.5157 0.2735 +vt 0.5157 0.2814 +vt 0.5079 0.2814 +vt 0.5079 0.2579 +vt 0.5157 0.2579 +vt 0.5157 0.2657 +vt 0.5079 0.2657 +vt 0.5235 0.2579 +vt 0.5313 0.2579 +vt 0.5313 0.2657 +vt 0.5235 0.2657 +vt 0.5079 0.3048 +vt 0.5157 0.3048 +vt 0.5157 0.3126 +vt 0.5079 0.3126 +vt 0.5079 0.2892 +vt 0.5157 0.2892 +vt 0.5157 0.2970 +vt 0.5079 0.2970 +vt 0.5235 0.2892 +vt 0.5313 0.2892 +vt 0.5313 0.2970 +vt 0.5235 0.2970 +vt 0.6016 0.2736 +vt 0.6094 0.2736 +vt 0.6094 0.2814 +vt 0.6016 0.2814 +vt 0.6016 0.2580 +vt 0.6094 0.2580 +vt 0.6094 0.2658 +vt 0.6016 0.2658 +vt 0.6172 0.2580 +vt 0.6250 0.2580 +vt 0.6250 0.2658 +vt 0.6172 0.2658 +vt 0.5703 0.2736 +vt 0.5782 0.2736 +vt 0.5782 0.2814 +vt 0.5703 0.2814 +vt 0.5704 0.2579 +vt 0.5782 0.2580 +vt 0.5782 0.2658 +vt 0.5704 0.2658 +vt 0.5860 0.2580 +vt 0.5938 0.2580 +vt 0.5938 0.2658 +vt 0.5860 0.2658 +vt 0.5703 0.3048 +vt 0.5781 0.3048 +vt 0.5781 0.3126 +vt 0.5703 0.3126 +vt 0.5703 0.2892 +vt 0.5782 0.2892 +vt 0.5781 0.2970 +vt 0.5703 0.2970 +vt 0.5860 0.2892 +vt 0.5938 0.2892 +vt 0.5938 0.2970 +vt 0.5860 0.2970 +vt 0.5391 0.4610 +vt 0.5469 0.4610 +vt 0.5469 0.4688 +vt 0.5391 0.4688 +vt 0.5391 0.4453 +vt 0.5469 0.4453 +vt 0.5469 0.4532 +vt 0.5391 0.4531 +vt 0.5547 0.4453 +vt 0.5625 0.4453 +vt 0.5625 0.4532 +vt 0.5547 0.4532 +vt 0.5078 0.4609 +vt 0.5156 0.4609 +vt 0.5156 0.4688 +vt 0.5078 0.4688 +vt 0.5078 0.4453 +vt 0.5156 0.4453 +vt 0.5156 0.4531 +vt 0.5078 0.4531 +vt 0.5234 0.4453 +vt 0.5313 0.4453 +vt 0.5312 0.4531 +vt 0.5234 0.4531 +vt 0.5078 0.4922 +vt 0.5156 0.4922 +vt 0.5156 0.5000 +vt 0.5078 0.5000 +vt 0.5078 0.4766 +vt 0.5156 0.4766 +vt 0.5156 0.4844 +vt 0.5078 0.4844 +vt 0.5234 0.4766 +vt 0.5312 0.4766 +vt 0.5312 0.4844 +vt 0.5234 0.4844 +vt 0.5391 0.3985 +vt 0.5469 0.3985 +vt 0.5469 0.4063 +vt 0.5391 0.4063 +vt 0.5391 0.3829 +vt 0.5469 0.3829 +vt 0.5469 0.3907 +vt 0.5391 0.3907 +vt 0.5547 0.3829 +vt 0.5625 0.3829 +vt 0.5625 0.3907 +vt 0.5547 0.3907 +vt 0.5078 0.3985 +vt 0.5157 0.3985 +vt 0.5156 0.4063 +vt 0.5078 0.4063 +vt 0.5078 0.3829 +vt 0.5157 0.3829 +vt 0.5157 0.3907 +vt 0.5078 0.3907 +vt 0.5235 0.3829 +vt 0.5313 0.3829 +vt 0.5313 0.3907 +vt 0.5235 0.3907 +vt 0.5078 0.4297 +vt 0.5156 0.4297 +vt 0.5156 0.4375 +vt 0.5078 0.4375 +vt 0.5078 0.4141 +vt 0.5156 0.4141 +vt 0.5156 0.4219 +vt 0.5078 0.4219 +vt 0.5235 0.4141 +vt 0.5313 0.4141 +vt 0.5313 0.4219 +vt 0.5235 0.4219 +vt 0.6015 0.3985 +vt 0.6094 0.3985 +vt 0.6093 0.4063 +vt 0.6015 0.4063 +vt 0.6015 0.3829 +vt 0.6094 0.3829 +vt 0.6094 0.3907 +vt 0.6015 0.3907 +vt 0.6172 0.3829 +vt 0.6250 0.3829 +vt 0.6250 0.3907 +vt 0.6172 0.3907 +vt 0.5703 0.3985 +vt 0.5781 0.3985 +vt 0.5781 0.4063 +vt 0.5703 0.4063 +vt 0.5703 0.3829 +vt 0.5781 0.3829 +vt 0.5781 0.3907 +vt 0.5703 0.3907 +vt 0.5859 0.3829 +vt 0.5937 0.3829 +vt 0.5937 0.3907 +vt 0.5859 0.3907 +vt 0.5703 0.4297 +vt 0.5781 0.4297 +vt 0.5781 0.4375 +vt 0.5703 0.4375 +vt 0.5703 0.4141 +vt 0.5781 0.4141 +vt 0.5781 0.4219 +vt 0.5703 0.4219 +vt 0.5859 0.4141 +vt 0.5937 0.4141 +vt 0.5937 0.4219 +vt 0.5859 0.4219 +vt 0.6641 0.0862 +vt 0.6719 0.0862 +vt 0.6719 0.0940 +vt 0.6641 0.0940 +vt 0.6641 0.0706 +vt 0.6719 0.0706 +vt 0.6719 0.0784 +vt 0.6641 0.0784 +vt 0.6797 0.0706 +vt 0.6875 0.0706 +vt 0.6875 0.0784 +vt 0.6797 0.0784 +vt 0.6329 0.0862 +vt 0.6407 0.0862 +vt 0.6407 0.0940 +vt 0.6329 0.0940 +vt 0.6329 0.0706 +vt 0.6407 0.0706 +vt 0.6407 0.0784 +vt 0.6329 0.0784 +vt 0.6485 0.0706 +vt 0.6563 0.0706 +vt 0.6563 0.0784 +vt 0.6485 0.0784 +vt 0.6329 0.1174 +vt 0.6407 0.1174 +vt 0.6407 0.1252 +vt 0.6329 0.1252 +vt 0.6329 0.1018 +vt 0.6407 0.1018 +vt 0.6407 0.1096 +vt 0.6329 0.1096 +vt 0.6485 0.1018 +vt 0.6563 0.1018 +vt 0.6563 0.1096 +vt 0.6485 0.1096 +vt 0.6641 0.0237 +vt 0.6719 0.0237 +vt 0.6719 0.0315 +vt 0.6641 0.0315 +vt 0.6641 0.0081 +vt 0.6719 0.0081 +vt 0.6719 0.0159 +vt 0.6641 0.0159 +vt 0.6797 0.0081 +vt 0.6876 0.0081 +vt 0.6876 0.0159 +vt 0.6797 0.0159 +vt 0.6329 0.0237 +vt 0.6407 0.0237 +vt 0.6407 0.0315 +vt 0.6329 0.0315 +vt 0.6329 0.0081 +vt 0.6407 0.0081 +vt 0.6407 0.0159 +vt 0.6329 0.0159 +vt 0.6485 0.0081 +vt 0.6563 0.0081 +vt 0.6563 0.0159 +vt 0.6485 0.0159 +vt 0.6329 0.0549 +vt 0.6407 0.0550 +vt 0.6407 0.0628 +vt 0.6329 0.0628 +vt 0.6329 0.0393 +vt 0.6407 0.0393 +vt 0.6407 0.0471 +vt 0.6329 0.0471 +vt 0.6485 0.0393 +vt 0.6563 0.0393 +vt 0.6563 0.0471 +vt 0.6485 0.0471 +vt 0.7266 0.0237 +vt 0.7344 0.0237 +vt 0.7344 0.0316 +vt 0.7266 0.0316 +vt 0.7266 0.0081 +vt 0.7344 0.0081 +vt 0.7344 0.0159 +vt 0.7266 0.0159 +vt 0.7422 0.0081 +vt 0.7500 0.0081 +vt 0.7500 0.0159 +vt 0.7422 0.0159 +vt 0.6954 0.0237 +vt 0.7032 0.0237 +vt 0.7032 0.0315 +vt 0.6954 0.0315 +vt 0.6954 0.0081 +vt 0.7032 0.0081 +vt 0.7032 0.0159 +vt 0.6954 0.0159 +vt 0.7110 0.0081 +vt 0.7188 0.0081 +vt 0.7188 0.0159 +vt 0.7110 0.0159 +vt 0.6953 0.0550 +vt 0.7032 0.0550 +vt 0.7032 0.0628 +vt 0.6953 0.0628 +vt 0.6954 0.0393 +vt 0.7032 0.0394 +vt 0.7032 0.0472 +vt 0.6954 0.0472 +vt 0.7110 0.0394 +vt 0.7188 0.0394 +vt 0.7188 0.0472 +vt 0.7110 0.0472 +vt 0.5392 0.0862 +vt 0.5470 0.0862 +vt 0.5470 0.0940 +vt 0.5392 0.0940 +vt 0.5392 0.0705 +vt 0.5470 0.0705 +vt 0.5470 0.0783 +vt 0.5392 0.0783 +vt 0.5548 0.0705 +vt 0.5626 0.0705 +vt 0.5626 0.0784 +vt 0.5548 0.0784 +vt 0.5079 0.0861 +vt 0.5157 0.0861 +vt 0.5157 0.0940 +vt 0.5079 0.0940 +vt 0.5079 0.0705 +vt 0.5158 0.0705 +vt 0.5157 0.0783 +vt 0.5079 0.0783 +vt 0.5236 0.0705 +vt 0.5314 0.0705 +vt 0.5314 0.0783 +vt 0.5236 0.0783 +vt 0.5079 0.1174 +vt 0.5157 0.1174 +vt 0.5157 0.1252 +vt 0.5079 0.1252 +vt 0.5079 0.1018 +vt 0.5157 0.1018 +vt 0.5157 0.1096 +vt 0.5079 0.1096 +vt 0.5235 0.1018 +vt 0.5314 0.1018 +vt 0.5314 0.1096 +vt 0.5235 0.1096 +vt 0.5392 0.0237 +vt 0.5470 0.0237 +vt 0.5470 0.0315 +vt 0.5392 0.0315 +vt 0.5392 0.0081 +vt 0.5470 0.0081 +vt 0.5470 0.0159 +vt 0.5392 0.0159 +vt 0.5548 0.0081 +vt 0.5626 0.0081 +vt 0.5626 0.0159 +vt 0.5548 0.0159 +vt 0.5080 0.0237 +vt 0.5158 0.0237 +vt 0.5158 0.0315 +vt 0.5080 0.0315 +vt 0.5080 0.0081 +vt 0.5158 0.0081 +vt 0.5158 0.0159 +vt 0.5080 0.0159 +vt 0.5236 0.0081 +vt 0.5314 0.0081 +vt 0.5314 0.0159 +vt 0.5236 0.0159 +vt 0.5079 0.0549 +vt 0.5158 0.0549 +vt 0.5158 0.0627 +vt 0.5079 0.0627 +vt 0.5080 0.0393 +vt 0.5158 0.0393 +vt 0.5158 0.0471 +vt 0.5079 0.0471 +vt 0.5236 0.0393 +vt 0.5314 0.0393 +vt 0.5314 0.0471 +vt 0.5236 0.0471 +vt 0.6017 0.0237 +vt 0.6095 0.0237 +vt 0.6095 0.0315 +vt 0.6017 0.0315 +vt 0.6017 0.0081 +vt 0.6095 0.0081 +vt 0.6095 0.0159 +vt 0.6017 0.0159 +vt 0.6173 0.0081 +vt 0.6251 0.0081 +vt 0.6251 0.0159 +vt 0.6173 0.0159 +vt 0.5704 0.0237 +vt 0.5782 0.0237 +vt 0.5782 0.0315 +vt 0.5704 0.0315 +vt 0.5704 0.0081 +vt 0.5782 0.0081 +vt 0.5782 0.0159 +vt 0.5704 0.0159 +vt 0.5860 0.0081 +vt 0.5939 0.0081 +vt 0.5939 0.0159 +vt 0.5860 0.0159 +vt 0.5704 0.0549 +vt 0.5782 0.0549 +vt 0.5782 0.0627 +vt 0.5704 0.0627 +vt 0.5704 0.0393 +vt 0.5782 0.0393 +vt 0.5782 0.0471 +vt 0.5704 0.0471 +vt 0.5860 0.0393 +vt 0.5938 0.0393 +vt 0.5938 0.0471 +vt 0.5860 0.0471 +vt 0.5391 0.2111 +vt 0.5469 0.2111 +vt 0.5469 0.2189 +vt 0.5391 0.2189 +vt 0.5391 0.1955 +vt 0.5469 0.1955 +vt 0.5469 0.2033 +vt 0.5391 0.2033 +vt 0.5548 0.1955 +vt 0.5626 0.1955 +vt 0.5626 0.2033 +vt 0.5548 0.2033 +vt 0.5079 0.2111 +vt 0.5157 0.2111 +vt 0.5157 0.2189 +vt 0.5079 0.2189 +vt 0.5079 0.1955 +vt 0.5157 0.1955 +vt 0.5157 0.2033 +vt 0.5079 0.2033 +vt 0.5235 0.1955 +vt 0.5313 0.1955 +vt 0.5313 0.2033 +vt 0.5235 0.2033 +vt 0.5079 0.2423 +vt 0.5157 0.2423 +vt 0.5157 0.2501 +vt 0.5079 0.2501 +vt 0.5079 0.2267 +vt 0.5157 0.2267 +vt 0.5157 0.2345 +vt 0.5079 0.2345 +vt 0.5235 0.2267 +vt 0.5313 0.2267 +vt 0.5313 0.2345 +vt 0.5235 0.2345 +vt 0.5392 0.1486 +vt 0.5470 0.1486 +vt 0.5470 0.1564 +vt 0.5391 0.1564 +vt 0.5392 0.1330 +vt 0.5470 0.1330 +vt 0.5470 0.1408 +vt 0.5392 0.1408 +vt 0.5548 0.1330 +vt 0.5626 0.1330 +vt 0.5626 0.1408 +vt 0.5548 0.1408 +vt 0.5079 0.1486 +vt 0.5157 0.1486 +vt 0.5157 0.1564 +vt 0.5079 0.1564 +vt 0.5079 0.1330 +vt 0.5157 0.1330 +vt 0.5157 0.1408 +vt 0.5079 0.1408 +vt 0.5235 0.1330 +vt 0.5313 0.1330 +vt 0.5313 0.1408 +vt 0.5235 0.1408 +vt 0.5079 0.1798 +vt 0.5157 0.1798 +vt 0.5157 0.1877 +vt 0.5079 0.1877 +vt 0.5079 0.1642 +vt 0.5157 0.1642 +vt 0.5157 0.1720 +vt 0.5079 0.1720 +vt 0.5235 0.1642 +vt 0.5313 0.1642 +vt 0.5313 0.1720 +vt 0.5235 0.1720 +vt 0.6016 0.1486 +vt 0.6094 0.1486 +vt 0.6094 0.1565 +vt 0.6016 0.1564 +vt 0.6016 0.1330 +vt 0.6094 0.1330 +vt 0.6094 0.1408 +vt 0.6016 0.1408 +vt 0.6172 0.1330 +vt 0.6250 0.1330 +vt 0.6250 0.1408 +vt 0.6172 0.1408 +vt 0.5704 0.1486 +vt 0.5782 0.1486 +vt 0.5782 0.1564 +vt 0.5704 0.1564 +vt 0.5704 0.1330 +vt 0.5782 0.1330 +vt 0.5782 0.1408 +vt 0.5704 0.1408 +vt 0.5860 0.1330 +vt 0.5938 0.1330 +vt 0.5938 0.1408 +vt 0.5860 0.1408 +vt 0.5704 0.1799 +vt 0.5782 0.1799 +vt 0.5782 0.1877 +vt 0.5704 0.1877 +vt 0.5704 0.1642 +vt 0.5782 0.1642 +vt 0.5782 0.1721 +vt 0.5704 0.1721 +vt 0.5860 0.1643 +vt 0.5938 0.1643 +vt 0.5938 0.1721 +vt 0.5860 0.1721 +vt 0.9140 0.0863 +vt 0.9218 0.0863 +vt 0.9218 0.0941 +vt 0.9140 0.0941 +vt 0.9140 0.0707 +vt 0.9218 0.0707 +vt 0.9218 0.0785 +vt 0.9140 0.0785 +vt 0.9296 0.0707 +vt 0.9374 0.0707 +vt 0.9374 0.0785 +vt 0.9296 0.0785 +vt 0.8827 0.0863 +vt 0.8906 0.0863 +vt 0.8906 0.0941 +vt 0.8827 0.0941 +vt 0.8827 0.0706 +vt 0.8906 0.0706 +vt 0.8906 0.0785 +vt 0.8827 0.0784 +vt 0.8984 0.0706 +vt 0.9062 0.0706 +vt 0.9062 0.0785 +vt 0.8984 0.0785 +vt 0.8827 0.1175 +vt 0.8905 0.1175 +vt 0.8905 0.1253 +vt 0.8827 0.1253 +vt 0.8827 0.1019 +vt 0.8905 0.1019 +vt 0.8905 0.1097 +vt 0.8827 0.1097 +vt 0.8984 0.1019 +vt 0.9062 0.1019 +vt 0.9062 0.1097 +vt 0.8984 0.1097 +vt 0.9140 0.0238 +vt 0.9218 0.0238 +vt 0.9218 0.0316 +vt 0.9140 0.0316 +vt 0.9140 0.0082 +vt 0.9218 0.0082 +vt 0.9218 0.0160 +vt 0.9140 0.0160 +vt 0.9296 0.0082 +vt 0.9374 0.0082 +vt 0.9374 0.0160 +vt 0.9296 0.0160 +vt 0.8828 0.0238 +vt 0.8906 0.0238 +vt 0.8906 0.0316 +vt 0.8828 0.0316 +vt 0.8828 0.0082 +vt 0.8906 0.0082 +vt 0.8906 0.0160 +vt 0.8828 0.0160 +vt 0.8984 0.0082 +vt 0.9062 0.0082 +vt 0.9062 0.0160 +vt 0.8984 0.0160 +vt 0.8828 0.0550 +vt 0.8906 0.0550 +vt 0.8906 0.0628 +vt 0.8828 0.0628 +vt 0.8828 0.0394 +vt 0.8906 0.0394 +vt 0.8906 0.0472 +vt 0.8828 0.0472 +vt 0.8984 0.0394 +vt 0.9062 0.0394 +vt 0.9062 0.0472 +vt 0.8984 0.0472 +vt 0.9765 0.0238 +vt 0.9843 0.0238 +vt 0.9843 0.0316 +vt 0.9765 0.0316 +vt 0.9765 0.0082 +vt 0.9843 0.0082 +vt 0.9843 0.0160 +vt 0.9765 0.0160 +vt 0.9921 0.0082 +vt 0.9999 0.0082 +vt 0.9999 0.0160 +vt 0.9921 0.0160 +vt 0.9452 0.0238 +vt 0.9530 0.0238 +vt 0.9530 0.0316 +vt 0.9452 0.0316 +vt 0.9452 0.0082 +vt 0.9530 0.0082 +vt 0.9530 0.0160 +vt 0.9452 0.0160 +vt 0.9609 0.0082 +vt 0.9687 0.0082 +vt 0.9687 0.0160 +vt 0.9609 0.0160 +vt 0.9452 0.0550 +vt 0.9530 0.0550 +vt 0.9530 0.0629 +vt 0.9452 0.0629 +vt 0.9452 0.0394 +vt 0.9530 0.0394 +vt 0.9530 0.0472 +vt 0.9452 0.0472 +vt 0.9608 0.0394 +vt 0.9687 0.0394 +vt 0.9687 0.0472 +vt 0.9608 0.0472 +vt 0.7890 0.0862 +vt 0.7969 0.0862 +vt 0.7968 0.0940 +vt 0.7890 0.0940 +vt 0.7890 0.0706 +vt 0.7969 0.0706 +vt 0.7969 0.0784 +vt 0.7890 0.0784 +vt 0.8047 0.0706 +vt 0.8125 0.0706 +vt 0.8125 0.0784 +vt 0.8047 0.0784 +vt 0.7578 0.0862 +vt 0.7656 0.0862 +vt 0.7656 0.0940 +vt 0.7578 0.0940 +vt 0.7578 0.0706 +vt 0.7656 0.0706 +vt 0.7656 0.0784 +vt 0.7578 0.0784 +vt 0.7734 0.0706 +vt 0.7812 0.0706 +vt 0.7812 0.0784 +vt 0.7734 0.0784 +vt 0.7578 0.1175 +vt 0.7656 0.1175 +vt 0.7656 0.1253 +vt 0.7578 0.1253 +vt 0.7578 0.1018 +vt 0.7656 0.1018 +vt 0.7656 0.1096 +vt 0.7578 0.1096 +vt 0.7734 0.1018 +vt 0.7812 0.1018 +vt 0.7812 0.1097 +vt 0.7734 0.1097 +vt 0.7891 0.0238 +vt 0.7969 0.0238 +vt 0.7969 0.0316 +vt 0.7891 0.0316 +vt 0.7891 0.0081 +vt 0.7969 0.0081 +vt 0.7969 0.0160 +vt 0.7891 0.0160 +vt 0.8047 0.0081 +vt 0.8125 0.0082 +vt 0.8125 0.0160 +vt 0.8047 0.0160 +vt 0.7578 0.0238 +vt 0.7656 0.0238 +vt 0.7656 0.0316 +vt 0.7578 0.0316 +vt 0.7578 0.0081 +vt 0.7656 0.0081 +vt 0.7656 0.0159 +vt 0.7578 0.0159 +vt 0.7734 0.0081 +vt 0.7813 0.0081 +vt 0.7813 0.0160 +vt 0.7734 0.0159 +vt 0.7578 0.0550 +vt 0.7656 0.0550 +vt 0.7656 0.0628 +vt 0.7578 0.0628 +vt 0.7578 0.0394 +vt 0.7656 0.0394 +vt 0.7656 0.0472 +vt 0.7578 0.0472 +vt 0.7734 0.0394 +vt 0.7812 0.0394 +vt 0.7812 0.0472 +vt 0.7734 0.0472 +vt 0.8515 0.0238 +vt 0.8593 0.0238 +vt 0.8593 0.0316 +vt 0.8515 0.0316 +vt 0.8515 0.0082 +vt 0.8593 0.0082 +vt 0.8593 0.0160 +vt 0.8515 0.0160 +vt 0.8672 0.0082 +vt 0.8750 0.0082 +vt 0.8750 0.0160 +vt 0.8671 0.0160 +vt 0.8203 0.0238 +vt 0.8281 0.0238 +vt 0.8281 0.0316 +vt 0.8203 0.0316 +vt 0.8203 0.0082 +vt 0.8281 0.0082 +vt 0.8281 0.0160 +vt 0.8203 0.0160 +vt 0.8359 0.0082 +vt 0.8437 0.0082 +vt 0.8437 0.0160 +vt 0.8359 0.0160 +vt 0.8203 0.0550 +vt 0.8281 0.0550 +vt 0.8281 0.0628 +vt 0.8203 0.0628 +vt 0.8203 0.0394 +vt 0.8281 0.0394 +vt 0.8281 0.0472 +vt 0.8203 0.0472 +vt 0.8359 0.0394 +vt 0.8437 0.0394 +vt 0.8437 0.0472 +vt 0.8359 0.0472 +vt 0.7890 0.2112 +vt 0.7968 0.2112 +vt 0.7968 0.2190 +vt 0.7890 0.2190 +vt 0.7890 0.1955 +vt 0.7968 0.1956 +vt 0.7968 0.2034 +vt 0.7890 0.2034 +vt 0.8046 0.1956 +vt 0.8124 0.1956 +vt 0.8124 0.2034 +vt 0.8046 0.2034 +vt 0.7578 0.2112 +vt 0.7656 0.2112 +vt 0.7656 0.2190 +vt 0.7578 0.2190 +vt 0.7578 0.1955 +vt 0.7656 0.1955 +vt 0.7656 0.2033 +vt 0.7578 0.2033 +vt 0.7734 0.1955 +vt 0.7812 0.1955 +vt 0.7812 0.2034 +vt 0.7734 0.2034 +vt 0.7578 0.2424 +vt 0.7656 0.2424 +vt 0.7656 0.2502 +vt 0.7578 0.2502 +vt 0.7578 0.2268 +vt 0.7656 0.2268 +vt 0.7656 0.2346 +vt 0.7578 0.2346 +vt 0.7734 0.2268 +vt 0.7812 0.2268 +vt 0.7812 0.2346 +vt 0.7734 0.2346 +vt 0.7890 0.1487 +vt 0.7968 0.1487 +vt 0.7968 0.1565 +vt 0.7890 0.1565 +vt 0.7890 0.1331 +vt 0.7968 0.1331 +vt 0.7968 0.1409 +vt 0.7890 0.1409 +vt 0.8046 0.1331 +vt 0.8125 0.1331 +vt 0.8125 0.1409 +vt 0.8046 0.1409 +vt 0.7578 0.1487 +vt 0.7656 0.1487 +vt 0.7656 0.1565 +vt 0.7578 0.1565 +vt 0.7578 0.1331 +vt 0.7656 0.1331 +vt 0.7656 0.1409 +vt 0.7578 0.1409 +vt 0.7734 0.1331 +vt 0.7812 0.1331 +vt 0.7812 0.1409 +vt 0.7734 0.1409 +vt 0.7578 0.1799 +vt 0.7656 0.1799 +vt 0.7656 0.1877 +vt 0.7578 0.1877 +vt 0.7578 0.1643 +vt 0.7656 0.1643 +vt 0.7656 0.1721 +vt 0.7578 0.1721 +vt 0.7734 0.1643 +vt 0.7812 0.1643 +vt 0.7812 0.1721 +vt 0.7734 0.1721 +vt 0.8515 0.1487 +vt 0.8593 0.1487 +vt 0.8593 0.1565 +vt 0.8515 0.1565 +vt 0.8515 0.1331 +vt 0.8593 0.1331 +vt 0.8593 0.1409 +vt 0.8515 0.1409 +vt 0.8671 0.1331 +vt 0.8749 0.1331 +vt 0.8749 0.1409 +vt 0.8671 0.1409 +vt 0.8203 0.1487 +vt 0.8281 0.1487 +vt 0.8281 0.1565 +vt 0.8203 0.1565 +vt 0.8203 0.1331 +vt 0.8281 0.1331 +vt 0.8281 0.1409 +vt 0.8203 0.1409 +vt 0.8359 0.1331 +vt 0.8437 0.1331 +vt 0.8437 0.1409 +vt 0.8359 0.1409 +vt 0.8202 0.1799 +vt 0.8281 0.1799 +vt 0.8281 0.1878 +vt 0.8202 0.1877 +vt 0.8203 0.1643 +vt 0.8281 0.1643 +vt 0.8281 0.1721 +vt 0.8202 0.1721 +vt 0.8359 0.1643 +vt 0.8437 0.1643 +vt 0.8437 0.1721 +vt 0.8359 0.1721 +vt 0.1643 0.3359 +vt 0.1721 0.3359 +vt 0.1721 0.3437 +vt 0.1643 0.3437 +vt 0.1643 0.3203 +vt 0.1721 0.3203 +vt 0.1721 0.3281 +vt 0.1643 0.3281 +vt 0.1799 0.3203 +vt 0.1877 0.3203 +vt 0.1877 0.3281 +vt 0.1799 0.3281 +vt 0.1331 0.3359 +vt 0.1409 0.3359 +vt 0.1409 0.3437 +vt 0.1331 0.3437 +vt 0.1331 0.3203 +vt 0.1409 0.3203 +vt 0.1409 0.3281 +vt 0.1331 0.3281 +vt 0.1487 0.3203 +vt 0.1565 0.3203 +vt 0.1565 0.3281 +vt 0.1487 0.3281 +vt 0.1331 0.3671 +vt 0.1409 0.3671 +vt 0.1409 0.3749 +vt 0.1330 0.3749 +vt 0.1331 0.3515 +vt 0.1409 0.3515 +vt 0.1409 0.3593 +vt 0.1331 0.3593 +vt 0.1487 0.3515 +vt 0.1565 0.3515 +vt 0.1565 0.3593 +vt 0.1487 0.3593 +vt 0.1643 0.2734 +vt 0.1721 0.2734 +vt 0.1721 0.2812 +vt 0.1643 0.2812 +vt 0.1643 0.2578 +vt 0.1721 0.2578 +vt 0.1721 0.2656 +vt 0.1643 0.2656 +vt 0.1799 0.2578 +vt 0.1877 0.2578 +vt 0.1877 0.2656 +vt 0.1799 0.2656 +vt 0.1331 0.2734 +vt 0.1409 0.2734 +vt 0.1409 0.2812 +vt 0.1331 0.2812 +vt 0.1331 0.2578 +vt 0.1409 0.2578 +vt 0.1409 0.2656 +vt 0.1331 0.2656 +vt 0.1487 0.2578 +vt 0.1565 0.2578 +vt 0.1565 0.2656 +vt 0.1487 0.2656 +vt 0.1331 0.3047 +vt 0.1409 0.3047 +vt 0.1409 0.3125 +vt 0.1331 0.3125 +vt 0.1331 0.2890 +vt 0.1409 0.2890 +vt 0.1409 0.2969 +vt 0.1331 0.2969 +vt 0.1487 0.2890 +vt 0.1565 0.2891 +vt 0.1565 0.2969 +vt 0.1487 0.2969 +vt 0.2268 0.2735 +vt 0.2346 0.2735 +vt 0.2346 0.2813 +vt 0.2268 0.2813 +vt 0.2268 0.2578 +vt 0.2346 0.2578 +vt 0.2346 0.2657 +vt 0.2268 0.2656 +vt 0.2424 0.2578 +vt 0.2502 0.2578 +vt 0.2502 0.2657 +vt 0.2424 0.2657 +vt 0.1955 0.2734 +vt 0.2034 0.2735 +vt 0.2034 0.2813 +vt 0.1955 0.2813 +vt 0.1956 0.2578 +vt 0.2034 0.2578 +vt 0.2034 0.2656 +vt 0.1955 0.2656 +vt 0.2112 0.2578 +vt 0.2190 0.2578 +vt 0.2190 0.2656 +vt 0.2112 0.2656 +vt 0.1955 0.3047 +vt 0.2033 0.3047 +vt 0.2033 0.3125 +vt 0.1955 0.3125 +vt 0.1955 0.2891 +vt 0.2034 0.2891 +vt 0.2033 0.2969 +vt 0.1955 0.2969 +vt 0.2112 0.2891 +vt 0.2190 0.2891 +vt 0.2190 0.2969 +vt 0.2112 0.2969 +vt 0.0394 0.3359 +vt 0.0472 0.3359 +vt 0.0472 0.3437 +vt 0.0394 0.3437 +vt 0.0394 0.3202 +vt 0.0472 0.3202 +vt 0.0472 0.3281 +vt 0.0394 0.3281 +vt 0.0550 0.3203 +vt 0.0628 0.3203 +vt 0.0628 0.3281 +vt 0.0550 0.3281 +vt 0.0081 0.3359 +vt 0.0159 0.3359 +vt 0.0159 0.3437 +vt 0.0081 0.3437 +vt 0.0081 0.3202 +vt 0.0159 0.3202 +vt 0.0159 0.3280 +vt 0.0081 0.3280 +vt 0.0237 0.3202 +vt 0.0316 0.3202 +vt 0.0316 0.3281 +vt 0.0237 0.3280 +vt 0.0081 0.3671 +vt 0.0159 0.3671 +vt 0.0159 0.3749 +vt 0.0081 0.3749 +vt 0.0081 0.3515 +vt 0.0159 0.3515 +vt 0.0159 0.3593 +vt 0.0081 0.3593 +vt 0.0237 0.3515 +vt 0.0315 0.3515 +vt 0.0315 0.3593 +vt 0.0237 0.3593 +vt 0.0394 0.2734 +vt 0.0472 0.2734 +vt 0.0472 0.2812 +vt 0.0394 0.2812 +vt 0.0394 0.2578 +vt 0.0472 0.2578 +vt 0.0472 0.2656 +vt 0.0394 0.2656 +vt 0.0550 0.2578 +vt 0.0628 0.2578 +vt 0.0628 0.2656 +vt 0.0550 0.2656 +vt 0.0081 0.2734 +vt 0.0160 0.2734 +vt 0.0160 0.2812 +vt 0.0081 0.2812 +vt 0.0082 0.2578 +vt 0.0160 0.2578 +vt 0.0160 0.2656 +vt 0.0082 0.2656 +vt 0.0238 0.2578 +vt 0.0316 0.2578 +vt 0.0316 0.2656 +vt 0.0238 0.2656 +vt 0.0081 0.3046 +vt 0.0159 0.3046 +vt 0.0159 0.3124 +vt 0.0081 0.3124 +vt 0.0081 0.2890 +vt 0.0160 0.2890 +vt 0.0159 0.2968 +vt 0.0081 0.2968 +vt 0.0238 0.2890 +vt 0.0316 0.2890 +vt 0.0316 0.2968 +vt 0.0238 0.2968 +vt 0.1018 0.2734 +vt 0.1097 0.2734 +vt 0.1097 0.2812 +vt 0.1018 0.2812 +vt 0.1019 0.2578 +vt 0.1097 0.2578 +vt 0.1097 0.2656 +vt 0.1019 0.2656 +vt 0.1175 0.2578 +vt 0.1253 0.2578 +vt 0.1253 0.2656 +vt 0.1175 0.2656 +vt 0.0706 0.2734 +vt 0.0784 0.2734 +vt 0.0784 0.2812 +vt 0.0706 0.2812 +vt 0.0706 0.2578 +vt 0.0784 0.2578 +vt 0.0784 0.2656 +vt 0.0706 0.2656 +vt 0.0862 0.2578 +vt 0.0940 0.2578 +vt 0.0940 0.2656 +vt 0.0862 0.2656 +vt 0.0706 0.3046 +vt 0.0784 0.3046 +vt 0.0784 0.3125 +vt 0.0706 0.3124 +vt 0.0706 0.2890 +vt 0.0784 0.2890 +vt 0.0784 0.2968 +vt 0.0706 0.2968 +vt 0.0862 0.2890 +vt 0.0940 0.2890 +vt 0.0940 0.2968 +vt 0.0862 0.2968 +vt 0.0393 0.4608 +vt 0.0471 0.4608 +vt 0.0471 0.4686 +vt 0.0393 0.4686 +vt 0.0393 0.4452 +vt 0.0471 0.4452 +vt 0.0471 0.4530 +vt 0.0393 0.4530 +vt 0.0549 0.4452 +vt 0.0627 0.4452 +vt 0.0627 0.4530 +vt 0.0549 0.4530 +vt 0.0081 0.4608 +vt 0.0159 0.4608 +vt 0.0159 0.4686 +vt 0.0081 0.4686 +vt 0.0081 0.4452 +vt 0.0159 0.4452 +vt 0.0159 0.4530 +vt 0.0081 0.4530 +vt 0.0237 0.4452 +vt 0.0315 0.4452 +vt 0.0315 0.4530 +vt 0.0237 0.4530 +vt 0.0081 0.4920 +vt 0.0159 0.4920 +vt 0.0159 0.4998 +vt 0.0081 0.4998 +vt 0.0081 0.4764 +vt 0.0159 0.4764 +vt 0.0159 0.4842 +vt 0.0081 0.4842 +vt 0.0237 0.4764 +vt 0.0315 0.4764 +vt 0.0315 0.4842 +vt 0.0237 0.4842 +vt 0.0393 0.3983 +vt 0.0471 0.3983 +vt 0.0471 0.4061 +vt 0.0393 0.4061 +vt 0.0393 0.3827 +vt 0.0472 0.3827 +vt 0.0472 0.3905 +vt 0.0393 0.3905 +vt 0.0550 0.3827 +vt 0.0628 0.3827 +vt 0.0628 0.3905 +vt 0.0550 0.3905 +vt 0.0081 0.3983 +vt 0.0159 0.3983 +vt 0.0159 0.4061 +vt 0.0081 0.4061 +vt 0.0081 0.3827 +vt 0.0159 0.3827 +vt 0.0159 0.3905 +vt 0.0081 0.3905 +vt 0.0237 0.3827 +vt 0.0315 0.3827 +vt 0.0315 0.3905 +vt 0.0237 0.3905 +vt 0.0081 0.4296 +vt 0.0159 0.4296 +vt 0.0159 0.4374 +vt 0.0081 0.4374 +vt 0.0081 0.4139 +vt 0.0159 0.4139 +vt 0.0159 0.4217 +vt 0.0081 0.4217 +vt 0.0237 0.4139 +vt 0.0315 0.4139 +vt 0.0315 0.4218 +vt 0.0237 0.4217 +vt 0.1018 0.3984 +vt 0.1096 0.3984 +vt 0.1096 0.4062 +vt 0.1018 0.4062 +vt 0.1018 0.3827 +vt 0.1096 0.3827 +vt 0.1096 0.3905 +vt 0.1018 0.3905 +vt 0.1174 0.3827 +vt 0.1252 0.3827 +vt 0.1252 0.3905 +vt 0.1174 0.3905 +vt 0.0706 0.3983 +vt 0.0784 0.3983 +vt 0.0784 0.4062 +vt 0.0706 0.4061 +vt 0.0706 0.3827 +vt 0.0784 0.3827 +vt 0.0784 0.3905 +vt 0.0706 0.3905 +vt 0.0862 0.3827 +vt 0.0940 0.3827 +vt 0.0940 0.3905 +vt 0.0862 0.3905 +vt 0.0706 0.4296 +vt 0.0784 0.4296 +vt 0.0784 0.4374 +vt 0.0706 0.4374 +vt 0.0706 0.4140 +vt 0.0784 0.4140 +vt 0.0784 0.4218 +vt 0.0706 0.4218 +vt 0.0862 0.4140 +vt 0.0940 0.4140 +vt 0.0940 0.4218 +vt 0.0862 0.4218 +vt 0.1644 0.0860 +vt 0.1722 0.0860 +vt 0.1722 0.0939 +vt 0.1644 0.0938 +vt 0.1644 0.0704 +vt 0.1722 0.0704 +vt 0.1722 0.0782 +vt 0.1644 0.0782 +vt 0.1800 0.0704 +vt 0.1878 0.0704 +vt 0.1878 0.0782 +vt 0.1800 0.0782 +vt 0.1331 0.0860 +vt 0.1409 0.0860 +vt 0.1409 0.0938 +vt 0.1331 0.0938 +vt 0.1331 0.0704 +vt 0.1410 0.0704 +vt 0.1410 0.0782 +vt 0.1331 0.0782 +vt 0.1488 0.0704 +vt 0.1566 0.0704 +vt 0.1566 0.0782 +vt 0.1488 0.0782 +vt 0.1331 0.1173 +vt 0.1409 0.1173 +vt 0.1409 0.1251 +vt 0.1331 0.1251 +vt 0.1331 0.1016 +vt 0.1409 0.1016 +vt 0.1409 0.1095 +vt 0.1331 0.1095 +vt 0.1488 0.1017 +vt 0.1566 0.1017 +vt 0.1566 0.1095 +vt 0.1487 0.1095 +vt 0.1644 0.0236 +vt 0.1722 0.0236 +vt 0.1722 0.0314 +vt 0.1644 0.0314 +vt 0.1644 0.0080 +vt 0.1722 0.0080 +vt 0.1722 0.0158 +vt 0.1644 0.0158 +vt 0.1800 0.0080 +vt 0.1878 0.0080 +vt 0.1878 0.0158 +vt 0.1800 0.0158 +vt 0.1332 0.0236 +vt 0.1410 0.0236 +vt 0.1410 0.0314 +vt 0.1332 0.0314 +vt 0.1332 0.0079 +vt 0.1410 0.0080 +vt 0.1410 0.0158 +vt 0.1332 0.0158 +vt 0.1488 0.0080 +vt 0.1566 0.0080 +vt 0.1566 0.0158 +vt 0.1488 0.0158 +vt 0.1332 0.0548 +vt 0.1410 0.0548 +vt 0.1410 0.0626 +vt 0.1331 0.0626 +vt 0.1332 0.0392 +vt 0.1410 0.0392 +vt 0.1410 0.0470 +vt 0.1332 0.0470 +vt 0.1488 0.0392 +vt 0.1566 0.0392 +vt 0.1566 0.0470 +vt 0.1488 0.0470 +vt 0.2269 0.0236 +vt 0.2347 0.0236 +vt 0.2347 0.0314 +vt 0.2269 0.0314 +vt 0.2269 0.0080 +vt 0.2347 0.0080 +vt 0.2347 0.0158 +vt 0.2269 0.0158 +vt 0.2425 0.0080 +vt 0.2503 0.0080 +vt 0.2503 0.0158 +vt 0.2425 0.0158 +vt 0.1956 0.0236 +vt 0.2034 0.0236 +vt 0.2034 0.0314 +vt 0.1956 0.0314 +vt 0.1956 0.0080 +vt 0.2034 0.0080 +vt 0.2034 0.0158 +vt 0.1956 0.0158 +vt 0.2112 0.0080 +vt 0.2191 0.0080 +vt 0.2191 0.0158 +vt 0.2112 0.0158 +vt 0.1956 0.0548 +vt 0.2034 0.0548 +vt 0.2034 0.0626 +vt 0.1956 0.0626 +vt 0.1956 0.0392 +vt 0.2034 0.0392 +vt 0.2034 0.0470 +vt 0.1956 0.0470 +vt 0.2112 0.0392 +vt 0.2190 0.0392 +vt 0.2190 0.0470 +vt 0.2112 0.0470 +vt 0.0394 0.0860 +vt 0.0473 0.0860 +vt 0.0472 0.0938 +vt 0.0394 0.0938 +vt 0.0394 0.0704 +vt 0.0473 0.0704 +vt 0.0473 0.0782 +vt 0.0394 0.0782 +vt 0.0551 0.0704 +vt 0.0629 0.0704 +vt 0.0629 0.0782 +vt 0.0551 0.0782 +vt 0.0082 0.0860 +vt 0.0160 0.0860 +vt 0.0160 0.0938 +vt 0.0082 0.0938 +vt 0.0082 0.0704 +vt 0.0160 0.0704 +vt 0.0160 0.0782 +vt 0.0082 0.0782 +vt 0.0238 0.0704 +vt 0.0316 0.0704 +vt 0.0316 0.0782 +vt 0.0238 0.0782 +vt 0.0082 0.1172 +vt 0.0160 0.1172 +vt 0.0160 0.1250 +vt 0.0082 0.1250 +vt 0.0082 0.1016 +vt 0.0160 0.1016 +vt 0.0160 0.1094 +vt 0.0082 0.1094 +vt 0.0238 0.1016 +vt 0.0316 0.1016 +vt 0.0316 0.1094 +vt 0.0238 0.1094 +vt 0.0395 0.0235 +vt 0.0473 0.0235 +vt 0.0473 0.0313 +vt 0.0395 0.0313 +vt 0.0395 0.0079 +vt 0.0473 0.0079 +vt 0.0473 0.0157 +vt 0.0395 0.0157 +vt 0.0551 0.0079 +vt 0.0629 0.0079 +vt 0.0629 0.0157 +vt 0.0551 0.0157 +vt 0.0082 0.0235 +vt 0.0160 0.0235 +vt 0.0160 0.0313 +vt 0.0082 0.0313 +vt 0.0082 0.0079 +vt 0.0160 0.0079 +vt 0.0160 0.0157 +vt 0.0082 0.0157 +vt 0.0239 0.0079 +vt 0.0317 0.0079 +vt 0.0317 0.0157 +vt 0.0238 0.0157 +vt 0.0082 0.0548 +vt 0.0160 0.0548 +vt 0.0160 0.0626 +vt 0.0082 0.0626 +vt 0.0082 0.0391 +vt 0.0160 0.0391 +vt 0.0160 0.0470 +vt 0.0082 0.0470 +vt 0.0238 0.0391 +vt 0.0316 0.0392 +vt 0.0316 0.0470 +vt 0.0238 0.0470 +vt 0.1019 0.0236 +vt 0.1097 0.0236 +vt 0.1097 0.0314 +vt 0.1019 0.0314 +vt 0.1019 0.0079 +vt 0.1097 0.0079 +vt 0.1097 0.0158 +vt 0.1019 0.0157 +vt 0.1175 0.0079 +vt 0.1254 0.0079 +vt 0.1254 0.0158 +vt 0.1175 0.0158 +vt 0.0707 0.0235 +vt 0.0785 0.0235 +vt 0.0785 0.0314 +vt 0.0707 0.0314 +vt 0.0707 0.0079 +vt 0.0785 0.0079 +vt 0.0785 0.0157 +vt 0.0707 0.0157 +vt 0.0863 0.0079 +vt 0.0941 0.0079 +vt 0.0941 0.0157 +vt 0.0863 0.0157 +vt 0.0707 0.0548 +vt 0.0785 0.0548 +vt 0.0785 0.0626 +vt 0.0707 0.0626 +vt 0.0707 0.0392 +vt 0.0785 0.0392 +vt 0.0785 0.0470 +vt 0.0707 0.0470 +vt 0.0863 0.0392 +vt 0.0941 0.0392 +vt 0.0941 0.0470 +vt 0.0863 0.0470 +vt 0.0394 0.2109 +vt 0.0472 0.2109 +vt 0.0472 0.2187 +vt 0.0394 0.2187 +vt 0.0394 0.1953 +vt 0.0472 0.1953 +vt 0.0472 0.2031 +vt 0.0394 0.2031 +vt 0.0550 0.1953 +vt 0.0628 0.1953 +vt 0.0628 0.2031 +vt 0.0550 0.2031 +vt 0.0082 0.2109 +vt 0.0160 0.2109 +vt 0.0160 0.2187 +vt 0.0082 0.2187 +vt 0.0082 0.1953 +vt 0.0160 0.1953 +vt 0.0160 0.2031 +vt 0.0082 0.2031 +vt 0.0238 0.1953 +vt 0.0316 0.1953 +vt 0.0316 0.2031 +vt 0.0238 0.2031 +vt 0.0082 0.2422 +vt 0.0160 0.2422 +vt 0.0160 0.2500 +vt 0.0082 0.2500 +vt 0.0082 0.2265 +vt 0.0160 0.2265 +vt 0.0160 0.2343 +vt 0.0082 0.2343 +vt 0.0238 0.2265 +vt 0.0316 0.2265 +vt 0.0316 0.2344 +vt 0.0238 0.2344 +vt 0.0394 0.1485 +vt 0.0472 0.1485 +vt 0.0472 0.1563 +vt 0.0394 0.1563 +vt 0.0394 0.1328 +vt 0.0472 0.1329 +vt 0.0472 0.1407 +vt 0.0394 0.1407 +vt 0.0550 0.1329 +vt 0.0629 0.1329 +vt 0.0629 0.1407 +vt 0.0550 0.1407 +vt 0.0082 0.1485 +vt 0.0160 0.1485 +vt 0.0160 0.1563 +vt 0.0082 0.1563 +vt 0.0082 0.1328 +vt 0.0160 0.1328 +vt 0.0160 0.1407 +vt 0.0082 0.1406 +vt 0.0238 0.1328 +vt 0.0316 0.1328 +vt 0.0316 0.1407 +vt 0.0238 0.1407 +vt 0.0082 0.1797 +vt 0.0160 0.1797 +vt 0.0160 0.1875 +vt 0.0082 0.1875 +vt 0.0082 0.1641 +vt 0.0160 0.1641 +vt 0.0160 0.1719 +vt 0.0082 0.1719 +vt 0.0238 0.1641 +vt 0.0316 0.1641 +vt 0.0316 0.1719 +vt 0.0238 0.1719 +vt 0.1019 0.1485 +vt 0.1097 0.1485 +vt 0.1097 0.1563 +vt 0.1019 0.1563 +vt 0.1019 0.1329 +vt 0.1097 0.1329 +vt 0.1097 0.1407 +vt 0.1019 0.1407 +vt 0.1175 0.1329 +vt 0.1253 0.1329 +vt 0.1253 0.1407 +vt 0.1175 0.1407 +vt 0.0707 0.1485 +vt 0.0785 0.1485 +vt 0.0785 0.1563 +vt 0.0707 0.1563 +vt 0.0707 0.1329 +vt 0.0785 0.1329 +vt 0.0785 0.1407 +vt 0.0707 0.1407 +vt 0.0863 0.1329 +vt 0.0941 0.1329 +vt 0.0941 0.1407 +vt 0.0863 0.1407 +vt 0.0706 0.1797 +vt 0.0785 0.1797 +vt 0.0785 0.1875 +vt 0.0706 0.1875 +vt 0.0707 0.1641 +vt 0.0785 0.1641 +vt 0.0785 0.1719 +vt 0.0706 0.1719 +vt 0.0863 0.1641 +vt 0.0941 0.1641 +vt 0.0941 0.1719 +vt 0.0863 0.1719 +vt 0.4142 0.0861 +vt 0.4220 0.0861 +vt 0.4220 0.0939 +vt 0.4142 0.0939 +vt 0.4142 0.0705 +vt 0.4221 0.0705 +vt 0.4220 0.0783 +vt 0.4142 0.0783 +vt 0.4299 0.0705 +vt 0.4377 0.0705 +vt 0.4377 0.0783 +vt 0.4299 0.0783 +vt 0.3830 0.0861 +vt 0.3908 0.0861 +vt 0.3908 0.0939 +vt 0.3830 0.0939 +vt 0.3830 0.0705 +vt 0.3908 0.0705 +vt 0.3908 0.0783 +vt 0.3830 0.0783 +vt 0.3986 0.0705 +vt 0.4064 0.0705 +vt 0.4064 0.0783 +vt 0.3986 0.0783 +vt 0.3830 0.1173 +vt 0.3908 0.1173 +vt 0.3908 0.1252 +vt 0.3830 0.1251 +vt 0.3830 0.1017 +vt 0.3908 0.1017 +vt 0.3908 0.1095 +vt 0.3830 0.1095 +vt 0.3986 0.1017 +vt 0.4064 0.1017 +vt 0.4064 0.1095 +vt 0.3986 0.1095 +vt 0.4143 0.0236 +vt 0.4221 0.0237 +vt 0.4221 0.0315 +vt 0.4143 0.0315 +vt 0.4143 0.0080 +vt 0.4221 0.0080 +vt 0.4221 0.0158 +vt 0.4143 0.0158 +vt 0.4299 0.0080 +vt 0.4377 0.0080 +vt 0.4377 0.0158 +vt 0.4299 0.0158 +vt 0.3830 0.0236 +vt 0.3908 0.0236 +vt 0.3908 0.0315 +vt 0.3830 0.0314 +vt 0.3830 0.0080 +vt 0.3908 0.0080 +vt 0.3908 0.0158 +vt 0.3830 0.0158 +vt 0.3986 0.0080 +vt 0.4065 0.0080 +vt 0.4065 0.0158 +vt 0.3986 0.0158 +vt 0.3830 0.0549 +vt 0.3908 0.0549 +vt 0.3908 0.0627 +vt 0.3830 0.0627 +vt 0.3830 0.0393 +vt 0.3908 0.0393 +vt 0.3908 0.0471 +vt 0.3830 0.0471 +vt 0.3986 0.0393 +vt 0.4064 0.0393 +vt 0.4064 0.0471 +vt 0.3986 0.0471 +vt 0.4767 0.0237 +vt 0.4845 0.0237 +vt 0.4845 0.0315 +vt 0.4767 0.0315 +vt 0.4767 0.0081 +vt 0.4845 0.0081 +vt 0.4845 0.0159 +vt 0.4767 0.0159 +vt 0.4923 0.0081 +vt 0.5002 0.0081 +vt 0.5002 0.0159 +vt 0.4923 0.0159 +vt 0.4455 0.0237 +vt 0.4533 0.0237 +vt 0.4533 0.0315 +vt 0.4455 0.0315 +vt 0.4455 0.0080 +vt 0.4533 0.0080 +vt 0.4533 0.0159 +vt 0.4455 0.0159 +vt 0.4611 0.0080 +vt 0.4689 0.0080 +vt 0.4689 0.0159 +vt 0.4611 0.0159 +vt 0.4455 0.0549 +vt 0.4533 0.0549 +vt 0.4533 0.0627 +vt 0.4455 0.0627 +vt 0.4455 0.0393 +vt 0.4533 0.0393 +vt 0.4533 0.0471 +vt 0.4455 0.0471 +vt 0.4611 0.0393 +vt 0.4689 0.0393 +vt 0.4689 0.0471 +vt 0.4611 0.0471 +vt 0.2893 0.0861 +vt 0.2971 0.0861 +vt 0.2971 0.0939 +vt 0.2893 0.0939 +vt 0.2893 0.0705 +vt 0.2971 0.0705 +vt 0.2971 0.0783 +vt 0.2893 0.0783 +vt 0.3049 0.0705 +vt 0.3127 0.0705 +vt 0.3127 0.0783 +vt 0.3049 0.0783 +vt 0.2581 0.0861 +vt 0.2659 0.0861 +vt 0.2659 0.0939 +vt 0.2581 0.0939 +vt 0.2581 0.0705 +vt 0.2659 0.0705 +vt 0.2659 0.0783 +vt 0.2581 0.0783 +vt 0.2737 0.0705 +vt 0.2815 0.0705 +vt 0.2815 0.0783 +vt 0.2737 0.0783 +vt 0.2581 0.1173 +vt 0.2659 0.1173 +vt 0.2659 0.1251 +vt 0.2581 0.1251 +vt 0.2581 0.1017 +vt 0.2659 0.1017 +vt 0.2659 0.1095 +vt 0.2581 0.1095 +vt 0.2737 0.1017 +vt 0.2815 0.1017 +vt 0.2815 0.1095 +vt 0.2737 0.1095 +vt 0.2893 0.0236 +vt 0.2971 0.0236 +vt 0.2971 0.0314 +vt 0.2893 0.0314 +vt 0.2893 0.0080 +vt 0.2971 0.0080 +vt 0.2971 0.0158 +vt 0.2893 0.0158 +vt 0.3049 0.0080 +vt 0.3128 0.0080 +vt 0.3128 0.0158 +vt 0.3049 0.0158 +vt 0.2581 0.0236 +vt 0.2659 0.0236 +vt 0.2659 0.0314 +vt 0.2581 0.0314 +vt 0.2581 0.0080 +vt 0.2659 0.0080 +vt 0.2659 0.0158 +vt 0.2581 0.0158 +vt 0.2737 0.0080 +vt 0.2815 0.0080 +vt 0.2815 0.0158 +vt 0.2737 0.0158 +vt 0.2581 0.0548 +vt 0.2659 0.0548 +vt 0.2659 0.0626 +vt 0.2581 0.0626 +vt 0.2581 0.0392 +vt 0.2659 0.0392 +vt 0.2659 0.0470 +vt 0.2581 0.0470 +vt 0.2737 0.0392 +vt 0.2815 0.0392 +vt 0.2815 0.0470 +vt 0.2737 0.0470 +vt 0.3518 0.0236 +vt 0.3596 0.0236 +vt 0.3596 0.0314 +vt 0.3518 0.0314 +vt 0.3518 0.0080 +vt 0.3596 0.0080 +vt 0.3596 0.0158 +vt 0.3518 0.0158 +vt 0.3674 0.0080 +vt 0.3752 0.0080 +vt 0.3752 0.0158 +vt 0.3674 0.0158 +vt 0.3206 0.0236 +vt 0.3284 0.0236 +vt 0.3284 0.0314 +vt 0.3206 0.0314 +vt 0.3206 0.0080 +vt 0.3284 0.0080 +vt 0.3284 0.0158 +vt 0.3206 0.0158 +vt 0.3362 0.0080 +vt 0.3440 0.0080 +vt 0.3440 0.0158 +vt 0.3362 0.0158 +vt 0.3205 0.0549 +vt 0.3284 0.0549 +vt 0.3284 0.0627 +vt 0.3205 0.0627 +vt 0.3206 0.0392 +vt 0.3284 0.0392 +vt 0.3284 0.0470 +vt 0.3205 0.0470 +vt 0.3362 0.0392 +vt 0.3440 0.0392 +vt 0.3440 0.0471 +vt 0.3362 0.0471 +vt 0.2893 0.2110 +vt 0.2971 0.2110 +vt 0.2971 0.2188 +vt 0.2893 0.2188 +vt 0.2893 0.1954 +vt 0.2971 0.1954 +vt 0.2971 0.2032 +vt 0.2893 0.2032 +vt 0.3049 0.1954 +vt 0.3127 0.1954 +vt 0.3127 0.2032 +vt 0.3049 0.2032 +vt 0.2580 0.2110 +vt 0.2658 0.2110 +vt 0.2658 0.2188 +vt 0.2580 0.2188 +vt 0.2580 0.1954 +vt 0.2658 0.1954 +vt 0.2658 0.2032 +vt 0.2580 0.2032 +vt 0.2737 0.1954 +vt 0.2815 0.1954 +vt 0.2815 0.2032 +vt 0.2737 0.2032 +vt 0.2580 0.2422 +vt 0.2658 0.2422 +vt 0.2658 0.2500 +vt 0.2580 0.2500 +vt 0.2580 0.2266 +vt 0.2658 0.2266 +vt 0.2658 0.2344 +vt 0.2580 0.2344 +vt 0.2736 0.2266 +vt 0.2815 0.2266 +vt 0.2815 0.2344 +vt 0.2736 0.2344 +vt 0.2893 0.1485 +vt 0.2971 0.1485 +vt 0.2971 0.1564 +vt 0.2893 0.1564 +vt 0.2893 0.1329 +vt 0.2971 0.1329 +vt 0.2971 0.1407 +vt 0.2893 0.1407 +vt 0.3049 0.1329 +vt 0.3127 0.1329 +vt 0.3127 0.1407 +vt 0.3049 0.1407 +vt 0.2581 0.1485 +vt 0.2659 0.1485 +vt 0.2659 0.1563 +vt 0.2581 0.1563 +vt 0.2581 0.1329 +vt 0.2659 0.1329 +vt 0.2659 0.1407 +vt 0.2581 0.1407 +vt 0.2737 0.1329 +vt 0.2815 0.1329 +vt 0.2815 0.1407 +vt 0.2737 0.1407 +vt 0.2580 0.1798 +vt 0.2659 0.1798 +vt 0.2658 0.1876 +vt 0.2580 0.1876 +vt 0.2580 0.1642 +vt 0.2659 0.1642 +vt 0.2659 0.1720 +vt 0.2580 0.1720 +vt 0.2737 0.1642 +vt 0.2815 0.1642 +vt 0.2815 0.1720 +vt 0.2737 0.1720 +vt 0.3518 0.1486 +vt 0.3596 0.1486 +vt 0.3596 0.1564 +vt 0.3517 0.1564 +vt 0.3518 0.1329 +vt 0.3596 0.1329 +vt 0.3596 0.1408 +vt 0.3518 0.1408 +vt 0.3674 0.1330 +vt 0.3752 0.1330 +vt 0.3752 0.1408 +vt 0.3674 0.1408 +vt 0.3205 0.1486 +vt 0.3283 0.1486 +vt 0.3283 0.1564 +vt 0.3205 0.1564 +vt 0.3205 0.1329 +vt 0.3283 0.1329 +vt 0.3283 0.1407 +vt 0.3205 0.1407 +vt 0.3361 0.1329 +vt 0.3439 0.1329 +vt 0.3439 0.1408 +vt 0.3361 0.1408 +vt 0.3205 0.1798 +vt 0.3283 0.1798 +vt 0.3283 0.1876 +vt 0.3205 0.1876 +vt 0.3205 0.1642 +vt 0.3283 0.1642 +vt 0.3283 0.1720 +vt 0.3205 0.1720 +vt 0.3361 0.1642 +vt 0.3439 0.1642 +vt 0.3439 0.1720 +vt 0.3361 0.1720 +vt 0.1641 0.8356 +vt 0.1719 0.8356 +vt 0.1719 0.8435 +vt 0.1641 0.8435 +vt 0.1641 0.8200 +vt 0.1719 0.8200 +vt 0.1719 0.8278 +vt 0.1641 0.8278 +vt 0.1798 0.8200 +vt 0.1876 0.8200 +vt 0.1876 0.8278 +vt 0.1798 0.8278 +vt 0.1329 0.8356 +vt 0.1407 0.8356 +vt 0.1407 0.8434 +vt 0.1329 0.8434 +vt 0.1329 0.8200 +vt 0.1407 0.8200 +vt 0.1407 0.8278 +vt 0.1329 0.8278 +vt 0.1485 0.8200 +vt 0.1563 0.8200 +vt 0.1563 0.8278 +vt 0.1485 0.8278 +vt 0.1329 0.8669 +vt 0.1407 0.8669 +vt 0.1407 0.8747 +vt 0.1329 0.8747 +vt 0.1329 0.8513 +vt 0.1407 0.8513 +vt 0.1407 0.8591 +vt 0.1329 0.8591 +vt 0.1485 0.8513 +vt 0.1563 0.8513 +vt 0.1563 0.8591 +vt 0.1485 0.8591 +vt 0.1642 0.7732 +vt 0.1720 0.7732 +vt 0.1720 0.7810 +vt 0.1642 0.7810 +vt 0.1642 0.7576 +vt 0.1720 0.7576 +vt 0.1720 0.7654 +vt 0.1642 0.7654 +vt 0.1798 0.7576 +vt 0.1876 0.7576 +vt 0.1876 0.7654 +vt 0.1798 0.7654 +vt 0.1329 0.7732 +vt 0.1407 0.7732 +vt 0.1407 0.7810 +vt 0.1329 0.7810 +vt 0.1329 0.7575 +vt 0.1407 0.7576 +vt 0.1407 0.7654 +vt 0.1329 0.7654 +vt 0.1485 0.7576 +vt 0.1563 0.7576 +vt 0.1563 0.7654 +vt 0.1485 0.7654 +vt 0.1329 0.8044 +vt 0.1407 0.8044 +vt 0.1407 0.8122 +vt 0.1329 0.8122 +vt 0.1329 0.7888 +vt 0.1407 0.7888 +vt 0.1407 0.7966 +vt 0.1329 0.7966 +vt 0.1485 0.7888 +vt 0.1563 0.7888 +vt 0.1563 0.7966 +vt 0.1485 0.7966 +vt 0.2266 0.7732 +vt 0.2344 0.7732 +vt 0.2344 0.7810 +vt 0.2266 0.7810 +vt 0.2266 0.7576 +vt 0.2344 0.7576 +vt 0.2344 0.7654 +vt 0.2266 0.7654 +vt 0.2422 0.7576 +vt 0.2501 0.7576 +vt 0.2500 0.7654 +vt 0.2422 0.7654 +vt 0.1954 0.7732 +vt 0.2032 0.7732 +vt 0.2032 0.7810 +vt 0.1954 0.7810 +vt 0.1954 0.7576 +vt 0.2032 0.7576 +vt 0.2032 0.7654 +vt 0.1954 0.7654 +vt 0.2110 0.7576 +vt 0.2188 0.7576 +vt 0.2188 0.7654 +vt 0.2110 0.7654 +vt 0.1954 0.8044 +vt 0.2032 0.8044 +vt 0.2032 0.8122 +vt 0.1954 0.8122 +vt 0.1954 0.7888 +vt 0.2032 0.7888 +vt 0.2032 0.7966 +vt 0.1954 0.7966 +vt 0.2110 0.7888 +vt 0.2188 0.7888 +vt 0.2188 0.7966 +vt 0.2110 0.7966 +vt 0.0392 0.8356 +vt 0.0470 0.8356 +vt 0.0470 0.8434 +vt 0.0392 0.8434 +vt 0.0392 0.8200 +vt 0.0470 0.8200 +vt 0.0470 0.8278 +vt 0.0392 0.8278 +vt 0.0548 0.8200 +vt 0.0626 0.8200 +vt 0.0626 0.8278 +vt 0.0548 0.8278 +vt 0.0080 0.8356 +vt 0.0158 0.8356 +vt 0.0158 0.8434 +vt 0.0080 0.8434 +vt 0.0080 0.8200 +vt 0.0158 0.8200 +vt 0.0158 0.8278 +vt 0.0080 0.8278 +vt 0.0236 0.8200 +vt 0.0314 0.8200 +vt 0.0314 0.8278 +vt 0.0236 0.8278 +vt 0.0080 0.8668 +vt 0.0158 0.8668 +vt 0.0158 0.8746 +vt 0.0079 0.8746 +vt 0.0080 0.8512 +vt 0.0158 0.8512 +vt 0.0158 0.8590 +vt 0.0080 0.8590 +vt 0.0236 0.8512 +vt 0.0314 0.8512 +vt 0.0314 0.8590 +vt 0.0236 0.8590 +vt 0.0392 0.7731 +vt 0.0470 0.7731 +vt 0.0470 0.7809 +vt 0.0392 0.7809 +vt 0.0392 0.7575 +vt 0.0470 0.7575 +vt 0.0470 0.7653 +vt 0.0392 0.7653 +vt 0.0548 0.7575 +vt 0.0626 0.7575 +vt 0.0626 0.7653 +vt 0.0548 0.7653 +vt 0.0080 0.7731 +vt 0.0158 0.7731 +vt 0.0158 0.7809 +vt 0.0080 0.7809 +vt 0.0080 0.7575 +vt 0.0158 0.7575 +vt 0.0158 0.7653 +vt 0.0080 0.7653 +vt 0.0236 0.7575 +vt 0.0314 0.7575 +vt 0.0314 0.7653 +vt 0.0236 0.7653 +vt 0.0080 0.8044 +vt 0.0158 0.8044 +vt 0.0158 0.8122 +vt 0.0080 0.8122 +vt 0.0080 0.7887 +vt 0.0158 0.7887 +vt 0.0158 0.7966 +vt 0.0080 0.7966 +vt 0.0236 0.7887 +vt 0.0314 0.7887 +vt 0.0314 0.7966 +vt 0.0236 0.7966 +vt 0.1017 0.7732 +vt 0.1095 0.7732 +vt 0.1095 0.7810 +vt 0.1017 0.7810 +vt 0.1017 0.7575 +vt 0.1095 0.7575 +vt 0.1095 0.7653 +vt 0.1017 0.7653 +vt 0.1173 0.7575 +vt 0.1251 0.7575 +vt 0.1251 0.7654 +vt 0.1173 0.7654 +vt 0.0705 0.7731 +vt 0.0783 0.7731 +vt 0.0783 0.7810 +vt 0.0704 0.7810 +vt 0.0705 0.7575 +vt 0.0783 0.7575 +vt 0.0783 0.7653 +vt 0.0705 0.7653 +vt 0.0861 0.7575 +vt 0.0939 0.7575 +vt 0.0939 0.7653 +vt 0.0861 0.7653 +vt 0.0704 0.8044 +vt 0.0782 0.8044 +vt 0.0782 0.8122 +vt 0.0704 0.8122 +vt 0.0704 0.7888 +vt 0.0783 0.7888 +vt 0.0783 0.7966 +vt 0.0704 0.7966 +vt 0.0861 0.7888 +vt 0.0939 0.7888 +vt 0.0939 0.7966 +vt 0.0861 0.7966 +vt 0.0392 0.9605 +vt 0.0470 0.9605 +vt 0.0470 0.9684 +vt 0.0392 0.9684 +vt 0.0392 0.9449 +vt 0.0470 0.9449 +vt 0.0470 0.9527 +vt 0.0392 0.9527 +vt 0.0548 0.9449 +vt 0.0626 0.9449 +vt 0.0626 0.9527 +vt 0.0548 0.9527 +vt 0.0079 0.9605 +vt 0.0157 0.9605 +vt 0.0157 0.9683 +vt 0.0079 0.9683 +vt 0.0079 0.9449 +vt 0.0157 0.9449 +vt 0.0157 0.9527 +vt 0.0079 0.9527 +vt 0.0235 0.9449 +vt 0.0314 0.9449 +vt 0.0313 0.9527 +vt 0.0235 0.9527 +vt 0.0079 0.9918 +vt 0.0157 0.9918 +vt 0.0157 0.9996 +vt 0.0079 0.9996 +vt 0.0079 0.9761 +vt 0.0157 0.9762 +vt 0.0157 0.9840 +vt 0.0079 0.9840 +vt 0.0235 0.9762 +vt 0.0313 0.9762 +vt 0.0313 0.9840 +vt 0.0235 0.9840 +vt 0.0392 0.8981 +vt 0.0470 0.8981 +vt 0.0470 0.9059 +vt 0.0392 0.9059 +vt 0.0392 0.8825 +vt 0.0470 0.8825 +vt 0.0470 0.8903 +vt 0.0392 0.8903 +vt 0.0548 0.8825 +vt 0.0626 0.8825 +vt 0.0626 0.8903 +vt 0.0548 0.8903 +vt 0.0079 0.8981 +vt 0.0157 0.8981 +vt 0.0157 0.9059 +vt 0.0079 0.9059 +vt 0.0079 0.8824 +vt 0.0158 0.8824 +vt 0.0158 0.8903 +vt 0.0079 0.8903 +vt 0.0236 0.8825 +vt 0.0314 0.8825 +vt 0.0314 0.8903 +vt 0.0236 0.8903 +vt 0.0079 0.9293 +vt 0.0157 0.9293 +vt 0.0157 0.9371 +vt 0.0079 0.9371 +vt 0.0079 0.9137 +vt 0.0157 0.9137 +vt 0.0157 0.9215 +vt 0.0079 0.9215 +vt 0.0236 0.9137 +vt 0.0314 0.9137 +vt 0.0314 0.9215 +vt 0.0236 0.9215 +vt 0.1016 0.8981 +vt 0.1095 0.8981 +vt 0.1095 0.9059 +vt 0.1016 0.9059 +vt 0.1016 0.8825 +vt 0.1095 0.8825 +vt 0.1095 0.8903 +vt 0.1016 0.8903 +vt 0.1173 0.8825 +vt 0.1251 0.8825 +vt 0.1251 0.8903 +vt 0.1173 0.8903 +vt 0.0704 0.8981 +vt 0.0782 0.8981 +vt 0.0782 0.9059 +vt 0.0704 0.9059 +vt 0.0704 0.8825 +vt 0.0782 0.8825 +vt 0.0782 0.8903 +vt 0.0704 0.8903 +vt 0.0860 0.8825 +vt 0.0938 0.8825 +vt 0.0938 0.8903 +vt 0.0860 0.8903 +vt 0.0704 0.9293 +vt 0.0782 0.9293 +vt 0.0782 0.9371 +vt 0.0704 0.9371 +vt 0.0704 0.9137 +vt 0.0782 0.9137 +vt 0.0782 0.9215 +vt 0.0704 0.9215 +vt 0.0860 0.9137 +vt 0.0938 0.9137 +vt 0.0938 0.9215 +vt 0.0860 0.9215 +vt 0.1642 0.5858 +vt 0.1720 0.5858 +vt 0.1720 0.5936 +vt 0.1642 0.5936 +vt 0.1642 0.5702 +vt 0.1720 0.5702 +vt 0.1720 0.5780 +vt 0.1642 0.5780 +vt 0.1798 0.5702 +vt 0.1876 0.5702 +vt 0.1876 0.5780 +vt 0.1798 0.5780 +vt 0.1330 0.5858 +vt 0.1408 0.5858 +vt 0.1408 0.5936 +vt 0.1330 0.5936 +vt 0.1330 0.5701 +vt 0.1408 0.5701 +vt 0.1408 0.5780 +vt 0.1330 0.5780 +vt 0.1486 0.5702 +vt 0.1564 0.5702 +vt 0.1564 0.5780 +vt 0.1486 0.5780 +vt 0.1330 0.6170 +vt 0.1408 0.6170 +vt 0.1408 0.6248 +vt 0.1330 0.6248 +vt 0.1330 0.6014 +vt 0.1408 0.6014 +vt 0.1408 0.6092 +vt 0.1330 0.6092 +vt 0.1486 0.6014 +vt 0.1564 0.6014 +vt 0.1564 0.6092 +vt 0.1486 0.6092 +vt 0.1642 0.5233 +vt 0.1720 0.5233 +vt 0.1720 0.5311 +vt 0.1642 0.5311 +vt 0.1642 0.5077 +vt 0.1720 0.5077 +vt 0.1720 0.5155 +vt 0.1642 0.5155 +vt 0.1799 0.5077 +vt 0.1877 0.5077 +vt 0.1877 0.5155 +vt 0.1799 0.5155 +vt 0.1330 0.5233 +vt 0.1408 0.5233 +vt 0.1408 0.5311 +vt 0.1330 0.5311 +vt 0.1330 0.5077 +vt 0.1408 0.5077 +vt 0.1408 0.5155 +vt 0.1330 0.5155 +vt 0.1486 0.5077 +vt 0.1564 0.5077 +vt 0.1564 0.5155 +vt 0.1486 0.5155 +vt 0.1330 0.5545 +vt 0.1408 0.5545 +vt 0.1408 0.5623 +vt 0.1330 0.5623 +vt 0.1330 0.5389 +vt 0.1408 0.5389 +vt 0.1408 0.5467 +vt 0.1330 0.5467 +vt 0.1486 0.5389 +vt 0.1564 0.5389 +vt 0.1564 0.5467 +vt 0.1486 0.5467 +vt 0.2267 0.5233 +vt 0.2345 0.5233 +vt 0.2345 0.5311 +vt 0.2267 0.5311 +vt 0.2267 0.5077 +vt 0.2345 0.5077 +vt 0.2345 0.5155 +vt 0.2267 0.5155 +vt 0.2423 0.5077 +vt 0.2501 0.5077 +vt 0.2501 0.5155 +vt 0.2423 0.5155 +vt 0.1955 0.5233 +vt 0.2033 0.5233 +vt 0.2033 0.5311 +vt 0.1955 0.5311 +vt 0.1955 0.5077 +vt 0.2033 0.5077 +vt 0.2033 0.5155 +vt 0.1955 0.5155 +vt 0.2111 0.5077 +vt 0.2189 0.5077 +vt 0.2189 0.5155 +vt 0.2111 0.5155 +vt 0.1955 0.5545 +vt 0.2033 0.5546 +vt 0.2033 0.5624 +vt 0.1955 0.5624 +vt 0.1955 0.5389 +vt 0.2033 0.5389 +vt 0.2033 0.5467 +vt 0.1955 0.5467 +vt 0.2111 0.5389 +vt 0.2189 0.5389 +vt 0.2189 0.5467 +vt 0.2111 0.5467 +vt 0.0393 0.5857 +vt 0.0471 0.5857 +vt 0.0471 0.5935 +vt 0.0393 0.5935 +vt 0.0393 0.5701 +vt 0.0471 0.5701 +vt 0.0471 0.5779 +vt 0.0393 0.5779 +vt 0.0549 0.5701 +vt 0.0627 0.5701 +vt 0.0627 0.5779 +vt 0.0549 0.5779 +vt 0.0080 0.5857 +vt 0.0159 0.5857 +vt 0.0158 0.5935 +vt 0.0080 0.5935 +vt 0.0080 0.5701 +vt 0.0159 0.5701 +vt 0.0159 0.5779 +vt 0.0080 0.5779 +vt 0.0237 0.5701 +vt 0.0315 0.5701 +vt 0.0315 0.5779 +vt 0.0237 0.5779 +vt 0.0080 0.6170 +vt 0.0158 0.6170 +vt 0.0158 0.6248 +vt 0.0080 0.6248 +vt 0.0080 0.6013 +vt 0.0158 0.6013 +vt 0.0158 0.6091 +vt 0.0080 0.6091 +vt 0.0237 0.6013 +vt 0.0315 0.6013 +vt 0.0315 0.6092 +vt 0.0237 0.6092 +vt 0.0393 0.5233 +vt 0.0471 0.5233 +vt 0.0471 0.5311 +vt 0.0393 0.5311 +vt 0.0393 0.5076 +vt 0.0471 0.5076 +vt 0.0471 0.5155 +vt 0.0393 0.5155 +vt 0.0549 0.5077 +vt 0.0627 0.5077 +vt 0.0627 0.5155 +vt 0.0549 0.5155 +vt 0.0081 0.5233 +vt 0.0159 0.5233 +vt 0.0159 0.5311 +vt 0.0081 0.5311 +vt 0.0081 0.5076 +vt 0.0159 0.5076 +vt 0.0159 0.5154 +vt 0.0081 0.5154 +vt 0.0237 0.5076 +vt 0.0315 0.5076 +vt 0.0315 0.5155 +vt 0.0237 0.5154 +vt 0.0081 0.5545 +vt 0.0159 0.5545 +vt 0.0159 0.5623 +vt 0.0081 0.5623 +vt 0.0081 0.5389 +vt 0.0159 0.5389 +vt 0.0159 0.5467 +vt 0.0081 0.5467 +vt 0.0237 0.5389 +vt 0.0315 0.5389 +vt 0.0315 0.5467 +vt 0.0237 0.5467 +vt 0.1018 0.5233 +vt 0.1096 0.5233 +vt 0.1096 0.5311 +vt 0.1018 0.5311 +vt 0.1018 0.5077 +vt 0.1096 0.5077 +vt 0.1096 0.5155 +vt 0.1018 0.5155 +vt 0.1174 0.5077 +vt 0.1252 0.5077 +vt 0.1252 0.5155 +vt 0.1174 0.5155 +vt 0.0705 0.5233 +vt 0.0783 0.5233 +vt 0.0783 0.5311 +vt 0.0705 0.5311 +vt 0.0705 0.5077 +vt 0.0783 0.5077 +vt 0.0783 0.5155 +vt 0.0705 0.5155 +vt 0.0862 0.5077 +vt 0.0940 0.5077 +vt 0.0940 0.5155 +vt 0.0862 0.5155 +vt 0.0705 0.5545 +vt 0.0783 0.5545 +vt 0.0783 0.5623 +vt 0.0705 0.5623 +vt 0.0705 0.5389 +vt 0.0783 0.5389 +vt 0.0783 0.5467 +vt 0.0705 0.5467 +vt 0.0861 0.5389 +vt 0.0940 0.5389 +vt 0.0939 0.5467 +vt 0.0861 0.5467 +vt 0.0392 0.7107 +vt 0.0470 0.7107 +vt 0.0470 0.7185 +vt 0.0392 0.7185 +vt 0.0392 0.6950 +vt 0.0471 0.6951 +vt 0.0470 0.7029 +vt 0.0392 0.7029 +vt 0.0549 0.6951 +vt 0.0627 0.6951 +vt 0.0627 0.7029 +vt 0.0549 0.7029 +vt 0.0080 0.7107 +vt 0.0158 0.7107 +vt 0.0158 0.7185 +vt 0.0080 0.7185 +vt 0.0080 0.6950 +vt 0.0158 0.6950 +vt 0.0158 0.7029 +vt 0.0080 0.7028 +vt 0.0236 0.6950 +vt 0.0314 0.6950 +vt 0.0314 0.7029 +vt 0.0236 0.7029 +vt 0.0080 0.7419 +vt 0.0158 0.7419 +vt 0.0158 0.7497 +vt 0.0080 0.7497 +vt 0.0080 0.7263 +vt 0.0158 0.7263 +vt 0.0158 0.7341 +vt 0.0080 0.7341 +vt 0.0236 0.7263 +vt 0.0314 0.7263 +vt 0.0314 0.7341 +vt 0.0236 0.7341 +vt 0.0393 0.6482 +vt 0.0471 0.6482 +vt 0.0471 0.6560 +vt 0.0393 0.6560 +vt 0.0393 0.6326 +vt 0.0471 0.6326 +vt 0.0471 0.6404 +vt 0.0393 0.6404 +vt 0.0549 0.6326 +vt 0.0627 0.6326 +vt 0.0627 0.6404 +vt 0.0549 0.6404 +vt 0.0080 0.6482 +vt 0.0158 0.6482 +vt 0.0158 0.6560 +vt 0.0080 0.6560 +vt 0.0080 0.6326 +vt 0.0158 0.6326 +vt 0.0158 0.6404 +vt 0.0080 0.6404 +vt 0.0236 0.6326 +vt 0.0315 0.6326 +vt 0.0315 0.6404 +vt 0.0236 0.6404 +vt 0.0080 0.6794 +vt 0.0158 0.6794 +vt 0.0158 0.6872 +vt 0.0080 0.6872 +vt 0.0080 0.6638 +vt 0.0158 0.6638 +vt 0.0158 0.6716 +vt 0.0080 0.6716 +vt 0.0236 0.6638 +vt 0.0314 0.6638 +vt 0.0314 0.6716 +vt 0.0236 0.6716 +vt 0.1017 0.6482 +vt 0.1095 0.6482 +vt 0.1095 0.6560 +vt 0.1017 0.6560 +vt 0.1017 0.6326 +vt 0.1095 0.6326 +vt 0.1095 0.6404 +vt 0.1017 0.6404 +vt 0.1173 0.6326 +vt 0.1252 0.6326 +vt 0.1252 0.6404 +vt 0.1173 0.6404 +vt 0.0705 0.6482 +vt 0.0783 0.6482 +vt 0.0783 0.6560 +vt 0.0705 0.6560 +vt 0.0705 0.6326 +vt 0.0783 0.6326 +vt 0.0783 0.6404 +vt 0.0705 0.6404 +vt 0.0861 0.6326 +vt 0.0939 0.6326 +vt 0.0939 0.6404 +vt 0.0861 0.6404 +vt 0.0705 0.6794 +vt 0.0783 0.6794 +vt 0.0783 0.6873 +vt 0.0705 0.6873 +vt 0.0705 0.6638 +vt 0.0783 0.6638 +vt 0.0783 0.6716 +vt 0.0705 0.6716 +vt 0.0861 0.6638 +vt 0.0939 0.6638 +vt 0.0939 0.6716 +vt 0.0861 0.6716 +vt 0.4141 0.5859 +vt 0.4219 0.5859 +vt 0.4219 0.5937 +vt 0.4141 0.5937 +vt 0.4141 0.5702 +vt 0.4219 0.5702 +vt 0.4219 0.5780 +vt 0.4141 0.5780 +vt 0.4297 0.5702 +vt 0.4375 0.5702 +vt 0.4375 0.5781 +vt 0.4297 0.5780 +vt 0.3828 0.5858 +vt 0.3907 0.5858 +vt 0.3907 0.5937 +vt 0.3828 0.5937 +vt 0.3829 0.5702 +vt 0.3907 0.5702 +vt 0.3907 0.5780 +vt 0.3829 0.5780 +vt 0.3985 0.5702 +vt 0.4063 0.5702 +vt 0.4063 0.5780 +vt 0.3985 0.5780 +vt 0.3828 0.6171 +vt 0.3906 0.6171 +vt 0.3906 0.6249 +vt 0.3828 0.6249 +vt 0.3828 0.6015 +vt 0.3907 0.6015 +vt 0.3906 0.6093 +vt 0.3828 0.6093 +vt 0.3985 0.6015 +vt 0.4063 0.6015 +vt 0.4063 0.6093 +vt 0.3985 0.6093 +vt 0.4141 0.5234 +vt 0.4219 0.5234 +vt 0.4219 0.5312 +vt 0.4141 0.5312 +vt 0.4141 0.5078 +vt 0.4219 0.5078 +vt 0.4219 0.5156 +vt 0.4141 0.5156 +vt 0.4297 0.5078 +vt 0.4375 0.5078 +vt 0.4375 0.5156 +vt 0.4297 0.5156 +vt 0.3829 0.5234 +vt 0.3907 0.5234 +vt 0.3907 0.5312 +vt 0.3829 0.5312 +vt 0.3829 0.5078 +vt 0.3907 0.5078 +vt 0.3907 0.5156 +vt 0.3829 0.5156 +vt 0.3985 0.5078 +vt 0.4063 0.5078 +vt 0.4063 0.5156 +vt 0.3985 0.5156 +vt 0.3829 0.5546 +vt 0.3907 0.5546 +vt 0.3907 0.5624 +vt 0.3829 0.5624 +vt 0.3829 0.5390 +vt 0.3907 0.5390 +vt 0.3907 0.5468 +vt 0.3829 0.5468 +vt 0.3985 0.5390 +vt 0.4063 0.5390 +vt 0.4063 0.5468 +vt 0.3985 0.5468 +vt 0.4766 0.5234 +vt 0.4844 0.5234 +vt 0.4844 0.5312 +vt 0.4766 0.5312 +vt 0.4766 0.5078 +vt 0.4844 0.5078 +vt 0.4844 0.5156 +vt 0.4766 0.5156 +vt 0.4922 0.5078 +vt 0.5000 0.5078 +vt 0.5000 0.5156 +vt 0.4922 0.5156 +vt 0.4453 0.5234 +vt 0.4531 0.5234 +vt 0.4531 0.5312 +vt 0.4453 0.5312 +vt 0.4453 0.5078 +vt 0.4531 0.5078 +vt 0.4531 0.5156 +vt 0.4453 0.5156 +vt 0.4610 0.5078 +vt 0.4688 0.5078 +vt 0.4688 0.5156 +vt 0.4610 0.5156 +vt 0.4453 0.5546 +vt 0.4531 0.5546 +vt 0.4531 0.5624 +vt 0.4453 0.5624 +vt 0.4453 0.5390 +vt 0.4531 0.5390 +vt 0.4531 0.5468 +vt 0.4453 0.5468 +vt 0.4609 0.5390 +vt 0.4688 0.5390 +vt 0.4688 0.5468 +vt 0.4609 0.5468 +vt 0.2891 0.5858 +vt 0.2970 0.5858 +vt 0.2970 0.5936 +vt 0.2891 0.5936 +vt 0.2892 0.5702 +vt 0.2970 0.5702 +vt 0.2970 0.5780 +vt 0.2892 0.5780 +vt 0.3048 0.5702 +vt 0.3126 0.5702 +vt 0.3126 0.5780 +vt 0.3048 0.5780 +vt 0.2579 0.5858 +vt 0.2657 0.5858 +vt 0.2657 0.5936 +vt 0.2579 0.5936 +vt 0.2579 0.5702 +vt 0.2657 0.5702 +vt 0.2657 0.5780 +vt 0.2579 0.5780 +vt 0.2735 0.5702 +vt 0.2813 0.5702 +vt 0.2813 0.5780 +vt 0.2735 0.5780 +vt 0.2579 0.6170 +vt 0.2657 0.6170 +vt 0.2657 0.6248 +vt 0.2579 0.6248 +vt 0.2579 0.6014 +vt 0.2657 0.6014 +vt 0.2657 0.6092 +vt 0.2579 0.6092 +vt 0.2735 0.6014 +vt 0.2813 0.6014 +vt 0.2813 0.6092 +vt 0.2735 0.6092 +vt 0.2892 0.5233 +vt 0.2970 0.5233 +vt 0.2970 0.5312 +vt 0.2892 0.5312 +vt 0.2892 0.5077 +vt 0.2970 0.5077 +vt 0.2970 0.5155 +vt 0.2892 0.5155 +vt 0.3048 0.5077 +vt 0.3126 0.5077 +vt 0.3126 0.5155 +vt 0.3048 0.5155 +vt 0.2579 0.5233 +vt 0.2657 0.5233 +vt 0.2657 0.5311 +vt 0.2579 0.5311 +vt 0.2579 0.5077 +vt 0.2657 0.5077 +vt 0.2657 0.5155 +vt 0.2579 0.5155 +vt 0.2736 0.5077 +vt 0.2814 0.5077 +vt 0.2814 0.5155 +vt 0.2736 0.5155 +vt 0.2579 0.5546 +vt 0.2657 0.5546 +vt 0.2657 0.5624 +vt 0.2579 0.5624 +vt 0.2579 0.5390 +vt 0.2657 0.5390 +vt 0.2657 0.5468 +vt 0.2579 0.5468 +vt 0.2735 0.5390 +vt 0.2814 0.5390 +vt 0.2814 0.5468 +vt 0.2735 0.5468 +vt 0.3516 0.5234 +vt 0.3594 0.5234 +vt 0.3594 0.5312 +vt 0.3516 0.5312 +vt 0.3516 0.5077 +vt 0.3594 0.5078 +vt 0.3594 0.5156 +vt 0.3516 0.5156 +vt 0.3673 0.5078 +vt 0.3751 0.5078 +vt 0.3751 0.5156 +vt 0.3673 0.5156 +vt 0.3204 0.5234 +vt 0.3282 0.5234 +vt 0.3282 0.5312 +vt 0.3204 0.5312 +vt 0.3204 0.5077 +vt 0.3282 0.5077 +vt 0.3282 0.5155 +vt 0.3204 0.5155 +vt 0.3360 0.5077 +vt 0.3438 0.5077 +vt 0.3438 0.5156 +vt 0.3360 0.5156 +vt 0.3204 0.5546 +vt 0.3282 0.5546 +vt 0.3282 0.5624 +vt 0.3204 0.5624 +vt 0.3204 0.5390 +vt 0.3282 0.5390 +vt 0.3282 0.5468 +vt 0.3204 0.5468 +vt 0.3360 0.5390 +vt 0.3438 0.5390 +vt 0.3438 0.5468 +vt 0.3360 0.5468 +vt 0.2891 0.7107 +vt 0.2969 0.7107 +vt 0.2969 0.7186 +vt 0.2891 0.7186 +vt 0.2891 0.6951 +vt 0.2969 0.6951 +vt 0.2969 0.7029 +vt 0.2891 0.7029 +vt 0.3047 0.6951 +vt 0.3125 0.6951 +vt 0.3125 0.7029 +vt 0.3047 0.7029 +vt 0.2579 0.7107 +vt 0.2657 0.7107 +vt 0.2657 0.7185 +vt 0.2579 0.7185 +vt 0.2579 0.6951 +vt 0.2657 0.6951 +vt 0.2657 0.7029 +vt 0.2579 0.7029 +vt 0.2735 0.6951 +vt 0.2813 0.6951 +vt 0.2813 0.7029 +vt 0.2735 0.7029 +vt 0.2579 0.7420 +vt 0.2657 0.7420 +vt 0.2657 0.7498 +vt 0.2579 0.7498 +vt 0.2579 0.7264 +vt 0.2657 0.7264 +vt 0.2657 0.7342 +vt 0.2579 0.7342 +vt 0.2735 0.7264 +vt 0.2813 0.7264 +vt 0.2813 0.7342 +vt 0.2735 0.7342 +vt 0.2891 0.6483 +vt 0.2969 0.6483 +vt 0.2969 0.6561 +vt 0.2891 0.6561 +vt 0.2891 0.6327 +vt 0.2969 0.6327 +vt 0.2969 0.6405 +vt 0.2891 0.6405 +vt 0.3047 0.6327 +vt 0.3126 0.6327 +vt 0.3126 0.6405 +vt 0.3047 0.6405 +vt 0.2579 0.6483 +vt 0.2657 0.6483 +vt 0.2657 0.6561 +vt 0.2579 0.6561 +vt 0.2579 0.6327 +vt 0.2657 0.6327 +vt 0.2657 0.6405 +vt 0.2579 0.6405 +vt 0.2735 0.6327 +vt 0.2813 0.6327 +vt 0.2813 0.6405 +vt 0.2735 0.6405 +vt 0.2579 0.6795 +vt 0.2657 0.6795 +vt 0.2657 0.6873 +vt 0.2579 0.6873 +vt 0.2579 0.6639 +vt 0.2657 0.6639 +vt 0.2657 0.6717 +vt 0.2579 0.6717 +vt 0.2735 0.6639 +vt 0.2813 0.6639 +vt 0.2813 0.6717 +vt 0.2735 0.6717 +vt 0.3516 0.6483 +vt 0.3594 0.6483 +vt 0.3594 0.6561 +vt 0.3516 0.6561 +vt 0.3516 0.6327 +vt 0.3594 0.6327 +vt 0.3594 0.6405 +vt 0.3516 0.6405 +vt 0.3672 0.6327 +vt 0.3750 0.6327 +vt 0.3750 0.6405 +vt 0.3672 0.6405 +vt 0.3204 0.6483 +vt 0.3282 0.6483 +vt 0.3282 0.6561 +vt 0.3204 0.6561 +vt 0.3204 0.6327 +vt 0.3282 0.6327 +vt 0.3282 0.6405 +vt 0.3204 0.6405 +vt 0.3360 0.6327 +vt 0.3438 0.6327 +vt 0.3438 0.6405 +vt 0.3360 0.6405 +vt 0.3204 0.6795 +vt 0.3282 0.6795 +vt 0.3282 0.6873 +vt 0.3203 0.6873 +vt 0.3204 0.6639 +vt 0.3282 0.6639 +vt 0.3282 0.6717 +vt 0.3204 0.6717 +vt 0.3360 0.6639 +vt 0.3438 0.6639 +vt 0.3438 0.6717 +vt 0.3360 0.6717 +vt 0.6639 0.8358 +vt 0.6717 0.8358 +vt 0.6717 0.8436 +vt 0.6639 0.8436 +vt 0.6639 0.8202 +vt 0.6717 0.8202 +vt 0.6717 0.8280 +vt 0.6639 0.8280 +vt 0.6795 0.8202 +vt 0.6873 0.8202 +vt 0.6873 0.8280 +vt 0.6795 0.8280 +vt 0.6326 0.8358 +vt 0.6404 0.8358 +vt 0.6404 0.8436 +vt 0.6326 0.8436 +vt 0.6326 0.8202 +vt 0.6405 0.8202 +vt 0.6405 0.8280 +vt 0.6326 0.8280 +vt 0.6483 0.8202 +vt 0.6561 0.8202 +vt 0.6561 0.8280 +vt 0.6483 0.8280 +vt 0.6326 0.8670 +vt 0.6404 0.8670 +vt 0.6404 0.8748 +vt 0.6326 0.8748 +vt 0.6326 0.8514 +vt 0.6404 0.8514 +vt 0.6404 0.8592 +vt 0.6326 0.8592 +vt 0.6483 0.8514 +vt 0.6561 0.8514 +vt 0.6561 0.8592 +vt 0.6482 0.8592 +vt 0.6639 0.7733 +vt 0.6717 0.7733 +vt 0.6717 0.7811 +vt 0.6639 0.7811 +vt 0.6639 0.7577 +vt 0.6717 0.7577 +vt 0.6717 0.7655 +vt 0.6639 0.7655 +vt 0.6795 0.7577 +vt 0.6873 0.7577 +vt 0.6873 0.7655 +vt 0.6795 0.7655 +vt 0.6327 0.7733 +vt 0.6405 0.7733 +vt 0.6405 0.7811 +vt 0.6327 0.7811 +vt 0.6327 0.7577 +vt 0.6405 0.7577 +vt 0.6405 0.7655 +vt 0.6327 0.7655 +vt 0.6483 0.7577 +vt 0.6561 0.7577 +vt 0.6561 0.7655 +vt 0.6483 0.7655 +vt 0.6326 0.8046 +vt 0.6405 0.8046 +vt 0.6405 0.8124 +vt 0.6326 0.8124 +vt 0.6327 0.7889 +vt 0.6405 0.7889 +vt 0.6405 0.7967 +vt 0.6327 0.7967 +vt 0.6483 0.7889 +vt 0.6561 0.7889 +vt 0.6561 0.7968 +vt 0.6483 0.7968 +vt 0.7264 0.7733 +vt 0.7342 0.7734 +vt 0.7342 0.7812 +vt 0.7264 0.7812 +vt 0.7264 0.7577 +vt 0.7342 0.7577 +vt 0.7342 0.7655 +vt 0.7264 0.7655 +vt 0.7420 0.7577 +vt 0.7498 0.7577 +vt 0.7498 0.7655 +vt 0.7420 0.7655 +vt 0.6951 0.7733 +vt 0.7029 0.7733 +vt 0.7029 0.7812 +vt 0.6951 0.7811 +vt 0.6951 0.7577 +vt 0.7029 0.7577 +vt 0.7029 0.7655 +vt 0.6951 0.7655 +vt 0.7107 0.7577 +vt 0.7186 0.7577 +vt 0.7186 0.7655 +vt 0.7107 0.7655 +vt 0.6951 0.8046 +vt 0.7029 0.8046 +vt 0.7029 0.8124 +vt 0.6951 0.8124 +vt 0.6951 0.7890 +vt 0.7029 0.7890 +vt 0.7029 0.7968 +vt 0.6951 0.7968 +vt 0.7107 0.7890 +vt 0.7185 0.7890 +vt 0.7185 0.7968 +vt 0.7107 0.7968 +vt 0.5389 0.8358 +vt 0.5467 0.8358 +vt 0.5467 0.8436 +vt 0.5389 0.8436 +vt 0.5389 0.8201 +vt 0.5468 0.8201 +vt 0.5468 0.8280 +vt 0.5389 0.8280 +vt 0.5546 0.8201 +vt 0.5624 0.8201 +vt 0.5624 0.8280 +vt 0.5546 0.8280 +vt 0.5077 0.8357 +vt 0.5155 0.8358 +vt 0.5155 0.8436 +vt 0.5077 0.8436 +vt 0.5077 0.8201 +vt 0.5155 0.8201 +vt 0.5155 0.8279 +vt 0.5077 0.8279 +vt 0.5233 0.8201 +vt 0.5311 0.8201 +vt 0.5311 0.8279 +vt 0.5233 0.8279 +vt 0.5077 0.8670 +vt 0.5155 0.8670 +vt 0.5155 0.8748 +vt 0.5077 0.8748 +vt 0.5077 0.8514 +vt 0.5155 0.8514 +vt 0.5155 0.8592 +vt 0.5077 0.8592 +vt 0.5233 0.8514 +vt 0.5311 0.8514 +vt 0.5311 0.8592 +vt 0.5233 0.8592 +vt 0.5390 0.7733 +vt 0.5468 0.7733 +vt 0.5468 0.7811 +vt 0.5390 0.7811 +vt 0.5390 0.7577 +vt 0.5468 0.7577 +vt 0.5468 0.7655 +vt 0.5390 0.7655 +vt 0.5546 0.7577 +vt 0.5624 0.7577 +vt 0.5624 0.7655 +vt 0.5546 0.7655 +vt 0.5077 0.7733 +vt 0.5155 0.7733 +vt 0.5155 0.7811 +vt 0.5077 0.7811 +vt 0.5077 0.7577 +vt 0.5155 0.7577 +vt 0.5155 0.7655 +vt 0.5077 0.7655 +vt 0.5233 0.7577 +vt 0.5312 0.7577 +vt 0.5312 0.7655 +vt 0.5233 0.7655 +vt 0.5077 0.8045 +vt 0.5155 0.8045 +vt 0.5155 0.8123 +vt 0.5077 0.8123 +vt 0.5077 0.7889 +vt 0.5155 0.7889 +vt 0.5155 0.7967 +vt 0.5077 0.7967 +vt 0.5233 0.7889 +vt 0.5311 0.7889 +vt 0.5311 0.7967 +vt 0.5233 0.7967 +vt 0.6014 0.7733 +vt 0.6092 0.7733 +vt 0.6092 0.7811 +vt 0.6014 0.7811 +vt 0.6014 0.7577 +vt 0.6092 0.7577 +vt 0.6092 0.7655 +vt 0.6014 0.7655 +vt 0.6170 0.7577 +vt 0.6249 0.7577 +vt 0.6249 0.7655 +vt 0.6170 0.7655 +vt 0.5702 0.7733 +vt 0.5780 0.7733 +vt 0.5780 0.7811 +vt 0.5702 0.7811 +vt 0.5702 0.7577 +vt 0.5780 0.7577 +vt 0.5780 0.7655 +vt 0.5702 0.7655 +vt 0.5858 0.7577 +vt 0.5936 0.7577 +vt 0.5936 0.7655 +vt 0.5858 0.7655 +vt 0.5702 0.8045 +vt 0.5780 0.8045 +vt 0.5780 0.8123 +vt 0.5702 0.8123 +vt 0.5702 0.7889 +vt 0.5780 0.7889 +vt 0.5780 0.7967 +vt 0.5702 0.7967 +vt 0.5858 0.7889 +vt 0.5936 0.7889 +vt 0.5936 0.7967 +vt 0.5858 0.7967 +vt 0.5389 0.9607 +vt 0.5467 0.9607 +vt 0.5467 0.9685 +vt 0.5389 0.9685 +vt 0.5389 0.9451 +vt 0.5467 0.9451 +vt 0.5467 0.9529 +vt 0.5389 0.9529 +vt 0.5545 0.9451 +vt 0.5623 0.9451 +vt 0.5623 0.9529 +vt 0.5545 0.9529 +vt 0.5077 0.9607 +vt 0.5155 0.9607 +vt 0.5155 0.9685 +vt 0.5077 0.9685 +vt 0.5077 0.9451 +vt 0.5155 0.9451 +vt 0.5155 0.9529 +vt 0.5077 0.9529 +vt 0.5233 0.9451 +vt 0.5311 0.9451 +vt 0.5311 0.9529 +vt 0.5233 0.9529 +vt 0.5077 0.9919 +vt 0.5155 0.9919 +vt 0.5155 0.9997 +vt 0.5077 0.9997 +vt 0.5077 0.9763 +vt 0.5155 0.9763 +vt 0.5155 0.9841 +vt 0.5077 0.9841 +vt 0.5233 0.9763 +vt 0.5311 0.9763 +vt 0.5311 0.9841 +vt 0.5233 0.9841 +vt 0.5389 0.8982 +vt 0.5467 0.8982 +vt 0.5467 0.9060 +vt 0.5389 0.9060 +vt 0.5389 0.8826 +vt 0.5467 0.8826 +vt 0.5467 0.8904 +vt 0.5389 0.8904 +vt 0.5545 0.8826 +vt 0.5624 0.8826 +vt 0.5623 0.8904 +vt 0.5545 0.8904 +vt 0.5077 0.8982 +vt 0.5155 0.8982 +vt 0.5155 0.9060 +vt 0.5077 0.9060 +vt 0.5077 0.8826 +vt 0.5155 0.8826 +vt 0.5155 0.8904 +vt 0.5077 0.8904 +vt 0.5233 0.8826 +vt 0.5311 0.8826 +vt 0.5311 0.8904 +vt 0.5233 0.8904 +vt 0.5077 0.9295 +vt 0.5155 0.9295 +vt 0.5155 0.9373 +vt 0.5077 0.9373 +vt 0.5077 0.9138 +vt 0.5155 0.9138 +vt 0.5155 0.9216 +vt 0.5077 0.9216 +vt 0.5233 0.9138 +vt 0.5311 0.9138 +vt 0.5311 0.9216 +vt 0.5233 0.9216 +vt 0.6014 0.8982 +vt 0.6092 0.8982 +vt 0.6092 0.9061 +vt 0.6014 0.9061 +vt 0.6014 0.8826 +vt 0.6092 0.8826 +vt 0.6092 0.8904 +vt 0.6014 0.8904 +vt 0.6170 0.8826 +vt 0.6248 0.8826 +vt 0.6248 0.8904 +vt 0.6170 0.8904 +vt 0.5702 0.8982 +vt 0.5780 0.8982 +vt 0.5780 0.9060 +vt 0.5702 0.9060 +vt 0.5702 0.8826 +vt 0.5780 0.8826 +vt 0.5780 0.8904 +vt 0.5702 0.8904 +vt 0.5858 0.8826 +vt 0.5936 0.8826 +vt 0.5936 0.8904 +vt 0.5858 0.8904 +vt 0.5701 0.9295 +vt 0.5780 0.9295 +vt 0.5780 0.9373 +vt 0.5701 0.9373 +vt 0.5701 0.9139 +vt 0.5780 0.9139 +vt 0.5780 0.9217 +vt 0.5701 0.9217 +vt 0.5858 0.9139 +vt 0.5936 0.9139 +vt 0.5936 0.9217 +vt 0.5858 0.9217 +vt 0.6640 0.5859 +vt 0.6718 0.5859 +vt 0.6718 0.5937 +vt 0.6639 0.5937 +vt 0.6640 0.5703 +vt 0.6718 0.5703 +vt 0.6718 0.5781 +vt 0.6640 0.5781 +vt 0.6796 0.5703 +vt 0.6874 0.5703 +vt 0.6874 0.5781 +vt 0.6796 0.5781 +vt 0.6327 0.5859 +vt 0.6405 0.5859 +vt 0.6405 0.5937 +vt 0.6327 0.5937 +vt 0.6327 0.5703 +vt 0.6405 0.5703 +vt 0.6405 0.5781 +vt 0.6327 0.5781 +vt 0.6483 0.5703 +vt 0.6561 0.5703 +vt 0.6561 0.5781 +vt 0.6483 0.5781 +vt 0.6327 0.6172 +vt 0.6405 0.6172 +vt 0.6405 0.6250 +vt 0.6327 0.6250 +vt 0.6327 0.6015 +vt 0.6405 0.6015 +vt 0.6405 0.6093 +vt 0.6327 0.6093 +vt 0.6483 0.6015 +vt 0.6561 0.6015 +vt 0.6561 0.6094 +vt 0.6483 0.6093 +vt 0.6640 0.5235 +vt 0.6718 0.5235 +vt 0.6718 0.5313 +vt 0.6640 0.5313 +vt 0.6640 0.5078 +vt 0.6718 0.5078 +vt 0.6718 0.5157 +vt 0.6640 0.5157 +vt 0.6796 0.5079 +vt 0.6874 0.5079 +vt 0.6874 0.5157 +vt 0.6796 0.5157 +vt 0.6327 0.5235 +vt 0.6405 0.5235 +vt 0.6405 0.5313 +vt 0.6327 0.5313 +vt 0.6327 0.5078 +vt 0.6406 0.5078 +vt 0.6405 0.5156 +vt 0.6327 0.5156 +vt 0.6484 0.5078 +vt 0.6562 0.5078 +vt 0.6562 0.5157 +vt 0.6484 0.5156 +vt 0.6327 0.5547 +vt 0.6405 0.5547 +vt 0.6405 0.5625 +vt 0.6327 0.5625 +vt 0.6327 0.5391 +vt 0.6405 0.5391 +vt 0.6405 0.5469 +vt 0.6327 0.5469 +vt 0.6483 0.5391 +vt 0.6562 0.5391 +vt 0.6562 0.5469 +vt 0.6483 0.5469 +vt 0.7264 0.5235 +vt 0.7342 0.5235 +vt 0.7342 0.5313 +vt 0.7264 0.5313 +vt 0.7264 0.5079 +vt 0.7343 0.5079 +vt 0.7342 0.5157 +vt 0.7264 0.5157 +vt 0.7421 0.5079 +vt 0.7499 0.5079 +vt 0.7499 0.5157 +vt 0.7421 0.5157 +vt 0.6952 0.5235 +vt 0.7030 0.5235 +vt 0.7030 0.5313 +vt 0.6952 0.5313 +vt 0.6952 0.5079 +vt 0.7030 0.5079 +vt 0.7030 0.5157 +vt 0.6952 0.5157 +vt 0.7108 0.5079 +vt 0.7186 0.5079 +vt 0.7186 0.5157 +vt 0.7108 0.5157 +vt 0.6952 0.5547 +vt 0.7030 0.5547 +vt 0.7030 0.5625 +vt 0.6952 0.5625 +vt 0.6952 0.5391 +vt 0.7030 0.5391 +vt 0.7030 0.5469 +vt 0.6952 0.5469 +vt 0.7108 0.5391 +vt 0.7186 0.5391 +vt 0.7186 0.5469 +vt 0.7108 0.5469 +vt 0.5390 0.5859 +vt 0.5468 0.5859 +vt 0.5468 0.5937 +vt 0.5390 0.5937 +vt 0.5390 0.5703 +vt 0.5468 0.5703 +vt 0.5468 0.5781 +vt 0.5390 0.5781 +vt 0.5546 0.5703 +vt 0.5624 0.5703 +vt 0.5624 0.5781 +vt 0.5546 0.5781 +vt 0.5078 0.5859 +vt 0.5156 0.5859 +vt 0.5156 0.5937 +vt 0.5078 0.5937 +vt 0.5078 0.5703 +vt 0.5156 0.5703 +vt 0.5156 0.5781 +vt 0.5078 0.5781 +vt 0.5234 0.5703 +vt 0.5312 0.5703 +vt 0.5312 0.5781 +vt 0.5234 0.5781 +vt 0.5078 0.6171 +vt 0.5156 0.6171 +vt 0.5156 0.6249 +vt 0.5078 0.6249 +vt 0.5078 0.6015 +vt 0.5156 0.6015 +vt 0.5156 0.6093 +vt 0.5078 0.6093 +vt 0.5234 0.6015 +vt 0.5312 0.6015 +vt 0.5312 0.6093 +vt 0.5234 0.6093 +vt 0.5390 0.5234 +vt 0.5468 0.5234 +vt 0.5468 0.5312 +vt 0.5390 0.5312 +vt 0.5390 0.5078 +vt 0.5468 0.5078 +vt 0.5468 0.5156 +vt 0.5390 0.5156 +vt 0.5547 0.5078 +vt 0.5625 0.5078 +vt 0.5625 0.5156 +vt 0.5547 0.5156 +vt 0.5078 0.5234 +vt 0.5156 0.5234 +vt 0.5156 0.5312 +vt 0.5078 0.5312 +vt 0.5078 0.5078 +vt 0.5156 0.5078 +vt 0.5156 0.5156 +vt 0.5078 0.5156 +vt 0.5234 0.5078 +vt 0.5312 0.5078 +vt 0.5312 0.5156 +vt 0.5234 0.5156 +vt 0.5078 0.5546 +vt 0.5156 0.5546 +vt 0.5156 0.5625 +vt 0.5078 0.5625 +vt 0.5078 0.5390 +vt 0.5156 0.5390 +vt 0.5156 0.5468 +vt 0.5078 0.5468 +vt 0.5234 0.5390 +vt 0.5312 0.5390 +vt 0.5312 0.5468 +vt 0.5234 0.5468 +vt 0.6015 0.5234 +vt 0.6093 0.5234 +vt 0.6093 0.5313 +vt 0.6015 0.5313 +vt 0.6015 0.5078 +vt 0.6093 0.5078 +vt 0.6093 0.5156 +vt 0.6015 0.5156 +vt 0.6171 0.5078 +vt 0.6249 0.5078 +vt 0.6249 0.5156 +vt 0.6171 0.5156 +vt 0.5703 0.5234 +vt 0.5781 0.5234 +vt 0.5781 0.5312 +vt 0.5703 0.5312 +vt 0.5703 0.5078 +vt 0.5781 0.5078 +vt 0.5781 0.5156 +vt 0.5703 0.5156 +vt 0.5859 0.5078 +vt 0.5937 0.5078 +vt 0.5937 0.5156 +vt 0.5859 0.5156 +vt 0.5703 0.5547 +vt 0.5781 0.5547 +vt 0.5781 0.5625 +vt 0.5703 0.5625 +vt 0.5703 0.5391 +vt 0.5781 0.5391 +vt 0.5781 0.5469 +vt 0.5703 0.5469 +vt 0.5859 0.5391 +vt 0.5937 0.5391 +vt 0.5937 0.5469 +vt 0.5859 0.5469 +vt 0.5390 0.7108 +vt 0.5468 0.7108 +vt 0.5468 0.7186 +vt 0.5390 0.7186 +vt 0.5390 0.6952 +vt 0.5468 0.6952 +vt 0.5468 0.7030 +vt 0.5390 0.7030 +vt 0.5546 0.6952 +vt 0.5624 0.6952 +vt 0.5624 0.7030 +vt 0.5546 0.7030 +vt 0.5077 0.7108 +vt 0.5156 0.7108 +vt 0.5156 0.7186 +vt 0.5077 0.7186 +vt 0.5077 0.6952 +vt 0.5156 0.6952 +vt 0.5156 0.7030 +vt 0.5077 0.7030 +vt 0.5234 0.6952 +vt 0.5312 0.6952 +vt 0.5312 0.7030 +vt 0.5234 0.7030 +vt 0.5077 0.7420 +vt 0.5155 0.7421 +vt 0.5155 0.7499 +vt 0.5077 0.7499 +vt 0.5077 0.7264 +vt 0.5155 0.7264 +vt 0.5155 0.7342 +vt 0.5077 0.7342 +vt 0.5234 0.7264 +vt 0.5312 0.7264 +vt 0.5312 0.7342 +vt 0.5234 0.7342 +vt 0.5390 0.6484 +vt 0.5468 0.6484 +vt 0.5468 0.6562 +vt 0.5390 0.6562 +vt 0.5390 0.6327 +vt 0.5468 0.6327 +vt 0.5468 0.6406 +vt 0.5390 0.6405 +vt 0.5546 0.6327 +vt 0.5624 0.6327 +vt 0.5624 0.6406 +vt 0.5546 0.6406 +vt 0.5078 0.6483 +vt 0.5156 0.6484 +vt 0.5156 0.6562 +vt 0.5078 0.6562 +vt 0.5078 0.6327 +vt 0.5156 0.6327 +vt 0.5156 0.6405 +vt 0.5078 0.6405 +vt 0.5234 0.6327 +vt 0.5312 0.6327 +vt 0.5312 0.6405 +vt 0.5234 0.6405 +vt 0.5078 0.6796 +vt 0.5156 0.6796 +vt 0.5156 0.6874 +vt 0.5078 0.6874 +vt 0.5078 0.6640 +vt 0.5156 0.6640 +vt 0.5156 0.6718 +vt 0.5078 0.6718 +vt 0.5234 0.6640 +vt 0.5312 0.6640 +vt 0.5312 0.6718 +vt 0.5234 0.6718 +vt 0.6015 0.6484 +vt 0.6093 0.6484 +vt 0.6093 0.6562 +vt 0.6015 0.6562 +vt 0.6015 0.6328 +vt 0.6093 0.6328 +vt 0.6093 0.6406 +vt 0.6015 0.6406 +vt 0.6171 0.6328 +vt 0.6249 0.6328 +vt 0.6249 0.6406 +vt 0.6171 0.6406 +vt 0.5702 0.6484 +vt 0.5780 0.6484 +vt 0.5780 0.6562 +vt 0.5702 0.6562 +vt 0.5702 0.6328 +vt 0.5780 0.6328 +vt 0.5780 0.6406 +vt 0.5702 0.6406 +vt 0.5859 0.6328 +vt 0.5937 0.6328 +vt 0.5937 0.6406 +vt 0.5858 0.6406 +vt 0.5702 0.6796 +vt 0.5780 0.6796 +vt 0.5780 0.6874 +vt 0.5702 0.6874 +vt 0.5702 0.6640 +vt 0.5780 0.6640 +vt 0.5780 0.6718 +vt 0.5702 0.6718 +vt 0.5858 0.6640 +vt 0.5937 0.6640 +vt 0.5936 0.6718 +vt 0.5858 0.6718 +vt 0.9138 0.5860 +vt 0.9216 0.5860 +vt 0.9216 0.5938 +vt 0.9138 0.5938 +vt 0.9138 0.5704 +vt 0.9216 0.5704 +vt 0.9216 0.5782 +vt 0.9138 0.5782 +vt 0.9294 0.5704 +vt 0.9372 0.5704 +vt 0.9372 0.5782 +vt 0.9294 0.5782 +vt 0.8826 0.5860 +vt 0.8904 0.5860 +vt 0.8904 0.5938 +vt 0.8826 0.5938 +vt 0.8826 0.5704 +vt 0.8904 0.5704 +vt 0.8904 0.5782 +vt 0.8826 0.5782 +vt 0.8982 0.5704 +vt 0.9060 0.5704 +vt 0.9060 0.5782 +vt 0.8982 0.5782 +vt 0.8826 0.6172 +vt 0.8904 0.6172 +vt 0.8904 0.6250 +vt 0.8826 0.6250 +vt 0.8826 0.6016 +vt 0.8904 0.6016 +vt 0.8904 0.6094 +vt 0.8826 0.6094 +vt 0.8982 0.6016 +vt 0.9060 0.6016 +vt 0.9060 0.6094 +vt 0.8982 0.6094 +vt 0.9138 0.5235 +vt 0.9216 0.5235 +vt 0.9216 0.5314 +vt 0.9138 0.5314 +vt 0.9138 0.5079 +vt 0.9217 0.5079 +vt 0.9216 0.5157 +vt 0.9138 0.5157 +vt 0.9295 0.5079 +vt 0.9373 0.5079 +vt 0.9373 0.5157 +vt 0.9295 0.5157 +vt 0.8826 0.5235 +vt 0.8904 0.5235 +vt 0.8904 0.5313 +vt 0.8826 0.5313 +vt 0.8826 0.5079 +vt 0.8904 0.5079 +vt 0.8904 0.5157 +vt 0.8826 0.5157 +vt 0.8982 0.5079 +vt 0.9060 0.5079 +vt 0.9060 0.5157 +vt 0.8982 0.5157 +vt 0.8826 0.5548 +vt 0.8904 0.5548 +vt 0.8904 0.5626 +vt 0.8826 0.5626 +vt 0.8826 0.5391 +vt 0.8904 0.5392 +vt 0.8904 0.5470 +vt 0.8826 0.5470 +vt 0.8982 0.5392 +vt 0.9060 0.5392 +vt 0.9060 0.5470 +vt 0.8982 0.5470 +vt 0.9763 0.5236 +vt 0.9841 0.5236 +vt 0.9841 0.5314 +vt 0.9763 0.5314 +vt 0.9763 0.5079 +vt 0.9841 0.5079 +vt 0.9841 0.5158 +vt 0.9763 0.5158 +vt 0.9919 0.5080 +vt 0.9997 0.5080 +vt 0.9997 0.5158 +vt 0.9919 0.5158 +vt 0.9451 0.5236 +vt 0.9529 0.5236 +vt 0.9529 0.5314 +vt 0.9451 0.5314 +vt 0.9451 0.5079 +vt 0.9529 0.5079 +vt 0.9529 0.5157 +vt 0.9451 0.5157 +vt 0.9607 0.5079 +vt 0.9685 0.5079 +vt 0.9685 0.5158 +vt 0.9607 0.5157 +vt 0.9451 0.5548 +vt 0.9529 0.5548 +vt 0.9529 0.5626 +vt 0.9451 0.5626 +vt 0.9451 0.5392 +vt 0.9529 0.5392 +vt 0.9529 0.5470 +vt 0.9451 0.5470 +vt 0.9607 0.5392 +vt 0.9685 0.5392 +vt 0.9685 0.5470 +vt 0.9607 0.5470 +vt 0.7889 0.5860 +vt 0.7967 0.5860 +vt 0.7967 0.5938 +vt 0.7889 0.5938 +vt 0.7889 0.5704 +vt 0.7967 0.5704 +vt 0.7967 0.5782 +vt 0.7889 0.5782 +vt 0.8045 0.5704 +vt 0.8123 0.5704 +vt 0.8123 0.5782 +vt 0.8045 0.5782 +vt 0.7577 0.5860 +vt 0.7655 0.5860 +vt 0.7655 0.5938 +vt 0.7576 0.5938 +vt 0.7577 0.5703 +vt 0.7655 0.5703 +vt 0.7655 0.5782 +vt 0.7577 0.5782 +vt 0.7733 0.5703 +vt 0.7811 0.5703 +vt 0.7811 0.5782 +vt 0.7733 0.5782 +vt 0.7576 0.6172 +vt 0.7654 0.6172 +vt 0.7654 0.6250 +vt 0.7576 0.6250 +vt 0.7576 0.6016 +vt 0.7655 0.6016 +vt 0.7655 0.6094 +vt 0.7576 0.6094 +vt 0.7733 0.6016 +vt 0.7811 0.6016 +vt 0.7811 0.6094 +vt 0.7733 0.6094 +vt 0.7889 0.5235 +vt 0.7967 0.5235 +vt 0.7967 0.5313 +vt 0.7889 0.5313 +vt 0.7889 0.5079 +vt 0.7967 0.5079 +vt 0.7967 0.5157 +vt 0.7889 0.5157 +vt 0.8045 0.5079 +vt 0.8123 0.5079 +vt 0.8123 0.5157 +vt 0.8045 0.5157 +vt 0.7577 0.5235 +vt 0.7655 0.5235 +vt 0.7655 0.5313 +vt 0.7577 0.5313 +vt 0.7577 0.5079 +vt 0.7655 0.5079 +vt 0.7655 0.5157 +vt 0.7577 0.5157 +vt 0.7733 0.5079 +vt 0.7811 0.5079 +vt 0.7811 0.5157 +vt 0.7733 0.5157 +vt 0.7577 0.5547 +vt 0.7655 0.5547 +vt 0.7655 0.5625 +vt 0.7577 0.5625 +vt 0.7577 0.5391 +vt 0.7655 0.5391 +vt 0.7655 0.5469 +vt 0.7577 0.5469 +vt 0.7733 0.5391 +vt 0.7811 0.5391 +vt 0.7811 0.5469 +vt 0.7733 0.5469 +vt 0.8514 0.5235 +vt 0.8592 0.5235 +vt 0.8592 0.5313 +vt 0.8514 0.5313 +vt 0.8514 0.5079 +vt 0.8592 0.5079 +vt 0.8592 0.5157 +vt 0.8514 0.5157 +vt 0.8670 0.5079 +vt 0.8748 0.5079 +vt 0.8748 0.5157 +vt 0.8670 0.5157 +vt 0.8201 0.5235 +vt 0.8279 0.5235 +vt 0.8279 0.5313 +vt 0.8201 0.5313 +vt 0.8201 0.5079 +vt 0.8280 0.5079 +vt 0.8279 0.5157 +vt 0.8201 0.5157 +vt 0.8358 0.5079 +vt 0.8436 0.5079 +vt 0.8436 0.5157 +vt 0.8358 0.5157 +vt 0.8201 0.5547 +vt 0.8279 0.5547 +vt 0.8279 0.5626 +vt 0.8201 0.5626 +vt 0.8201 0.5391 +vt 0.8279 0.5391 +vt 0.8279 0.5469 +vt 0.8201 0.5469 +vt 0.8357 0.5391 +vt 0.8436 0.5391 +vt 0.8436 0.5469 +vt 0.8357 0.5469 +vt 0.7888 0.7109 +vt 0.7967 0.7109 +vt 0.7967 0.7187 +vt 0.7888 0.7187 +vt 0.7888 0.6953 +vt 0.7967 0.6953 +vt 0.7967 0.7031 +vt 0.7888 0.7031 +vt 0.8045 0.6953 +vt 0.8123 0.6953 +vt 0.8123 0.7031 +vt 0.8045 0.7031 +vt 0.7576 0.7109 +vt 0.7654 0.7109 +vt 0.7654 0.7187 +vt 0.7576 0.7187 +vt 0.7576 0.6953 +vt 0.7654 0.6953 +vt 0.7654 0.7031 +vt 0.7576 0.7031 +vt 0.7732 0.6953 +vt 0.7810 0.6953 +vt 0.7810 0.7031 +vt 0.7732 0.7031 +vt 0.7576 0.7421 +vt 0.7654 0.7421 +vt 0.7654 0.7499 +vt 0.7576 0.7499 +vt 0.7576 0.7265 +vt 0.7654 0.7265 +vt 0.7654 0.7343 +vt 0.7576 0.7343 +vt 0.7732 0.7265 +vt 0.7810 0.7265 +vt 0.7810 0.7343 +vt 0.7732 0.7343 +vt 0.7889 0.6484 +vt 0.7967 0.6484 +vt 0.7967 0.6562 +vt 0.7889 0.6562 +vt 0.7889 0.6328 +vt 0.7967 0.6328 +vt 0.7967 0.6406 +vt 0.7889 0.6406 +vt 0.8045 0.6328 +vt 0.8123 0.6328 +vt 0.8123 0.6406 +vt 0.8045 0.6406 +vt 0.7576 0.6484 +vt 0.7654 0.6484 +vt 0.7654 0.6562 +vt 0.7576 0.6562 +vt 0.7576 0.6328 +vt 0.7654 0.6328 +vt 0.7654 0.6406 +vt 0.7576 0.6406 +vt 0.7733 0.6328 +vt 0.7811 0.6328 +vt 0.7811 0.6406 +vt 0.7733 0.6406 +vt 0.7576 0.6797 +vt 0.7654 0.6797 +vt 0.7654 0.6875 +vt 0.7576 0.6875 +vt 0.7576 0.6640 +vt 0.7654 0.6640 +vt 0.7654 0.6719 +vt 0.7576 0.6719 +vt 0.7732 0.6640 +vt 0.7811 0.6641 +vt 0.7810 0.6719 +vt 0.7732 0.6719 +vt 0.8513 0.6485 +vt 0.8591 0.6485 +vt 0.8591 0.6563 +vt 0.8513 0.6563 +vt 0.8513 0.6328 +vt 0.8591 0.6328 +vt 0.8591 0.6406 +vt 0.8513 0.6406 +vt 0.8670 0.6328 +vt 0.8748 0.6328 +vt 0.8748 0.6407 +vt 0.8670 0.6407 +vt 0.8201 0.6484 +vt 0.8279 0.6484 +vt 0.8279 0.6563 +vt 0.8201 0.6563 +vt 0.8201 0.6328 +vt 0.8279 0.6328 +vt 0.8279 0.6406 +vt 0.8201 0.6406 +vt 0.8357 0.6328 +vt 0.8435 0.6328 +vt 0.8435 0.6406 +vt 0.8357 0.6406 +vt 0.8201 0.6797 +vt 0.8279 0.6797 +vt 0.8279 0.6875 +vt 0.8201 0.6875 +vt 0.8201 0.6641 +vt 0.8279 0.6641 +vt 0.8279 0.6719 +vt 0.8201 0.6719 +vt 0.8357 0.6641 +vt 0.8435 0.6641 +vt 0.8435 0.6719 +vt 0.8357 0.6719 +vt 0.9138 0.7109 +vt 0.9216 0.7109 +vt 0.9216 0.7188 +vt 0.9138 0.7188 +vt 0.9138 0.6953 +vt 0.9216 0.6953 +vt 0.9216 0.7031 +vt 0.9138 0.7031 +vt 0.9294 0.6953 +vt 0.9372 0.6953 +vt 0.9372 0.7031 +vt 0.9294 0.7031 +vt 0.8825 0.7109 +vt 0.8904 0.7109 +vt 0.8904 0.7187 +vt 0.8825 0.7187 +vt 0.8825 0.6953 +vt 0.8904 0.6953 +vt 0.8904 0.7031 +vt 0.8825 0.7031 +vt 0.8982 0.6953 +vt 0.9060 0.6953 +vt 0.9060 0.7031 +vt 0.8982 0.7031 +vt 0.8825 0.7422 +vt 0.8903 0.7422 +vt 0.8903 0.7500 +vt 0.8825 0.7500 +vt 0.8825 0.7265 +vt 0.8903 0.7266 +vt 0.8903 0.7344 +vt 0.8825 0.7344 +vt 0.8982 0.7266 +vt 0.9060 0.7266 +vt 0.9060 0.7344 +vt 0.8982 0.7344 +vt 0.9138 0.6485 +vt 0.9216 0.6485 +vt 0.9216 0.6563 +vt 0.9138 0.6563 +vt 0.9138 0.6329 +vt 0.9216 0.6329 +vt 0.9216 0.6407 +vt 0.9138 0.6407 +vt 0.9294 0.6329 +vt 0.9372 0.6329 +vt 0.9372 0.6407 +vt 0.9294 0.6407 +vt 0.8826 0.6485 +vt 0.8904 0.6485 +vt 0.8904 0.6563 +vt 0.8826 0.6563 +vt 0.8826 0.6328 +vt 0.8904 0.6329 +vt 0.8904 0.6407 +vt 0.8826 0.6407 +vt 0.8982 0.6329 +vt 0.9060 0.6329 +vt 0.9060 0.6407 +vt 0.8982 0.6407 +vt 0.8826 0.6797 +vt 0.8904 0.6797 +vt 0.8904 0.6875 +vt 0.8826 0.6875 +vt 0.8826 0.6641 +vt 0.8904 0.6641 +vt 0.8904 0.6719 +vt 0.8826 0.6719 +vt 0.8982 0.6641 +vt 0.9060 0.6641 +vt 0.9060 0.6719 +vt 0.8982 0.6719 +vt 0.9763 0.6485 +vt 0.9841 0.6485 +vt 0.9841 0.6563 +vt 0.9763 0.6563 +vt 0.9763 0.6329 +vt 0.9841 0.6329 +vt 0.9841 0.6407 +vt 0.9763 0.6407 +vt 0.9919 0.6329 +vt 0.9997 0.6329 +vt 0.9997 0.6407 +vt 0.9919 0.6407 +vt 0.9450 0.6485 +vt 0.9528 0.6485 +vt 0.9528 0.6563 +vt 0.9450 0.6563 +vt 0.9450 0.6329 +vt 0.9528 0.6329 +vt 0.9528 0.6407 +vt 0.9450 0.6407 +vt 0.9607 0.6329 +vt 0.9685 0.6329 +vt 0.9685 0.6407 +vt 0.9607 0.6407 +vt 0.9450 0.6797 +vt 0.9528 0.6797 +vt 0.9528 0.6875 +vt 0.9450 0.6875 +vt 0.9450 0.6641 +vt 0.9528 0.6641 +vt 0.9528 0.6719 +vt 0.9450 0.6719 +vt 0.9606 0.6641 +vt 0.9685 0.6641 +vt 0.9684 0.6719 +vt 0.9606 0.6719 +vt 0.6639 0.7109 +vt 0.6717 0.7109 +vt 0.6717 0.7187 +vt 0.6639 0.7187 +vt 0.6639 0.6952 +vt 0.6717 0.6952 +vt 0.6717 0.7031 +vt 0.6639 0.7031 +vt 0.6795 0.6953 +vt 0.6873 0.6953 +vt 0.6873 0.7031 +vt 0.6795 0.7031 +vt 0.6327 0.7109 +vt 0.6405 0.7109 +vt 0.6405 0.7187 +vt 0.6327 0.7187 +vt 0.6327 0.6952 +vt 0.6405 0.6952 +vt 0.6405 0.7030 +vt 0.6327 0.7030 +vt 0.6483 0.6952 +vt 0.6561 0.6952 +vt 0.6561 0.7031 +vt 0.6483 0.7031 +vt 0.6327 0.7421 +vt 0.6405 0.7421 +vt 0.6405 0.7499 +vt 0.6327 0.7499 +vt 0.6327 0.7265 +vt 0.6405 0.7265 +vt 0.6405 0.7343 +vt 0.6327 0.7343 +vt 0.6483 0.7265 +vt 0.6561 0.7265 +vt 0.6561 0.7343 +vt 0.6483 0.7343 +vt 0.6639 0.6484 +vt 0.6717 0.6484 +vt 0.6717 0.6562 +vt 0.6639 0.6562 +vt 0.6639 0.6328 +vt 0.6717 0.6328 +vt 0.6717 0.6406 +vt 0.6639 0.6406 +vt 0.6796 0.6328 +vt 0.6874 0.6328 +vt 0.6874 0.6406 +vt 0.6796 0.6406 +vt 0.6327 0.6484 +vt 0.6405 0.6484 +vt 0.6405 0.6562 +vt 0.6327 0.6562 +vt 0.6327 0.6328 +vt 0.6405 0.6328 +vt 0.6405 0.6406 +vt 0.6327 0.6406 +vt 0.6483 0.6328 +vt 0.6561 0.6328 +vt 0.6561 0.6406 +vt 0.6483 0.6406 +vt 0.6327 0.6796 +vt 0.6405 0.6796 +vt 0.6405 0.6874 +vt 0.6327 0.6874 +vt 0.6327 0.6640 +vt 0.6405 0.6640 +vt 0.6405 0.6718 +vt 0.6327 0.6718 +vt 0.6483 0.6640 +vt 0.6561 0.6640 +vt 0.6561 0.6718 +vt 0.6483 0.6718 +vt 0.7264 0.6484 +vt 0.7342 0.6484 +vt 0.7342 0.6562 +vt 0.7264 0.6562 +vt 0.7264 0.6328 +vt 0.7342 0.6328 +vt 0.7342 0.6406 +vt 0.7264 0.6406 +vt 0.7420 0.6328 +vt 0.7498 0.6328 +vt 0.7498 0.6406 +vt 0.7420 0.6406 +vt 0.6952 0.6484 +vt 0.7030 0.6484 +vt 0.7030 0.6562 +vt 0.6952 0.6562 +vt 0.6952 0.6328 +vt 0.7030 0.6328 +vt 0.7030 0.6406 +vt 0.6952 0.6406 +vt 0.7108 0.6328 +vt 0.7186 0.6328 +vt 0.7186 0.6406 +vt 0.7108 0.6406 +vt 0.6952 0.6796 +vt 0.7030 0.6796 +vt 0.7030 0.6875 +vt 0.6952 0.6874 +vt 0.6952 0.6640 +vt 0.7030 0.6640 +vt 0.7030 0.6718 +vt 0.6952 0.6718 +vt 0.7108 0.6640 +vt 0.7186 0.6640 +vt 0.7186 0.6718 +vt 0.7108 0.6718 +vt 0.6638 0.9607 +vt 0.6716 0.9607 +vt 0.6716 0.9685 +vt 0.6638 0.9685 +vt 0.6638 0.9451 +vt 0.6716 0.9451 +vt 0.6716 0.9529 +vt 0.6638 0.9529 +vt 0.6795 0.9451 +vt 0.6873 0.9451 +vt 0.6873 0.9529 +vt 0.6795 0.9529 +vt 0.6326 0.9607 +vt 0.6404 0.9607 +vt 0.6404 0.9685 +vt 0.6326 0.9685 +vt 0.6326 0.9451 +vt 0.6404 0.9451 +vt 0.6404 0.9529 +vt 0.6326 0.9529 +vt 0.6482 0.9451 +vt 0.6560 0.9451 +vt 0.6560 0.9529 +vt 0.6482 0.9529 +vt 0.6326 0.9920 +vt 0.6404 0.9920 +vt 0.6404 0.9998 +vt 0.6326 0.9998 +vt 0.6326 0.9763 +vt 0.6404 0.9763 +vt 0.6404 0.9841 +vt 0.6326 0.9841 +vt 0.6482 0.9763 +vt 0.6560 0.9763 +vt 0.6560 0.9842 +vt 0.6482 0.9842 +vt 0.6639 0.8983 +vt 0.6717 0.8983 +vt 0.6717 0.9061 +vt 0.6639 0.9061 +vt 0.6639 0.8826 +vt 0.6717 0.8826 +vt 0.6717 0.8905 +vt 0.6639 0.8905 +vt 0.6795 0.8827 +vt 0.6873 0.8827 +vt 0.6873 0.8905 +vt 0.6795 0.8905 +vt 0.6326 0.8983 +vt 0.6404 0.8983 +vt 0.6404 0.9061 +vt 0.6326 0.9061 +vt 0.6326 0.8826 +vt 0.6404 0.8826 +vt 0.6404 0.8904 +vt 0.6326 0.8904 +vt 0.6482 0.8826 +vt 0.6561 0.8826 +vt 0.6560 0.8905 +vt 0.6482 0.8905 +vt 0.6326 0.9295 +vt 0.6404 0.9295 +vt 0.6404 0.9373 +vt 0.6326 0.9373 +vt 0.6326 0.9139 +vt 0.6404 0.9139 +vt 0.6404 0.9217 +vt 0.6326 0.9217 +vt 0.6482 0.9139 +vt 0.6560 0.9139 +vt 0.6560 0.9217 +vt 0.6482 0.9217 +vt 0.7263 0.8983 +vt 0.7341 0.8983 +vt 0.7341 0.9061 +vt 0.7263 0.9061 +vt 0.7263 0.8827 +vt 0.7341 0.8827 +vt 0.7341 0.8905 +vt 0.7263 0.8905 +vt 0.7419 0.8827 +vt 0.7498 0.8827 +vt 0.7497 0.8905 +vt 0.7419 0.8905 +vt 0.6951 0.8983 +vt 0.7029 0.8983 +vt 0.7029 0.9061 +vt 0.6951 0.9061 +vt 0.6951 0.8827 +vt 0.7029 0.8827 +vt 0.7029 0.8905 +vt 0.6951 0.8905 +vt 0.7107 0.8827 +vt 0.7185 0.8827 +vt 0.7185 0.8905 +vt 0.7107 0.8905 +vt 0.6951 0.9295 +vt 0.7029 0.9295 +vt 0.7029 0.9373 +vt 0.6951 0.9373 +vt 0.6951 0.9139 +vt 0.7029 0.9139 +vt 0.7029 0.9217 +vt 0.6951 0.9217 +vt 0.7107 0.9139 +vt 0.7185 0.9139 +vt 0.7185 0.9217 +vt 0.7107 0.9217 +vt 0.4140 0.7108 +vt 0.4219 0.7108 +vt 0.4218 0.7186 +vt 0.4140 0.7186 +vt 0.4140 0.6952 +vt 0.4219 0.6952 +vt 0.4219 0.7030 +vt 0.4140 0.7030 +vt 0.4297 0.6952 +vt 0.4375 0.6952 +vt 0.4375 0.7030 +vt 0.4297 0.7030 +vt 0.3828 0.7108 +vt 0.3906 0.7108 +vt 0.3906 0.7186 +vt 0.3828 0.7186 +vt 0.3828 0.6952 +vt 0.3906 0.6952 +vt 0.3906 0.7030 +vt 0.3828 0.7030 +vt 0.3984 0.6952 +vt 0.4062 0.6952 +vt 0.4062 0.7030 +vt 0.3984 0.7030 +vt 0.3828 0.7420 +vt 0.3906 0.7420 +vt 0.3906 0.7498 +vt 0.3828 0.7498 +vt 0.3828 0.7264 +vt 0.3906 0.7264 +vt 0.3906 0.7342 +vt 0.3828 0.7342 +vt 0.3984 0.7264 +vt 0.4062 0.7264 +vt 0.4062 0.7342 +vt 0.3984 0.7342 +vt 0.4141 0.6483 +vt 0.4219 0.6483 +vt 0.4219 0.6561 +vt 0.4141 0.6561 +vt 0.4141 0.6327 +vt 0.4219 0.6327 +vt 0.4219 0.6405 +vt 0.4141 0.6405 +vt 0.4297 0.6327 +vt 0.4375 0.6327 +vt 0.4375 0.6405 +vt 0.4297 0.6405 +vt 0.3828 0.6483 +vt 0.3906 0.6483 +vt 0.3906 0.6561 +vt 0.3828 0.6561 +vt 0.3828 0.6327 +vt 0.3906 0.6327 +vt 0.3906 0.6405 +vt 0.3828 0.6405 +vt 0.3985 0.6327 +vt 0.4063 0.6327 +vt 0.4063 0.6405 +vt 0.3984 0.6405 +vt 0.3828 0.6795 +vt 0.3906 0.6795 +vt 0.3906 0.6874 +vt 0.3828 0.6874 +vt 0.3828 0.6639 +vt 0.3906 0.6639 +vt 0.3906 0.6717 +vt 0.3828 0.6717 +vt 0.3984 0.6639 +vt 0.4062 0.6639 +vt 0.4062 0.6717 +vt 0.3984 0.6717 +vt 0.4765 0.6483 +vt 0.4843 0.6483 +vt 0.4843 0.6561 +vt 0.4765 0.6561 +vt 0.4765 0.6327 +vt 0.4843 0.6327 +vt 0.4843 0.6405 +vt 0.4765 0.6405 +vt 0.4922 0.6327 +vt 0.5000 0.6327 +vt 0.5000 0.6405 +vt 0.4921 0.6405 +vt 0.4453 0.6483 +vt 0.4531 0.6483 +vt 0.4531 0.6561 +vt 0.4453 0.6561 +vt 0.4453 0.6327 +vt 0.4531 0.6327 +vt 0.4531 0.6405 +vt 0.4453 0.6405 +vt 0.4609 0.6327 +vt 0.4687 0.6327 +vt 0.4687 0.6405 +vt 0.4609 0.6405 +vt 0.4453 0.6796 +vt 0.4531 0.6796 +vt 0.4531 0.6874 +vt 0.4453 0.6874 +vt 0.4453 0.6639 +vt 0.4531 0.6639 +vt 0.4531 0.6718 +vt 0.4453 0.6718 +vt 0.4609 0.6640 +vt 0.4687 0.6640 +vt 0.4687 0.6718 +vt 0.4609 0.6718 +vt 0.1642 0.7107 +vt 0.1720 0.7107 +vt 0.1720 0.7185 +vt 0.1642 0.7185 +vt 0.1642 0.6951 +vt 0.1720 0.6951 +vt 0.1720 0.7029 +vt 0.1642 0.7029 +vt 0.1798 0.6951 +vt 0.1876 0.6951 +vt 0.1876 0.7029 +vt 0.1798 0.7029 +vt 0.1329 0.7107 +vt 0.1407 0.7107 +vt 0.1407 0.7185 +vt 0.1329 0.7185 +vt 0.1329 0.6951 +vt 0.1408 0.6951 +vt 0.1407 0.7029 +vt 0.1329 0.7029 +vt 0.1486 0.6951 +vt 0.1564 0.6951 +vt 0.1564 0.7029 +vt 0.1486 0.7029 +vt 0.1329 0.7419 +vt 0.1407 0.7419 +vt 0.1407 0.7497 +vt 0.1329 0.7497 +vt 0.1329 0.7263 +vt 0.1407 0.7263 +vt 0.1407 0.7341 +vt 0.1329 0.7341 +vt 0.1486 0.7263 +vt 0.1564 0.7263 +vt 0.1564 0.7341 +vt 0.1485 0.7341 +vt 0.1642 0.6482 +vt 0.1720 0.6482 +vt 0.1720 0.6561 +vt 0.1642 0.6560 +vt 0.1642 0.6326 +vt 0.1720 0.6326 +vt 0.1720 0.6404 +vt 0.1642 0.6404 +vt 0.1798 0.6326 +vt 0.1876 0.6326 +vt 0.1876 0.6404 +vt 0.1798 0.6404 +vt 0.1330 0.6482 +vt 0.1408 0.6482 +vt 0.1408 0.6560 +vt 0.1330 0.6560 +vt 0.1330 0.6326 +vt 0.1408 0.6326 +vt 0.1408 0.6404 +vt 0.1330 0.6404 +vt 0.1486 0.6326 +vt 0.1564 0.6326 +vt 0.1564 0.6404 +vt 0.1486 0.6404 +vt 0.1329 0.6795 +vt 0.1408 0.6795 +vt 0.1408 0.6873 +vt 0.1329 0.6873 +vt 0.1330 0.6638 +vt 0.1408 0.6638 +vt 0.1408 0.6717 +vt 0.1330 0.6717 +vt 0.1486 0.6639 +vt 0.1564 0.6639 +vt 0.1564 0.6717 +vt 0.1486 0.6717 +vt 0.2267 0.6483 +vt 0.2345 0.6483 +vt 0.2345 0.6561 +vt 0.2267 0.6561 +vt 0.2267 0.6326 +vt 0.2345 0.6326 +vt 0.2345 0.6405 +vt 0.2267 0.6405 +vt 0.2423 0.6326 +vt 0.2501 0.6327 +vt 0.2501 0.6405 +vt 0.2423 0.6405 +vt 0.1954 0.6482 +vt 0.2032 0.6483 +vt 0.2032 0.6561 +vt 0.1954 0.6561 +vt 0.1954 0.6326 +vt 0.2032 0.6326 +vt 0.2032 0.6404 +vt 0.1954 0.6404 +vt 0.2110 0.6326 +vt 0.2189 0.6326 +vt 0.2189 0.6404 +vt 0.2110 0.6404 +vt 0.1954 0.6795 +vt 0.2032 0.6795 +vt 0.2032 0.6873 +vt 0.1954 0.6873 +vt 0.1954 0.6639 +vt 0.2032 0.6639 +vt 0.2032 0.6717 +vt 0.1954 0.6717 +vt 0.2110 0.6639 +vt 0.2188 0.6639 +vt 0.2188 0.6717 +vt 0.2110 0.6717 +vt 0.1641 0.9606 +vt 0.1719 0.9606 +vt 0.1719 0.9684 +vt 0.1641 0.9684 +vt 0.1641 0.9450 +vt 0.1719 0.9450 +vt 0.1719 0.9528 +vt 0.1641 0.9528 +vt 0.1797 0.9450 +vt 0.1875 0.9450 +vt 0.1875 0.9528 +vt 0.1797 0.9528 +vt 0.1329 0.9606 +vt 0.1407 0.9606 +vt 0.1407 0.9684 +vt 0.1329 0.9684 +vt 0.1329 0.9450 +vt 0.1407 0.9450 +vt 0.1407 0.9528 +vt 0.1329 0.9528 +vt 0.1485 0.9450 +vt 0.1563 0.9450 +vt 0.1563 0.9528 +vt 0.1485 0.9528 +vt 0.1328 0.9918 +vt 0.1407 0.9918 +vt 0.1407 0.9996 +vt 0.1328 0.9996 +vt 0.1329 0.9762 +vt 0.1407 0.9762 +vt 0.1407 0.9840 +vt 0.1329 0.9840 +vt 0.1485 0.9762 +vt 0.1563 0.9762 +vt 0.1563 0.9840 +vt 0.1485 0.9840 +vt 0.1641 0.8981 +vt 0.1719 0.8981 +vt 0.1719 0.9059 +vt 0.1641 0.9059 +vt 0.1641 0.8825 +vt 0.1719 0.8825 +vt 0.1719 0.8903 +vt 0.1641 0.8903 +vt 0.1797 0.8825 +vt 0.1875 0.8825 +vt 0.1875 0.8903 +vt 0.1797 0.8903 +vt 0.1329 0.8981 +vt 0.1407 0.8981 +vt 0.1407 0.9059 +vt 0.1329 0.9059 +vt 0.1329 0.8825 +vt 0.1407 0.8825 +vt 0.1407 0.8903 +vt 0.1329 0.8903 +vt 0.1485 0.8825 +vt 0.1563 0.8825 +vt 0.1563 0.8903 +vt 0.1485 0.8903 +vt 0.1329 0.9293 +vt 0.1407 0.9293 +vt 0.1407 0.9371 +vt 0.1329 0.9371 +vt 0.1329 0.9137 +vt 0.1407 0.9137 +vt 0.1407 0.9215 +vt 0.1329 0.9215 +vt 0.1485 0.9137 +vt 0.1563 0.9137 +vt 0.1563 0.9215 +vt 0.1485 0.9215 +vt 0.2266 0.8981 +vt 0.2344 0.8981 +vt 0.2344 0.9059 +vt 0.2266 0.9059 +vt 0.2266 0.8825 +vt 0.2344 0.8825 +vt 0.2344 0.8903 +vt 0.2266 0.8903 +vt 0.2422 0.8825 +vt 0.2500 0.8825 +vt 0.2500 0.8903 +vt 0.2422 0.8903 +vt 0.1953 0.8981 +vt 0.2032 0.8981 +vt 0.2032 0.9059 +vt 0.1953 0.9059 +vt 0.1954 0.8825 +vt 0.2032 0.8825 +vt 0.2032 0.8903 +vt 0.1953 0.8903 +vt 0.2110 0.8825 +vt 0.2188 0.8825 +vt 0.2188 0.8903 +vt 0.2110 0.8903 +vt 0.1953 0.9294 +vt 0.2031 0.9294 +vt 0.2031 0.9372 +vt 0.1953 0.9372 +vt 0.1953 0.9137 +vt 0.2032 0.9137 +vt 0.2031 0.9216 +vt 0.1953 0.9215 +vt 0.2110 0.9137 +vt 0.2188 0.9137 +vt 0.2188 0.9216 +vt 0.2110 0.9216 +vt 0.4142 0.2110 +vt 0.4220 0.2111 +vt 0.4220 0.2189 +vt 0.4142 0.2189 +vt 0.4142 0.1954 +vt 0.4220 0.1954 +vt 0.4220 0.2032 +vt 0.4142 0.2032 +vt 0.4298 0.1954 +vt 0.4376 0.1954 +vt 0.4376 0.2032 +vt 0.4298 0.2032 +vt 0.3830 0.2110 +vt 0.3908 0.2110 +vt 0.3908 0.2189 +vt 0.3830 0.2188 +vt 0.3830 0.1954 +vt 0.3908 0.1954 +vt 0.3908 0.2032 +vt 0.3830 0.2032 +vt 0.3986 0.1954 +vt 0.4064 0.1954 +vt 0.4064 0.2032 +vt 0.3986 0.2032 +vt 0.3830 0.2423 +vt 0.3908 0.2423 +vt 0.3908 0.2501 +vt 0.3830 0.2501 +vt 0.3830 0.2267 +vt 0.3908 0.2267 +vt 0.3908 0.2345 +vt 0.3830 0.2345 +vt 0.3986 0.2267 +vt 0.4064 0.2267 +vt 0.4064 0.2345 +vt 0.3986 0.2345 +vt 0.4142 0.1486 +vt 0.4220 0.1486 +vt 0.4220 0.1564 +vt 0.4142 0.1564 +vt 0.4142 0.1330 +vt 0.4220 0.1330 +vt 0.4220 0.1408 +vt 0.4142 0.1408 +vt 0.4298 0.1330 +vt 0.4376 0.1330 +vt 0.4376 0.1408 +vt 0.4298 0.1408 +vt 0.3830 0.1486 +vt 0.3908 0.1486 +vt 0.3908 0.1564 +vt 0.3830 0.1564 +vt 0.3830 0.1330 +vt 0.3908 0.1330 +vt 0.3908 0.1408 +vt 0.3830 0.1408 +vt 0.3986 0.1330 +vt 0.4064 0.1330 +vt 0.4064 0.1408 +vt 0.3986 0.1408 +vt 0.3830 0.1798 +vt 0.3908 0.1798 +vt 0.3908 0.1876 +vt 0.3830 0.1876 +vt 0.3830 0.1642 +vt 0.3908 0.1642 +vt 0.3908 0.1720 +vt 0.3830 0.1720 +vt 0.3986 0.1642 +vt 0.4064 0.1642 +vt 0.4064 0.1720 +vt 0.3986 0.1720 +vt 0.4767 0.1486 +vt 0.4845 0.1486 +vt 0.4845 0.1564 +vt 0.4767 0.1564 +vt 0.4767 0.1330 +vt 0.4845 0.1330 +vt 0.4845 0.1408 +vt 0.4767 0.1408 +vt 0.4923 0.1330 +vt 0.5001 0.1330 +vt 0.5001 0.1408 +vt 0.4923 0.1408 +vt 0.4455 0.1486 +vt 0.4533 0.1486 +vt 0.4533 0.1564 +vt 0.4454 0.1564 +vt 0.4455 0.1330 +vt 0.4533 0.1330 +vt 0.4533 0.1408 +vt 0.4455 0.1408 +vt 0.4611 0.1330 +vt 0.4689 0.1330 +vt 0.4689 0.1408 +vt 0.4611 0.1408 +vt 0.4454 0.1798 +vt 0.4533 0.1798 +vt 0.4532 0.1876 +vt 0.4454 0.1876 +vt 0.4454 0.1642 +vt 0.4533 0.1642 +vt 0.4533 0.1720 +vt 0.4454 0.1720 +vt 0.4611 0.1642 +vt 0.4689 0.1642 +vt 0.4689 0.1720 +vt 0.4611 0.1720 +vt 0.1643 0.2110 +vt 0.1721 0.2110 +vt 0.1721 0.2188 +vt 0.1643 0.2188 +vt 0.1643 0.1954 +vt 0.1721 0.1954 +vt 0.1721 0.2032 +vt 0.1643 0.2032 +vt 0.1800 0.1954 +vt 0.1878 0.1954 +vt 0.1878 0.2032 +vt 0.1800 0.2032 +vt 0.1331 0.2110 +vt 0.1409 0.2110 +vt 0.1409 0.2188 +vt 0.1331 0.2188 +vt 0.1331 0.1953 +vt 0.1409 0.1953 +vt 0.1409 0.2032 +vt 0.1331 0.2032 +vt 0.1487 0.1954 +vt 0.1565 0.1954 +vt 0.1565 0.2032 +vt 0.1487 0.2032 +vt 0.1331 0.2422 +vt 0.1409 0.2422 +vt 0.1409 0.2500 +vt 0.1331 0.2500 +vt 0.1331 0.2266 +vt 0.1409 0.2266 +vt 0.1409 0.2344 +vt 0.1331 0.2344 +vt 0.1487 0.2266 +vt 0.1565 0.2266 +vt 0.1565 0.2344 +vt 0.1487 0.2344 +vt 0.1644 0.1485 +vt 0.1722 0.1485 +vt 0.1722 0.1563 +vt 0.1644 0.1563 +vt 0.1644 0.1329 +vt 0.1722 0.1329 +vt 0.1722 0.1407 +vt 0.1644 0.1407 +vt 0.1800 0.1329 +vt 0.1878 0.1329 +vt 0.1878 0.1407 +vt 0.1800 0.1407 +vt 0.1331 0.1485 +vt 0.1409 0.1485 +vt 0.1409 0.1563 +vt 0.1331 0.1563 +vt 0.1331 0.1329 +vt 0.1409 0.1329 +vt 0.1409 0.1407 +vt 0.1331 0.1407 +vt 0.1487 0.1329 +vt 0.1566 0.1329 +vt 0.1565 0.1407 +vt 0.1487 0.1407 +vt 0.1331 0.1797 +vt 0.1409 0.1797 +vt 0.1409 0.1875 +vt 0.1331 0.1875 +vt 0.1331 0.1641 +vt 0.1409 0.1641 +vt 0.1409 0.1719 +vt 0.1331 0.1719 +vt 0.1487 0.1641 +vt 0.1565 0.1641 +vt 0.1565 0.1719 +vt 0.1487 0.1719 +vt 0.2268 0.1485 +vt 0.2346 0.1485 +vt 0.2346 0.1563 +vt 0.2268 0.1563 +vt 0.2268 0.1329 +vt 0.2346 0.1329 +vt 0.2346 0.1407 +vt 0.2268 0.1407 +vt 0.2424 0.1329 +vt 0.2502 0.1329 +vt 0.2502 0.1407 +vt 0.2424 0.1407 +vt 0.1956 0.1485 +vt 0.2034 0.1485 +vt 0.2034 0.1563 +vt 0.1956 0.1563 +vt 0.1956 0.1329 +vt 0.2034 0.1329 +vt 0.2034 0.1407 +vt 0.1956 0.1407 +vt 0.2112 0.1329 +vt 0.2190 0.1329 +vt 0.2190 0.1407 +vt 0.2112 0.1407 +vt 0.1956 0.1797 +vt 0.2034 0.1798 +vt 0.2034 0.1876 +vt 0.1956 0.1876 +vt 0.1956 0.1641 +vt 0.2034 0.1641 +vt 0.2034 0.1719 +vt 0.1956 0.1719 +vt 0.2112 0.1641 +vt 0.2190 0.1641 +vt 0.2190 0.1719 +vt 0.2112 0.1719 +vt 0.1643 0.4608 +vt 0.1721 0.4608 +vt 0.1721 0.4686 +vt 0.1643 0.4686 +vt 0.1643 0.4452 +vt 0.1721 0.4452 +vt 0.1721 0.4530 +vt 0.1643 0.4530 +vt 0.1799 0.4452 +vt 0.1877 0.4452 +vt 0.1877 0.4530 +vt 0.1799 0.4530 +vt 0.1330 0.4608 +vt 0.1408 0.4608 +vt 0.1408 0.4686 +vt 0.1330 0.4686 +vt 0.1330 0.4452 +vt 0.1408 0.4452 +vt 0.1408 0.4530 +vt 0.1330 0.4530 +vt 0.1486 0.4452 +vt 0.1565 0.4452 +vt 0.1564 0.4530 +vt 0.1486 0.4530 +vt 0.1330 0.4921 +vt 0.1408 0.4921 +vt 0.1408 0.4999 +vt 0.1330 0.4999 +vt 0.1330 0.4764 +vt 0.1408 0.4764 +vt 0.1408 0.4843 +vt 0.1330 0.4843 +vt 0.1486 0.4764 +vt 0.1564 0.4765 +vt 0.1564 0.4843 +vt 0.1486 0.4843 +vt 0.1643 0.3984 +vt 0.1721 0.3984 +vt 0.1721 0.4062 +vt 0.1643 0.4062 +vt 0.1643 0.3828 +vt 0.1721 0.3828 +vt 0.1721 0.3906 +vt 0.1643 0.3906 +vt 0.1799 0.3828 +vt 0.1877 0.3828 +vt 0.1877 0.3906 +vt 0.1799 0.3906 +vt 0.1330 0.3984 +vt 0.1408 0.3984 +vt 0.1408 0.4062 +vt 0.1330 0.4062 +vt 0.1330 0.3827 +vt 0.1409 0.3827 +vt 0.1409 0.3906 +vt 0.1330 0.3906 +vt 0.1487 0.3827 +vt 0.1565 0.3828 +vt 0.1565 0.3906 +vt 0.1487 0.3906 +vt 0.1330 0.4296 +vt 0.1408 0.4296 +vt 0.1408 0.4374 +vt 0.1330 0.4374 +vt 0.1330 0.4140 +vt 0.1408 0.4140 +vt 0.1408 0.4218 +vt 0.1330 0.4218 +vt 0.1487 0.4140 +vt 0.1565 0.4140 +vt 0.1565 0.4218 +vt 0.1486 0.4218 +vt 0.2267 0.3984 +vt 0.2345 0.3984 +vt 0.2345 0.4062 +vt 0.2267 0.4062 +vt 0.2267 0.3828 +vt 0.2346 0.3828 +vt 0.2346 0.3906 +vt 0.2267 0.3906 +vt 0.2424 0.3828 +vt 0.2502 0.3828 +vt 0.2502 0.3906 +vt 0.2424 0.3906 +vt 0.1955 0.3984 +vt 0.2033 0.3984 +vt 0.2033 0.4062 +vt 0.1955 0.4062 +vt 0.1955 0.3828 +vt 0.2033 0.3828 +vt 0.2033 0.3906 +vt 0.1955 0.3906 +vt 0.2111 0.3828 +vt 0.2189 0.3828 +vt 0.2189 0.3906 +vt 0.2111 0.3906 +vt 0.1955 0.4296 +vt 0.2033 0.4296 +vt 0.2033 0.4374 +vt 0.1955 0.4374 +vt 0.1955 0.4140 +vt 0.2033 0.4140 +vt 0.2033 0.4218 +vt 0.1955 0.4218 +vt 0.2111 0.4140 +vt 0.2189 0.4140 +vt 0.2189 0.4218 +vt 0.2111 0.4218 +vt 0.9139 0.2112 +vt 0.9217 0.2112 +vt 0.9217 0.2190 +vt 0.9139 0.2190 +vt 0.9139 0.1956 +vt 0.9218 0.1956 +vt 0.9218 0.2034 +vt 0.9139 0.2034 +vt 0.9296 0.1956 +vt 0.9374 0.1956 +vt 0.9374 0.2034 +vt 0.9296 0.2034 +vt 0.8827 0.2112 +vt 0.8905 0.2112 +vt 0.8905 0.2190 +vt 0.8827 0.2190 +vt 0.8827 0.1956 +vt 0.8905 0.1956 +vt 0.8905 0.2034 +vt 0.8827 0.2034 +vt 0.8983 0.1956 +vt 0.9061 0.1956 +vt 0.9061 0.2034 +vt 0.8983 0.2034 +vt 0.8827 0.2424 +vt 0.8905 0.2424 +vt 0.8905 0.2502 +vt 0.8827 0.2502 +vt 0.8827 0.2268 +vt 0.8905 0.2268 +vt 0.8905 0.2346 +vt 0.8827 0.2346 +vt 0.8983 0.2268 +vt 0.9061 0.2268 +vt 0.9061 0.2346 +vt 0.8983 0.2346 +vt 0.9140 0.1487 +vt 0.9218 0.1487 +vt 0.9218 0.1565 +vt 0.9140 0.1565 +vt 0.9140 0.1331 +vt 0.9218 0.1331 +vt 0.9218 0.1409 +vt 0.9140 0.1409 +vt 0.9296 0.1331 +vt 0.9374 0.1331 +vt 0.9374 0.1409 +vt 0.9296 0.1409 +vt 0.8827 0.1487 +vt 0.8905 0.1487 +vt 0.8905 0.1565 +vt 0.8827 0.1565 +vt 0.8827 0.1331 +vt 0.8905 0.1331 +vt 0.8905 0.1409 +vt 0.8827 0.1409 +vt 0.8983 0.1331 +vt 0.9062 0.1331 +vt 0.9062 0.1409 +vt 0.8983 0.1409 +vt 0.8827 0.1800 +vt 0.8905 0.1800 +vt 0.8905 0.1878 +vt 0.8827 0.1878 +vt 0.8827 0.1643 +vt 0.8905 0.1643 +vt 0.8905 0.1722 +vt 0.8827 0.1722 +vt 0.8983 0.1643 +vt 0.9061 0.1644 +vt 0.9061 0.1722 +vt 0.8983 0.1722 +vt 0.9764 0.1488 +vt 0.9842 0.1488 +vt 0.9842 0.1566 +vt 0.9764 0.1566 +vt 0.9764 0.1331 +vt 0.9842 0.1331 +vt 0.9842 0.1410 +vt 0.9764 0.1409 +vt 0.9920 0.1331 +vt 0.9999 0.1331 +vt 0.9999 0.1410 +vt 0.9920 0.1410 +vt 0.9452 0.1487 +vt 0.9530 0.1487 +vt 0.9530 0.1566 +vt 0.9452 0.1566 +vt 0.9452 0.1331 +vt 0.9530 0.1331 +vt 0.9530 0.1409 +vt 0.9452 0.1409 +vt 0.9608 0.1331 +vt 0.9686 0.1331 +vt 0.9686 0.1409 +vt 0.9608 0.1409 +vt 0.9452 0.1800 +vt 0.9530 0.1800 +vt 0.9530 0.1878 +vt 0.9452 0.1878 +vt 0.9452 0.1644 +vt 0.9530 0.1644 +vt 0.9530 0.1722 +vt 0.9452 0.1722 +vt 0.9608 0.1644 +vt 0.9686 0.1644 +vt 0.9686 0.1722 +vt 0.9608 0.1722 +vt 0.6641 0.2111 +vt 0.6719 0.2111 +vt 0.6719 0.2189 +vt 0.6641 0.2189 +vt 0.6641 0.1955 +vt 0.6719 0.1955 +vt 0.6719 0.2033 +vt 0.6641 0.2033 +vt 0.6797 0.1955 +vt 0.6875 0.1955 +vt 0.6875 0.2033 +vt 0.6797 0.2033 +vt 0.6328 0.2111 +vt 0.6406 0.2111 +vt 0.6406 0.2189 +vt 0.6328 0.2189 +vt 0.6328 0.1955 +vt 0.6406 0.1955 +vt 0.6406 0.2033 +vt 0.6328 0.2033 +vt 0.6485 0.1955 +vt 0.6563 0.1955 +vt 0.6563 0.2033 +vt 0.6485 0.2033 +vt 0.6328 0.2424 +vt 0.6406 0.2424 +vt 0.6406 0.2502 +vt 0.6328 0.2502 +vt 0.6328 0.2267 +vt 0.6406 0.2267 +vt 0.6406 0.2345 +vt 0.6328 0.2345 +vt 0.6484 0.2267 +vt 0.6563 0.2267 +vt 0.6563 0.2345 +vt 0.6484 0.2345 +vt 0.6641 0.1487 +vt 0.6719 0.1487 +vt 0.6719 0.1565 +vt 0.6641 0.1565 +vt 0.6641 0.1330 +vt 0.6719 0.1330 +vt 0.6719 0.1409 +vt 0.6641 0.1409 +vt 0.6797 0.1330 +vt 0.6875 0.1330 +vt 0.6875 0.1409 +vt 0.6797 0.1409 +vt 0.6329 0.1486 +vt 0.6407 0.1487 +vt 0.6407 0.1565 +vt 0.6329 0.1565 +vt 0.6329 0.1330 +vt 0.6407 0.1330 +vt 0.6407 0.1408 +vt 0.6329 0.1408 +vt 0.6485 0.1330 +vt 0.6563 0.1330 +vt 0.6563 0.1408 +vt 0.6485 0.1408 +vt 0.6328 0.1799 +vt 0.6407 0.1799 +vt 0.6406 0.1877 +vt 0.6328 0.1877 +vt 0.6328 0.1643 +vt 0.6407 0.1643 +vt 0.6407 0.1721 +vt 0.6328 0.1721 +vt 0.6485 0.1643 +vt 0.6563 0.1643 +vt 0.6563 0.1721 +vt 0.6485 0.1721 +vt 0.7266 0.1487 +vt 0.7344 0.1487 +vt 0.7344 0.1565 +vt 0.7266 0.1565 +vt 0.7266 0.1331 +vt 0.7344 0.1331 +vt 0.7344 0.1409 +vt 0.7266 0.1409 +vt 0.7422 0.1331 +vt 0.7500 0.1331 +vt 0.7500 0.1409 +vt 0.7422 0.1409 +vt 0.6953 0.1487 +vt 0.7031 0.1487 +vt 0.7031 0.1565 +vt 0.6953 0.1565 +vt 0.6953 0.1331 +vt 0.7031 0.1331 +vt 0.7031 0.1409 +vt 0.6953 0.1409 +vt 0.7109 0.1331 +vt 0.7188 0.1331 +vt 0.7187 0.1409 +vt 0.7109 0.1409 +vt 0.6953 0.1799 +vt 0.7031 0.1799 +vt 0.7031 0.1877 +vt 0.6953 0.1877 +vt 0.6953 0.1643 +vt 0.7031 0.1643 +vt 0.7031 0.1721 +vt 0.6953 0.1721 +vt 0.7109 0.1643 +vt 0.7187 0.1643 +vt 0.7187 0.1721 +vt 0.7109 0.1721 +vt 0.6640 0.4610 +vt 0.6718 0.4610 +vt 0.6718 0.4688 +vt 0.6640 0.4688 +vt 0.6640 0.4454 +vt 0.6718 0.4454 +vt 0.6718 0.4532 +vt 0.6640 0.4532 +vt 0.6796 0.4454 +vt 0.6874 0.4454 +vt 0.6874 0.4532 +vt 0.6796 0.4532 +vt 0.6328 0.4610 +vt 0.6406 0.4610 +vt 0.6406 0.4688 +vt 0.6328 0.4688 +vt 0.6328 0.4454 +vt 0.6406 0.4454 +vt 0.6406 0.4532 +vt 0.6328 0.4532 +vt 0.6484 0.4454 +vt 0.6562 0.4454 +vt 0.6562 0.4532 +vt 0.6484 0.4532 +vt 0.6327 0.4922 +vt 0.6406 0.4922 +vt 0.6406 0.5000 +vt 0.6327 0.5000 +vt 0.6328 0.4766 +vt 0.6406 0.4766 +vt 0.6406 0.4844 +vt 0.6327 0.4844 +vt 0.6484 0.4766 +vt 0.6562 0.4766 +vt 0.6562 0.4844 +vt 0.6484 0.4844 +vt 0.6640 0.3985 +vt 0.6718 0.3985 +vt 0.6718 0.4063 +vt 0.6640 0.4063 +vt 0.6640 0.3829 +vt 0.6718 0.3829 +vt 0.6718 0.3907 +vt 0.6640 0.3907 +vt 0.6796 0.3829 +vt 0.6874 0.3829 +vt 0.6874 0.3907 +vt 0.6796 0.3907 +vt 0.6328 0.3985 +vt 0.6406 0.3985 +vt 0.6406 0.4063 +vt 0.6328 0.4063 +vt 0.6328 0.3829 +vt 0.6406 0.3829 +vt 0.6406 0.3907 +vt 0.6328 0.3907 +vt 0.6484 0.3829 +vt 0.6562 0.3829 +vt 0.6562 0.3907 +vt 0.6484 0.3907 +vt 0.6328 0.4298 +vt 0.6406 0.4298 +vt 0.6406 0.4376 +vt 0.6328 0.4376 +vt 0.6328 0.4141 +vt 0.6406 0.4141 +vt 0.6406 0.4219 +vt 0.6328 0.4219 +vt 0.6484 0.4141 +vt 0.6562 0.4141 +vt 0.6562 0.4220 +vt 0.6484 0.4219 +vt 0.7265 0.3985 +vt 0.7343 0.3986 +vt 0.7343 0.4064 +vt 0.7265 0.4064 +vt 0.7265 0.3829 +vt 0.7343 0.3829 +vt 0.7343 0.3907 +vt 0.7265 0.3907 +vt 0.7421 0.3829 +vt 0.7499 0.3829 +vt 0.7499 0.3907 +vt 0.7421 0.3907 +vt 0.6952 0.3985 +vt 0.7031 0.3985 +vt 0.7030 0.4063 +vt 0.6952 0.4063 +vt 0.6952 0.3829 +vt 0.7031 0.3829 +vt 0.7031 0.3907 +vt 0.6952 0.3907 +vt 0.7109 0.3829 +vt 0.7187 0.3829 +vt 0.7187 0.3907 +vt 0.7109 0.3907 +vt 0.6952 0.4298 +vt 0.7030 0.4298 +vt 0.7030 0.4376 +vt 0.6952 0.4376 +vt 0.6952 0.4142 +vt 0.7030 0.4142 +vt 0.7030 0.4220 +vt 0.6952 0.4220 +vt 0.7109 0.4142 +vt 0.7187 0.4142 +vt 0.7187 0.4220 +vt 0.7109 0.4220 +vt 0.9139 0.4611 +vt 0.9217 0.4611 +vt 0.9217 0.4689 +vt 0.9139 0.4689 +vt 0.9139 0.4455 +vt 0.9217 0.4455 +vt 0.9217 0.4533 +vt 0.9139 0.4533 +vt 0.9295 0.4455 +vt 0.9373 0.4455 +vt 0.9373 0.4533 +vt 0.9295 0.4533 +vt 0.8826 0.4611 +vt 0.8904 0.4611 +vt 0.8904 0.4689 +vt 0.8826 0.4689 +vt 0.8826 0.4454 +vt 0.8904 0.4455 +vt 0.8904 0.4533 +vt 0.8826 0.4533 +vt 0.8982 0.4455 +vt 0.9061 0.4455 +vt 0.9061 0.4533 +vt 0.8982 0.4533 +vt 0.8826 0.4923 +vt 0.8904 0.4923 +vt 0.8904 0.5001 +vt 0.8826 0.5001 +vt 0.8826 0.4767 +vt 0.8904 0.4767 +vt 0.8904 0.4845 +vt 0.8826 0.4845 +vt 0.8982 0.4767 +vt 0.9060 0.4767 +vt 0.9060 0.4845 +vt 0.8982 0.4845 +vt 0.9139 0.3986 +vt 0.9217 0.3986 +vt 0.9217 0.4064 +vt 0.9139 0.4064 +vt 0.9139 0.3830 +vt 0.9217 0.3830 +vt 0.9217 0.3908 +vt 0.9139 0.3908 +vt 0.9295 0.3830 +vt 0.9373 0.3830 +vt 0.9373 0.3908 +vt 0.9295 0.3908 +vt 0.8826 0.3986 +vt 0.8905 0.3986 +vt 0.8905 0.4064 +vt 0.8826 0.4064 +vt 0.8827 0.3830 +vt 0.8905 0.3830 +vt 0.8905 0.3908 +vt 0.8826 0.3908 +vt 0.8983 0.3830 +vt 0.9061 0.3830 +vt 0.9061 0.3908 +vt 0.8983 0.3908 +vt 0.8826 0.4298 +vt 0.8904 0.4298 +vt 0.8904 0.4376 +vt 0.8826 0.4376 +vt 0.8826 0.4142 +vt 0.8904 0.4142 +vt 0.8904 0.4220 +vt 0.8826 0.4220 +vt 0.8983 0.4142 +vt 0.9061 0.4142 +vt 0.9061 0.4220 +vt 0.8983 0.4220 +vt 0.9763 0.3986 +vt 0.9842 0.3986 +vt 0.9842 0.4064 +vt 0.9763 0.4064 +vt 0.9764 0.3830 +vt 0.9842 0.3830 +vt 0.9842 0.3908 +vt 0.9763 0.3908 +vt 0.9920 0.3830 +vt 0.9998 0.3830 +vt 0.9998 0.3908 +vt 0.9920 0.3908 +vt 0.9451 0.3986 +vt 0.9529 0.3986 +vt 0.9529 0.4064 +vt 0.9451 0.4064 +vt 0.9451 0.3830 +vt 0.9529 0.3830 +vt 0.9529 0.3908 +vt 0.9451 0.3908 +vt 0.9607 0.3830 +vt 0.9685 0.3830 +vt 0.9685 0.3908 +vt 0.9607 0.3908 +vt 0.9451 0.4299 +vt 0.9529 0.4299 +vt 0.9529 0.4377 +vt 0.9451 0.4377 +vt 0.9451 0.4142 +vt 0.9529 0.4142 +vt 0.9529 0.4220 +vt 0.9451 0.4220 +vt 0.9607 0.4142 +vt 0.9685 0.4142 +vt 0.9685 0.4221 +vt 0.9607 0.4220 +vt 0.4141 0.4609 +vt 0.4219 0.4609 +vt 0.4219 0.4687 +vt 0.4141 0.4687 +vt 0.4141 0.4453 +vt 0.4219 0.4453 +vt 0.4219 0.4531 +vt 0.4141 0.4531 +vt 0.4297 0.4453 +vt 0.4376 0.4453 +vt 0.4375 0.4531 +vt 0.4297 0.4531 +vt 0.3829 0.4609 +vt 0.3907 0.4609 +vt 0.3907 0.4687 +vt 0.3829 0.4687 +vt 0.3829 0.4453 +vt 0.3907 0.4453 +vt 0.3907 0.4531 +vt 0.3829 0.4531 +vt 0.3985 0.4453 +vt 0.4063 0.4453 +vt 0.4063 0.4531 +vt 0.3985 0.4531 +vt 0.3829 0.4921 +vt 0.3907 0.4921 +vt 0.3907 0.5000 +vt 0.3829 0.4999 +vt 0.3829 0.4765 +vt 0.3907 0.4765 +vt 0.3907 0.4843 +vt 0.3829 0.4843 +vt 0.3985 0.4765 +vt 0.4063 0.4765 +vt 0.4063 0.4843 +vt 0.3985 0.4843 +vt 0.4141 0.3985 +vt 0.4219 0.3985 +vt 0.4219 0.4063 +vt 0.4141 0.4063 +vt 0.4141 0.3828 +vt 0.4220 0.3828 +vt 0.4220 0.3906 +vt 0.4141 0.3906 +vt 0.4298 0.3828 +vt 0.4376 0.3828 +vt 0.4376 0.3906 +vt 0.4298 0.3906 +vt 0.3829 0.3984 +vt 0.3907 0.3984 +vt 0.3907 0.4063 +vt 0.3829 0.4062 +vt 0.3829 0.3828 +vt 0.3907 0.3828 +vt 0.3907 0.3906 +vt 0.3829 0.3906 +vt 0.3985 0.3828 +vt 0.4063 0.3828 +vt 0.4063 0.3906 +vt 0.3985 0.3906 +vt 0.3829 0.4297 +vt 0.3907 0.4297 +vt 0.3907 0.4375 +vt 0.3829 0.4375 +vt 0.3829 0.4141 +vt 0.3907 0.4141 +vt 0.3907 0.4219 +vt 0.3829 0.4219 +vt 0.3985 0.4141 +vt 0.4063 0.4141 +vt 0.4063 0.4219 +vt 0.3985 0.4219 +vt 0.4766 0.3985 +vt 0.4844 0.3985 +vt 0.4844 0.4063 +vt 0.4766 0.4063 +vt 0.4766 0.3829 +vt 0.4844 0.3829 +vt 0.4844 0.3907 +vt 0.4766 0.3907 +vt 0.4922 0.3829 +vt 0.5000 0.3829 +vt 0.5000 0.3907 +vt 0.4922 0.3907 +vt 0.4454 0.3985 +vt 0.4532 0.3985 +vt 0.4532 0.4063 +vt 0.4454 0.4063 +vt 0.4454 0.3828 +vt 0.4532 0.3828 +vt 0.4532 0.3907 +vt 0.4454 0.3907 +vt 0.4610 0.3828 +vt 0.4688 0.3829 +vt 0.4688 0.3907 +vt 0.4610 0.3907 +vt 0.4454 0.4297 +vt 0.4532 0.4297 +vt 0.4532 0.4375 +vt 0.4454 0.4375 +vt 0.4454 0.4141 +vt 0.4532 0.4141 +vt 0.4532 0.4219 +vt 0.4454 0.4219 +vt 0.4610 0.4141 +vt 0.4688 0.4141 +vt 0.4688 0.4219 +vt 0.4610 0.4219 +vt 0.4140 0.9607 +vt 0.4218 0.9607 +vt 0.4218 0.9685 +vt 0.4140 0.9685 +vt 0.4140 0.9450 +vt 0.4218 0.9450 +vt 0.4218 0.9529 +vt 0.4140 0.9528 +vt 0.4296 0.9450 +vt 0.4374 0.9450 +vt 0.4374 0.9529 +vt 0.4296 0.9529 +vt 0.3827 0.9606 +vt 0.3905 0.9606 +vt 0.3905 0.9685 +vt 0.3827 0.9685 +vt 0.3827 0.9450 +vt 0.3905 0.9450 +vt 0.3905 0.9528 +vt 0.3827 0.9528 +vt 0.3984 0.9450 +vt 0.4062 0.9450 +vt 0.4062 0.9528 +vt 0.3984 0.9528 +vt 0.3827 0.9919 +vt 0.3905 0.9919 +vt 0.3905 0.9997 +vt 0.3827 0.9997 +vt 0.3827 0.9763 +vt 0.3905 0.9763 +vt 0.3905 0.9841 +vt 0.3827 0.9841 +vt 0.3983 0.9763 +vt 0.4062 0.9763 +vt 0.4062 0.9841 +vt 0.3983 0.9841 +vt 0.4140 0.8982 +vt 0.4218 0.8982 +vt 0.4218 0.9060 +vt 0.4140 0.9060 +vt 0.4140 0.8826 +vt 0.4218 0.8826 +vt 0.4218 0.8904 +vt 0.4140 0.8904 +vt 0.4296 0.8826 +vt 0.4374 0.8826 +vt 0.4374 0.8904 +vt 0.4296 0.8904 +vt 0.3828 0.8982 +vt 0.3906 0.8982 +vt 0.3906 0.9060 +vt 0.3827 0.9060 +vt 0.3828 0.8826 +vt 0.3906 0.8826 +vt 0.3906 0.8904 +vt 0.3828 0.8904 +vt 0.3984 0.8826 +vt 0.4062 0.8826 +vt 0.4062 0.8904 +vt 0.3984 0.8904 +vt 0.3827 0.9294 +vt 0.3906 0.9294 +vt 0.3905 0.9372 +vt 0.3827 0.9372 +vt 0.3827 0.9138 +vt 0.3906 0.9138 +vt 0.3906 0.9216 +vt 0.3827 0.9216 +vt 0.3984 0.9138 +vt 0.4062 0.9138 +vt 0.4062 0.9216 +vt 0.3984 0.9216 +vt 0.4765 0.8982 +vt 0.4843 0.8982 +vt 0.4843 0.9060 +vt 0.4765 0.9060 +vt 0.4765 0.8826 +vt 0.4843 0.8826 +vt 0.4843 0.8904 +vt 0.4765 0.8904 +vt 0.4921 0.8826 +vt 0.4999 0.8826 +vt 0.4999 0.8904 +vt 0.4921 0.8904 +vt 0.4452 0.8982 +vt 0.4530 0.8982 +vt 0.4530 0.9060 +vt 0.4452 0.9060 +vt 0.4452 0.8826 +vt 0.4530 0.8826 +vt 0.4530 0.8904 +vt 0.4452 0.8904 +vt 0.4608 0.8826 +vt 0.4686 0.8826 +vt 0.4686 0.8904 +vt 0.4608 0.8904 +vt 0.4452 0.9294 +vt 0.4530 0.9294 +vt 0.4530 0.9372 +vt 0.4452 0.9372 +vt 0.4452 0.9138 +vt 0.4530 0.9138 +vt 0.4530 0.9216 +vt 0.4452 0.9216 +vt 0.4608 0.9138 +vt 0.4686 0.9138 +vt 0.4686 0.9216 +vt 0.4608 0.9216 +vt 0.9137 0.9608 +vt 0.9215 0.9608 +vt 0.9215 0.9686 +vt 0.9137 0.9686 +vt 0.9137 0.9452 +vt 0.9215 0.9452 +vt 0.9215 0.9530 +vt 0.9137 0.9530 +vt 0.9293 0.9452 +vt 0.9371 0.9452 +vt 0.9371 0.9530 +vt 0.9293 0.9530 +vt 0.8825 0.9608 +vt 0.8903 0.9608 +vt 0.8903 0.9686 +vt 0.8825 0.9686 +vt 0.8825 0.9452 +vt 0.8903 0.9452 +vt 0.8903 0.9530 +vt 0.8825 0.9530 +vt 0.8981 0.9452 +vt 0.9059 0.9452 +vt 0.9059 0.9530 +vt 0.8981 0.9530 +vt 0.8825 0.9920 +vt 0.8903 0.9920 +vt 0.8903 0.9998 +vt 0.8825 0.9998 +vt 0.8825 0.9764 +vt 0.8903 0.9764 +vt 0.8903 0.9842 +vt 0.8825 0.9842 +vt 0.8981 0.9764 +vt 0.9059 0.9764 +vt 0.9059 0.9842 +vt 0.8981 0.9842 +vt 0.9137 0.8983 +vt 0.9215 0.8983 +vt 0.9215 0.9062 +vt 0.9137 0.9061 +vt 0.9137 0.8827 +vt 0.9215 0.8827 +vt 0.9215 0.8905 +vt 0.9137 0.8905 +vt 0.9293 0.8827 +vt 0.9371 0.8827 +vt 0.9371 0.8905 +vt 0.9293 0.8905 +vt 0.8825 0.8983 +vt 0.8903 0.8983 +vt 0.8903 0.9061 +vt 0.8825 0.9061 +vt 0.8825 0.8827 +vt 0.8903 0.8827 +vt 0.8903 0.8905 +vt 0.8825 0.8905 +vt 0.8981 0.8827 +vt 0.9059 0.8827 +vt 0.9059 0.8905 +vt 0.8981 0.8905 +vt 0.8825 0.9296 +vt 0.8903 0.9296 +vt 0.8903 0.9374 +vt 0.8825 0.9374 +vt 0.8825 0.9139 +vt 0.8903 0.9139 +vt 0.8903 0.9218 +vt 0.8825 0.9218 +vt 0.8981 0.9140 +vt 0.9059 0.9140 +vt 0.9059 0.9218 +vt 0.8981 0.9218 +vt 0.9762 0.8984 +vt 0.9840 0.8984 +vt 0.9840 0.9062 +vt 0.9762 0.9062 +vt 0.9762 0.8827 +vt 0.9840 0.8827 +vt 0.9840 0.8906 +vt 0.9762 0.8906 +vt 0.9918 0.8827 +vt 0.9996 0.8828 +vt 0.9996 0.8906 +vt 0.9918 0.8906 +vt 0.9450 0.8983 +vt 0.9528 0.8984 +vt 0.9528 0.9062 +vt 0.9449 0.9062 +vt 0.9450 0.8827 +vt 0.9528 0.8827 +vt 0.9528 0.8905 +vt 0.9450 0.8905 +vt 0.9606 0.8827 +vt 0.9684 0.8827 +vt 0.9684 0.8905 +vt 0.9606 0.8905 +vt 0.9449 0.9296 +vt 0.9527 0.9296 +vt 0.9527 0.9374 +vt 0.9449 0.9374 +vt 0.9449 0.9140 +vt 0.9528 0.9140 +vt 0.9528 0.9218 +vt 0.9449 0.9218 +vt 0.9606 0.9140 +vt 0.9684 0.9140 +vt 0.9684 0.9218 +vt 0.9606 0.9218 +vt 0.9762 0.9296 +vt 0.9840 0.9296 +vt 0.9840 0.9374 +vt 0.9762 0.9374 +vt 0.9762 0.9140 +vt 0.9840 0.9140 +vt 0.9840 0.9218 +vt 0.9762 0.9218 +vt 0.9918 0.9140 +vt 0.9996 0.9140 +vt 0.9996 0.9218 +vt 0.9918 0.9218 +vt 0.9137 0.9296 +vt 0.9215 0.9296 +vt 0.9215 0.9374 +vt 0.9137 0.9374 +vt 0.9137 0.9140 +vt 0.9215 0.9140 +vt 0.9215 0.9218 +vt 0.9137 0.9218 +vt 0.9293 0.9140 +vt 0.9371 0.9140 +vt 0.9371 0.9218 +vt 0.9293 0.9218 +vt 0.9137 0.9920 +vt 0.9215 0.9920 +vt 0.9215 0.9998 +vt 0.9137 0.9998 +vt 0.9137 0.9764 +vt 0.9215 0.9764 +vt 0.9215 0.9842 +vt 0.9137 0.9842 +vt 0.9293 0.9764 +vt 0.9371 0.9764 +vt 0.9371 0.9842 +vt 0.9293 0.9842 +vt 0.4764 0.9294 +vt 0.4843 0.9294 +vt 0.4843 0.9373 +vt 0.4764 0.9372 +vt 0.4764 0.9138 +vt 0.4843 0.9138 +vt 0.4843 0.9216 +vt 0.4764 0.9216 +vt 0.4921 0.9138 +vt 0.4999 0.9138 +vt 0.4999 0.9216 +vt 0.4921 0.9216 +vt 0.4140 0.9294 +vt 0.4218 0.9294 +vt 0.4218 0.9372 +vt 0.4140 0.9372 +vt 0.4140 0.9138 +vt 0.4218 0.9138 +vt 0.4218 0.9216 +vt 0.4140 0.9216 +vt 0.4296 0.9138 +vt 0.4374 0.9138 +vt 0.4374 0.9216 +vt 0.4296 0.9216 +vt 0.4140 0.9919 +vt 0.4218 0.9919 +vt 0.4218 0.9997 +vt 0.4140 0.9997 +vt 0.4140 0.9763 +vt 0.4218 0.9763 +vt 0.4218 0.9841 +vt 0.4140 0.9841 +vt 0.4296 0.9763 +vt 0.4374 0.9763 +vt 0.4374 0.9841 +vt 0.4296 0.9841 +vt 0.4766 0.4297 +vt 0.4844 0.4297 +vt 0.4844 0.4375 +vt 0.4766 0.4375 +vt 0.4766 0.4141 +vt 0.4844 0.4141 +vt 0.4844 0.4219 +vt 0.4766 0.4219 +vt 0.4922 0.4141 +vt 0.5000 0.4141 +vt 0.5000 0.4219 +vt 0.4922 0.4219 +vt 0.4141 0.4297 +vt 0.4219 0.4297 +vt 0.4219 0.4375 +vt 0.4141 0.4375 +vt 0.4141 0.4141 +vt 0.4219 0.4141 +vt 0.4219 0.4219 +vt 0.4141 0.4219 +vt 0.4298 0.4141 +vt 0.4376 0.4141 +vt 0.4376 0.4219 +vt 0.4298 0.4219 +vt 0.4141 0.4922 +vt 0.4219 0.4922 +vt 0.4219 0.5000 +vt 0.4141 0.5000 +vt 0.4141 0.4765 +vt 0.4219 0.4765 +vt 0.4219 0.4843 +vt 0.4141 0.4843 +vt 0.4297 0.4765 +vt 0.4375 0.4765 +vt 0.4375 0.4843 +vt 0.4297 0.4843 +vt 0.9763 0.4299 +vt 0.9841 0.4299 +vt 0.9841 0.4377 +vt 0.9763 0.4377 +vt 0.9763 0.4142 +vt 0.9841 0.4142 +vt 0.9841 0.4221 +vt 0.9763 0.4221 +vt 0.9920 0.4143 +vt 0.9998 0.4143 +vt 0.9998 0.4221 +vt 0.9920 0.4221 +vt 0.9139 0.4298 +vt 0.9217 0.4298 +vt 0.9217 0.4377 +vt 0.9139 0.4377 +vt 0.9139 0.4142 +vt 0.9217 0.4142 +vt 0.9217 0.4220 +vt 0.9139 0.4220 +vt 0.9295 0.4142 +vt 0.9373 0.4142 +vt 0.9373 0.4220 +vt 0.9295 0.4220 +vt 0.9138 0.4923 +vt 0.9217 0.4923 +vt 0.9217 0.5001 +vt 0.9138 0.5001 +vt 0.9139 0.4767 +vt 0.9217 0.4767 +vt 0.9217 0.4845 +vt 0.9139 0.4845 +vt 0.9295 0.4767 +vt 0.9373 0.4767 +vt 0.9373 0.4845 +vt 0.9295 0.4845 +vt 0.7265 0.4298 +vt 0.7343 0.4298 +vt 0.7343 0.4376 +vt 0.7265 0.4376 +vt 0.7265 0.4142 +vt 0.7343 0.4142 +vt 0.7343 0.4220 +vt 0.7265 0.4220 +vt 0.7421 0.4142 +vt 0.7499 0.4142 +vt 0.7499 0.4220 +vt 0.7421 0.4220 +vt 0.6640 0.4298 +vt 0.6718 0.4298 +vt 0.6718 0.4376 +vt 0.6640 0.4376 +vt 0.6640 0.4141 +vt 0.6718 0.4141 +vt 0.6718 0.4220 +vt 0.6640 0.4220 +vt 0.6796 0.4142 +vt 0.6874 0.4142 +vt 0.6874 0.4220 +vt 0.6796 0.4220 +vt 0.6640 0.4922 +vt 0.6718 0.4922 +vt 0.6718 0.5000 +vt 0.6640 0.5000 +vt 0.6640 0.4766 +vt 0.6718 0.4766 +vt 0.6718 0.4844 +vt 0.6640 0.4844 +vt 0.6796 0.4766 +vt 0.6874 0.4766 +vt 0.6874 0.4844 +vt 0.6796 0.4844 +vt 0.7265 0.1799 +vt 0.7344 0.1799 +vt 0.7344 0.1877 +vt 0.7265 0.1877 +vt 0.7265 0.1643 +vt 0.7344 0.1643 +vt 0.7344 0.1721 +vt 0.7265 0.1721 +vt 0.7422 0.1643 +vt 0.7500 0.1643 +vt 0.7500 0.1721 +vt 0.7422 0.1721 +vt 0.6641 0.1799 +vt 0.6719 0.1799 +vt 0.6719 0.1877 +vt 0.6641 0.1877 +vt 0.6641 0.1643 +vt 0.6719 0.1643 +vt 0.6719 0.1721 +vt 0.6641 0.1721 +vt 0.6797 0.1643 +vt 0.6875 0.1643 +vt 0.6875 0.1721 +vt 0.6797 0.1721 +vt 0.6641 0.2424 +vt 0.6719 0.2424 +vt 0.6719 0.2502 +vt 0.6641 0.2502 +vt 0.6641 0.2267 +vt 0.6719 0.2267 +vt 0.6719 0.2346 +vt 0.6641 0.2346 +vt 0.6797 0.2267 +vt 0.6875 0.2268 +vt 0.6875 0.2346 +vt 0.6797 0.2346 +vt 0.9764 0.1800 +vt 0.9842 0.1800 +vt 0.9842 0.1878 +vt 0.9764 0.1878 +vt 0.9764 0.1644 +vt 0.9842 0.1644 +vt 0.9842 0.1722 +vt 0.9764 0.1722 +vt 0.9920 0.1644 +vt 0.9998 0.1644 +vt 0.9998 0.1722 +vt 0.9920 0.1722 +vt 0.9139 0.1800 +vt 0.9218 0.1800 +vt 0.9218 0.1878 +vt 0.9139 0.1878 +vt 0.9140 0.1644 +vt 0.9218 0.1644 +vt 0.9218 0.1722 +vt 0.9140 0.1722 +vt 0.9296 0.1644 +vt 0.9374 0.1644 +vt 0.9374 0.1722 +vt 0.9296 0.1722 +vt 0.9139 0.2424 +vt 0.9217 0.2424 +vt 0.9217 0.2502 +vt 0.9139 0.2502 +vt 0.9139 0.2268 +vt 0.9217 0.2268 +vt 0.9217 0.2346 +vt 0.9139 0.2346 +vt 0.9296 0.2268 +vt 0.9374 0.2268 +vt 0.9374 0.2346 +vt 0.9295 0.2346 +vt 0.2267 0.4296 +vt 0.2345 0.4296 +vt 0.2345 0.4374 +vt 0.2267 0.4374 +vt 0.2267 0.4140 +vt 0.2345 0.4140 +vt 0.2345 0.4218 +vt 0.2267 0.4218 +vt 0.2424 0.4140 +vt 0.2502 0.4140 +vt 0.2502 0.4218 +vt 0.2423 0.4218 +vt 0.1643 0.4296 +vt 0.1721 0.4296 +vt 0.1721 0.4374 +vt 0.1643 0.4374 +vt 0.1643 0.4140 +vt 0.1721 0.4140 +vt 0.1721 0.4218 +vt 0.1643 0.4218 +vt 0.1799 0.4140 +vt 0.1877 0.4140 +vt 0.1877 0.4218 +vt 0.1799 0.4218 +vt 0.1642 0.4921 +vt 0.1721 0.4921 +vt 0.1720 0.4999 +vt 0.1642 0.4999 +vt 0.1642 0.4765 +vt 0.1721 0.4765 +vt 0.1721 0.4843 +vt 0.1642 0.4843 +vt 0.1799 0.4765 +vt 0.1877 0.4765 +vt 0.1877 0.4843 +vt 0.1799 0.4843 +vt 0.2268 0.1798 +vt 0.2346 0.1798 +vt 0.2346 0.1876 +vt 0.2268 0.1876 +vt 0.2268 0.1641 +vt 0.2346 0.1641 +vt 0.2346 0.1720 +vt 0.2268 0.1720 +vt 0.2424 0.1641 +vt 0.2502 0.1641 +vt 0.2502 0.1720 +vt 0.2424 0.1720 +vt 0.1643 0.1797 +vt 0.1722 0.1797 +vt 0.1721 0.1875 +vt 0.1643 0.1875 +vt 0.1643 0.1641 +vt 0.1722 0.1641 +vt 0.1722 0.1719 +vt 0.1643 0.1719 +vt 0.1800 0.1641 +vt 0.1878 0.1641 +vt 0.1878 0.1719 +vt 0.1800 0.1719 +vt 0.1643 0.2422 +vt 0.1721 0.2422 +vt 0.1721 0.2500 +vt 0.1643 0.2500 +vt 0.1643 0.2266 +vt 0.1721 0.2266 +vt 0.1721 0.2344 +vt 0.1643 0.2344 +vt 0.1799 0.2266 +vt 0.1878 0.2266 +vt 0.1878 0.2344 +vt 0.1799 0.2344 +vt 0.4767 0.1798 +vt 0.4845 0.1798 +vt 0.4845 0.1876 +vt 0.4767 0.1876 +vt 0.4767 0.1642 +vt 0.4845 0.1642 +vt 0.4845 0.1720 +vt 0.4767 0.1720 +vt 0.4923 0.1642 +vt 0.5001 0.1642 +vt 0.5001 0.1720 +vt 0.4923 0.1720 +vt 0.4142 0.1798 +vt 0.4220 0.1798 +vt 0.4220 0.1876 +vt 0.4142 0.1876 +vt 0.4142 0.1642 +vt 0.4220 0.1642 +vt 0.4220 0.1720 +vt 0.4142 0.1720 +vt 0.4298 0.1642 +vt 0.4376 0.1642 +vt 0.4376 0.1720 +vt 0.4298 0.1720 +vt 0.4142 0.2423 +vt 0.4220 0.2423 +vt 0.4220 0.2501 +vt 0.4142 0.2501 +vt 0.4142 0.2267 +vt 0.4220 0.2267 +vt 0.4220 0.2345 +vt 0.4142 0.2345 +vt 0.4298 0.2267 +vt 0.4376 0.2267 +vt 0.4376 0.2345 +vt 0.4298 0.2345 +vt 0.2266 0.9294 +vt 0.2344 0.9294 +vt 0.2344 0.9372 +vt 0.2266 0.9372 +vt 0.2266 0.9137 +vt 0.2344 0.9138 +vt 0.2344 0.9216 +vt 0.2266 0.9216 +vt 0.2422 0.9138 +vt 0.2500 0.9138 +vt 0.2500 0.9216 +vt 0.2422 0.9216 +vt 0.1641 0.9293 +vt 0.1719 0.9293 +vt 0.1719 0.9372 +vt 0.1641 0.9372 +vt 0.1641 0.9137 +vt 0.1719 0.9137 +vt 0.1719 0.9215 +vt 0.1641 0.9215 +vt 0.1797 0.9137 +vt 0.1875 0.9137 +vt 0.1875 0.9215 +vt 0.1797 0.9215 +vt 0.1641 0.9918 +vt 0.1719 0.9918 +vt 0.1719 0.9996 +vt 0.1641 0.9996 +vt 0.1641 0.9762 +vt 0.1719 0.9762 +vt 0.1719 0.9840 +vt 0.1641 0.9840 +vt 0.1797 0.9762 +vt 0.1875 0.9762 +vt 0.1875 0.9840 +vt 0.1797 0.9840 +vt 0.2267 0.6795 +vt 0.2345 0.6795 +vt 0.2345 0.6873 +vt 0.2266 0.6873 +vt 0.2267 0.6639 +vt 0.2345 0.6639 +vt 0.2345 0.6717 +vt 0.2267 0.6717 +vt 0.2423 0.6639 +vt 0.2501 0.6639 +vt 0.2501 0.6717 +vt 0.2423 0.6717 +vt 0.1642 0.6795 +vt 0.1720 0.6795 +vt 0.1720 0.6873 +vt 0.1642 0.6873 +vt 0.1642 0.6639 +vt 0.1720 0.6639 +vt 0.1720 0.6717 +vt 0.1642 0.6717 +vt 0.1798 0.6639 +vt 0.1876 0.6639 +vt 0.1876 0.6717 +vt 0.1798 0.6717 +vt 0.1642 0.7419 +vt 0.1720 0.7419 +vt 0.1720 0.7498 +vt 0.1642 0.7498 +vt 0.1642 0.7263 +vt 0.1720 0.7263 +vt 0.1720 0.7341 +vt 0.1642 0.7341 +vt 0.1798 0.7263 +vt 0.1876 0.7263 +vt 0.1876 0.7341 +vt 0.1798 0.7341 +vt 0.4765 0.6796 +vt 0.4843 0.6796 +vt 0.4843 0.6874 +vt 0.4765 0.6874 +vt 0.4765 0.6640 +vt 0.4843 0.6640 +vt 0.4843 0.6718 +vt 0.4765 0.6718 +vt 0.4921 0.6640 +vt 0.5000 0.6640 +vt 0.4999 0.6718 +vt 0.4921 0.6718 +vt 0.4141 0.6796 +vt 0.4219 0.6796 +vt 0.4219 0.6874 +vt 0.4141 0.6874 +vt 0.4141 0.6639 +vt 0.4219 0.6639 +vt 0.4219 0.6717 +vt 0.4141 0.6717 +vt 0.4297 0.6639 +vt 0.4375 0.6639 +vt 0.4375 0.6718 +vt 0.4297 0.6717 +vt 0.4140 0.7420 +vt 0.4218 0.7420 +vt 0.4218 0.7498 +vt 0.4140 0.7498 +vt 0.4140 0.7264 +vt 0.4218 0.7264 +vt 0.4218 0.7342 +vt 0.4140 0.7342 +vt 0.4297 0.7264 +vt 0.4375 0.7264 +vt 0.4375 0.7342 +vt 0.4297 0.7342 +vt 0.7263 0.9295 +vt 0.7341 0.9295 +vt 0.7341 0.9373 +vt 0.7263 0.9373 +vt 0.7263 0.9139 +vt 0.7341 0.9139 +vt 0.7341 0.9217 +vt 0.7263 0.9217 +vt 0.7419 0.9139 +vt 0.7497 0.9139 +vt 0.7497 0.9217 +vt 0.7419 0.9217 +vt 0.6638 0.9295 +vt 0.6717 0.9295 +vt 0.6717 0.9373 +vt 0.6638 0.9373 +vt 0.6638 0.9139 +vt 0.6717 0.9139 +vt 0.6717 0.9217 +vt 0.6638 0.9217 +vt 0.6795 0.9139 +vt 0.6873 0.9139 +vt 0.6873 0.9217 +vt 0.6795 0.9217 +vt 0.6638 0.9920 +vt 0.6716 0.9920 +vt 0.6716 0.9998 +vt 0.6638 0.9998 +vt 0.6638 0.9763 +vt 0.6716 0.9763 +vt 0.6716 0.9842 +vt 0.6638 0.9842 +vt 0.6794 0.9764 +vt 0.6873 0.9764 +vt 0.6873 0.9842 +vt 0.6794 0.9842 +vt 0.7264 0.6796 +vt 0.7342 0.6797 +vt 0.7342 0.6875 +vt 0.7264 0.6875 +vt 0.7264 0.6640 +vt 0.7342 0.6640 +vt 0.7342 0.6718 +vt 0.7264 0.6718 +vt 0.7420 0.6640 +vt 0.7498 0.6640 +vt 0.7498 0.6718 +vt 0.7420 0.6718 +vt 0.6639 0.6796 +vt 0.6717 0.6796 +vt 0.6717 0.6874 +vt 0.6639 0.6874 +vt 0.6639 0.6640 +vt 0.6717 0.6640 +vt 0.6717 0.6718 +vt 0.6639 0.6718 +vt 0.6795 0.6640 +vt 0.6874 0.6640 +vt 0.6873 0.6718 +vt 0.6795 0.6718 +vt 0.6639 0.7421 +vt 0.6717 0.7421 +vt 0.6717 0.7499 +vt 0.6639 0.7499 +vt 0.6639 0.7265 +vt 0.6717 0.7265 +vt 0.6717 0.7343 +vt 0.6639 0.7343 +vt 0.6795 0.7265 +vt 0.6873 0.7265 +vt 0.6873 0.7343 +vt 0.6795 0.7343 +vt 0.9763 0.6797 +vt 0.9841 0.6797 +vt 0.9841 0.6875 +vt 0.9763 0.6875 +vt 0.9763 0.6641 +vt 0.9841 0.6641 +vt 0.9841 0.6719 +vt 0.9763 0.6719 +vt 0.9919 0.6641 +vt 0.9997 0.6641 +vt 0.9997 0.6719 +vt 0.9919 0.6719 +vt 0.9138 0.6797 +vt 0.9216 0.6797 +vt 0.9216 0.6875 +vt 0.9138 0.6875 +vt 0.9138 0.6641 +vt 0.9216 0.6641 +vt 0.9216 0.6719 +vt 0.9138 0.6719 +vt 0.9294 0.6641 +vt 0.9372 0.6641 +vt 0.9372 0.6719 +vt 0.9294 0.6719 +vt 0.9138 0.7422 +vt 0.9216 0.7422 +vt 0.9216 0.7500 +vt 0.9138 0.7500 +vt 0.9138 0.7266 +vt 0.9216 0.7266 +vt 0.9216 0.7344 +vt 0.9138 0.7344 +vt 0.9294 0.7266 +vt 0.9372 0.7266 +vt 0.9372 0.7344 +vt 0.9294 0.7344 +vt 0.8513 0.6797 +vt 0.8591 0.6797 +vt 0.8591 0.6875 +vt 0.8513 0.6875 +vt 0.8513 0.6641 +vt 0.8591 0.6641 +vt 0.8591 0.6719 +vt 0.8513 0.6719 +vt 0.8669 0.6641 +vt 0.8748 0.6641 +vt 0.8747 0.6719 +vt 0.8669 0.6719 +vt 0.7889 0.6797 +vt 0.7967 0.6797 +vt 0.7967 0.6875 +vt 0.7889 0.6875 +vt 0.7889 0.6641 +vt 0.7967 0.6641 +vt 0.7967 0.6719 +vt 0.7889 0.6719 +vt 0.8045 0.6641 +vt 0.8123 0.6641 +vt 0.8123 0.6719 +vt 0.8045 0.6719 +vt 0.7888 0.7421 +vt 0.7966 0.7421 +vt 0.7966 0.7499 +vt 0.7888 0.7499 +vt 0.7888 0.7265 +vt 0.7966 0.7265 +vt 0.7966 0.7343 +vt 0.7888 0.7343 +vt 0.8045 0.7265 +vt 0.8123 0.7265 +vt 0.8123 0.7343 +vt 0.8045 0.7343 +vt 0.8514 0.5548 +vt 0.8592 0.5548 +vt 0.8592 0.5626 +vt 0.8514 0.5626 +vt 0.8514 0.5391 +vt 0.8592 0.5391 +vt 0.8592 0.5469 +vt 0.8514 0.5469 +vt 0.8670 0.5391 +vt 0.8748 0.5391 +vt 0.8748 0.5470 +vt 0.8670 0.5470 +vt 0.7889 0.5547 +vt 0.7967 0.5547 +vt 0.7967 0.5625 +vt 0.7889 0.5625 +vt 0.7889 0.5391 +vt 0.7967 0.5391 +vt 0.7967 0.5469 +vt 0.7889 0.5469 +vt 0.8045 0.5391 +vt 0.8123 0.5391 +vt 0.8123 0.5469 +vt 0.8045 0.5469 +vt 0.7889 0.6172 +vt 0.7967 0.6172 +vt 0.7967 0.6250 +vt 0.7889 0.6250 +vt 0.7889 0.6016 +vt 0.7967 0.6016 +vt 0.7967 0.6094 +vt 0.7889 0.6094 +vt 0.8045 0.6016 +vt 0.8123 0.6016 +vt 0.8123 0.6094 +vt 0.8045 0.6094 +vt 0.9763 0.5548 +vt 0.9841 0.5548 +vt 0.9841 0.5626 +vt 0.9763 0.5626 +vt 0.9763 0.5392 +vt 0.9841 0.5392 +vt 0.9841 0.5470 +vt 0.9763 0.5470 +vt 0.9919 0.5392 +vt 0.9997 0.5392 +vt 0.9997 0.5470 +vt 0.9919 0.5470 +vt 0.9138 0.5548 +vt 0.9216 0.5548 +vt 0.9216 0.5626 +vt 0.9138 0.5626 +vt 0.9138 0.5392 +vt 0.9216 0.5392 +vt 0.9216 0.5470 +vt 0.9138 0.5470 +vt 0.9294 0.5392 +vt 0.9373 0.5392 +vt 0.9373 0.5470 +vt 0.9294 0.5470 +vt 0.9138 0.6172 +vt 0.9216 0.6172 +vt 0.9216 0.6251 +vt 0.9138 0.6251 +vt 0.9138 0.6016 +vt 0.9216 0.6016 +vt 0.9216 0.6094 +vt 0.9138 0.6094 +vt 0.9294 0.6016 +vt 0.9372 0.6016 +vt 0.9372 0.6094 +vt 0.9294 0.6094 +vt 0.6015 0.6796 +vt 0.6093 0.6796 +vt 0.6093 0.6874 +vt 0.6015 0.6874 +vt 0.6015 0.6640 +vt 0.6093 0.6640 +vt 0.6093 0.6718 +vt 0.6015 0.6718 +vt 0.6171 0.6640 +vt 0.6249 0.6640 +vt 0.6249 0.6718 +vt 0.6171 0.6718 +vt 0.5390 0.6796 +vt 0.5468 0.6796 +vt 0.5468 0.6874 +vt 0.5390 0.6874 +vt 0.5390 0.6640 +vt 0.5468 0.6640 +vt 0.5468 0.6718 +vt 0.5390 0.6718 +vt 0.5546 0.6640 +vt 0.5624 0.6640 +vt 0.5624 0.6718 +vt 0.5546 0.6718 +vt 0.5390 0.7421 +vt 0.5468 0.7421 +vt 0.5468 0.7499 +vt 0.5390 0.7499 +vt 0.5390 0.7264 +vt 0.5468 0.7264 +vt 0.5468 0.7343 +vt 0.5390 0.7343 +vt 0.5546 0.7264 +vt 0.5624 0.7264 +vt 0.5624 0.7343 +vt 0.5546 0.7343 +vt 0.6015 0.5547 +vt 0.6093 0.5547 +vt 0.6093 0.5625 +vt 0.6015 0.5625 +vt 0.6015 0.5391 +vt 0.6093 0.5391 +vt 0.6093 0.5469 +vt 0.6015 0.5469 +vt 0.6171 0.5391 +vt 0.6249 0.5391 +vt 0.6249 0.5469 +vt 0.6171 0.5469 +vt 0.5390 0.5547 +vt 0.5468 0.5547 +vt 0.5468 0.5625 +vt 0.5390 0.5625 +vt 0.5390 0.5390 +vt 0.5468 0.5390 +vt 0.5468 0.5469 +vt 0.5390 0.5468 +vt 0.5546 0.5390 +vt 0.5625 0.5390 +vt 0.5625 0.5469 +vt 0.5546 0.5469 +vt 0.5390 0.6171 +vt 0.5468 0.6171 +vt 0.5468 0.6249 +vt 0.5390 0.6249 +vt 0.5390 0.6015 +vt 0.5468 0.6015 +vt 0.5468 0.6093 +vt 0.5390 0.6093 +vt 0.5546 0.6015 +vt 0.5624 0.6015 +vt 0.5624 0.6093 +vt 0.5546 0.6093 +vt 0.7264 0.5547 +vt 0.7342 0.5547 +vt 0.7342 0.5625 +vt 0.7264 0.5625 +vt 0.7264 0.5391 +vt 0.7342 0.5391 +vt 0.7342 0.5469 +vt 0.7264 0.5469 +vt 0.7420 0.5391 +vt 0.7499 0.5391 +vt 0.7499 0.5469 +vt 0.7420 0.5469 +vt 0.6640 0.5547 +vt 0.6718 0.5547 +vt 0.6718 0.5625 +vt 0.6640 0.5625 +vt 0.6640 0.5391 +vt 0.6718 0.5391 +vt 0.6718 0.5469 +vt 0.6640 0.5469 +vt 0.6796 0.5391 +vt 0.6874 0.5391 +vt 0.6874 0.5469 +vt 0.6796 0.5469 +vt 0.6639 0.6172 +vt 0.6717 0.6172 +vt 0.6717 0.6250 +vt 0.6639 0.6250 +vt 0.6639 0.6015 +vt 0.6718 0.6015 +vt 0.6718 0.6094 +vt 0.6639 0.6094 +vt 0.6796 0.6016 +vt 0.6874 0.6016 +vt 0.6874 0.6094 +vt 0.6796 0.6094 +vt 0.6014 0.9295 +vt 0.6092 0.9295 +vt 0.6092 0.9373 +vt 0.6014 0.9373 +vt 0.6014 0.9139 +vt 0.6092 0.9139 +vt 0.6092 0.9217 +vt 0.6014 0.9217 +vt 0.6170 0.9139 +vt 0.6248 0.9139 +vt 0.6248 0.9217 +vt 0.6170 0.9217 +vt 0.5389 0.9295 +vt 0.5467 0.9295 +vt 0.5467 0.9373 +vt 0.5389 0.9373 +vt 0.5389 0.9138 +vt 0.5467 0.9138 +vt 0.5467 0.9217 +vt 0.5389 0.9217 +vt 0.5545 0.9138 +vt 0.5623 0.9138 +vt 0.5623 0.9217 +vt 0.5545 0.9217 +vt 0.5389 0.9919 +vt 0.5467 0.9919 +vt 0.5467 0.9997 +vt 0.5389 0.9997 +vt 0.5389 0.9763 +vt 0.5467 0.9763 +vt 0.5467 0.9841 +vt 0.5389 0.9841 +vt 0.5545 0.9763 +vt 0.5623 0.9763 +vt 0.5623 0.9841 +vt 0.5545 0.9841 +vt 0.6014 0.8045 +vt 0.6092 0.8045 +vt 0.6092 0.8124 +vt 0.6014 0.8124 +vt 0.6014 0.7889 +vt 0.6092 0.7889 +vt 0.6092 0.7967 +vt 0.6014 0.7967 +vt 0.6170 0.7889 +vt 0.6248 0.7889 +vt 0.6248 0.7967 +vt 0.6170 0.7967 +vt 0.5389 0.8045 +vt 0.5468 0.8045 +vt 0.5468 0.8123 +vt 0.5389 0.8123 +vt 0.5390 0.7889 +vt 0.5468 0.7889 +vt 0.5468 0.7967 +vt 0.5390 0.7967 +vt 0.5546 0.7889 +vt 0.5624 0.7889 +vt 0.5624 0.7967 +vt 0.5546 0.7967 +vt 0.5389 0.8670 +vt 0.5467 0.8670 +vt 0.5467 0.8748 +vt 0.5389 0.8748 +vt 0.5389 0.8514 +vt 0.5467 0.8514 +vt 0.5467 0.8592 +vt 0.5389 0.8592 +vt 0.5546 0.8514 +vt 0.5624 0.8514 +vt 0.5624 0.8592 +vt 0.5545 0.8592 +vt 0.7263 0.8046 +vt 0.7342 0.8046 +vt 0.7342 0.8124 +vt 0.7263 0.8124 +vt 0.7264 0.7890 +vt 0.7342 0.7890 +vt 0.7342 0.7968 +vt 0.7264 0.7968 +vt 0.7420 0.7890 +vt 0.7498 0.7890 +vt 0.7498 0.7968 +vt 0.7420 0.7968 +vt 0.6639 0.8046 +vt 0.6717 0.8046 +vt 0.6717 0.8124 +vt 0.6639 0.8124 +vt 0.6639 0.7889 +vt 0.6717 0.7889 +vt 0.6717 0.7968 +vt 0.6639 0.7968 +vt 0.6795 0.7890 +vt 0.6873 0.7890 +vt 0.6873 0.7968 +vt 0.6795 0.7968 +vt 0.6639 0.8670 +vt 0.6717 0.8670 +vt 0.6717 0.8748 +vt 0.6639 0.8748 +vt 0.6639 0.8514 +vt 0.6717 0.8514 +vt 0.6717 0.8592 +vt 0.6639 0.8592 +vt 0.6795 0.8514 +vt 0.6873 0.8514 +vt 0.6873 0.8592 +vt 0.6795 0.8592 +vt 0.3516 0.6795 +vt 0.3594 0.6795 +vt 0.3594 0.6873 +vt 0.3516 0.6873 +vt 0.3516 0.6639 +vt 0.3594 0.6639 +vt 0.3594 0.6717 +vt 0.3516 0.6717 +vt 0.3672 0.6639 +vt 0.3750 0.6639 +vt 0.3750 0.6717 +vt 0.3672 0.6717 +vt 0.2891 0.6795 +vt 0.2969 0.6795 +vt 0.2969 0.6873 +vt 0.2891 0.6873 +vt 0.2891 0.6639 +vt 0.2969 0.6639 +vt 0.2969 0.6717 +vt 0.2891 0.6717 +vt 0.3047 0.6639 +vt 0.3125 0.6639 +vt 0.3125 0.6717 +vt 0.3047 0.6717 +vt 0.2891 0.7420 +vt 0.2969 0.7420 +vt 0.2969 0.7498 +vt 0.2891 0.7498 +vt 0.2891 0.7264 +vt 0.2969 0.7264 +vt 0.2969 0.7342 +vt 0.2891 0.7342 +vt 0.3047 0.7264 +vt 0.3125 0.7264 +vt 0.3125 0.7342 +vt 0.3047 0.7342 +vt 0.3516 0.5546 +vt 0.3594 0.5546 +vt 0.3594 0.5624 +vt 0.3516 0.5624 +vt 0.3516 0.5390 +vt 0.3594 0.5390 +vt 0.3594 0.5468 +vt 0.3516 0.5468 +vt 0.3672 0.5390 +vt 0.3751 0.5390 +vt 0.3751 0.5468 +vt 0.3672 0.5468 +vt 0.2892 0.5546 +vt 0.2970 0.5546 +vt 0.2970 0.5624 +vt 0.2892 0.5624 +vt 0.2892 0.5390 +vt 0.2970 0.5390 +vt 0.2970 0.5468 +vt 0.2892 0.5468 +vt 0.3048 0.5390 +vt 0.3126 0.5390 +vt 0.3126 0.5468 +vt 0.3048 0.5468 +vt 0.2891 0.6170 +vt 0.2969 0.6170 +vt 0.2969 0.6249 +vt 0.2891 0.6249 +vt 0.2891 0.6014 +vt 0.2970 0.6014 +vt 0.2969 0.6092 +vt 0.2891 0.6092 +vt 0.3048 0.6014 +vt 0.3126 0.6014 +vt 0.3126 0.6092 +vt 0.3048 0.6092 +vt 0.4766 0.5546 +vt 0.4844 0.5546 +vt 0.4844 0.5624 +vt 0.4766 0.5624 +vt 0.4766 0.5390 +vt 0.4844 0.5390 +vt 0.4844 0.5468 +vt 0.4766 0.5468 +vt 0.4922 0.5390 +vt 0.5000 0.5390 +vt 0.5000 0.5468 +vt 0.4922 0.5468 +vt 0.4141 0.5546 +vt 0.4219 0.5546 +vt 0.4219 0.5624 +vt 0.4141 0.5624 +vt 0.4141 0.5390 +vt 0.4219 0.5390 +vt 0.4219 0.5468 +vt 0.4141 0.5468 +vt 0.4297 0.5390 +vt 0.4375 0.5390 +vt 0.4375 0.5468 +vt 0.4297 0.5468 +vt 0.4141 0.6171 +vt 0.4219 0.6171 +vt 0.4219 0.6249 +vt 0.4141 0.6249 +vt 0.4141 0.6015 +vt 0.4219 0.6015 +vt 0.4219 0.6093 +vt 0.4141 0.6093 +vt 0.4297 0.6015 +vt 0.4375 0.6015 +vt 0.4375 0.6093 +vt 0.4297 0.6093 +vt 0.1017 0.6795 +vt 0.1095 0.6795 +vt 0.1095 0.6873 +vt 0.1017 0.6873 +vt 0.1017 0.6638 +vt 0.1095 0.6638 +vt 0.1095 0.6716 +vt 0.1017 0.6716 +vt 0.1173 0.6638 +vt 0.1251 0.6638 +vt 0.1251 0.6717 +vt 0.1173 0.6716 +vt 0.0392 0.6794 +vt 0.0471 0.6794 +vt 0.0471 0.6872 +vt 0.0392 0.6872 +vt 0.0393 0.6638 +vt 0.0471 0.6638 +vt 0.0471 0.6716 +vt 0.0392 0.6716 +vt 0.0549 0.6638 +vt 0.0627 0.6638 +vt 0.0627 0.6716 +vt 0.0549 0.6716 +vt 0.0392 0.7419 +vt 0.0470 0.7419 +vt 0.0470 0.7497 +vt 0.0392 0.7497 +vt 0.0392 0.7263 +vt 0.0470 0.7263 +vt 0.0470 0.7341 +vt 0.0392 0.7341 +vt 0.0548 0.7263 +vt 0.0627 0.7263 +vt 0.0627 0.7341 +vt 0.0548 0.7341 +vt 0.1018 0.5545 +vt 0.1096 0.5545 +vt 0.1096 0.5623 +vt 0.1018 0.5623 +vt 0.1018 0.5389 +vt 0.1096 0.5389 +vt 0.1096 0.5467 +vt 0.1018 0.5467 +vt 0.1174 0.5389 +vt 0.1252 0.5389 +vt 0.1252 0.5467 +vt 0.1174 0.5467 +vt 0.0393 0.5545 +vt 0.0471 0.5545 +vt 0.0471 0.5623 +vt 0.0393 0.5623 +vt 0.0393 0.5389 +vt 0.0471 0.5389 +vt 0.0471 0.5467 +vt 0.0393 0.5467 +vt 0.0549 0.5389 +vt 0.0627 0.5389 +vt 0.0627 0.5467 +vt 0.0549 0.5467 +vt 0.0393 0.6170 +vt 0.0471 0.6170 +vt 0.0471 0.6248 +vt 0.0393 0.6248 +vt 0.0393 0.6013 +vt 0.0471 0.6014 +vt 0.0471 0.6092 +vt 0.0393 0.6092 +vt 0.0549 0.6014 +vt 0.0627 0.6014 +vt 0.0627 0.6092 +vt 0.0549 0.6092 +vt 0.2267 0.5546 +vt 0.2345 0.5546 +vt 0.2345 0.5624 +vt 0.2267 0.5624 +vt 0.2267 0.5389 +vt 0.2345 0.5389 +vt 0.2345 0.5468 +vt 0.2267 0.5468 +vt 0.2423 0.5389 +vt 0.2501 0.5389 +vt 0.2501 0.5468 +vt 0.2423 0.5468 +vt 0.1642 0.5545 +vt 0.1720 0.5545 +vt 0.1720 0.5623 +vt 0.1642 0.5623 +vt 0.1642 0.5389 +vt 0.1720 0.5389 +vt 0.1720 0.5467 +vt 0.1642 0.5467 +vt 0.1798 0.5389 +vt 0.1877 0.5389 +vt 0.1877 0.5467 +vt 0.1798 0.5467 +vt 0.1642 0.6170 +vt 0.1720 0.6170 +vt 0.1720 0.6248 +vt 0.1642 0.6248 +vt 0.1642 0.6014 +vt 0.1720 0.6014 +vt 0.1720 0.6092 +vt 0.1642 0.6092 +vt 0.1798 0.6014 +vt 0.1876 0.6014 +vt 0.1876 0.6092 +vt 0.1798 0.6092 +vt 0.1016 0.9293 +vt 0.1094 0.9293 +vt 0.1094 0.9371 +vt 0.1016 0.9371 +vt 0.1016 0.9137 +vt 0.1094 0.9137 +vt 0.1094 0.9215 +vt 0.1016 0.9215 +vt 0.1173 0.9137 +vt 0.1251 0.9137 +vt 0.1251 0.9215 +vt 0.1173 0.9215 +vt 0.0392 0.9293 +vt 0.0470 0.9293 +vt 0.0470 0.9371 +vt 0.0392 0.9371 +vt 0.0392 0.9137 +vt 0.0470 0.9137 +vt 0.0470 0.9215 +vt 0.0392 0.9215 +vt 0.0548 0.9137 +vt 0.0626 0.9137 +vt 0.0626 0.9215 +vt 0.0548 0.9215 +vt 0.0391 0.9918 +vt 0.0470 0.9918 +vt 0.0470 0.9996 +vt 0.0391 0.9996 +vt 0.0392 0.9762 +vt 0.0470 0.9762 +vt 0.0470 0.9840 +vt 0.0391 0.9840 +vt 0.0548 0.9762 +vt 0.0626 0.9762 +vt 0.0626 0.9840 +vt 0.0548 0.9840 +vt 0.1017 0.8044 +vt 0.1095 0.8044 +vt 0.1095 0.8122 +vt 0.1017 0.8122 +vt 0.1017 0.7888 +vt 0.1095 0.7888 +vt 0.1095 0.7966 +vt 0.1017 0.7966 +vt 0.1173 0.7888 +vt 0.1251 0.7888 +vt 0.1251 0.7966 +vt 0.1173 0.7966 +vt 0.0392 0.8044 +vt 0.0470 0.8044 +vt 0.0470 0.8122 +vt 0.0392 0.8122 +vt 0.0392 0.7888 +vt 0.0470 0.7888 +vt 0.0470 0.7966 +vt 0.0392 0.7966 +vt 0.0548 0.7888 +vt 0.0626 0.7888 +vt 0.0626 0.7966 +vt 0.0548 0.7966 +vt 0.0392 0.8668 +vt 0.0470 0.8668 +vt 0.0470 0.8746 +vt 0.0392 0.8746 +vt 0.0392 0.8512 +vt 0.0470 0.8512 +vt 0.0470 0.8590 +vt 0.0392 0.8590 +vt 0.0548 0.8512 +vt 0.0626 0.8512 +vt 0.0626 0.8590 +vt 0.0548 0.8590 +vt 0.2266 0.8044 +vt 0.2344 0.8044 +vt 0.2344 0.8122 +vt 0.2266 0.8122 +vt 0.2266 0.7888 +vt 0.2344 0.7888 +vt 0.2344 0.7966 +vt 0.2266 0.7966 +vt 0.2422 0.7888 +vt 0.2500 0.7888 +vt 0.2500 0.7966 +vt 0.2422 0.7966 +vt 0.1641 0.8044 +vt 0.1720 0.8044 +vt 0.1719 0.8122 +vt 0.1641 0.8122 +vt 0.1641 0.7888 +vt 0.1720 0.7888 +vt 0.1720 0.7966 +vt 0.1641 0.7966 +vt 0.1798 0.7888 +vt 0.1876 0.7888 +vt 0.1876 0.7966 +vt 0.1798 0.7966 +vt 0.1641 0.8669 +vt 0.1719 0.8669 +vt 0.1719 0.8747 +vt 0.1641 0.8747 +vt 0.1641 0.8513 +vt 0.1719 0.8513 +vt 0.1719 0.8591 +vt 0.1641 0.8591 +vt 0.1797 0.8513 +vt 0.1876 0.8513 +vt 0.1876 0.8591 +vt 0.1797 0.8591 +vt 0.3517 0.1798 +vt 0.3596 0.1798 +vt 0.3595 0.1876 +vt 0.3517 0.1876 +vt 0.3517 0.1642 +vt 0.3596 0.1642 +vt 0.3596 0.1720 +vt 0.3517 0.1720 +vt 0.3674 0.1642 +vt 0.3752 0.1642 +vt 0.3752 0.1720 +vt 0.3674 0.1720 +vt 0.2893 0.1798 +vt 0.2971 0.1798 +vt 0.2971 0.1876 +vt 0.2893 0.1876 +vt 0.2893 0.1642 +vt 0.2971 0.1642 +vt 0.2971 0.1720 +vt 0.2893 0.1720 +vt 0.3049 0.1642 +vt 0.3127 0.1642 +vt 0.3127 0.1720 +vt 0.3049 0.1720 +vt 0.2893 0.2422 +vt 0.2971 0.2422 +vt 0.2971 0.2501 +vt 0.2893 0.2501 +vt 0.2893 0.2266 +vt 0.2971 0.2266 +vt 0.2971 0.2344 +vt 0.2893 0.2344 +vt 0.3049 0.2266 +vt 0.3127 0.2266 +vt 0.3127 0.2344 +vt 0.3049 0.2344 +vt 0.3518 0.0549 +vt 0.3596 0.0549 +vt 0.3596 0.0627 +vt 0.3518 0.0627 +vt 0.3518 0.0392 +vt 0.3596 0.0393 +vt 0.3596 0.0471 +vt 0.3518 0.0471 +vt 0.3674 0.0393 +vt 0.3752 0.0393 +vt 0.3752 0.0471 +vt 0.3674 0.0471 +vt 0.2893 0.0548 +vt 0.2971 0.0548 +vt 0.2971 0.0627 +vt 0.2893 0.0627 +vt 0.2893 0.0392 +vt 0.2971 0.0392 +vt 0.2971 0.0470 +vt 0.2893 0.0470 +vt 0.3049 0.0392 +vt 0.3127 0.0392 +vt 0.3127 0.0470 +vt 0.3049 0.0470 +vt 0.2893 0.1173 +vt 0.2971 0.1173 +vt 0.2971 0.1251 +vt 0.2893 0.1251 +vt 0.2893 0.1017 +vt 0.2971 0.1017 +vt 0.2971 0.1095 +vt 0.2893 0.1095 +vt 0.3049 0.1017 +vt 0.3127 0.1017 +vt 0.3127 0.1095 +vt 0.3049 0.1095 +vt 0.4767 0.0549 +vt 0.4845 0.0549 +vt 0.4845 0.0627 +vt 0.4767 0.0627 +vt 0.4767 0.0393 +vt 0.4845 0.0393 +vt 0.4845 0.0471 +vt 0.4767 0.0471 +vt 0.4923 0.0393 +vt 0.5001 0.0393 +vt 0.5001 0.0471 +vt 0.4923 0.0471 +vt 0.4142 0.0549 +vt 0.4221 0.0549 +vt 0.4221 0.0627 +vt 0.4142 0.0627 +vt 0.4143 0.0393 +vt 0.4221 0.0393 +vt 0.4221 0.0471 +vt 0.4142 0.0471 +vt 0.4299 0.0393 +vt 0.4377 0.0393 +vt 0.4377 0.0471 +vt 0.4299 0.0471 +vt 0.4142 0.1173 +vt 0.4220 0.1174 +vt 0.4220 0.1252 +vt 0.4142 0.1252 +vt 0.4142 0.1017 +vt 0.4220 0.1017 +vt 0.4220 0.1095 +vt 0.4142 0.1095 +vt 0.4298 0.1017 +vt 0.4377 0.1017 +vt 0.4377 0.1095 +vt 0.4298 0.1095 +vt 0.1019 0.1797 +vt 0.1097 0.1797 +vt 0.1097 0.1875 +vt 0.1019 0.1875 +vt 0.1019 0.1641 +vt 0.1097 0.1641 +vt 0.1097 0.1719 +vt 0.1019 0.1719 +vt 0.1175 0.1641 +vt 0.1253 0.1641 +vt 0.1253 0.1719 +vt 0.1175 0.1719 +vt 0.0394 0.1797 +vt 0.0472 0.1797 +vt 0.0472 0.1875 +vt 0.0394 0.1875 +vt 0.0394 0.1641 +vt 0.0472 0.1641 +vt 0.0472 0.1719 +vt 0.0394 0.1719 +vt 0.0550 0.1641 +vt 0.0628 0.1641 +vt 0.0628 0.1719 +vt 0.0550 0.1719 +vt 0.0394 0.2422 +vt 0.0472 0.2422 +vt 0.0472 0.2500 +vt 0.0394 0.2500 +vt 0.0394 0.2265 +vt 0.0472 0.2266 +vt 0.0472 0.2344 +vt 0.0394 0.2344 +vt 0.0550 0.2266 +vt 0.0628 0.2266 +vt 0.0628 0.2344 +vt 0.0550 0.2344 +vt 0.1019 0.0548 +vt 0.1097 0.0548 +vt 0.1097 0.0626 +vt 0.1019 0.0626 +vt 0.1019 0.0392 +vt 0.1097 0.0392 +vt 0.1097 0.0470 +vt 0.1019 0.0470 +vt 0.1175 0.0392 +vt 0.1253 0.0392 +vt 0.1253 0.0470 +vt 0.1175 0.0470 +vt 0.0395 0.0548 +vt 0.0473 0.0548 +vt 0.0473 0.0626 +vt 0.0395 0.0626 +vt 0.0395 0.0392 +vt 0.0473 0.0392 +vt 0.0473 0.0470 +vt 0.0395 0.0470 +vt 0.0551 0.0392 +vt 0.0629 0.0392 +vt 0.0629 0.0470 +vt 0.0551 0.0470 +vt 0.0394 0.1172 +vt 0.0472 0.1172 +vt 0.0472 0.1250 +vt 0.0394 0.1250 +vt 0.0394 0.1016 +vt 0.0472 0.1016 +vt 0.0472 0.1094 +vt 0.0394 0.1094 +vt 0.0551 0.1016 +vt 0.0629 0.1016 +vt 0.0629 0.1094 +vt 0.0551 0.1094 +vt 0.2268 0.0548 +vt 0.2347 0.0548 +vt 0.2347 0.0626 +vt 0.2268 0.0626 +vt 0.2269 0.0392 +vt 0.2347 0.0392 +vt 0.2347 0.0470 +vt 0.2269 0.0470 +vt 0.2425 0.0392 +vt 0.2503 0.0392 +vt 0.2503 0.0470 +vt 0.2425 0.0470 +vt 0.1644 0.0548 +vt 0.1722 0.0548 +vt 0.1722 0.0626 +vt 0.1644 0.0626 +vt 0.1644 0.0392 +vt 0.1722 0.0392 +vt 0.1722 0.0470 +vt 0.1644 0.0470 +vt 0.1800 0.0392 +vt 0.1878 0.0392 +vt 0.1878 0.0470 +vt 0.1800 0.0470 +vt 0.1644 0.1173 +vt 0.1722 0.1173 +vt 0.1722 0.1251 +vt 0.1644 0.1251 +vt 0.1644 0.1017 +vt 0.1722 0.1017 +vt 0.1722 0.1095 +vt 0.1644 0.1095 +vt 0.1800 0.1017 +vt 0.1878 0.1017 +vt 0.1878 0.1095 +vt 0.1800 0.1095 +vt 0.1018 0.4296 +vt 0.1096 0.4296 +vt 0.1096 0.4374 +vt 0.1018 0.4374 +vt 0.1018 0.4140 +vt 0.1096 0.4140 +vt 0.1096 0.4218 +vt 0.1018 0.4218 +vt 0.1174 0.4140 +vt 0.1252 0.4140 +vt 0.1252 0.4218 +vt 0.1174 0.4218 +vt 0.0393 0.4296 +vt 0.0471 0.4296 +vt 0.0471 0.4374 +vt 0.0393 0.4374 +vt 0.0393 0.4139 +vt 0.0471 0.4139 +vt 0.0471 0.4218 +vt 0.0393 0.4218 +vt 0.0550 0.4140 +vt 0.0628 0.4140 +vt 0.0628 0.4218 +vt 0.0549 0.4218 +vt 0.0393 0.4920 +vt 0.0471 0.4920 +vt 0.0471 0.4998 +vt 0.0393 0.4998 +vt 0.0393 0.4764 +vt 0.0471 0.4764 +vt 0.0471 0.4842 +vt 0.0393 0.4842 +vt 0.0549 0.4764 +vt 0.0627 0.4764 +vt 0.0627 0.4842 +vt 0.0549 0.4842 +vt 0.1018 0.3047 +vt 0.1096 0.3047 +vt 0.1096 0.3125 +vt 0.1018 0.3125 +vt 0.1018 0.2890 +vt 0.1097 0.2890 +vt 0.1096 0.2968 +vt 0.1018 0.2968 +vt 0.1175 0.2890 +vt 0.1253 0.2890 +vt 0.1253 0.2969 +vt 0.1175 0.2968 +vt 0.0394 0.3046 +vt 0.0472 0.3046 +vt 0.0472 0.3124 +vt 0.0394 0.3124 +vt 0.0394 0.2890 +vt 0.0472 0.2890 +vt 0.0472 0.2968 +vt 0.0394 0.2968 +vt 0.0550 0.2890 +vt 0.0628 0.2890 +vt 0.0628 0.2968 +vt 0.0550 0.2968 +vt 0.0394 0.3671 +vt 0.0472 0.3671 +vt 0.0472 0.3749 +vt 0.0393 0.3749 +vt 0.0394 0.3515 +vt 0.0472 0.3515 +vt 0.0472 0.3593 +vt 0.0394 0.3593 +vt 0.0550 0.3515 +vt 0.0628 0.3515 +vt 0.0628 0.3593 +vt 0.0550 0.3593 +vt 0.2268 0.3047 +vt 0.2346 0.3047 +vt 0.2346 0.3125 +vt 0.2268 0.3125 +vt 0.2268 0.2891 +vt 0.2346 0.2891 +vt 0.2346 0.2969 +vt 0.2268 0.2969 +vt 0.2424 0.2891 +vt 0.2502 0.2891 +vt 0.2502 0.2969 +vt 0.2424 0.2969 +vt 0.1643 0.3047 +vt 0.1721 0.3047 +vt 0.1721 0.3125 +vt 0.1643 0.3125 +vt 0.1643 0.2891 +vt 0.1721 0.2891 +vt 0.1721 0.2969 +vt 0.1643 0.2969 +vt 0.1799 0.2891 +vt 0.1877 0.2891 +vt 0.1877 0.2969 +vt 0.1799 0.2969 +vt 0.1643 0.3671 +vt 0.1721 0.3671 +vt 0.1721 0.3749 +vt 0.1643 0.3749 +vt 0.1643 0.3515 +vt 0.1721 0.3515 +vt 0.1721 0.3593 +vt 0.1643 0.3593 +vt 0.1799 0.3515 +vt 0.1877 0.3515 +vt 0.1877 0.3593 +vt 0.1799 0.3593 +vt 0.8515 0.1800 +vt 0.8593 0.1800 +vt 0.8593 0.1878 +vt 0.8515 0.1878 +vt 0.8515 0.1643 +vt 0.8593 0.1643 +vt 0.8593 0.1721 +vt 0.8515 0.1721 +vt 0.8671 0.1643 +vt 0.8749 0.1643 +vt 0.8749 0.1721 +vt 0.8671 0.1721 +vt 0.7890 0.1799 +vt 0.7968 0.1799 +vt 0.7968 0.1877 +vt 0.7890 0.1877 +vt 0.7890 0.1643 +vt 0.7968 0.1643 +vt 0.7968 0.1721 +vt 0.7890 0.1721 +vt 0.8046 0.1643 +vt 0.8124 0.1643 +vt 0.8124 0.1721 +vt 0.8046 0.1721 +vt 0.7890 0.2424 +vt 0.7968 0.2424 +vt 0.7968 0.2502 +vt 0.7890 0.2502 +vt 0.7890 0.2268 +vt 0.7968 0.2268 +vt 0.7968 0.2346 +vt 0.7890 0.2346 +vt 0.8046 0.2268 +vt 0.8124 0.2268 +vt 0.8124 0.2346 +vt 0.8046 0.2346 +vt 0.8515 0.0550 +vt 0.8593 0.0550 +vt 0.8593 0.0628 +vt 0.8515 0.0628 +vt 0.8515 0.0394 +vt 0.8593 0.0394 +vt 0.8593 0.0472 +vt 0.8515 0.0472 +vt 0.8671 0.0394 +vt 0.8750 0.0394 +vt 0.8749 0.0472 +vt 0.8671 0.0472 +vt 0.7891 0.0550 +vt 0.7969 0.0550 +vt 0.7969 0.0628 +vt 0.7890 0.0628 +vt 0.7891 0.0394 +vt 0.7969 0.0394 +vt 0.7969 0.0472 +vt 0.7891 0.0472 +vt 0.8047 0.0394 +vt 0.8125 0.0394 +vt 0.8125 0.0472 +vt 0.8047 0.0472 +vt 0.7890 0.1175 +vt 0.7968 0.1175 +vt 0.7968 0.1253 +vt 0.7890 0.1253 +vt 0.7890 0.1018 +vt 0.7968 0.1018 +vt 0.7968 0.1097 +vt 0.7890 0.1097 +vt 0.8047 0.1019 +vt 0.8125 0.1019 +vt 0.8125 0.1097 +vt 0.8047 0.1097 +vt 0.9765 0.0551 +vt 0.9843 0.0551 +vt 0.9843 0.0629 +vt 0.9765 0.0629 +vt 0.9765 0.0394 +vt 0.9843 0.0394 +vt 0.9843 0.0472 +vt 0.9765 0.0472 +vt 0.9921 0.0394 +vt 0.9999 0.0394 +vt 0.9999 0.0473 +vt 0.9921 0.0472 +vt 0.9140 0.0550 +vt 0.9218 0.0550 +vt 0.9218 0.0628 +vt 0.9140 0.0628 +vt 0.9140 0.0394 +vt 0.9218 0.0394 +vt 0.9218 0.0472 +vt 0.9140 0.0472 +vt 0.9296 0.0394 +vt 0.9374 0.0394 +vt 0.9374 0.0472 +vt 0.9296 0.0472 +vt 0.9140 0.1175 +vt 0.9218 0.1175 +vt 0.9218 0.1253 +vt 0.9140 0.1253 +vt 0.9140 0.1019 +vt 0.9218 0.1019 +vt 0.9218 0.1097 +vt 0.9140 0.1097 +vt 0.9296 0.1019 +vt 0.9374 0.1019 +vt 0.9374 0.1097 +vt 0.9296 0.1097 +vt 0.6016 0.1799 +vt 0.6094 0.1799 +vt 0.6094 0.1877 +vt 0.6016 0.1877 +vt 0.6016 0.1643 +vt 0.6094 0.1643 +vt 0.6094 0.1721 +vt 0.6016 0.1721 +vt 0.6172 0.1643 +vt 0.6250 0.1643 +vt 0.6250 0.1721 +vt 0.6172 0.1721 +vt 0.5391 0.1799 +vt 0.5470 0.1799 +vt 0.5469 0.1877 +vt 0.5391 0.1877 +vt 0.5391 0.1642 +vt 0.5470 0.1642 +vt 0.5470 0.1720 +vt 0.5391 0.1720 +vt 0.5548 0.1642 +vt 0.5626 0.1642 +vt 0.5626 0.1721 +vt 0.5548 0.1721 +vt 0.5391 0.2423 +vt 0.5469 0.2423 +vt 0.5469 0.2501 +vt 0.5391 0.2501 +vt 0.5391 0.2267 +vt 0.5469 0.2267 +vt 0.5469 0.2345 +vt 0.5391 0.2345 +vt 0.5547 0.2267 +vt 0.5626 0.2267 +vt 0.5626 0.2345 +vt 0.5547 0.2345 +vt 0.6016 0.0549 +vt 0.6095 0.0549 +vt 0.6095 0.0627 +vt 0.6016 0.0627 +vt 0.6017 0.0393 +vt 0.6095 0.0393 +vt 0.6095 0.0471 +vt 0.6017 0.0471 +vt 0.6173 0.0393 +vt 0.6251 0.0393 +vt 0.6251 0.0471 +vt 0.6173 0.0471 +vt 0.5392 0.0549 +vt 0.5470 0.0549 +vt 0.5470 0.0627 +vt 0.5392 0.0627 +vt 0.5392 0.0393 +vt 0.5470 0.0393 +vt 0.5470 0.0471 +vt 0.5392 0.0471 +vt 0.5548 0.0393 +vt 0.5626 0.0393 +vt 0.5626 0.0471 +vt 0.5548 0.0471 +vt 0.5392 0.1174 +vt 0.5470 0.1174 +vt 0.5470 0.1252 +vt 0.5392 0.1252 +vt 0.5392 0.1018 +vt 0.5470 0.1018 +vt 0.5470 0.1096 +vt 0.5392 0.1096 +vt 0.5548 0.1018 +vt 0.5626 0.1018 +vt 0.5626 0.1096 +vt 0.5548 0.1096 +vt 0.7266 0.0550 +vt 0.7344 0.0550 +vt 0.7344 0.0628 +vt 0.7266 0.0628 +vt 0.7266 0.0394 +vt 0.7344 0.0394 +vt 0.7344 0.0472 +vt 0.7266 0.0472 +vt 0.7422 0.0394 +vt 0.7500 0.0394 +vt 0.7500 0.0472 +vt 0.7422 0.0472 +vt 0.6641 0.0550 +vt 0.6719 0.0550 +vt 0.6719 0.0628 +vt 0.6641 0.0628 +vt 0.6641 0.0393 +vt 0.6719 0.0393 +vt 0.6719 0.0472 +vt 0.6641 0.0471 +vt 0.6797 0.0393 +vt 0.6875 0.0393 +vt 0.6875 0.0472 +vt 0.6797 0.0472 +vt 0.6641 0.1174 +vt 0.6719 0.1174 +vt 0.6719 0.1252 +vt 0.6641 0.1252 +vt 0.6641 0.1018 +vt 0.6719 0.1018 +vt 0.6719 0.1096 +vt 0.6641 0.1096 +vt 0.6797 0.1018 +vt 0.6875 0.1018 +vt 0.6875 0.1096 +vt 0.6797 0.1096 +vt 0.6015 0.4297 +vt 0.6093 0.4297 +vt 0.6093 0.4376 +vt 0.6015 0.4376 +vt 0.6015 0.4141 +vt 0.6093 0.4141 +vt 0.6093 0.4219 +vt 0.6015 0.4219 +vt 0.6172 0.4141 +vt 0.6250 0.4141 +vt 0.6250 0.4219 +vt 0.6172 0.4219 +vt 0.5391 0.4297 +vt 0.5469 0.4297 +vt 0.5469 0.4375 +vt 0.5391 0.4375 +vt 0.5391 0.4141 +vt 0.5469 0.4141 +vt 0.5469 0.4219 +vt 0.5391 0.4219 +vt 0.5547 0.4141 +vt 0.5625 0.4141 +vt 0.5625 0.4219 +vt 0.5547 0.4219 +vt 0.5390 0.4922 +vt 0.5469 0.4922 +vt 0.5469 0.5000 +vt 0.5390 0.5000 +vt 0.5391 0.4766 +vt 0.5469 0.4766 +vt 0.5469 0.4844 +vt 0.5390 0.4844 +vt 0.5547 0.4766 +vt 0.5625 0.4766 +vt 0.5625 0.4844 +vt 0.5547 0.4844 +vt 0.6016 0.3048 +vt 0.6094 0.3048 +vt 0.6094 0.3126 +vt 0.6016 0.3126 +vt 0.6016 0.2892 +vt 0.6094 0.2892 +vt 0.6094 0.2970 +vt 0.6016 0.2970 +vt 0.6172 0.2892 +vt 0.6250 0.2892 +vt 0.6250 0.2970 +vt 0.6172 0.2970 +vt 0.5391 0.3048 +vt 0.5469 0.3048 +vt 0.5469 0.3126 +vt 0.5391 0.3126 +vt 0.5391 0.2892 +vt 0.5469 0.2892 +vt 0.5469 0.2970 +vt 0.5391 0.2970 +vt 0.5547 0.2892 +vt 0.5625 0.2892 +vt 0.5625 0.2970 +vt 0.5547 0.2970 +vt 0.5391 0.3673 +vt 0.5469 0.3673 +vt 0.5469 0.3751 +vt 0.5391 0.3751 +vt 0.5391 0.3516 +vt 0.5469 0.3516 +vt 0.5469 0.3594 +vt 0.5391 0.3594 +vt 0.5547 0.3516 +vt 0.5625 0.3516 +vt 0.5625 0.3595 +vt 0.5547 0.3595 +vt 0.7265 0.3048 +vt 0.7343 0.3048 +vt 0.7343 0.3127 +vt 0.7265 0.3127 +vt 0.7265 0.2892 +vt 0.7343 0.2892 +vt 0.7343 0.2970 +vt 0.7265 0.2970 +vt 0.7421 0.2892 +vt 0.7499 0.2892 +vt 0.7499 0.2970 +vt 0.7421 0.2970 +vt 0.6640 0.3048 +vt 0.6718 0.3048 +vt 0.6718 0.3126 +vt 0.6640 0.3126 +vt 0.6640 0.2892 +vt 0.6719 0.2892 +vt 0.6718 0.2970 +vt 0.6640 0.2970 +vt 0.6797 0.2892 +vt 0.6875 0.2892 +vt 0.6875 0.2970 +vt 0.6797 0.2970 +vt 0.6640 0.3673 +vt 0.6718 0.3673 +vt 0.6718 0.3751 +vt 0.6640 0.3751 +vt 0.6640 0.3517 +vt 0.6718 0.3517 +vt 0.6718 0.3595 +vt 0.6640 0.3595 +vt 0.6796 0.3517 +vt 0.6874 0.3517 +vt 0.6874 0.3595 +vt 0.6796 0.3595 +vt 0.8514 0.4298 +vt 0.8592 0.4298 +vt 0.8592 0.4376 +vt 0.8514 0.4376 +vt 0.8514 0.4142 +vt 0.8592 0.4142 +vt 0.8592 0.4220 +vt 0.8514 0.4220 +vt 0.8670 0.4142 +vt 0.8748 0.4142 +vt 0.8748 0.4220 +vt 0.8670 0.4220 +vt 0.7889 0.4298 +vt 0.7967 0.4298 +vt 0.7967 0.4376 +vt 0.7889 0.4376 +vt 0.7889 0.4142 +vt 0.7967 0.4142 +vt 0.7967 0.4220 +vt 0.7889 0.4220 +vt 0.8046 0.4142 +vt 0.8124 0.4142 +vt 0.8124 0.4220 +vt 0.8046 0.4220 +vt 0.7889 0.4923 +vt 0.7967 0.4923 +vt 0.7967 0.5001 +vt 0.7889 0.5001 +vt 0.7889 0.4767 +vt 0.7967 0.4767 +vt 0.7967 0.4845 +vt 0.7889 0.4845 +vt 0.8045 0.4767 +vt 0.8123 0.4767 +vt 0.8123 0.4845 +vt 0.8045 0.4845 +vt 0.8514 0.3049 +vt 0.8592 0.3049 +vt 0.8592 0.3127 +vt 0.8514 0.3127 +vt 0.8514 0.2893 +vt 0.8593 0.2893 +vt 0.8593 0.2971 +vt 0.8514 0.2971 +vt 0.8671 0.2893 +vt 0.8749 0.2893 +vt 0.8749 0.2971 +vt 0.8671 0.2971 +vt 0.7890 0.3049 +vt 0.7968 0.3049 +vt 0.7968 0.3127 +vt 0.7890 0.3127 +vt 0.7890 0.2892 +vt 0.7968 0.2893 +vt 0.7968 0.2971 +vt 0.7890 0.2971 +vt 0.8046 0.2893 +vt 0.8124 0.2893 +vt 0.8124 0.2971 +vt 0.8046 0.2971 +vt 0.7890 0.3673 +vt 0.7968 0.3673 +vt 0.7968 0.3751 +vt 0.7890 0.3751 +vt 0.7890 0.3517 +vt 0.7968 0.3517 +vt 0.7968 0.3595 +vt 0.7890 0.3595 +vt 0.8046 0.3517 +vt 0.8124 0.3517 +vt 0.8124 0.3595 +vt 0.8046 0.3595 +vt 0.9764 0.3049 +vt 0.9842 0.3049 +vt 0.9842 0.3127 +vt 0.9764 0.3127 +vt 0.9764 0.2893 +vt 0.9842 0.2893 +vt 0.9842 0.2971 +vt 0.9764 0.2971 +vt 0.9920 0.2893 +vt 0.9998 0.2893 +vt 0.9998 0.2971 +vt 0.9920 0.2971 +vt 0.9139 0.3049 +vt 0.9217 0.3049 +vt 0.9217 0.3127 +vt 0.9139 0.3127 +vt 0.9139 0.2893 +vt 0.9217 0.2893 +vt 0.9217 0.2971 +vt 0.9139 0.2971 +vt 0.9295 0.2893 +vt 0.9373 0.2893 +vt 0.9373 0.2971 +vt 0.9295 0.2971 +vt 0.9139 0.3674 +vt 0.9217 0.3674 +vt 0.9217 0.3752 +vt 0.9139 0.3752 +vt 0.9139 0.3518 +vt 0.9217 0.3518 +vt 0.9217 0.3596 +vt 0.9139 0.3596 +vt 0.9295 0.3518 +vt 0.9373 0.3518 +vt 0.9373 0.3596 +vt 0.9295 0.3596 +vt 0.3517 0.4297 +vt 0.3595 0.4297 +vt 0.3595 0.4375 +vt 0.3517 0.4375 +vt 0.3517 0.4140 +vt 0.3595 0.4140 +vt 0.3595 0.4219 +vt 0.3517 0.4219 +vt 0.3673 0.4141 +vt 0.3751 0.4141 +vt 0.3751 0.4219 +vt 0.3673 0.4219 +vt 0.2892 0.4296 +vt 0.2970 0.4296 +vt 0.2970 0.4375 +vt 0.2892 0.4375 +vt 0.2892 0.4140 +vt 0.2970 0.4140 +vt 0.2970 0.4218 +vt 0.2892 0.4218 +vt 0.3048 0.4140 +vt 0.3126 0.4140 +vt 0.3126 0.4218 +vt 0.3048 0.4218 +vt 0.2892 0.4921 +vt 0.2970 0.4921 +vt 0.2970 0.4999 +vt 0.2892 0.4999 +vt 0.2892 0.4765 +vt 0.2970 0.4765 +vt 0.2970 0.4843 +vt 0.2892 0.4843 +vt 0.3048 0.4765 +vt 0.3126 0.4765 +vt 0.3126 0.4843 +vt 0.3048 0.4843 +vt 0.3517 0.3047 +vt 0.3595 0.3047 +vt 0.3595 0.3125 +vt 0.3517 0.3125 +vt 0.3517 0.2891 +vt 0.3595 0.2891 +vt 0.3595 0.2969 +vt 0.3517 0.2969 +vt 0.3673 0.2891 +vt 0.3751 0.2891 +vt 0.3751 0.2969 +vt 0.3673 0.2969 +vt 0.2892 0.3047 +vt 0.2970 0.3047 +vt 0.2970 0.3125 +vt 0.2892 0.3125 +vt 0.2892 0.2891 +vt 0.2971 0.2891 +vt 0.2970 0.2969 +vt 0.2892 0.2969 +vt 0.3049 0.2891 +vt 0.3127 0.2891 +vt 0.3127 0.2969 +vt 0.3049 0.2969 +vt 0.2892 0.3672 +vt 0.2970 0.3672 +vt 0.2970 0.3750 +vt 0.2892 0.3750 +vt 0.2892 0.3516 +vt 0.2970 0.3516 +vt 0.2970 0.3594 +vt 0.2892 0.3594 +vt 0.3048 0.3516 +vt 0.3126 0.3516 +vt 0.3126 0.3594 +vt 0.3048 0.3594 +vt 0.4766 0.3048 +vt 0.4844 0.3048 +vt 0.4844 0.3126 +vt 0.4766 0.3126 +vt 0.4766 0.2892 +vt 0.4845 0.2892 +vt 0.4844 0.2970 +vt 0.4766 0.2970 +vt 0.4923 0.2892 +vt 0.5001 0.2892 +vt 0.5001 0.2970 +vt 0.4923 0.2970 +vt 0.4142 0.3047 +vt 0.4220 0.3048 +vt 0.4220 0.3126 +vt 0.4142 0.3126 +vt 0.4142 0.2891 +vt 0.4220 0.2891 +vt 0.4220 0.2969 +vt 0.4142 0.2969 +vt 0.4298 0.2891 +vt 0.4376 0.2891 +vt 0.4376 0.2969 +vt 0.4298 0.2969 +vt 0.4142 0.3672 +vt 0.4220 0.3672 +vt 0.4220 0.3750 +vt 0.4141 0.3750 +vt 0.4142 0.3516 +vt 0.4220 0.3516 +vt 0.4220 0.3594 +vt 0.4142 0.3594 +vt 0.4298 0.3516 +vt 0.4376 0.3516 +vt 0.4376 0.3594 +vt 0.4298 0.3594 +vt 0.3515 0.9294 +vt 0.3593 0.9294 +vt 0.3593 0.9372 +vt 0.3515 0.9372 +vt 0.3515 0.9138 +vt 0.3593 0.9138 +vt 0.3593 0.9216 +vt 0.3515 0.9216 +vt 0.3671 0.9138 +vt 0.3749 0.9138 +vt 0.3749 0.9216 +vt 0.3671 0.9216 +vt 0.2890 0.9294 +vt 0.2968 0.9294 +vt 0.2968 0.9372 +vt 0.2890 0.9372 +vt 0.2890 0.9138 +vt 0.2969 0.9138 +vt 0.2969 0.9216 +vt 0.2890 0.9216 +vt 0.3047 0.9138 +vt 0.3125 0.9138 +vt 0.3125 0.9216 +vt 0.3047 0.9216 +vt 0.2890 0.9919 +vt 0.2968 0.9919 +vt 0.2968 0.9997 +vt 0.2890 0.9997 +vt 0.2890 0.9762 +vt 0.2968 0.9762 +vt 0.2968 0.9840 +vt 0.2890 0.9840 +vt 0.3046 0.9762 +vt 0.3125 0.9762 +vt 0.3124 0.9841 +vt 0.3046 0.9840 +vt 0.3515 0.8045 +vt 0.3594 0.8045 +vt 0.3594 0.8123 +vt 0.3515 0.8123 +vt 0.3516 0.7889 +vt 0.3594 0.7889 +vt 0.3594 0.7967 +vt 0.3515 0.7967 +vt 0.3672 0.7889 +vt 0.3750 0.7889 +vt 0.3750 0.7967 +vt 0.3672 0.7967 +vt 0.2891 0.8044 +vt 0.2969 0.8045 +vt 0.2969 0.8123 +vt 0.2891 0.8123 +vt 0.2891 0.7888 +vt 0.2969 0.7888 +vt 0.2969 0.7966 +vt 0.2891 0.7966 +vt 0.3047 0.7888 +vt 0.3125 0.7888 +vt 0.3125 0.7966 +vt 0.3047 0.7966 +vt 0.2891 0.8669 +vt 0.2969 0.8669 +vt 0.2969 0.8747 +vt 0.2891 0.8747 +vt 0.2891 0.8513 +vt 0.2969 0.8513 +vt 0.2969 0.8591 +vt 0.2891 0.8591 +vt 0.3047 0.8513 +vt 0.3125 0.8513 +vt 0.3125 0.8591 +vt 0.3047 0.8591 +vt 0.4765 0.8045 +vt 0.4843 0.8045 +vt 0.4843 0.8123 +vt 0.4765 0.8123 +vt 0.4765 0.7889 +vt 0.4843 0.7889 +vt 0.4843 0.7967 +vt 0.4765 0.7967 +vt 0.4921 0.7889 +vt 0.4999 0.7889 +vt 0.4999 0.7967 +vt 0.4921 0.7967 +vt 0.4140 0.8045 +vt 0.4218 0.8045 +vt 0.4218 0.8123 +vt 0.4140 0.8123 +vt 0.4140 0.7889 +vt 0.4218 0.7889 +vt 0.4218 0.7967 +vt 0.4140 0.7967 +vt 0.4296 0.7889 +vt 0.4374 0.7889 +vt 0.4374 0.7967 +vt 0.4296 0.7967 +vt 0.4140 0.8670 +vt 0.4218 0.8670 +vt 0.4218 0.8748 +vt 0.4140 0.8748 +vt 0.4140 0.8513 +vt 0.4218 0.8513 +vt 0.4218 0.8591 +vt 0.4140 0.8591 +vt 0.4296 0.8513 +vt 0.4374 0.8513 +vt 0.4374 0.8592 +vt 0.4296 0.8592 +vt 0.8512 0.9296 +vt 0.8591 0.9296 +vt 0.8590 0.9374 +vt 0.8512 0.9374 +vt 0.8512 0.9139 +vt 0.8591 0.9139 +vt 0.8591 0.9217 +vt 0.8512 0.9217 +vt 0.8669 0.9139 +vt 0.8747 0.9139 +vt 0.8747 0.9218 +vt 0.8669 0.9217 +vt 0.7888 0.9295 +vt 0.7966 0.9295 +vt 0.7966 0.9373 +vt 0.7888 0.9373 +vt 0.7888 0.9139 +vt 0.7966 0.9139 +vt 0.7966 0.9217 +vt 0.7888 0.9217 +vt 0.8044 0.9139 +vt 0.8122 0.9139 +vt 0.8122 0.9217 +vt 0.8044 0.9217 +vt 0.7888 0.9920 +vt 0.7966 0.9920 +vt 0.7966 0.9998 +vt 0.7888 0.9998 +vt 0.7888 0.9764 +vt 0.7966 0.9764 +vt 0.7966 0.9842 +vt 0.7888 0.9842 +vt 0.8044 0.9764 +vt 0.8122 0.9764 +vt 0.8122 0.9842 +vt 0.8044 0.9842 +vt 0.8513 0.8046 +vt 0.8591 0.8046 +vt 0.8591 0.8124 +vt 0.8513 0.8124 +vt 0.8513 0.7890 +vt 0.8591 0.7890 +vt 0.8591 0.7968 +vt 0.8513 0.7968 +vt 0.8669 0.7890 +vt 0.8747 0.7890 +vt 0.8747 0.7968 +vt 0.8669 0.7968 +vt 0.7888 0.8046 +vt 0.7966 0.8046 +vt 0.7966 0.8124 +vt 0.7888 0.8124 +vt 0.7888 0.7890 +vt 0.7966 0.7890 +vt 0.7966 0.7968 +vt 0.7888 0.7968 +vt 0.8044 0.7890 +vt 0.8122 0.7890 +vt 0.8122 0.7968 +vt 0.8044 0.7968 +vt 0.7888 0.8671 +vt 0.7966 0.8671 +vt 0.7966 0.8749 +vt 0.7888 0.8749 +vt 0.7888 0.8515 +vt 0.7966 0.8515 +vt 0.7966 0.8593 +vt 0.7888 0.8593 +vt 0.8044 0.8515 +vt 0.8122 0.8515 +vt 0.8122 0.8593 +vt 0.8044 0.8593 +vt 0.9762 0.8047 +vt 0.9840 0.8047 +vt 0.9840 0.8125 +vt 0.9762 0.8125 +vt 0.9762 0.7890 +vt 0.9840 0.7890 +vt 0.9840 0.7969 +vt 0.9762 0.7969 +vt 0.9918 0.7890 +vt 0.9996 0.7891 +vt 0.9996 0.7969 +vt 0.9918 0.7969 +vt 0.9137 0.8046 +vt 0.9216 0.8046 +vt 0.9216 0.8125 +vt 0.9137 0.8124 +vt 0.9138 0.7890 +vt 0.9216 0.7890 +vt 0.9216 0.7968 +vt 0.9138 0.7968 +vt 0.9294 0.7890 +vt 0.9372 0.7890 +vt 0.9372 0.7968 +vt 0.9294 0.7968 +vt 0.9137 0.8671 +vt 0.9215 0.8671 +vt 0.9215 0.8749 +vt 0.9137 0.8749 +vt 0.9137 0.8515 +vt 0.9215 0.8515 +vt 0.9215 0.8593 +vt 0.9137 0.8593 +vt 0.9293 0.8515 +vt 0.9372 0.8515 +vt 0.9372 0.8593 +vt 0.9293 0.8593 +vt 0.9762 0.8671 +vt 0.9840 0.8671 +vt 0.9840 0.8749 +vt 0.9762 0.8749 +vt 0.9762 0.8515 +vt 0.9840 0.8515 +vt 0.9840 0.8593 +vt 0.9762 0.8593 +vt 0.9918 0.8515 +vt 0.9996 0.8515 +vt 0.9996 0.8593 +vt 0.9918 0.8593 +vt 0.8513 0.8671 +vt 0.8591 0.8671 +vt 0.8591 0.8749 +vt 0.8513 0.8749 +vt 0.8513 0.8515 +vt 0.8591 0.8515 +vt 0.8591 0.8593 +vt 0.8513 0.8593 +vt 0.8669 0.8515 +vt 0.8747 0.8515 +vt 0.8747 0.8593 +vt 0.8669 0.8593 +vt 0.8512 0.9920 +vt 0.8590 0.9920 +vt 0.8590 0.9998 +vt 0.8512 0.9998 +vt 0.8512 0.9764 +vt 0.8590 0.9764 +vt 0.8590 0.9842 +vt 0.8512 0.9842 +vt 0.8668 0.9764 +vt 0.8747 0.9764 +vt 0.8747 0.9842 +vt 0.8668 0.9842 +vt 0.4765 0.8670 +vt 0.4843 0.8670 +vt 0.4843 0.8748 +vt 0.4765 0.8748 +vt 0.4765 0.8514 +vt 0.4843 0.8514 +vt 0.4843 0.8592 +vt 0.4765 0.8592 +vt 0.4921 0.8514 +vt 0.4999 0.8514 +vt 0.4999 0.8592 +vt 0.4921 0.8592 +vt 0.3515 0.8669 +vt 0.3593 0.8669 +vt 0.3593 0.8747 +vt 0.3515 0.8747 +vt 0.3515 0.8513 +vt 0.3593 0.8513 +vt 0.3593 0.8591 +vt 0.3515 0.8591 +vt 0.3671 0.8513 +vt 0.3750 0.8513 +vt 0.3750 0.8591 +vt 0.3671 0.8591 +vt 0.3515 0.9919 +vt 0.3593 0.9919 +vt 0.3593 0.9997 +vt 0.3515 0.9997 +vt 0.3515 0.9763 +vt 0.3593 0.9763 +vt 0.3593 0.9841 +vt 0.3515 0.9841 +vt 0.3671 0.9763 +vt 0.3749 0.9763 +vt 0.3749 0.9841 +vt 0.3671 0.9841 +vt 0.4766 0.3672 +vt 0.4844 0.3672 +vt 0.4844 0.3750 +vt 0.4766 0.3750 +vt 0.4766 0.3516 +vt 0.4844 0.3516 +vt 0.4844 0.3594 +vt 0.4766 0.3594 +vt 0.4922 0.3516 +vt 0.5000 0.3516 +vt 0.5000 0.3594 +vt 0.4922 0.3594 +vt 0.3517 0.3672 +vt 0.3595 0.3672 +vt 0.3595 0.3750 +vt 0.3517 0.3750 +vt 0.3517 0.3516 +vt 0.3595 0.3516 +vt 0.3595 0.3594 +vt 0.3517 0.3594 +vt 0.3673 0.3516 +vt 0.3751 0.3516 +vt 0.3751 0.3594 +vt 0.3673 0.3594 +vt 0.3516 0.4921 +vt 0.3595 0.4921 +vt 0.3595 0.4999 +vt 0.3516 0.4999 +vt 0.3516 0.4765 +vt 0.3595 0.4765 +vt 0.3595 0.4843 +vt 0.3516 0.4843 +vt 0.3673 0.4765 +vt 0.3751 0.4765 +vt 0.3751 0.4843 +vt 0.3673 0.4843 +vt 0.9764 0.3674 +vt 0.9842 0.3674 +vt 0.9842 0.3752 +vt 0.9764 0.3752 +vt 0.9764 0.3518 +vt 0.9842 0.3518 +vt 0.9842 0.3596 +vt 0.9764 0.3596 +vt 0.9920 0.3518 +vt 0.9998 0.3518 +vt 0.9998 0.3596 +vt 0.9920 0.3596 +vt 0.8514 0.3674 +vt 0.8592 0.3674 +vt 0.8592 0.3752 +vt 0.8514 0.3752 +vt 0.8514 0.3517 +vt 0.8592 0.3517 +vt 0.8592 0.3595 +vt 0.8514 0.3595 +vt 0.8670 0.3517 +vt 0.8749 0.3517 +vt 0.8748 0.3596 +vt 0.8670 0.3596 +vt 0.8514 0.4923 +vt 0.8592 0.4923 +vt 0.8592 0.5001 +vt 0.8514 0.5001 +vt 0.8514 0.4767 +vt 0.8592 0.4767 +vt 0.8592 0.4845 +vt 0.8514 0.4845 +vt 0.8670 0.4767 +vt 0.8748 0.4767 +vt 0.8748 0.4845 +vt 0.8670 0.4845 +vt 0.7265 0.3673 +vt 0.7343 0.3673 +vt 0.7343 0.3751 +vt 0.7265 0.3751 +vt 0.7265 0.3517 +vt 0.7343 0.3517 +vt 0.7343 0.3595 +vt 0.7265 0.3595 +vt 0.7421 0.3517 +vt 0.7499 0.3517 +vt 0.7499 0.3595 +vt 0.7421 0.3595 +vt 0.6016 0.3673 +vt 0.6094 0.3673 +vt 0.6094 0.3751 +vt 0.6015 0.3751 +vt 0.6016 0.3517 +vt 0.6094 0.3517 +vt 0.6094 0.3595 +vt 0.6016 0.3595 +vt 0.6172 0.3517 +vt 0.6250 0.3517 +vt 0.6250 0.3595 +vt 0.6172 0.3595 +vt 0.6015 0.4922 +vt 0.6093 0.4922 +vt 0.6093 0.5000 +vt 0.6015 0.5000 +vt 0.6015 0.4766 +vt 0.6093 0.4766 +vt 0.6093 0.4844 +vt 0.6015 0.4844 +vt 0.6171 0.4766 +vt 0.6249 0.4766 +vt 0.6249 0.4844 +vt 0.6171 0.4844 +vt 0.7266 0.1174 +vt 0.7344 0.1174 +vt 0.7344 0.1253 +vt 0.7266 0.1253 +vt 0.7266 0.1018 +vt 0.7344 0.1018 +vt 0.7344 0.1096 +vt 0.7266 0.1096 +vt 0.7422 0.1018 +vt 0.7500 0.1018 +vt 0.7500 0.1096 +vt 0.7422 0.1096 +vt 0.6016 0.1174 +vt 0.6094 0.1174 +vt 0.6094 0.1252 +vt 0.6016 0.1252 +vt 0.6016 0.1018 +vt 0.6094 0.1018 +vt 0.6094 0.1096 +vt 0.6016 0.1096 +vt 0.6173 0.1018 +vt 0.6251 0.1018 +vt 0.6251 0.1096 +vt 0.6172 0.1096 +vt 0.6016 0.2423 +vt 0.6094 0.2423 +vt 0.6094 0.2502 +vt 0.6016 0.2501 +vt 0.6016 0.2267 +vt 0.6094 0.2267 +vt 0.6094 0.2345 +vt 0.6016 0.2345 +vt 0.6172 0.2267 +vt 0.6250 0.2267 +vt 0.6250 0.2345 +vt 0.6172 0.2345 +vt 0.9764 0.1175 +vt 0.9842 0.1175 +vt 0.9842 0.1253 +vt 0.9764 0.1253 +vt 0.9764 0.1019 +vt 0.9843 0.1019 +vt 0.9842 0.1097 +vt 0.9764 0.1097 +vt 0.9921 0.1019 +vt 0.9999 0.1019 +vt 0.9999 0.1097 +vt 0.9921 0.1097 +vt 0.8515 0.1175 +vt 0.8593 0.1175 +vt 0.8593 0.1253 +vt 0.8515 0.1253 +vt 0.8515 0.1019 +vt 0.8593 0.1019 +vt 0.8593 0.1097 +vt 0.8515 0.1097 +vt 0.8671 0.1019 +vt 0.8749 0.1019 +vt 0.8749 0.1097 +vt 0.8671 0.1097 +vt 0.8515 0.2424 +vt 0.8593 0.2424 +vt 0.8593 0.2502 +vt 0.8515 0.2502 +vt 0.8515 0.2268 +vt 0.8593 0.2268 +vt 0.8593 0.2346 +vt 0.8515 0.2346 +vt 0.8671 0.2268 +vt 0.8749 0.2268 +vt 0.8749 0.2346 +vt 0.8671 0.2346 +vt 0.2268 0.3672 +vt 0.2346 0.3672 +vt 0.2346 0.3750 +vt 0.2267 0.3750 +vt 0.2268 0.3515 +vt 0.2346 0.3515 +vt 0.2346 0.3594 +vt 0.2268 0.3593 +vt 0.2424 0.3515 +vt 0.2502 0.3515 +vt 0.2502 0.3594 +vt 0.2424 0.3594 +vt 0.1018 0.3671 +vt 0.1096 0.3671 +vt 0.1096 0.3749 +vt 0.1018 0.3749 +vt 0.1018 0.3515 +vt 0.1096 0.3515 +vt 0.1096 0.3593 +vt 0.1018 0.3593 +vt 0.1174 0.3515 +vt 0.1252 0.3515 +vt 0.1252 0.3593 +vt 0.1174 0.3593 +vt 0.1018 0.4921 +vt 0.1096 0.4921 +vt 0.1096 0.4999 +vt 0.1018 0.4999 +vt 0.1018 0.4764 +vt 0.1096 0.4764 +vt 0.1096 0.4842 +vt 0.1018 0.4842 +vt 0.1174 0.4764 +vt 0.1252 0.4764 +vt 0.1252 0.4843 +vt 0.1174 0.4842 +vt 0.2268 0.1173 +vt 0.2346 0.1173 +vt 0.2346 0.1251 +vt 0.2268 0.1251 +vt 0.2268 0.1017 +vt 0.2346 0.1017 +vt 0.2346 0.1095 +vt 0.2268 0.1095 +vt 0.2425 0.1017 +vt 0.2503 0.1017 +vt 0.2503 0.1095 +vt 0.2424 0.1095 +vt 0.1019 0.1173 +vt 0.1097 0.1173 +vt 0.1097 0.1251 +vt 0.1019 0.1251 +vt 0.1019 0.1016 +vt 0.1097 0.1016 +vt 0.1097 0.1094 +vt 0.1019 0.1094 +vt 0.1175 0.1016 +vt 0.1253 0.1016 +vt 0.1253 0.1095 +vt 0.1175 0.1095 +vt 0.1019 0.2422 +vt 0.1097 0.2422 +vt 0.1097 0.2500 +vt 0.1019 0.2500 +vt 0.1019 0.2266 +vt 0.1097 0.2266 +vt 0.1097 0.2344 +vt 0.1019 0.2344 +vt 0.1175 0.2266 +vt 0.1253 0.2266 +vt 0.1253 0.2344 +vt 0.1175 0.2344 +vt 0.4767 0.1174 +vt 0.4845 0.1174 +vt 0.4845 0.1252 +vt 0.4767 0.1252 +vt 0.4767 0.1018 +vt 0.4845 0.1018 +vt 0.4845 0.1096 +vt 0.4767 0.1096 +vt 0.4923 0.1018 +vt 0.5001 0.1018 +vt 0.5001 0.1096 +vt 0.4923 0.1096 +vt 0.3518 0.1173 +vt 0.3596 0.1173 +vt 0.3596 0.1251 +vt 0.3518 0.1251 +vt 0.3518 0.1017 +vt 0.3596 0.1017 +vt 0.3596 0.1095 +vt 0.3518 0.1095 +vt 0.3674 0.1017 +vt 0.3752 0.1017 +vt 0.3752 0.1095 +vt 0.3674 0.1095 +vt 0.3517 0.2423 +vt 0.3595 0.2423 +vt 0.3595 0.2501 +vt 0.3517 0.2501 +vt 0.3517 0.2266 +vt 0.3595 0.2266 +vt 0.3595 0.2345 +vt 0.3517 0.2345 +vt 0.3673 0.2267 +vt 0.3752 0.2267 +vt 0.3752 0.2345 +vt 0.3673 0.2345 +vt 0.2266 0.8669 +vt 0.2344 0.8669 +vt 0.2344 0.8747 +vt 0.2266 0.8747 +vt 0.2266 0.8513 +vt 0.2344 0.8513 +vt 0.2344 0.8591 +vt 0.2266 0.8591 +vt 0.2422 0.8513 +vt 0.2500 0.8513 +vt 0.2500 0.8591 +vt 0.2422 0.8591 +vt 0.1017 0.8669 +vt 0.1095 0.8669 +vt 0.1095 0.8747 +vt 0.1017 0.8747 +vt 0.1017 0.8512 +vt 0.1095 0.8512 +vt 0.1095 0.8591 +vt 0.1017 0.8590 +vt 0.1173 0.8512 +vt 0.1251 0.8512 +vt 0.1251 0.8591 +vt 0.1173 0.8591 +vt 0.1016 0.9918 +vt 0.1094 0.9918 +vt 0.1094 0.9996 +vt 0.1016 0.9996 +vt 0.1016 0.9762 +vt 0.1094 0.9762 +vt 0.1094 0.9840 +vt 0.1016 0.9840 +vt 0.1172 0.9762 +vt 0.1250 0.9762 +vt 0.1250 0.9840 +vt 0.1172 0.9840 +vt 0.2267 0.6170 +vt 0.2345 0.6170 +vt 0.2345 0.6248 +vt 0.2267 0.6248 +vt 0.2267 0.6014 +vt 0.2345 0.6014 +vt 0.2345 0.6092 +vt 0.2267 0.6092 +vt 0.2423 0.6014 +vt 0.2501 0.6014 +vt 0.2501 0.6092 +vt 0.2423 0.6092 +vt 0.1017 0.6170 +vt 0.1095 0.6170 +vt 0.1095 0.6248 +vt 0.1017 0.6248 +vt 0.1017 0.6014 +vt 0.1095 0.6014 +vt 0.1095 0.6092 +vt 0.1017 0.6092 +vt 0.1174 0.6014 +vt 0.1252 0.6014 +vt 0.1252 0.6092 +vt 0.1174 0.6092 +vt 0.1017 0.7419 +vt 0.1095 0.7419 +vt 0.1095 0.7497 +vt 0.1017 0.7497 +vt 0.1017 0.7263 +vt 0.1095 0.7263 +vt 0.1095 0.7341 +vt 0.1017 0.7341 +vt 0.1173 0.7263 +vt 0.1251 0.7263 +vt 0.1251 0.7341 +vt 0.1173 0.7341 +vt 0.4765 0.6171 +vt 0.4843 0.6171 +vt 0.4843 0.6249 +vt 0.4765 0.6249 +vt 0.4765 0.6015 +vt 0.4844 0.6015 +vt 0.4844 0.6093 +vt 0.4765 0.6093 +vt 0.4922 0.6015 +vt 0.5000 0.6015 +vt 0.5000 0.6093 +vt 0.4922 0.6093 +vt 0.3516 0.6171 +vt 0.3594 0.6171 +vt 0.3594 0.6249 +vt 0.3516 0.6249 +vt 0.3516 0.6014 +vt 0.3594 0.6015 +vt 0.3594 0.6093 +vt 0.3516 0.6093 +vt 0.3672 0.6015 +vt 0.3750 0.6015 +vt 0.3750 0.6093 +vt 0.3672 0.6093 +vt 0.3516 0.7420 +vt 0.3594 0.7420 +vt 0.3594 0.7498 +vt 0.3516 0.7498 +vt 0.3516 0.7264 +vt 0.3594 0.7264 +vt 0.3594 0.7342 +vt 0.3516 0.7342 +vt 0.3672 0.7264 +vt 0.3750 0.7264 +vt 0.3750 0.7342 +vt 0.3672 0.7342 +vt 0.7263 0.8670 +vt 0.7341 0.8671 +vt 0.7341 0.8749 +vt 0.7263 0.8749 +vt 0.7263 0.8514 +vt 0.7341 0.8514 +vt 0.7341 0.8592 +vt 0.7263 0.8592 +vt 0.7420 0.8514 +vt 0.7498 0.8514 +vt 0.7498 0.8592 +vt 0.7419 0.8592 +vt 0.6014 0.8670 +vt 0.6092 0.8670 +vt 0.6092 0.8748 +vt 0.6014 0.8748 +vt 0.6014 0.8514 +vt 0.6092 0.8514 +vt 0.6092 0.8592 +vt 0.6014 0.8592 +vt 0.6170 0.8514 +vt 0.6248 0.8514 +vt 0.6248 0.8592 +vt 0.6170 0.8592 +vt 0.6014 0.9919 +vt 0.6092 0.9919 +vt 0.6092 0.9998 +vt 0.6014 0.9998 +vt 0.6014 0.9763 +vt 0.6092 0.9763 +vt 0.6092 0.9841 +vt 0.6014 0.9841 +vt 0.6170 0.9763 +vt 0.6248 0.9763 +vt 0.6248 0.9841 +vt 0.6170 0.9841 +vt 0.7264 0.6172 +vt 0.7342 0.6172 +vt 0.7342 0.6250 +vt 0.7264 0.6250 +vt 0.7264 0.6016 +vt 0.7342 0.6016 +vt 0.7342 0.6094 +vt 0.7264 0.6094 +vt 0.7420 0.6016 +vt 0.7498 0.6016 +vt 0.7498 0.6094 +vt 0.7420 0.6094 +vt 0.6015 0.6171 +vt 0.6093 0.6171 +vt 0.6093 0.6250 +vt 0.6015 0.6250 +vt 0.6015 0.6015 +vt 0.6093 0.6015 +vt 0.6093 0.6093 +vt 0.6015 0.6093 +vt 0.6171 0.6015 +vt 0.6249 0.6015 +vt 0.6249 0.6093 +vt 0.6171 0.6093 +vt 0.6014 0.7421 +vt 0.6092 0.7421 +vt 0.6092 0.7499 +vt 0.6014 0.7499 +vt 0.6014 0.7265 +vt 0.6092 0.7265 +vt 0.6092 0.7343 +vt 0.6014 0.7343 +vt 0.6171 0.7265 +vt 0.6249 0.7265 +vt 0.6249 0.7343 +vt 0.6171 0.7343 +vt 0.9763 0.6173 +vt 0.9841 0.6173 +vt 0.9841 0.6251 +vt 0.9763 0.6251 +vt 0.9763 0.6016 +vt 0.9841 0.6016 +vt 0.9841 0.6095 +vt 0.9763 0.6095 +vt 0.9919 0.6017 +vt 0.9997 0.6017 +vt 0.9997 0.6095 +vt 0.9919 0.6095 +vt 0.8513 0.6172 +vt 0.8591 0.6172 +vt 0.8591 0.6250 +vt 0.8513 0.6250 +vt 0.8513 0.6016 +vt 0.8592 0.6016 +vt 0.8592 0.6094 +vt 0.8513 0.6094 +vt 0.8670 0.6016 +vt 0.8748 0.6016 +vt 0.8748 0.6094 +vt 0.8670 0.6094 +vt 0.8513 0.7422 +vt 0.8591 0.7422 +vt 0.8591 0.7500 +vt 0.8513 0.7500 +vt 0.8513 0.7265 +vt 0.8591 0.7265 +vt 0.8591 0.7343 +vt 0.8513 0.7343 +vt 0.8669 0.7265 +vt 0.8747 0.7265 +vt 0.8747 0.7344 +vt 0.8669 0.7344 +vt 0.9762 0.7422 +vt 0.9840 0.7422 +vt 0.9840 0.7500 +vt 0.9762 0.7500 +vt 0.9762 0.7266 +vt 0.9840 0.7266 +vt 0.9840 0.7344 +vt 0.9762 0.7344 +vt 0.9919 0.7266 +vt 0.9997 0.7266 +vt 0.9997 0.7344 +vt 0.9919 0.7344 +vt 0.7264 0.7421 +vt 0.7342 0.7421 +vt 0.7342 0.7499 +vt 0.7264 0.7499 +vt 0.7264 0.7265 +vt 0.7342 0.7265 +vt 0.7342 0.7343 +vt 0.7264 0.7343 +vt 0.7420 0.7265 +vt 0.7498 0.7265 +vt 0.7498 0.7343 +vt 0.7420 0.7343 +vt 0.7263 0.9920 +vt 0.7341 0.9920 +vt 0.7341 0.9998 +vt 0.7263 0.9998 +vt 0.7263 0.9764 +vt 0.7341 0.9764 +vt 0.7341 0.9842 +vt 0.7263 0.9842 +vt 0.7419 0.9764 +vt 0.7497 0.9764 +vt 0.7497 0.9842 +vt 0.7419 0.9842 +vt 0.4765 0.7420 +vt 0.4843 0.7420 +vt 0.4843 0.7499 +vt 0.4765 0.7498 +vt 0.4765 0.7264 +vt 0.4843 0.7264 +vt 0.4843 0.7342 +vt 0.4765 0.7342 +vt 0.4921 0.7264 +vt 0.4999 0.7264 +vt 0.4999 0.7342 +vt 0.4921 0.7342 +vt 0.2266 0.7420 +vt 0.2344 0.7420 +vt 0.2344 0.7498 +vt 0.2266 0.7498 +vt 0.2266 0.7263 +vt 0.2344 0.7263 +vt 0.2344 0.7342 +vt 0.2266 0.7342 +vt 0.2423 0.7263 +vt 0.2501 0.7264 +vt 0.2501 0.7342 +vt 0.2423 0.7342 +vt 0.2266 0.9918 +vt 0.2344 0.9918 +vt 0.2344 0.9996 +vt 0.2266 0.9996 +vt 0.2266 0.9762 +vt 0.2344 0.9762 +vt 0.2344 0.9840 +vt 0.2266 0.9840 +vt 0.2422 0.9762 +vt 0.2500 0.9762 +vt 0.2500 0.9840 +vt 0.2422 0.9840 +vt 0.4767 0.2423 +vt 0.4845 0.2423 +vt 0.4845 0.2501 +vt 0.4767 0.2501 +vt 0.4767 0.2267 +vt 0.4845 0.2267 +vt 0.4845 0.2345 +vt 0.4767 0.2345 +vt 0.4923 0.2267 +vt 0.5001 0.2267 +vt 0.5001 0.2345 +vt 0.4923 0.2345 +vt 0.2268 0.2422 +vt 0.2346 0.2422 +vt 0.2346 0.2500 +vt 0.2268 0.2500 +vt 0.2268 0.2266 +vt 0.2346 0.2266 +vt 0.2346 0.2344 +vt 0.2268 0.2344 +vt 0.2424 0.2266 +vt 0.2502 0.2266 +vt 0.2502 0.2344 +vt 0.2424 0.2344 +vt 0.2267 0.4921 +vt 0.2345 0.4921 +vt 0.2345 0.4999 +vt 0.2267 0.4999 +vt 0.2267 0.4765 +vt 0.2345 0.4765 +vt 0.2345 0.4843 +vt 0.2267 0.4843 +vt 0.2423 0.4765 +vt 0.2501 0.4765 +vt 0.2501 0.4843 +vt 0.2423 0.4843 +vt 0.9764 0.2425 +vt 0.9842 0.2425 +vt 0.9842 0.2503 +vt 0.9764 0.2503 +vt 0.9764 0.2268 +vt 0.9842 0.2268 +vt 0.9842 0.2347 +vt 0.9764 0.2347 +vt 0.9920 0.2268 +vt 0.9998 0.2268 +vt 0.9998 0.2347 +vt 0.9920 0.2347 +vt 0.7265 0.2424 +vt 0.7343 0.2424 +vt 0.7343 0.2502 +vt 0.7265 0.2502 +vt 0.7265 0.2268 +vt 0.7343 0.2268 +vt 0.7343 0.2346 +vt 0.7265 0.2346 +vt 0.7421 0.2268 +vt 0.7500 0.2268 +vt 0.7500 0.2346 +vt 0.7421 0.2346 +vt 0.7264 0.4922 +vt 0.7343 0.4923 +vt 0.7343 0.5001 +vt 0.7264 0.5001 +vt 0.7265 0.4766 +vt 0.7343 0.4766 +vt 0.7343 0.4844 +vt 0.7264 0.4844 +vt 0.7421 0.4766 +vt 0.7499 0.4766 +vt 0.7499 0.4844 +vt 0.7421 0.4844 +vt 0.9763 0.4923 +vt 0.9841 0.4923 +vt 0.9841 0.5001 +vt 0.9763 0.5001 +vt 0.9763 0.4767 +vt 0.9841 0.4767 +vt 0.9841 0.4845 +vt 0.9763 0.4845 +vt 0.9919 0.4767 +vt 0.9997 0.4767 +vt 0.9997 0.4845 +vt 0.9919 0.4845 +vt 0.4766 0.4922 +vt 0.4844 0.4922 +vt 0.4844 0.5000 +vt 0.4766 0.5000 +vt 0.4766 0.4766 +vt 0.4844 0.4766 +vt 0.4844 0.4844 +vt 0.4766 0.4844 +vt 0.4922 0.4766 +vt 0.5000 0.4766 +vt 0.5000 0.4844 +vt 0.4922 0.4844 +vt 0.4764 0.9919 +vt 0.4842 0.9919 +vt 0.4842 0.9997 +vt 0.4764 0.9997 +vt 0.4764 0.9763 +vt 0.4842 0.9763 +vt 0.4842 0.9841 +vt 0.4764 0.9841 +vt 0.4920 0.9763 +vt 0.4999 0.9763 +vt 0.4999 0.9841 +vt 0.4920 0.9841 +vt 0.9762 0.9921 +vt 0.9840 0.9921 +vt 0.9840 0.9999 +vt 0.9762 0.9999 +vt 0.9762 0.9764 +vt 0.9840 0.9764 +vt 0.9840 0.9843 +vt 0.9762 0.9842 +vt 0.9918 0.9764 +vt 0.9996 0.9764 +vt 0.9996 0.9843 +vt 0.9918 0.9843 +vt 0.0002 0.6638 +vt 0.0002 0.6716 +vt 0.0002 0.6560 +vt 0.0002 0.6794 +vt 0.0002 0.6872 +vt 0.0002 0.6326 +vt 0.0002 0.6404 +vt 0.0002 0.6248 +vt 0.0002 0.6482 +vt 0.0002 0.7263 +vt 0.0002 0.7341 +vt 0.0002 0.7185 +vt 0.0002 0.7419 +vt 0.0002 0.7497 +vt 0.0002 0.6950 +vt 0.0002 0.7028 +vt 0.0002 0.7107 +vt 0.0003 0.5389 +vt 0.0002 0.5467 +vt 0.0003 0.5311 +vt 0.0002 0.5545 +vt 0.0002 0.5623 +vt 0.0003 0.5076 +vt 0.0003 0.5154 +vt 0.0003 0.4998 +vt 0.0003 0.5233 +vt 0.0002 0.6013 +vt 0.0002 0.6091 +vt 0.0002 0.5935 +vt 0.0002 0.6170 +vt 0.0002 0.5701 +vt 0.0002 0.5779 +vt 0.0002 0.5857 +vt 0.0001 0.9137 +vt 0.0001 0.9215 +vt 0.0001 0.9059 +vt 0.0001 0.9293 +vt 0.0001 0.9371 +vt 0.0001 0.8824 +vt 0.0001 0.8903 +vt 0.0001 0.8746 +vt 0.0001 0.8981 +vt 0.0001 0.9761 +vt 0.0001 0.9840 +vt 0.0001 0.9683 +vt 0.0001 0.9918 +vt 0.0001 0.9996 +vt 0.0001 0.9449 +vt 0.0001 0.9527 +vt 0.0001 0.9605 +vt 0.0002 0.7887 +vt 0.0002 0.7965 +vt 0.0002 0.7809 +vt 0.0002 0.8044 +vt 0.0002 0.8122 +vt 0.0002 0.7575 +vt 0.0002 0.7653 +vt 0.0002 0.7731 +vt 0.0001 0.8512 +vt 0.0001 0.8590 +vt 0.0002 0.8434 +vt 0.0001 0.8668 +vt 0.0002 0.8200 +vt 0.0002 0.8278 +vt 0.0002 0.8356 +vt 0.3284 0.0002 +vt 0.3362 0.0002 +vt 0.3440 0.0002 +vt 0.3128 0.0002 +vt 0.3206 0.0002 +vt 0.3596 0.0002 +vt 0.3674 0.0002 +vt 0.3752 0.0002 +vt 0.3518 0.0002 +vt 0.2659 0.0002 +vt 0.2737 0.0002 +vt 0.2815 0.0002 +vt 0.2503 0.0002 +vt 0.2581 0.0002 +vt 0.2971 0.0002 +vt 0.3049 0.0002 +vt 0.2893 0.0002 +vt 0.4533 0.0002 +vt 0.4611 0.0002 +vt 0.4689 0.0002 +vt 0.4377 0.0002 +vt 0.4455 0.0002 +vt 0.4845 0.0002 +vt 0.4923 0.0002 +vt 0.5002 0.0003 +vt 0.4767 0.0002 +vt 0.3908 0.0002 +vt 0.3986 0.0002 +vt 0.4065 0.0002 +vt 0.3830 0.0002 +vt 0.4221 0.0002 +vt 0.4299 0.0002 +vt 0.4143 0.0002 +vt 0.0004 0.1641 +vt 0.0004 0.1719 +vt 0.0004 0.1563 +vt 0.0004 0.1797 +vt 0.0004 0.1875 +vt 0.0004 0.1328 +vt 0.0004 0.1406 +vt 0.0004 0.1250 +vt 0.0004 0.1485 +vt 0.0004 0.2265 +vt 0.0004 0.2343 +vt 0.0004 0.2187 +vt 0.0004 0.2422 +vt 0.0003 0.2500 +vt 0.0004 0.1953 +vt 0.0004 0.2031 +vt 0.0004 0.2109 +vt 0.0785 0.0001 +vt 0.0863 0.0001 +vt 0.0941 0.0001 +vt 0.0629 0.0001 +vt 0.0707 0.0001 +vt 0.1097 0.0001 +vt 0.1176 0.0001 +vt 0.1254 0.0001 +vt 0.1019 0.0001 +vt 0.0004 0.0391 +vt 0.0004 0.0469 +vt 0.0004 0.0313 +vt 0.0004 0.0548 +vt 0.0004 0.0626 +vt 0.0160 0.0001 +vt 0.0239 0.0001 +vt 0.0317 0.0001 +vt 0.0004 0.0079 +vt 0.0004 0.0157 +vt 0.0004 0.0001 +vt 0.0082 0.0001 +vt 0.0004 0.0235 +vt 0.0473 0.0001 +vt 0.0551 0.0001 +vt 0.0395 0.0001 +vt 0.0004 0.1016 +vt 0.0004 0.1094 +vt 0.0004 0.0938 +vt 0.0004 0.1172 +vt 0.0004 0.0704 +vt 0.0004 0.0782 +vt 0.0004 0.0860 +vt 0.2034 0.0002 +vt 0.2112 0.0002 +vt 0.2191 0.0002 +vt 0.1878 0.0002 +vt 0.1956 0.0002 +vt 0.2347 0.0002 +vt 0.2425 0.0002 +vt 0.2269 0.0002 +vt 0.1410 0.0001 +vt 0.1488 0.0001 +vt 0.1566 0.0001 +vt 0.1332 0.0001 +vt 0.1722 0.0002 +vt 0.1800 0.0002 +vt 0.1644 0.0002 +vt 0.0003 0.4139 +vt 0.0003 0.4217 +vt 0.0003 0.4061 +vt 0.0003 0.4295 +vt 0.0003 0.4374 +vt 0.0003 0.3827 +vt 0.0003 0.3905 +vt 0.0003 0.3749 +vt 0.0003 0.3983 +vt 0.0003 0.4764 +vt 0.0003 0.4842 +vt 0.0003 0.4686 +vt 0.0003 0.4920 +vt 0.0003 0.4452 +vt 0.0003 0.4530 +vt 0.0003 0.4608 +vt 0.0003 0.2890 +vt 0.0003 0.2968 +vt 0.0003 0.2812 +vt 0.0003 0.3046 +vt 0.0003 0.3124 +vt 0.0003 0.2578 +vt 0.0003 0.2656 +vt 0.0003 0.2734 +vt 0.0003 0.3515 +vt 0.0003 0.3593 +vt 0.0003 0.3437 +vt 0.0003 0.3671 +vt 0.0003 0.3202 +vt 0.0003 0.3280 +vt 0.0003 0.3359 +vt 0.8281 0.0003 +vt 0.8359 0.0003 +vt 0.8437 0.0004 +vt 0.8125 0.0003 +vt 0.8203 0.0003 +vt 0.8593 0.0004 +vt 0.8672 0.0004 +vt 0.8750 0.0004 +vt 0.8515 0.0004 +vt 0.7656 0.0003 +vt 0.7735 0.0003 +vt 0.7813 0.0003 +vt 0.7500 0.0003 +vt 0.7578 0.0003 +vt 0.7969 0.0003 +vt 0.8047 0.0003 +vt 0.7891 0.0003 +vt 0.9530 0.0004 +vt 0.9609 0.0004 +vt 0.9687 0.0004 +vt 0.9374 0.0004 +vt 0.9452 0.0004 +vt 0.9843 0.0004 +vt 0.9921 0.0004 +vt 0.9999 0.0004 +vt 0.9765 0.0004 +vt 0.8906 0.0004 +vt 0.8984 0.0004 +vt 0.9062 0.0004 +vt 0.8828 0.0004 +vt 0.9218 0.0004 +vt 0.9296 0.0004 +vt 0.9140 0.0004 +vt 0.5782 0.0003 +vt 0.5860 0.0003 +vt 0.5939 0.0003 +vt 0.5626 0.0003 +vt 0.5704 0.0003 +vt 0.6095 0.0003 +vt 0.6173 0.0003 +vt 0.6251 0.0003 +vt 0.6017 0.0003 +vt 0.5158 0.0003 +vt 0.5236 0.0003 +vt 0.5314 0.0003 +vt 0.5080 0.0003 +vt 0.5470 0.0003 +vt 0.5548 0.0003 +vt 0.5392 0.0003 +vt 0.7032 0.0003 +vt 0.7110 0.0003 +vt 0.7188 0.0003 +vt 0.6876 0.0003 +vt 0.6954 0.0003 +vt 0.7344 0.0003 +vt 0.7422 0.0003 +vt 0.7266 0.0003 +vt 0.6407 0.0003 +vt 0.6485 0.0003 +vt 0.6563 0.0003 +vt 0.6329 0.0003 +vt 0.6719 0.0003 +vt 0.6797 0.0003 +vt 0.6641 0.0003 +vn 0.0000 1.0000 0.0000 +vn 0.0000 -0.0000 1.0000 +vn -1.0000 0.0000 0.0000 +vn 0.0000 0.0000 -1.0000 +vn 1.0000 0.0000 0.0000 +usemtl None +s off +f 1/1/1 2/2/1 4/3/1 3/4/1 +s 1 +f 338/5/2 334/6/2 846/7/2 850/8/2 +f 431/9/3 433/10/3 945/11/3 943/12/3 +f 395/13/2 389/14/2 901/15/2 907/16/2 +f 248/17/4 249/18/4 761/19/4 760/20/4 +f 79/21/4 184/22/4 696/23/4 591/24/4 +f 509/25/2 507/26/2 1019/27/2 1021/28/2 +f 133/29/5 130/30/5 642/31/5 645/32/5 +f 356/33/2 345/34/2 857/35/2 868/36/2 +f 33/37/4 230/38/4 742/39/4 545/40/4 +f 383/41/2 380/42/2 892/43/2 895/44/2 +f 222/45/4 223/46/4 735/47/4 734/48/4 +f 153/49/4 46/50/4 558/51/4 665/52/4 +f 67/53/5 132/54/5 644/55/5 579/56/5 +f 295/57/3 301/58/3 813/59/3 807/60/3 +f 22/61/4 23/62/4 535/63/4 534/64/4 +f 417/65/2 421/66/2 933/67/2 929/68/2 +f 66/69/5 67/53/5 579/56/5 578/70/5 +f 111/71/4 152/72/4 664/73/4 623/74/4 +f 336/75/2 341/76/2 853/77/2 848/78/2 +f 48/79/4 49/80/4 561/81/4 560/82/4 +f 409/83/2 414/84/2 926/85/2 921/86/2 +f 26/87/5 27/88/5 539/89/5 538/90/5 +f 274/91/3 264/92/3 776/93/3 786/94/3 +f 358/95/3 360/96/3 872/97/3 870/98/3 +f 292/99/3 291/100/3 803/101/3 804/102/3 +f 231/103/4 102/104/4 614/105/4 743/106/4 +f 471/107/2 472/108/2 984/109/2 983/110/2 +f 433/10/3 437/111/3 949/112/3 945/11/3 +f 350/113/2 347/114/2 859/115/2 862/116/2 +f 476/117/2 17672/118/2 17676/119/2 988/120/2 +f 221/121/5 42/122/5 554/123/5 733/124/5 +f 496/125/2 497/126/2 1009/127/2 1008/128/2 +f 240/129/4 241/130/4 753/131/4 752/132/4 +f 59/133/5 140/134/5 652/135/5 571/136/5 +f 119/137/4 144/138/4 656/139/4 631/140/4 +f 107/141/5 234/142/5 746/143/5 619/144/5 +f 174/145/4 175/146/4 687/147/4 686/148/4 +f 300/149/3 321/150/3 833/151/3 812/152/3 +f 377/153/2 383/41/2 895/44/2 889/154/2 +f 104/155/4 105/156/4 617/157/4 616/158/4 +f 200/159/4 201/160/4 713/161/4 712/162/4 +f 125/163/5 252/164/5 764/165/5 637/166/5 +f 270/167/3 269/168/3 781/169/3 782/170/3 +f 269/168/3 271/171/3 783/172/3 781/169/3 +f 237/173/5 26/87/5 538/90/5 749/174/5 +f 206/175/4 207/176/4 719/177/4 718/178/4 +f 141/179/5 122/180/5 634/181/5 653/182/5 +f 482/183/2 479/184/2 991/185/2 994/186/2 +f 70/187/4 71/188/4 583/189/4 582/190/4 +f 10/191/5 11/192/5 523/193/5 522/194/5 +f 429/195/3 449/196/3 961/197/3 941/198/3 +f 352/199/2 353/200/2 865/201/2 864/202/2 +f 419/203/2 420/204/2 932/205/2 931/206/2 +f 340/207/2 328/208/2 840/209/2 852/210/2 +f 88/211/4 89/212/4 601/213/4 600/214/4 +f 212/215/5 213/216/5 725/217/5 724/218/5 +f 483/219/2 484/220/2 996/221/2 995/222/2 +f 512/223/2 516/224/2 1028/225/2 1024/226/2 +f 420/204/2 410/227/2 922/228/2 932/205/2 +f 30/229/4 31/230/4 543/231/4 542/232/4 +f 264/92/3 263/233/3 775/234/3 776/93/3 +f 24/235/4 25/236/4 537/237/4 536/238/4 +f 353/200/2 357/239/2 869/240/2 865/201/2 +f 165/241/5 98/242/5 610/243/5 677/244/5 +f 16/245/4 17/246/4 529/247/4 528/248/4 +f 7/249/4 256/250/4 768/251/4 519/252/4 +f 503/253/2 504/254/2 1016/255/2 1015/256/2 +f 159/257/4 40/258/4 552/259/4 671/260/4 +f 462/261/2 463/262/2 975/263/2 974/264/2 +f 35/265/5 194/266/5 706/267/5 547/268/5 +f 213/216/5 50/269/5 562/270/5 725/217/5 +f 371/271/3 370/272/3 882/273/3 883/274/3 +f 497/126/2 501/275/2 1013/276/2 1009/127/2 +f 370/272/3 368/277/3 880/278/3 882/273/3 +f 169/279/4 14/280/4 526/281/4 681/282/4 +f 287/283/3 286/284/3 798/285/3 799/286/3 +f 182/287/4 183/288/4 695/289/4 694/290/4 +f 191/291/4 30/229/4 542/232/4 703/292/4 +f 487/293/2 488/294/2 1000/295/2 999/296/2 +f 355/297/2 356/33/2 868/36/2 867/298/2 +f 65/299/4 198/300/4 710/301/4 577/302/4 +f 257/303/4 128/304/4 640/305/4 769/306/4 +f 37/307/5 162/308/5 674/309/5 549/310/5 +f 368/277/3 367/311/3 879/312/3 880/278/3 +f 128/304/4 129/313/4 641/314/4 640/305/4 +f 63/315/4 200/159/4 712/162/4 575/316/4 +f 148/317/5 149/318/5 661/319/5 660/320/5 +f 188/321/5 189/322/5 701/323/5 700/324/5 +f 513/325/2 510/326/2 1022/327/2 1025/328/2 +f 112/329/4 113/330/4 625/331/4 624/332/4 +f 282/333/3 284/334/3 796/335/3 794/336/3 +f 379/337/2 375/338/2 887/339/2 891/340/2 +f 195/341/5 68/342/5 580/343/5 707/344/5 +f 406/345/3 405/346/3 917/347/3 918/348/3 +f 330/349/2 331/350/2 843/351/2 842/352/2 +f 223/46/4 94/353/4 606/354/4 735/47/4 +f 115/355/5 242/356/5 754/357/5 627/358/5 +f 411/359/2 407/360/2 919/361/2 923/362/2 +f 58/363/5 59/133/5 571/136/5 570/364/5 +f 184/22/4 185/365/4 697/366/4 696/23/4 +f 164/367/5 165/241/5 677/244/5 676/368/5 +f 376/369/2 377/153/2 889/154/2 888/370/2 +f 81/371/4 182/287/4 694/290/4 593/372/4 +f 204/373/5 205/374/5 717/375/5 716/376/5 +f 374/377/3 373/378/3 885/379/3 886/380/3 +f 310/381/3 312/382/3 824/383/3 822/384/3 +f 253/385/5 10/191/5 522/194/5 765/386/5 +f 315/387/3 273/388/3 785/389/3 827/390/3 +f 373/378/3 372/391/3 884/392/3 885/379/3 +f 346/393/2 342/394/2 854/395/2 858/396/2 +f 275/397/3 274/91/3 786/94/3 787/398/3 +f 43/399/5 156/400/5 668/401/5 555/402/5 +f 168/403/4 169/279/4 681/282/4 680/404/4 +f 400/405/3 402/406/3 914/407/3 912/408/3 +f 32/409/4 33/37/4 545/40/4 544/410/4 +f 55/411/4 208/412/4 720/413/4 567/414/4 +f 21/415/5 180/416/5 692/417/5 533/418/5 +f 73/419/4 190/420/4 702/421/4 585/422/4 +f 321/150/3 319/423/3 831/424/3 833/151/3 +f 49/80/4 214/425/4 726/426/4 561/81/4 +f 337/427/2 338/5/2 850/8/2 849/428/2 +f 122/180/5 123/429/5 635/430/5 634/181/5 +f 57/431/4 206/175/4 718/178/4 569/432/4 +f 514/433/2 515/434/2 1027/435/2 1026/436/2 +f 361/437/3 359/438/3 871/439/3 873/440/3 +f 284/334/3 434/441/3 946/442/3 796/335/3 +f 296/443/3 294/444/3 806/445/3 808/446/3 +f 474/447/2 470/448/2 982/449/2 986/450/2 +f 145/451/4 54/452/4 566/453/4 657/454/4 +f 313/455/3 311/456/3 823/457/3 825/458/3 +f 319/423/3 318/459/3 830/460/3 831/424/3 +f 150/461/4 151/462/4 663/463/4 662/464/4 +f 192/465/4 193/466/4 705/467/4 704/468/4 +f 348/469/2 349/470/2 861/471/2 860/472/2 +f 265/473/3 267/474/3 779/475/3 777/476/3 +f 327/477/2 333/478/2 845/479/2 839/480/2 +f 72/481/4 73/419/4 585/422/4 584/482/4 +f 297/483/3 296/443/3 808/446/3 809/484/3 +f 194/266/5 195/341/5 707/344/5 706/267/5 +f 291/100/3 290/485/3 802/486/3 803/101/3 +f 459/487/2 460/488/2 972/489/2 971/490/2 +f 87/491/4 176/492/4 688/493/4 599/494/4 +f 389/14/2 390/495/2 902/496/2 901/15/2 +f 405/346/3 404/497/3 916/498/3 917/347/3 +f 335/499/2 336/75/2 848/78/2 847/500/2 +f 410/227/2 411/359/2 923/362/2 922/228/2 +f 498/501/2 495/502/2 1007/503/2 1010/504/2 +f 312/382/3 317/505/3 829/506/3 824/383/3 +f 425/507/3 423/508/3 935/509/3 937/510/3 +f 504/254/2 509/25/2 1021/28/2 1016/255/2 +f 480/511/2 481/512/2 993/513/2 992/514/2 +f 266/515/3 265/473/3 777/476/3 778/516/3 +f 385/517/3 384/518/3 896/519/3 897/520/3 +f 85/521/5 212/215/5 724/218/5 597/522/5 +f 254/523/4 255/524/4 767/525/4 766/526/4 +f 42/122/5 43/399/5 555/402/5 554/123/5 +f 189/322/5 74/527/5 586/528/5 701/323/5 +f 52/529/5 53/530/5 565/531/5 564/532/5 +f 351/533/2 352/199/2 864/202/2 863/534/2 +f 12/535/5 13/536/5 525/537/5 524/538/5 +f 501/275/2 499/539/2 1011/540/2 1013/276/2 +f 407/360/2 408/541/2 920/542/2 919/361/2 +f 311/456/3 310/381/3 822/384/3 823/457/3 +f 9/543/4 254/523/4 766/526/4 521/544/4 +f 147/545/5 116/546/5 628/547/5 659/548/5 +f 117/549/5 244/550/5 756/551/5 629/552/5 +f 475/553/2 476/117/2 988/120/2 987/554/2 +f 129/313/4 134/555/4 646/556/4 641/314/4 +f 207/176/4 78/557/4 590/558/4 719/177/4 +f 394/559/2 395/13/2 907/16/2 906/560/2 +f 203/561/5 60/562/5 572/563/5 715/564/5 +f 232/565/4 233/566/4 745/567/4 744/568/4 +f 322/569/3 314/570/3 826/571/3 834/572/3 +f 384/518/3 386/573/3 898/574/3 896/519/3 +f 306/575/3 305/576/3 817/577/3 818/578/3 +f 449/196/3 447/579/3 959/580/3 961/197/3 +f 243/581/5 20/582/5 532/583/5 755/584/5 +f 334/6/2 335/499/2 847/500/2 846/7/2 +f 242/356/5 243/581/5 755/584/5 754/357/5 +f 458/585/2 459/487/2 971/490/2 970/586/2 +f 190/420/4 191/291/4 703/292/4 702/421/4 +f 83/587/5 210/588/5 722/589/5 595/590/5 +f 493/591/2 513/325/2 1025/328/2 1005/592/2 +f 271/171/3 276/593/3 788/594/3 783/172/3 +f 404/497/3 388/595/3 900/596/3 916/498/3 +f 68/342/5 69/597/5 581/598/5 580/343/5 +f 430/599/3 428/600/3 940/601/3 942/602/3 +f 450/603/3 442/604/3 954/605/3 962/606/3 +f 218/607/5 219/608/5 731/609/5 730/610/5 +f 143/611/4 56/612/4 568/613/4 655/614/4 +f 432/615/3 431/9/3 943/12/3 944/616/3 +f 256/250/4 257/303/4 769/306/4 768/251/4 +f 114/617/5 115/355/5 627/358/5 626/618/5 +f 80/619/4 81/371/4 593/372/4 592/620/4 +f 29/621/5 188/321/5 700/324/5 541/622/5 +f 428/600/3 427/623/3 939/624/3 940/601/3 +f 95/625/4 168/403/4 680/404/4 607/626/4 +f 272/627/3 270/167/3 782/170/3 784/628/3 +f 333/478/2 330/349/2 842/352/2 845/479/2 +f 506/629/2 502/630/2 1014/631/2 1018/632/2 +f 146/633/5 147/545/5 659/548/5 658/634/5 +f 423/508/3 422/635/3 934/636/3 935/509/3 +f 285/637/3 283/638/3 795/639/3 797/640/3 +f 249/18/4 120/641/4 632/642/4 761/19/4 +f 437/111/3 436/643/3 948/644/3 949/112/3 +f 171/645/5 92/646/5 604/647/5 683/648/5 +f 246/649/4 247/650/4 759/651/4 758/652/4 +f 422/635/3 424/653/3 936/654/3 934/636/3 +f 447/579/3 446/655/3 958/656/3 959/580/3 +f 510/326/2 511/657/2 1023/658/2 1022/327/2 +f 491/659/2 492/660/2 1004/661/2 1003/662/2 +f 93/663/5 220/664/5 732/665/5 605/666/5 +f 154/667/5 155/668/5 667/669/5 666/670/5 +f 100/671/5 101/672/5 613/673/5 612/674/5 +f 408/541/2 409/83/2 921/86/2 920/542/2 +f 118/675/4 119/137/4 631/140/4 630/676/4 +f 477/677/5 172/678/5 684/679/5 989/680/5 +f 211/681/5 52/529/5 564/532/5 723/682/5 +f 451/683/3 450/603/3 962/606/3 963/684/3 +f 138/685/5 139/686/5 651/687/5 650/688/5 +f 325/689/2 326/690/2 838/691/2 837/692/2 +f 108/693/5 109/694/5 621/695/5 620/696/5 +f 41/697/4 222/45/4 734/48/4 553/698/4 +f 507/26/2 508/699/2 1020/700/2 1019/27/2 +f 286/284/3 288/701/3 800/702/3 798/285/3 +f 366/703/3 364/704/3 876/705/3 878/706/3 +f 436/643/3 435/707/3 947/708/3 948/644/3 +f 391/709/2 399/710/2 911/711/2 903/712/2 +f 463/262/2 464/713/2 976/714/2 975/263/2 +f 490/715/2 486/716/2 998/717/2 1002/718/2 +f 508/699/2 465/719/2 977/720/2 1020/700/2 +f 364/704/3 363/721/3 875/722/3 876/705/3 +f 301/58/3 299/723/3 811/724/3 813/59/3 +f 34/725/5 35/265/5 547/268/5 546/726/5 +f 262/727/3 268/728/3 780/729/3 774/730/3 +f 163/731/5 100/671/5 612/674/5 675/732/5 +f 45/733/5 154/667/5 666/670/5 557/734/5 +f 106/735/5 107/141/5 619/144/5 618/736/5 +f 345/34/2 346/393/2 858/396/2 857/35/2 +f 481/512/2 485/737/2 997/738/2 993/513/2 +f 369/739/3 374/377/3 886/380/3 881/740/3 +f 281/741/3 280/742/3 792/743/3 793/744/3 +f 317/505/3 316/745/3 828/746/3 829/506/3 +f 135/747/4 64/748/4 576/749/4 647/750/4 +f 180/416/5 181/751/5 693/752/5 692/417/5 +f 103/753/4 160/754/4 672/755/4 615/756/4 +f 15/757/4 248/17/4 760/20/4 527/758/4 +f 328/208/2 329/759/2 841/760/2 840/209/2 +f 516/224/2 514/433/2 1026/436/2 1028/225/2 +f 225/761/4 96/762/4 608/763/4 737/764/4 +f 359/438/3 358/95/3 870/98/3 871/439/3 +f 102/104/4 103/753/4 615/756/4 614/105/4 +f 17/246/4 246/649/4 758/652/4 529/247/4 +f 489/765/2 490/715/2 1002/718/2 1001/766/2 +f 362/767/3 361/437/3 873/440/3 874/768/3 +f 251/769/5 12/535/5 524/538/5 763/770/5 +f 484/220/2 473/771/2 985/772/2 996/221/2 +f 473/771/2 474/447/2 986/450/2 985/772/2 +f 121/773/4 142/774/4 654/775/4 633/776/4 +f 241/130/4 112/329/4 624/332/4 753/131/4 +f 347/114/2 348/469/2 860/472/2 859/115/2 +f 46/50/4 47/777/4 559/778/4 558/51/4 +f 62/779/4 63/315/4 575/316/4 574/780/4 +f 224/781/4 225/761/4 737/764/4 736/782/4 +f 210/588/5 211/681/5 723/682/5 722/589/5 +f 158/783/4 159/257/4 671/260/4 670/784/4 +f 27/88/5 186/785/5 698/786/5 539/89/5 +f 205/374/5 58/363/5 570/364/5 717/375/5 +f 349/470/2 498/501/2 1010/504/2 861/471/2 +f 98/242/5 99/787/5 611/788/5 610/243/5 +f 308/789/3 307/790/3 819/791/3 820/792/3 +f 343/793/2 344/794/2 856/795/2 855/796/2 +f 198/300/4 199/797/4 711/798/4 710/301/4 +f 199/797/4 70/187/4 582/190/4 711/798/4 +f 393/799/3 392/800/3 904/801/3 905/802/3 +f 382/803/2 418/804/2 930/805/2 894/806/2 +f 14/280/4 15/757/4 527/758/4 526/281/4 +f 440/807/3 445/808/3 957/809/3 952/810/3 +f 445/808/3 444/811/3 956/812/3 957/809/3 +f 263/233/3 261/813/3 773/814/3 775/234/3 +f 173/815/5 90/816/5 602/817/5 685/818/5 +f 247/650/4 118/675/4 630/676/4 759/651/4 +f 412/819/2 413/820/2 925/821/2 924/822/2 +f 402/406/3 406/345/3 918/348/3 914/407/3 +f 418/804/2 415/823/2 927/824/2 930/805/2 +f 139/686/5 124/825/5 636/826/5 651/687/5 +f 461/827/2 458/585/2 970/586/2 973/828/2 +f 479/184/2 480/511/2 992/514/2 991/185/2 +f 53/530/5 146/633/5 658/634/5 565/531/5 +f 390/495/2 391/709/2 903/712/2 902/496/2 +f 342/394/2 343/793/2 855/796/2 854/395/2 +f 92/646/5 93/663/5 605/666/5 604/647/5 +f 56/612/4 57/431/4 569/432/4 568/613/4 +f 227/829/5 36/830/5 548/831/5 739/832/5 +f 44/833/5 45/733/5 557/734/5 556/834/5 +f 331/350/2 332/835/2 844/836/2 843/351/2 +f 244/550/5 245/837/5 757/838/5 756/551/5 +f 299/723/3 298/839/3 810/840/3 811/724/3 +f 156/400/5 157/841/5 669/842/5 668/401/5 +f 323/843/3 322/569/3 834/572/3 835/844/3 +f 50/269/5 51/845/5 563/846/5 562/270/5 +f 136/847/4 137/848/4 649/849/4 648/850/4 +f 140/134/5 141/179/5 653/182/5 652/135/5 +f 261/813/3 260/851/3 772/852/3 773/814/3 +f 387/853/3 385/517/3 897/520/3 899/854/3 +f 228/855/5 229/856/5 741/857/5 740/858/5 +f 386/573/3 396/859/3 908/860/3 898/574/3 +f 84/861/5 85/521/5 597/522/5 596/862/5 +f 278/863/3 277/864/3 789/865/3 790/866/3 +f 220/664/5 221/121/5 733/124/5 732/665/5 +f 77/867/5 204/373/5 716/376/5 589/868/5 +f 233/566/4 104/155/4 616/158/4 745/567/4 +f 151/462/4 48/79/4 560/82/4 663/463/4 +f 293/869/3 295/57/3 807/60/3 805/870/3 +f 298/839/3 300/149/3 812/152/3 810/840/3 +f 434/441/3 432/615/3 944/616/3 946/442/3 +f 380/42/2 381/871/2 893/872/2 892/43/2 +f 435/707/3 426/873/3 938/874/3 947/708/3 +f 74/527/5 75/875/5 587/876/5 586/528/5 +f 196/877/5 197/878/5 709/879/5 708/880/5 +f 157/841/5 106/735/5 618/736/5 669/842/5 +f 332/835/2 354/881/2 866/882/2 844/836/2 +f 252/164/5 253/385/5 765/386/5 764/165/5 +f 515/434/2 505/883/2 1017/884/2 1027/435/2 +f 170/885/5 171/645/5 683/648/5 682/886/5 +f 97/887/4 166/888/4 678/889/4 609/890/4 +f 131/891/5 258/892/5 770/893/5 643/894/5 +f 230/38/4 231/103/4 743/106/4 742/39/4 +f 500/895/2 489/765/2 1001/766/2 1012/896/2 +f 245/837/5 18/897/5 530/898/5 757/838/5 +f 397/899/2 398/900/2 910/901/2 909/902/2 +f 511/657/2 512/223/2 1024/226/2 1023/658/2 +f 470/448/2 471/107/2 983/110/2 982/449/2 +f 202/903/5 203/561/5 715/564/5 714/904/5 +f 82/905/5 83/587/5 595/590/5 594/906/5 +f 78/557/4 79/21/4 591/24/4 590/558/4 +f 142/774/4 143/611/4 655/614/4 654/775/4 +f 167/907/4 16/245/4 528/248/4 679/908/4 +f 215/909/4 86/910/4 598/911/4 727/912/4 +f 365/913/3 403/914/3 915/915/3 877/916/3 +f 76/917/5 77/867/5 589/868/5 588/918/5 +f 13/536/5 170/885/5 682/886/5 525/537/5 +f 381/871/2 382/803/2 894/806/2 893/872/2 +f 467/919/2 468/920/2 980/921/2 979/922/2 +f 208/412/4 209/923/4 721/924/4 720/413/4 +f 96/762/4 97/887/4 609/890/4 608/763/4 +f 64/748/4 65/299/4 577/302/4 576/749/4 +f 60/562/5 61/925/5 573/926/5 572/563/5 +f 19/927/5 164/367/5 676/368/5 531/928/5 +f 250/929/5 251/769/5 763/770/5 762/930/5 +f 469/931/2 467/919/2 979/922/2 981/932/2 +f 457/933/2 453/934/2 965/935/2 969/936/2 +f 109/694/5 236/937/5 748/938/5 621/695/5 +f 236/937/5 237/173/5 749/174/5 748/938/5 +f 6/939/4 7/249/4 519/252/4 518/940/4 +f 36/830/5 37/307/5 549/310/5 548/831/5 +f 130/30/5 131/891/5 643/894/5 642/31/5 +f 123/429/5 250/929/5 762/930/5 635/430/5 +f 258/892/5 259/941/5 771/942/5 770/893/5 +f 90/816/5 91/943/5 603/944/5 602/817/5 +f 399/710/2 397/899/2 909/902/2 911/711/2 +f 446/655/3 448/945/3 960/946/3 958/656/3 +f 216/947/4 217/948/4 729/949/4 728/950/4 +f 187/951/5 76/917/5 588/918/5 699/952/5 +f 464/713/2 469/931/2 981/932/2 976/714/2 +f 105/156/4 158/783/4 670/784/4 617/157/4 +f 235/953/5 28/954/5 540/955/5 747/956/5 +f 466/957/2 462/261/2 974/264/2 978/958/2 +f 505/883/2 506/629/2 1018/632/2 1017/884/2 +f 175/146/4 17671/959/4 17675/960/4 687/147/4 +f 219/608/5 44/833/5 556/834/5 731/609/5 +f 314/570/3 313/455/3 825/458/3 826/571/3 +f 495/502/2 496/125/2 1008/128/2 1007/503/2 +f 453/934/2 454/961/2 966/962/2 965/935/2 +f 452/963/3 451/683/3 963/684/3 964/964/3 +f 344/794/2 350/113/2 862/116/2 856/795/2 +f 492/660/2 493/591/2 1005/592/2 1004/661/2 +f 51/845/5 148/317/5 660/320/5 563/846/5 +f 277/864/3 279/965/3 791/966/3 789/865/3 +f 155/668/5 108/693/5 620/696/5 667/669/5 +f 454/961/2 455/967/2 967/968/2 966/962/2 +f 426/873/3 425/507/3 937/510/3 938/874/3 +f 302/969/3 304/970/3 816/971/3 814/972/3 +f 488/294/2 494/973/2 1006/974/2 1000/295/2 +f 217/948/4 88/211/4 600/214/4 729/949/4 +f 421/66/2 419/203/2 931/206/2 933/67/2 +f 320/975/3 324/976/3 836/977/3 832/978/3 +f 424/653/3 430/599/3 942/602/3 936/654/3 +f 99/787/5 226/979/5 738/980/5 611/788/5 +f 61/925/5 138/685/5 650/688/5 573/926/5 +f 367/311/3 369/739/3 881/740/3 879/312/3 +f 127/981/4 136/847/4 648/850/4 639/982/4 +f 38/983/4 39/984/4 551/985/4 550/986/4 +f 89/212/4 174/145/4 686/148/4 601/213/4 +f 502/630/2 503/253/2 1015/256/2 1014/631/2 +f 360/96/3 366/703/3 878/706/3 872/97/3 +f 316/745/3 315/387/3 827/390/3 828/746/3 +f 305/576/3 303/987/3 815/988/3 817/577/3 +f 23/62/4 240/129/4 752/132/4 535/63/4 +f 304/970/3 309/989/3 821/990/3 816/971/3 +f 378/991/2 379/337/2 891/340/2 890/992/2 +f 197/878/5 66/69/5 578/70/5 709/879/5 +f 289/993/3 287/283/3 799/286/3 801/994/3 +f 357/239/2 355/297/2 867/298/2 869/240/2 +f 20/582/5 21/415/5 533/418/5 532/583/5 +f 144/138/4 145/451/4 657/454/4 656/139/4 +f 472/108/2 478/995/2 990/996/2 984/109/2 +f 485/737/2 483/219/2 995/222/2 997/738/2 +f 375/338/2 376/369/2 888/370/2 887/339/2 +f 290/485/3 281/741/3 793/744/3 802/486/3 +f 178/997/5 179/998/5 691/999/5 690/1000/5 +f 468/920/2 456/1001/2 968/1002/2 980/921/2 +f 181/751/5 82/905/5 594/906/5 693/752/5 +f 86/910/4 87/491/4 599/494/4 598/911/4 +f 309/989/3 308/789/3 820/792/3 821/990/3 +f 91/943/5 218/607/5 730/610/5 603/944/5 +f 214/425/4 215/909/4 727/912/4 726/426/4 +f 47/777/4 216/947/4 728/950/4 559/778/4 +f 31/230/4 232/565/4 744/568/4 543/231/4 +f 134/555/4 135/747/4 647/750/4 646/556/4 +f 226/979/5 227/829/5 739/832/5 738/980/5 +f 161/1003/4 38/983/4 550/986/4 673/1004/4 +f 238/1005/4 239/1006/4 751/1007/4 750/1008/4 +f 318/459/3 320/975/3 832/978/3 830/460/3 +f 160/754/4 161/1003/4 673/1004/4 672/755/4 +f 456/1001/2 457/933/2 969/936/2 968/1002/2 +f 5/1009/5 17670/1010/5 17674/1011/5 517/1012/5 +f 441/1013/3 439/1014/3 951/1015/3 953/1016/3 +f 478/995/2 475/553/2 987/554/2 990/996/2 +f 448/945/3 452/963/3 964/964/3 960/946/3 +f 372/391/3 362/767/3 874/768/3 884/392/3 +f 460/488/2 482/183/2 994/186/2 972/489/2 +f 396/859/3 393/799/3 905/802/3 908/860/3 +f 132/54/5 133/29/5 645/32/5 644/55/5 +f 413/820/2 337/427/2 849/428/2 925/821/2 +f 172/678/5 173/815/5 685/818/5 684/679/5 +f 101/672/5 228/855/5 740/858/5 613/673/5 +f 329/759/2 325/689/2 837/692/2 841/760/2 +f 201/160/4 72/481/4 584/482/4 713/161/4 +f 179/998/5 84/861/5 596/862/5 691/999/5 +f 303/987/3 302/969/3 814/972/3 815/988/3 +f 438/1017/3 440/807/3 952/810/3 950/1018/3 +f 392/800/3 17673/1019/3 17677/1020/3 904/801/3 +f 486/716/2 487/293/2 999/296/2 998/717/2 +f 176/492/4 177/1021/4 689/1022/4 688/493/4 +f 354/881/2 351/533/2 863/534/2 866/882/2 +f 307/790/3 297/483/3 809/484/3 819/791/3 +f 280/742/3 278/863/3 790/866/3 792/743/3 +f 260/851/3 262/727/3 774/730/3 772/852/3 +f 443/1023/3 371/271/3 883/274/3 955/1024/3 +f 259/941/5 5/1009/5 517/1012/5 771/942/5 +f 444/811/3 443/1023/3 955/1024/3 956/812/3 +f 326/690/2 327/477/2 839/480/2 838/691/2 +f 229/856/5 34/725/5 546/726/5 741/857/5 +f 283/638/3 282/333/3 794/336/3 795/639/3 +f 239/1006/4 110/1025/4 622/1026/4 751/1007/4 +f 75/875/5 202/903/5 714/904/5 587/876/5 +f 439/1014/3 438/1017/3 950/1018/3 951/1015/3 +f 288/701/3 292/99/3 804/102/3 800/702/3 +f 54/452/4 55/411/4 567/414/4 566/453/4 +f 25/236/4 238/1005/4 750/1008/4 537/237/4 +f 116/546/5 117/549/5 629/552/5 628/547/5 +f 69/597/5 196/877/5 708/880/5 581/598/5 +f 255/524/4 126/1027/4 638/1028/4 767/525/4 +f 499/539/2 500/895/2 1012/896/2 1011/540/2 +f 40/258/4 41/697/4 553/698/4 552/259/4 +f 28/954/5 29/621/5 541/622/5 540/955/5 +f 209/923/4 80/619/4 592/620/4 721/924/4 +f 71/188/4 192/465/4 704/468/4 583/189/4 +f 403/914/3 401/1029/3 913/1030/3 915/915/3 +f 398/900/2 378/991/2 890/992/2 910/901/2 +f 324/976/3 323/843/3 835/844/3 836/977/3 +f 414/84/2 412/819/2 924/822/2 926/85/2 +f 273/388/3 272/627/3 784/628/3 785/389/3 +f 415/823/2 416/1031/2 928/1032/2 927/824/2 +f 39/984/4 224/781/4 736/782/4 551/985/4 +f 193/466/4 32/409/4 544/410/4 705/467/4 +f 276/593/3 275/397/3 787/398/3 788/594/3 +f 185/365/4 24/235/4 536/238/4 697/366/4 +f 113/330/4 150/461/4 662/464/4 625/331/4 +f 18/897/5 19/927/5 531/928/5 530/898/5 +f 11/192/5 178/997/5 690/1000/5 523/193/5 +f 162/308/5 163/731/5 675/732/5 674/309/5 +f 124/825/5 125/163/5 637/166/5 636/826/5 +f 110/1025/4 111/71/4 623/74/4 622/1026/4 +f 8/1033/4 9/543/4 521/544/4 520/1034/4 +f 152/72/4 153/49/4 665/52/4 664/73/4 +f 149/318/5 114/617/5 626/618/5 661/319/5 +f 186/785/5 187/951/5 699/952/5 698/786/5 +f 427/623/3 429/195/3 941/198/3 939/624/3 +f 388/595/3 387/853/3 899/854/3 900/596/3 +f 401/1029/3 400/405/3 912/408/3 913/1030/3 +f 455/967/2 461/827/2 973/828/2 967/968/2 +f 126/1027/4 127/981/4 639/982/4 638/1028/4 +f 177/1021/4 8/1033/4 520/1034/4 689/1022/4 +f 137/848/4 62/779/4 574/780/4 649/849/4 +f 234/142/5 235/953/5 747/956/5 746/143/5 +f 339/1035/2 340/207/2 852/210/2 851/1036/2 +f 268/728/3 266/515/3 778/516/3 780/729/3 +f 494/973/2 491/659/2 1003/662/2 1006/974/2 +f 294/444/3 293/869/3 805/870/3 806/445/3 +f 183/288/4 22/61/4 534/64/4 695/289/4 +f 279/965/3 285/637/3 797/640/3 791/966/3 +f 267/474/3 289/993/3 801/994/3 779/475/3 +f 363/721/3 365/913/3 877/916/3 875/722/3 +f 465/719/2 466/957/2 978/958/2 977/720/2 +f 341/76/2 339/1035/2 851/1036/2 853/77/2 +f 416/1031/2 417/65/2 929/68/2 928/1032/2 +f 166/888/4 167/907/4 679/908/4 678/889/4 +f 442/604/3 441/1013/3 953/1016/3 954/605/3 +f 120/641/4 121/773/4 633/776/4 632/642/4 +f 94/353/4 95/625/4 607/626/4 606/354/4 +f 1029/1037/1 1030/1038/1 1031/1039/1 1032/1040/1 +f 1033/1041/1 1034/1042/1 1035/1043/1 1036/1044/1 +f 1037/1045/1 1038/1046/1 1039/1047/1 1040/1048/1 +f 1041/1049/1 1042/1050/1 1043/1051/1 1044/1052/1 +f 1045/1053/1 1046/1054/1 1047/1055/1 1048/1056/1 +f 1049/1057/1 1050/1058/1 1051/1059/1 1052/1060/1 +f 1053/1061/1 1054/1062/1 1055/1063/1 1056/1064/1 +f 1057/1065/1 1058/1066/1 1059/1067/1 1060/1068/1 +f 1061/1069/1 1062/1070/1 1063/1071/1 1064/1072/1 +f 1065/1073/1 1066/1074/1 1067/1075/1 1068/1076/1 +f 1069/1077/1 1070/1078/1 1071/1079/1 1072/1080/1 +f 1073/1081/1 1074/1082/1 1075/1083/1 1076/1084/1 +f 1077/1085/1 1078/1086/1 1079/1087/1 1080/1088/1 +f 1081/1089/1 1082/1090/1 1083/1091/1 1084/1092/1 +f 1085/1093/1 1086/1094/1 1087/1095/1 1088/1096/1 +f 1089/1097/1 1090/1098/1 1091/1099/1 1092/1100/1 +f 1093/1101/1 1094/1102/1 1095/1103/1 1096/1104/1 +f 1097/1105/1 1098/1106/1 1099/1107/1 1100/1108/1 +f 1101/1109/1 1102/1110/1 1103/1111/1 1104/1112/1 +f 1105/1113/1 1106/1114/1 1107/1115/1 1108/1116/1 +f 1109/1117/1 1110/1118/1 1111/1119/1 1112/1120/1 +f 1113/1121/1 1114/1122/1 1115/1123/1 1116/1124/1 +f 1117/1125/1 1118/1126/1 1119/1127/1 1120/1128/1 +f 1121/1129/1 1122/1130/1 1123/1131/1 1124/1132/1 +f 1125/1133/1 1126/1134/1 1127/1135/1 1128/1136/1 +f 1129/1137/1 1130/1138/1 1131/1139/1 1132/1140/1 +f 1133/1141/1 1134/1142/1 1135/1143/1 1136/1144/1 +f 1137/1145/1 1138/1146/1 1139/1147/1 1140/1148/1 +f 1141/1149/1 1142/1150/1 1143/1151/1 1144/1152/1 +f 1145/1153/1 1146/1154/1 1147/1155/1 1148/1156/1 +f 1149/1157/1 1150/1158/1 1151/1159/1 1152/1160/1 +f 1153/1161/1 1154/1162/1 1155/1163/1 1156/1164/1 +f 1157/1165/1 1158/1166/1 1159/1167/1 1160/1168/1 +f 1161/1169/1 1162/1170/1 1163/1171/1 1164/1172/1 +f 1165/1173/1 1166/1174/1 1167/1175/1 1168/1176/1 +f 1169/1177/1 1170/1178/1 1171/1179/1 1172/1180/1 +f 1173/1181/1 1174/1182/1 1175/1183/1 1176/1184/1 +f 1177/1185/1 1178/1186/1 1179/1187/1 1180/1188/1 +f 1181/1189/1 1182/1190/1 1183/1191/1 1184/1192/1 +f 1185/1193/1 1186/1194/1 1187/1195/1 1188/1196/1 +f 1189/1197/1 1190/1198/1 1191/1199/1 1192/1200/1 +f 1193/1201/1 1194/1202/1 1195/1203/1 1196/1204/1 +f 1197/1205/1 1198/1206/1 1199/1207/1 1200/1208/1 +f 1201/1209/1 1202/1210/1 1203/1211/1 1204/1212/1 +f 1205/1213/1 1206/1214/1 1207/1215/1 1208/1216/1 +f 1209/1217/1 1210/1218/1 1211/1219/1 1212/1220/1 +f 1213/1221/1 1214/1222/1 1215/1223/1 1216/1224/1 +f 1217/1225/1 1218/1226/1 1219/1227/1 1220/1228/1 +f 1221/1229/1 1222/1230/1 1223/1231/1 1224/1232/1 +f 1225/1233/1 1226/1234/1 1227/1235/1 1228/1236/1 +f 1229/1237/1 1230/1238/1 1231/1239/1 1232/1240/1 +f 1233/1241/1 1234/1242/1 1235/1243/1 1236/1244/1 +f 1237/1245/1 1238/1246/1 1239/1247/1 1240/1248/1 +f 1241/1249/1 1242/1250/1 1243/1251/1 1244/1252/1 +f 1245/1253/1 1246/1254/1 1247/1255/1 1248/1256/1 +f 1249/1257/1 1250/1258/1 1251/1259/1 1252/1260/1 +f 1253/1261/1 1254/1262/1 1255/1263/1 1256/1264/1 +f 1257/1265/1 1258/1266/1 1259/1267/1 1260/1268/1 +f 1261/1269/1 1262/1270/1 1263/1271/1 1264/1272/1 +f 1265/1273/1 1266/1274/1 1267/1275/1 1268/1276/1 +f 1269/1277/1 1270/1278/1 1271/1279/1 1272/1280/1 +f 1273/1281/1 1274/1282/1 1275/1283/1 1276/1284/1 +f 1277/1285/1 1278/1286/1 1279/1287/1 1280/1288/1 +f 1281/1289/1 1282/1290/1 1283/1291/1 1284/1292/1 +f 1285/1293/1 1286/1294/1 1287/1295/1 1288/1296/1 +f 1289/1297/1 1290/1298/1 1291/1299/1 1292/1300/1 +f 1293/1301/1 1294/1302/1 1295/1303/1 1296/1304/1 +f 1297/1305/1 1298/1306/1 1299/1307/1 1300/1308/1 +f 1301/1309/1 1302/1310/1 1303/1311/1 1304/1312/1 +f 1305/1313/1 1306/1314/1 1307/1315/1 1308/1316/1 +f 1309/1317/1 1310/1318/1 1311/1319/1 1312/1320/1 +f 1313/1321/1 1314/1322/1 1315/1323/1 1316/1324/1 +f 1317/1325/1 1318/1326/1 1319/1327/1 1320/1328/1 +f 1321/1329/1 1322/1330/1 1323/1331/1 1324/1332/1 +f 1325/1333/1 1326/1334/1 1327/1335/1 1328/1336/1 +f 1329/1337/1 1330/1338/1 1331/1339/1 1332/1340/1 +f 1333/1341/1 1334/1342/1 1335/1343/1 1336/1344/1 +f 1337/1345/1 1338/1346/1 1339/1347/1 1340/1348/1 +f 1341/1349/1 1342/1350/1 1343/1351/1 1344/1352/1 +f 1345/1353/1 1346/1354/1 1347/1355/1 1348/1356/1 +f 1349/1357/1 1350/1358/1 1351/1359/1 1352/1360/1 +f 1353/1361/1 1354/1362/1 1355/1363/1 1356/1364/1 +f 1357/1365/1 1358/1366/1 1359/1367/1 1360/1368/1 +f 1361/1369/1 1362/1370/1 1363/1371/1 1364/1372/1 +f 1365/1373/1 1366/1374/1 1367/1375/1 1368/1376/1 +f 1369/1377/1 1370/1378/1 1371/1379/1 1372/1380/1 +f 1373/1381/1 1374/1382/1 1375/1383/1 1376/1384/1 +f 1377/1385/1 1378/1386/1 1379/1387/1 1380/1388/1 +f 1381/1389/1 1382/1390/1 1383/1391/1 1384/1392/1 +f 1385/1393/1 1386/1394/1 1387/1395/1 1388/1396/1 +f 1389/1397/1 1390/1398/1 1391/1399/1 1392/1400/1 +f 1393/1401/1 1394/1402/1 1395/1403/1 1396/1404/1 +f 1397/1405/1 1398/1406/1 1399/1407/1 1400/1408/1 +f 1401/1409/1 1402/1410/1 1403/1411/1 1404/1412/1 +f 1405/1413/1 1406/1414/1 1407/1415/1 1408/1416/1 +f 1409/1417/1 1410/1418/1 1411/1419/1 1412/1420/1 +f 1413/1421/1 1414/1422/1 1415/1423/1 1416/1424/1 +f 1417/1425/1 1418/1426/1 1419/1427/1 1420/1428/1 +f 1421/1429/1 1422/1430/1 1423/1431/1 1424/1432/1 +f 1425/1433/1 1426/1434/1 1427/1435/1 1428/1436/1 +f 1429/1437/1 1430/1438/1 1431/1439/1 1432/1440/1 +f 1433/1441/1 1434/1442/1 1435/1443/1 1436/1444/1 +f 1437/1445/1 1438/1446/1 1439/1447/1 1440/1448/1 +f 1441/1449/1 1442/1450/1 1443/1451/1 1444/1452/1 +f 1445/1453/1 1446/1454/1 1447/1455/1 1448/1456/1 +f 1449/1457/1 1450/1458/1 1451/1459/1 1452/1460/1 +f 1453/1461/1 1454/1462/1 1455/1463/1 1456/1464/1 +f 1457/1465/1 1458/1466/1 1459/1467/1 1460/1468/1 +f 1461/1469/1 1462/1470/1 1463/1471/1 1464/1472/1 +f 1465/1473/1 1466/1474/1 1467/1475/1 1468/1476/1 +f 1469/1477/1 1470/1478/1 1471/1479/1 1472/1480/1 +f 1473/1481/1 1474/1482/1 1475/1483/1 1476/1484/1 +f 1477/1485/1 1478/1486/1 1479/1487/1 1480/1488/1 +f 1481/1489/1 1482/1490/1 1483/1491/1 1484/1492/1 +f 1485/1493/1 1486/1494/1 1487/1495/1 1488/1496/1 +f 1489/1497/1 1490/1498/1 1491/1499/1 1492/1500/1 +f 1493/1501/1 1494/1502/1 1495/1503/1 1496/1504/1 +f 1497/1505/1 1498/1506/1 1499/1507/1 1500/1508/1 +f 1501/1509/1 1502/1510/1 1503/1511/1 1504/1512/1 +f 1505/1513/1 1506/1514/1 1507/1515/1 1508/1516/1 +f 1509/1517/1 1510/1518/1 1511/1519/1 1512/1520/1 +f 1513/1521/1 1514/1522/1 1515/1523/1 1516/1524/1 +f 1517/1525/1 1518/1526/1 1519/1527/1 1520/1528/1 +f 1521/1529/1 1522/1530/1 1523/1531/1 1524/1532/1 +f 1525/1533/1 1526/1534/1 1527/1535/1 1528/1536/1 +f 1529/1537/1 1530/1538/1 1531/1539/1 1532/1540/1 +f 1533/1541/1 1534/1542/1 1535/1543/1 1536/1544/1 +f 1537/1545/1 1538/1546/1 1539/1547/1 1540/1548/1 +f 1541/1549/1 1542/1550/1 1543/1551/1 1544/1552/1 +f 1545/1553/1 1546/1554/1 1547/1555/1 1548/1556/1 +f 1549/1557/1 1550/1558/1 1551/1559/1 1552/1560/1 +f 1553/1561/1 1554/1562/1 1555/1563/1 1556/1564/1 +f 1557/1565/1 1558/1566/1 1559/1567/1 1560/1568/1 +f 1561/1569/1 1562/1570/1 1563/1571/1 1564/1572/1 +f 1565/1573/1 1566/1574/1 1567/1575/1 1568/1576/1 +f 1569/1577/1 1570/1578/1 1571/1579/1 1572/1580/1 +f 1573/1581/1 1574/1582/1 1575/1583/1 1576/1584/1 +f 1577/1585/1 1578/1586/1 1579/1587/1 1580/1588/1 +f 1581/1589/1 1582/1590/1 1583/1591/1 1584/1592/1 +f 1585/1593/1 1586/1594/1 1587/1595/1 1588/1596/1 +f 1589/1597/1 1590/1598/1 1591/1599/1 1592/1600/1 +f 1593/1601/1 1594/1602/1 1595/1603/1 1596/1604/1 +f 1597/1605/1 1598/1606/1 1599/1607/1 1600/1608/1 +f 1601/1609/1 1602/1610/1 1603/1611/1 1604/1612/1 +f 1605/1613/1 1606/1614/1 1607/1615/1 1608/1616/1 +f 1609/1617/1 1610/1618/1 1611/1619/1 1612/1620/1 +f 1613/1621/1 1614/1622/1 1615/1623/1 1616/1624/1 +f 1617/1625/1 1618/1626/1 1619/1627/1 1620/1628/1 +f 1621/1629/1 1622/1630/1 1623/1631/1 1624/1632/1 +f 1625/1633/1 1626/1634/1 1627/1635/1 1628/1636/1 +f 1629/1637/1 1630/1638/1 1631/1639/1 1632/1640/1 +f 1633/1641/1 1634/1642/1 1635/1643/1 1636/1644/1 +f 1637/1645/1 1638/1646/1 1639/1647/1 1640/1648/1 +f 1641/1649/1 1642/1650/1 1643/1651/1 1644/1652/1 +f 1645/1653/1 1646/1654/1 1647/1655/1 1648/1656/1 +f 1649/1657/1 1650/1658/1 1651/1659/1 1652/1660/1 +f 1653/1661/1 1654/1662/1 1655/1663/1 1656/1664/1 +f 1657/1665/1 1658/1666/1 1659/1667/1 1660/1668/1 +f 1661/1669/1 1662/1670/1 1663/1671/1 1664/1672/1 +f 1665/1673/1 1666/1674/1 1667/1675/1 1668/1676/1 +f 1669/1677/1 1670/1678/1 1671/1679/1 1672/1680/1 +f 1673/1681/1 1674/1682/1 1675/1683/1 1676/1684/1 +f 1677/1685/1 1678/1686/1 1679/1687/1 1680/1688/1 +f 1681/1689/1 1682/1690/1 1683/1691/1 1684/1692/1 +f 1685/1693/1 1686/1694/1 1687/1695/1 1688/1696/1 +f 1689/1697/1 1690/1698/1 1691/1699/1 1692/1700/1 +f 1693/1701/1 1694/1702/1 1695/1703/1 1696/1704/1 +f 1697/1705/1 1698/1706/1 1699/1707/1 1700/1708/1 +f 1701/1709/1 1702/1710/1 1703/1711/1 1704/1712/1 +f 1705/1713/1 1706/1714/1 1707/1715/1 1708/1716/1 +f 1709/1717/1 1710/1718/1 1711/1719/1 1712/1720/1 +f 1713/1721/1 1714/1722/1 1715/1723/1 1716/1724/1 +f 1717/1725/1 1718/1726/1 1719/1727/1 1720/1728/1 +f 1721/1729/1 1722/1730/1 1723/1731/1 1724/1732/1 +f 1725/1733/1 1726/1734/1 1727/1735/1 1728/1736/1 +f 1729/1737/1 1730/1738/1 1731/1739/1 1732/1740/1 +f 1733/1741/1 1734/1742/1 1735/1743/1 1736/1744/1 +f 1737/1745/1 1738/1746/1 1739/1747/1 1740/1748/1 +f 1741/1749/1 1742/1750/1 1743/1751/1 1744/1752/1 +f 1745/1753/1 1746/1754/1 1747/1755/1 1748/1756/1 +f 1749/1757/1 1750/1758/1 1751/1759/1 1752/1760/1 +f 1753/1761/1 1754/1762/1 1755/1763/1 1756/1764/1 +f 1757/1765/1 1758/1766/1 1759/1767/1 1760/1768/1 +f 1761/1769/1 1762/1770/1 1763/1771/1 1764/1772/1 +f 1765/1773/1 1766/1774/1 1767/1775/1 1768/1776/1 +f 1769/1777/1 1770/1778/1 1771/1779/1 1772/1780/1 +f 1773/1781/1 1774/1782/1 1775/1783/1 1776/1784/1 +f 1777/1785/1 1778/1786/1 1779/1787/1 1780/1788/1 +f 1781/1789/1 1782/1790/1 1783/1791/1 1784/1792/1 +f 1785/1793/1 1786/1794/1 1787/1795/1 1788/1796/1 +f 1789/1797/1 1790/1798/1 1791/1799/1 1792/1800/1 +f 1793/1801/1 1794/1802/1 1795/1803/1 1796/1804/1 +f 1797/1805/1 1798/1806/1 1799/1807/1 1800/1808/1 +f 1801/1809/1 1802/1810/1 1803/1811/1 1804/1812/1 +f 1805/1813/1 1806/1814/1 1807/1815/1 1808/1816/1 +f 1809/1817/1 1810/1818/1 1811/1819/1 1812/1820/1 +f 1813/1821/1 1814/1822/1 1815/1823/1 1816/1824/1 +f 1817/1825/1 1818/1826/1 1819/1827/1 1820/1828/1 +f 1821/1829/1 1822/1830/1 1823/1831/1 1824/1832/1 +f 1825/1833/1 1826/1834/1 1827/1835/1 1828/1836/1 +f 1829/1837/1 1830/1838/1 1831/1839/1 1832/1840/1 +f 1833/1841/1 1834/1842/1 1835/1843/1 1836/1844/1 +f 1837/1845/1 1838/1846/1 1839/1847/1 1840/1848/1 +f 1841/1849/1 1842/1850/1 1843/1851/1 1844/1852/1 +f 1845/1853/1 1846/1854/1 1847/1855/1 1848/1856/1 +f 1849/1857/1 1850/1858/1 1851/1859/1 1852/1860/1 +f 1853/1861/1 1854/1862/1 1855/1863/1 1856/1864/1 +f 1857/1865/1 1858/1866/1 1859/1867/1 1860/1868/1 +f 1861/1869/1 1862/1870/1 1863/1871/1 1864/1872/1 +f 1865/1873/1 1866/1874/1 1867/1875/1 1868/1876/1 +f 1869/1877/1 1870/1878/1 1871/1879/1 1872/1880/1 +f 1873/1881/1 1874/1882/1 1875/1883/1 1876/1884/1 +f 1877/1885/1 1878/1886/1 1879/1887/1 1880/1888/1 +f 1881/1889/1 1882/1890/1 1883/1891/1 1884/1892/1 +f 1885/1893/1 1886/1894/1 1887/1895/1 1888/1896/1 +f 1889/1897/1 1890/1898/1 1891/1899/1 1892/1900/1 +f 1893/1901/1 1894/1902/1 1895/1903/1 1896/1904/1 +f 1897/1905/1 1898/1906/1 1899/1907/1 1900/1908/1 +f 1901/1909/1 1902/1910/1 1903/1911/1 1904/1912/1 +f 1905/1913/1 1906/1914/1 1907/1915/1 1908/1916/1 +f 1909/1917/1 1910/1918/1 1911/1919/1 1912/1920/1 +f 1913/1921/1 1914/1922/1 1915/1923/1 1916/1924/1 +f 1917/1925/1 1918/1926/1 1919/1927/1 1920/1928/1 +f 1921/1929/1 1922/1930/1 1923/1931/1 1924/1932/1 +f 1925/1933/1 1926/1934/1 1927/1935/1 1928/1936/1 +f 1929/1937/1 1930/1938/1 1931/1939/1 1932/1940/1 +f 1933/1941/1 1934/1942/1 1935/1943/1 1936/1944/1 +f 1937/1945/1 1938/1946/1 1939/1947/1 1940/1948/1 +f 1941/1949/1 1942/1950/1 1943/1951/1 1944/1952/1 +f 1945/1953/1 1946/1954/1 1947/1955/1 1948/1956/1 +f 1949/1957/1 1950/1958/1 1951/1959/1 1952/1960/1 +f 1953/1961/1 1954/1962/1 1955/1963/1 1956/1964/1 +f 1957/1965/1 1958/1966/1 1959/1967/1 1960/1968/1 +f 1961/1969/1 1962/1970/1 1963/1971/1 1964/1972/1 +f 1965/1973/1 1966/1974/1 1967/1975/1 1968/1976/1 +f 1969/1977/1 1970/1978/1 1971/1979/1 1972/1980/1 +f 1973/1981/1 1974/1982/1 1975/1983/1 1976/1984/1 +f 1977/1985/1 1978/1986/1 1979/1987/1 1980/1988/1 +f 1981/1989/1 1982/1990/1 1983/1991/1 1984/1992/1 +f 1985/1993/1 1986/1994/1 1987/1995/1 1988/1996/1 +f 1989/1997/1 1990/1998/1 1991/1999/1 1992/2000/1 +f 1993/2001/1 1994/2002/1 1995/2003/1 1996/2004/1 +f 1997/2005/1 1998/2006/1 1999/2007/1 2000/2008/1 +f 2001/2009/1 2002/2010/1 2003/2011/1 2004/2012/1 +f 2005/2013/1 2006/2014/1 2007/2015/1 2008/2016/1 +f 2009/2017/1 2010/2018/1 2011/2019/1 2012/2020/1 +f 2013/2021/1 2014/2022/1 2015/2023/1 2016/2024/1 +f 2017/2025/1 2018/2026/1 2019/2027/1 2020/2028/1 +f 2021/2029/1 2022/2030/1 2023/2031/1 2024/2032/1 +f 2025/2033/1 2026/2034/1 2027/2035/1 2028/2036/1 +f 2029/2037/1 2030/2038/1 2031/2039/1 2032/2040/1 +f 2033/2041/1 2034/2042/1 2035/2043/1 2036/2044/1 +f 2037/2045/1 2038/2046/1 2039/2047/1 2040/2048/1 +f 2041/2049/1 2042/2050/1 2043/2051/1 2044/2052/1 +f 2045/2053/1 2046/2054/1 2047/2055/1 2048/2056/1 +f 2049/2057/1 2050/2058/1 2051/2059/1 2052/2060/1 +f 2053/2061/1 2054/2062/1 2055/2063/1 2056/2064/1 +f 2057/2065/1 2058/2066/1 2059/2067/1 2060/2068/1 +f 2061/2069/1 2062/2070/1 2063/2071/1 2064/2072/1 +f 2065/2073/1 2066/2074/1 2067/2075/1 2068/2076/1 +f 2069/2077/1 2070/2078/1 2071/2079/1 2072/2080/1 +f 2073/2081/1 2074/2082/1 2075/2083/1 2076/2084/1 +f 2077/2085/1 2078/2086/1 2079/2087/1 2080/2088/1 +f 2081/2089/1 2082/2090/1 2083/2091/1 2084/2092/1 +f 2085/2093/1 2086/2094/1 2087/2095/1 2088/2096/1 +f 2089/2097/1 2090/2098/1 2091/2099/1 2092/2100/1 +f 2093/2101/1 2094/2102/1 2095/2103/1 2096/2104/1 +f 2097/2105/1 2098/2106/1 2099/2107/1 2100/2108/1 +f 2101/2109/1 2102/2110/1 2103/2111/1 2104/2112/1 +f 2105/2113/1 2106/2114/1 2107/2115/1 2108/2116/1 +f 2109/2117/1 2110/2118/1 2111/2119/1 2112/2120/1 +f 2113/2121/1 2114/2122/1 2115/2123/1 2116/2124/1 +f 2117/2125/1 2118/2126/1 2119/2127/1 2120/2128/1 +f 2121/2129/1 2122/2130/1 2123/2131/1 2124/2132/1 +f 2125/2133/1 2126/2134/1 2127/2135/1 2128/2136/1 +f 2129/2137/1 2130/2138/1 2131/2139/1 2132/2140/1 +f 2133/2141/1 2134/2142/1 2135/2143/1 2136/2144/1 +f 2137/2145/1 2138/2146/1 2139/2147/1 2140/2148/1 +f 2141/2149/1 2142/2150/1 2143/2151/1 2144/2152/1 +f 2145/2153/1 2146/2154/1 2147/2155/1 2148/2156/1 +f 2149/2157/1 2150/2158/1 2151/2159/1 2152/2160/1 +f 2153/2161/1 2154/2162/1 2155/2163/1 2156/2164/1 +f 2157/2165/1 2158/2166/1 2159/2167/1 2160/2168/1 +f 2161/2169/1 2162/2170/1 2163/2171/1 2164/2172/1 +f 2165/2173/1 2166/2174/1 2167/2175/1 2168/2176/1 +f 2169/2177/1 2170/2178/1 2171/2179/1 2172/2180/1 +f 2173/2181/1 2174/2182/1 2175/2183/1 2176/2184/1 +f 2177/2185/1 2178/2186/1 2179/2187/1 2180/2188/1 +f 2181/2189/1 2182/2190/1 2183/2191/1 2184/2192/1 +f 2185/2193/1 2186/2194/1 2187/2195/1 2188/2196/1 +f 2189/2197/1 2190/2198/1 2191/2199/1 2192/2200/1 +f 2193/2201/1 2194/2202/1 2195/2203/1 2196/2204/1 +f 2197/2205/1 2198/2206/1 2199/2207/1 2200/2208/1 +f 2201/2209/1 2202/2210/1 2203/2211/1 2204/2212/1 +f 2205/2213/1 2206/2214/1 2207/2215/1 2208/2216/1 +f 2209/2217/1 2210/2218/1 2211/2219/1 2212/2220/1 +f 2213/2221/1 2214/2222/1 2215/2223/1 2216/2224/1 +f 2217/2225/1 2218/2226/1 2219/2227/1 2220/2228/1 +f 2221/2229/1 2222/2230/1 2223/2231/1 2224/2232/1 +f 2225/2233/1 2226/2234/1 2227/2235/1 2228/2236/1 +f 2229/2237/1 2230/2238/1 2231/2239/1 2232/2240/1 +f 2233/2241/1 2234/2242/1 2235/2243/1 2236/2244/1 +f 2237/2245/1 2238/2246/1 2239/2247/1 2240/2248/1 +f 2241/2249/1 2242/2250/1 2243/2251/1 2244/2252/1 +f 2245/2253/1 2246/2254/1 2247/2255/1 2248/2256/1 +f 2249/2257/1 2250/2258/1 2251/2259/1 2252/2260/1 +f 2253/2261/1 2254/2262/1 2255/2263/1 2256/2264/1 +f 2257/2265/1 2258/2266/1 2259/2267/1 2260/2268/1 +f 2261/2269/1 2262/2270/1 2263/2271/1 2264/2272/1 +f 2265/2273/1 2266/2274/1 2267/2275/1 2268/2276/1 +f 2269/2277/1 2270/2278/1 2271/2279/1 2272/2280/1 +f 2273/2281/1 2274/2282/1 2275/2283/1 2276/2284/1 +f 2277/2285/1 2278/2286/1 2279/2287/1 2280/2288/1 +f 2281/2289/1 2282/2290/1 2283/2291/1 2284/2292/1 +f 2285/2293/1 2286/2294/1 2287/2295/1 2288/2296/1 +f 2289/2297/1 2290/2298/1 2291/2299/1 2292/2300/1 +f 2293/2301/1 2294/2302/1 2295/2303/1 2296/2304/1 +f 2297/2305/1 2298/2306/1 2299/2307/1 2300/2308/1 +f 2301/2309/1 2302/2310/1 2303/2311/1 2304/2312/1 +f 2305/2313/1 2306/2314/1 2307/2315/1 2308/2316/1 +f 2309/2317/1 2310/2318/1 2311/2319/1 2312/2320/1 +f 2313/2321/1 2314/2322/1 2315/2323/1 2316/2324/1 +f 2317/2325/1 2318/2326/1 2319/2327/1 2320/2328/1 +f 2321/2329/1 2322/2330/1 2323/2331/1 2324/2332/1 +f 2325/2333/1 2326/2334/1 2327/2335/1 2328/2336/1 +f 2329/2337/1 2330/2338/1 2331/2339/1 2332/2340/1 +f 2333/2341/1 2334/2342/1 2335/2343/1 2336/2344/1 +f 2337/2345/1 2338/2346/1 2339/2347/1 2340/2348/1 +f 2341/2349/1 2342/2350/1 2343/2351/1 2344/2352/1 +f 2345/2353/1 2346/2354/1 2347/2355/1 2348/2356/1 +f 2349/2357/1 2350/2358/1 2351/2359/1 2352/2360/1 +f 2353/2361/1 2354/2362/1 2355/2363/1 2356/2364/1 +f 2357/2365/1 2358/2366/1 2359/2367/1 2360/2368/1 +f 2361/2369/1 2362/2370/1 2363/2371/1 2364/2372/1 +f 2365/2373/1 2366/2374/1 2367/2375/1 2368/2376/1 +f 2369/2377/1 2370/2378/1 2371/2379/1 2372/2380/1 +f 2373/2381/1 2374/2382/1 2375/2383/1 2376/2384/1 +f 2377/2385/1 2378/2386/1 2379/2387/1 2380/2388/1 +f 2381/2389/1 2382/2390/1 2383/2391/1 2384/2392/1 +f 2385/2393/1 2386/2394/1 2387/2395/1 2388/2396/1 +f 2389/2397/1 2390/2398/1 2391/2399/1 2392/2400/1 +f 2393/2401/1 2394/2402/1 2395/2403/1 2396/2404/1 +f 2397/2405/1 2398/2406/1 2399/2407/1 2400/2408/1 +f 2401/2409/1 2402/2410/1 2403/2411/1 2404/2412/1 +f 2405/2413/1 2406/2414/1 2407/2415/1 2408/2416/1 +f 2409/2417/1 2410/2418/1 2411/2419/1 2412/2420/1 +f 2413/2421/1 2414/2422/1 2415/2423/1 2416/2424/1 +f 2417/2425/1 2418/2426/1 2419/2427/1 2420/2428/1 +f 2421/2429/1 2422/2430/1 2423/2431/1 2424/2432/1 +f 2425/2433/1 2426/2434/1 2427/2435/1 2428/2436/1 +f 2429/2437/1 2430/2438/1 2431/2439/1 2432/2440/1 +f 2433/2441/1 2434/2442/1 2435/2443/1 2436/2444/1 +f 2437/2445/1 2438/2446/1 2439/2447/1 2440/2448/1 +f 2441/2449/1 2442/2450/1 2443/2451/1 2444/2452/1 +f 2445/2453/1 2446/2454/1 2447/2455/1 2448/2456/1 +f 2449/2457/1 2450/2458/1 2451/2459/1 2452/2460/1 +f 2453/2461/1 2454/2462/1 2455/2463/1 2456/2464/1 +f 2457/2465/1 2458/2466/1 2459/2467/1 2460/2468/1 +f 2461/2469/1 2462/2470/1 2463/2471/1 2464/2472/1 +f 2465/2473/1 2466/2474/1 2467/2475/1 2468/2476/1 +f 2469/2477/1 2470/2478/1 2471/2479/1 2472/2480/1 +f 2473/2481/1 2474/2482/1 2475/2483/1 2476/2484/1 +f 2477/2485/1 2478/2486/1 2479/2487/1 2480/2488/1 +f 2481/2489/1 2482/2490/1 2483/2491/1 2484/2492/1 +f 2485/2493/1 2486/2494/1 2487/2495/1 2488/2496/1 +f 2489/2497/1 2490/2498/1 2491/2499/1 2492/2500/1 +f 2493/2501/1 2494/2502/1 2495/2503/1 2496/2504/1 +f 2497/2505/1 2498/2506/1 2499/2507/1 2500/2508/1 +f 2501/2509/1 2502/2510/1 2503/2511/1 2504/2512/1 +f 2505/2513/1 2506/2514/1 2507/2515/1 2508/2516/1 +f 2509/2517/1 2510/2518/1 2511/2519/1 2512/2520/1 +f 2513/2521/1 2514/2522/1 2515/2523/1 2516/2524/1 +f 2517/2525/1 2518/2526/1 2519/2527/1 2520/2528/1 +f 2521/2529/1 2522/2530/1 2523/2531/1 2524/2532/1 +f 2525/2533/1 2526/2534/1 2527/2535/1 2528/2536/1 +f 2529/2537/1 2530/2538/1 2531/2539/1 2532/2540/1 +f 2533/2541/1 2534/2542/1 2535/2543/1 2536/2544/1 +f 2537/2545/1 2538/2546/1 2539/2547/1 2540/2548/1 +f 2541/2549/1 2542/2550/1 2543/2551/1 2544/2552/1 +f 2545/2553/1 2546/2554/1 2547/2555/1 2548/2556/1 +f 2549/2557/1 2550/2558/1 2551/2559/1 2552/2560/1 +f 2553/2561/1 2554/2562/1 2555/2563/1 2556/2564/1 +f 2557/2565/1 2558/2566/1 2559/2567/1 2560/2568/1 +f 2561/2569/1 2562/2570/1 2563/2571/1 2564/2572/1 +f 2565/2573/1 2566/2574/1 2567/2575/1 2568/2576/1 +f 2569/2577/1 2570/2578/1 2571/2579/1 2572/2580/1 +f 2573/2581/1 2574/2582/1 2575/2583/1 2576/2584/1 +f 2577/2585/1 2578/2586/1 2579/2587/1 2580/2588/1 +f 2581/2589/1 2582/2590/1 2583/2591/1 2584/2592/1 +f 2585/2593/1 2586/2594/1 2587/2595/1 2588/2596/1 +f 2589/2597/1 2590/2598/1 2591/2599/1 2592/2600/1 +f 2593/2601/1 2594/2602/1 2595/2603/1 2596/2604/1 +f 2597/2605/1 2598/2606/1 2599/2607/1 2600/2608/1 +f 2601/2609/1 2602/2610/1 2603/2611/1 2604/2612/1 +f 2605/2613/1 2606/2614/1 2607/2615/1 2608/2616/1 +f 2609/2617/1 2610/2618/1 2611/2619/1 2612/2620/1 +f 2613/2621/1 2614/2622/1 2615/2623/1 2616/2624/1 +f 2617/2625/1 2618/2626/1 2619/2627/1 2620/2628/1 +f 2621/2629/1 2622/2630/1 2623/2631/1 2624/2632/1 +f 2625/2633/1 2626/2634/1 2627/2635/1 2628/2636/1 +f 2629/2637/1 2630/2638/1 2631/2639/1 2632/2640/1 +f 2633/2641/1 2634/2642/1 2635/2643/1 2636/2644/1 +f 2637/2645/1 2638/2646/1 2639/2647/1 2640/2648/1 +f 2641/2649/1 2642/2650/1 2643/2651/1 2644/2652/1 +f 2645/2653/1 2646/2654/1 2647/2655/1 2648/2656/1 +f 2649/2657/1 2650/2658/1 2651/2659/1 2652/2660/1 +f 2653/2661/1 2654/2662/1 2655/2663/1 2656/2664/1 +f 2657/2665/1 2658/2666/1 2659/2667/1 2660/2668/1 +f 2661/2669/1 2662/2670/1 2663/2671/1 2664/2672/1 +f 2665/2673/1 2666/2674/1 2667/2675/1 2668/2676/1 +f 2669/2677/1 2670/2678/1 2671/2679/1 2672/2680/1 +f 2673/2681/1 2674/2682/1 2675/2683/1 2676/2684/1 +f 2677/2685/1 2678/2686/1 2679/2687/1 2680/2688/1 +f 2681/2689/1 2682/2690/1 2683/2691/1 2684/2692/1 +f 2685/2693/1 2686/2694/1 2687/2695/1 2688/2696/1 +f 2689/2697/1 2690/2698/1 2691/2699/1 2692/2700/1 +f 2693/2701/1 2694/2702/1 2695/2703/1 2696/2704/1 +f 2697/2705/1 2698/2706/1 2699/2707/1 2700/2708/1 +f 2701/2709/1 2702/2710/1 2703/2711/1 2704/2712/1 +f 2705/2713/1 2706/2714/1 2707/2715/1 2708/2716/1 +f 2709/2717/1 2710/2718/1 2711/2719/1 2712/2720/1 +f 2713/2721/1 2714/2722/1 2715/2723/1 2716/2724/1 +f 2717/2725/1 2718/2726/1 2719/2727/1 2720/2728/1 +f 2721/2729/1 2722/2730/1 2723/2731/1 2724/2732/1 +f 2725/2733/1 2726/2734/1 2727/2735/1 2728/2736/1 +f 2729/2737/1 2730/2738/1 2731/2739/1 2732/2740/1 +f 2733/2741/1 2734/2742/1 2735/2743/1 2736/2744/1 +f 2737/2745/1 2738/2746/1 2739/2747/1 2740/2748/1 +f 2741/2749/1 2742/2750/1 2743/2751/1 2744/2752/1 +f 2745/2753/1 2746/2754/1 2747/2755/1 2748/2756/1 +f 2749/2757/1 2750/2758/1 2751/2759/1 2752/2760/1 +f 2753/2761/1 2754/2762/1 2755/2763/1 2756/2764/1 +f 2757/2765/1 2758/2766/1 2759/2767/1 2760/2768/1 +f 2761/2769/1 2762/2770/1 2763/2771/1 2764/2772/1 +f 2765/2773/1 2766/2774/1 2767/2775/1 2768/2776/1 +f 2769/2777/1 2770/2778/1 2771/2779/1 2772/2780/1 +f 2773/2781/1 2774/2782/1 2775/2783/1 2776/2784/1 +f 2777/2785/1 2778/2786/1 2779/2787/1 2780/2788/1 +f 2781/2789/1 2782/2790/1 2783/2791/1 2784/2792/1 +f 2785/2793/1 2786/2794/1 2787/2795/1 2788/2796/1 +f 2789/2797/1 2790/2798/1 2791/2799/1 2792/2800/1 +f 2793/2801/1 2794/2802/1 2795/2803/1 2796/2804/1 +f 2797/2805/1 2798/2806/1 2799/2807/1 2800/2808/1 +f 2801/2809/1 2802/2810/1 2803/2811/1 2804/2812/1 +f 2805/2813/1 2806/2814/1 2807/2815/1 2808/2816/1 +f 2809/2817/1 2810/2818/1 2811/2819/1 2812/2820/1 +f 2813/2821/1 2814/2822/1 2815/2823/1 2816/2824/1 +f 2817/2825/1 2818/2826/1 2819/2827/1 2820/2828/1 +f 2821/2829/1 2822/2830/1 2823/2831/1 2824/2832/1 +f 2825/2833/1 2826/2834/1 2827/2835/1 2828/2836/1 +f 2829/2837/1 2830/2838/1 2831/2839/1 2832/2840/1 +f 2833/2841/1 2834/2842/1 2835/2843/1 2836/2844/1 +f 2837/2845/1 2838/2846/1 2839/2847/1 2840/2848/1 +f 2841/2849/1 2842/2850/1 2843/2851/1 2844/2852/1 +f 2845/2853/1 2846/2854/1 2847/2855/1 2848/2856/1 +f 2849/2857/1 2850/2858/1 2851/2859/1 2852/2860/1 +f 2853/2861/1 2854/2862/1 2855/2863/1 2856/2864/1 +f 2857/2865/1 2858/2866/1 2859/2867/1 2860/2868/1 +f 2861/2869/1 2862/2870/1 2863/2871/1 2864/2872/1 +f 2865/2873/1 2866/2874/1 2867/2875/1 2868/2876/1 +f 2869/2877/1 2870/2878/1 2871/2879/1 2872/2880/1 +f 2873/2881/1 2874/2882/1 2875/2883/1 2876/2884/1 +f 2877/2885/1 2878/2886/1 2879/2887/1 2880/2888/1 +f 2881/2889/1 2882/2890/1 2883/2891/1 2884/2892/1 +f 2885/2893/1 2886/2894/1 2887/2895/1 2888/2896/1 +f 2889/2897/1 2890/2898/1 2891/2899/1 2892/2900/1 +f 2893/2901/1 2894/2902/1 2895/2903/1 2896/2904/1 +f 2897/2905/1 2898/2906/1 2899/2907/1 2900/2908/1 +f 2901/2909/1 2902/2910/1 2903/2911/1 2904/2912/1 +f 2905/2913/1 2906/2914/1 2907/2915/1 2908/2916/1 +f 2909/2917/1 2910/2918/1 2911/2919/1 2912/2920/1 +f 2913/2921/1 2914/2922/1 2915/2923/1 2916/2924/1 +f 2917/2925/1 2918/2926/1 2919/2927/1 2920/2928/1 +f 2921/2929/1 2922/2930/1 2923/2931/1 2924/2932/1 +f 2925/2933/1 2926/2934/1 2927/2935/1 2928/2936/1 +f 2929/2937/1 2930/2938/1 2931/2939/1 2932/2940/1 +f 2933/2941/1 2934/2942/1 2935/2943/1 2936/2944/1 +f 2937/2945/1 2938/2946/1 2939/2947/1 2940/2948/1 +f 2941/2949/1 2942/2950/1 2943/2951/1 2944/2952/1 +f 2945/2953/1 2946/2954/1 2947/2955/1 2948/2956/1 +f 2949/2957/1 2950/2958/1 2951/2959/1 2952/2960/1 +f 2953/2961/1 2954/2962/1 2955/2963/1 2956/2964/1 +f 2957/2965/1 2958/2966/1 2959/2967/1 2960/2968/1 +f 2961/2969/1 2962/2970/1 2963/2971/1 2964/2972/1 +f 2965/2973/1 2966/2974/1 2967/2975/1 2968/2976/1 +f 2969/2977/1 2970/2978/1 2971/2979/1 2972/2980/1 +f 2973/2981/1 2974/2982/1 2975/2983/1 2976/2984/1 +f 2977/2985/1 2978/2986/1 2979/2987/1 2980/2988/1 +f 2981/2989/1 2982/2990/1 2983/2991/1 2984/2992/1 +f 2985/2993/1 2986/2994/1 2987/2995/1 2988/2996/1 +f 2989/2997/1 2990/2998/1 2991/2999/1 2992/3000/1 +f 2993/3001/1 2994/3002/1 2995/3003/1 2996/3004/1 +f 2997/3005/1 2998/3006/1 2999/3007/1 3000/3008/1 +f 3001/3009/1 3002/3010/1 3003/3011/1 3004/3012/1 +f 3005/3013/1 3006/3014/1 3007/3015/1 3008/3016/1 +f 3009/3017/1 3010/3018/1 3011/3019/1 3012/3020/1 +f 3013/3021/1 3014/3022/1 3015/3023/1 3016/3024/1 +f 3017/3025/1 3018/3026/1 3019/3027/1 3020/3028/1 +f 3021/3029/1 3022/3030/1 3023/3031/1 3024/3032/1 +f 3025/3033/1 3026/3034/1 3027/3035/1 3028/3036/1 +f 3029/3037/1 3030/3038/1 3031/3039/1 3032/3040/1 +f 3033/3041/1 3034/3042/1 3035/3043/1 3036/3044/1 +f 3037/3045/1 3038/3046/1 3039/3047/1 3040/3048/1 +f 3041/3049/1 3042/3050/1 3043/3051/1 3044/3052/1 +f 3045/3053/1 3046/3054/1 3047/3055/1 3048/3056/1 +f 3049/3057/1 3050/3058/1 3051/3059/1 3052/3060/1 +f 3053/3061/1 3054/3062/1 3055/3063/1 3056/3064/1 +f 3057/3065/1 3058/3066/1 3059/3067/1 3060/3068/1 +f 3061/3069/1 3062/3070/1 3063/3071/1 3064/3072/1 +f 3065/3073/1 3066/3074/1 3067/3075/1 3068/3076/1 +f 3069/3077/1 3070/3078/1 3071/3079/1 3072/3080/1 +f 3073/3081/1 3074/3082/1 3075/3083/1 3076/3084/1 +f 3077/3085/1 3078/3086/1 3079/3087/1 3080/3088/1 +f 3081/3089/1 3082/3090/1 3083/3091/1 3084/3092/1 +f 3085/3093/1 3086/3094/1 3087/3095/1 3088/3096/1 +f 3089/3097/1 3090/3098/1 3091/3099/1 3092/3100/1 +f 3093/3101/1 3094/3102/1 3095/3103/1 3096/3104/1 +f 3097/3105/1 3098/3106/1 3099/3107/1 3100/3108/1 +f 3101/3109/1 3102/3110/1 3103/3111/1 3104/3112/1 +f 3105/3113/1 3106/3114/1 3107/3115/1 3108/3116/1 +f 3109/3117/1 3110/3118/1 3111/3119/1 3112/3120/1 +f 3113/3121/1 3114/3122/1 3115/3123/1 3116/3124/1 +f 3117/3125/1 3118/3126/1 3119/3127/1 3120/3128/1 +f 3121/3129/1 3122/3130/1 3123/3131/1 3124/3132/1 +f 3125/3133/1 3126/3134/1 3127/3135/1 3128/3136/1 +f 3129/3137/1 3130/3138/1 3131/3139/1 3132/3140/1 +f 3133/3141/1 3134/3142/1 3135/3143/1 3136/3144/1 +f 3137/3145/1 3138/3146/1 3139/3147/1 3140/3148/1 +f 3141/3149/1 3142/3150/1 3143/3151/1 3144/3152/1 +f 3145/3153/1 3146/3154/1 3147/3155/1 3148/3156/1 +f 3149/3157/1 3150/3158/1 3151/3159/1 3152/3160/1 +f 3153/3161/1 3154/3162/1 3155/3163/1 3156/3164/1 +f 3157/3165/1 3158/3166/1 3159/3167/1 3160/3168/1 +f 3161/3169/1 3162/3170/1 3163/3171/1 3164/3172/1 +f 3165/3173/1 3166/3174/1 3167/3175/1 3168/3176/1 +f 3169/3177/1 3170/3178/1 3171/3179/1 3172/3180/1 +f 3173/3181/1 3174/3182/1 3175/3183/1 3176/3184/1 +f 3177/3185/1 3178/3186/1 3179/3187/1 3180/3188/1 +f 3181/3189/1 3182/3190/1 3183/3191/1 3184/3192/1 +f 3185/3193/1 3186/3194/1 3187/3195/1 3188/3196/1 +f 3189/3197/1 3190/3198/1 3191/3199/1 3192/3200/1 +f 3193/3201/1 3194/3202/1 3195/3203/1 3196/3204/1 +f 3197/3205/1 3198/3206/1 3199/3207/1 3200/3208/1 +f 3201/3209/1 3202/3210/1 3203/3211/1 3204/3212/1 +f 3205/3213/1 3206/3214/1 3207/3215/1 3208/3216/1 +f 3209/3217/1 3210/3218/1 3211/3219/1 3212/3220/1 +f 3213/3221/1 3214/3222/1 3215/3223/1 3216/3224/1 +f 3217/3225/1 3218/3226/1 3219/3227/1 3220/3228/1 +f 3221/3229/1 3222/3230/1 3223/3231/1 3224/3232/1 +f 3225/3233/1 3226/3234/1 3227/3235/1 3228/3236/1 +f 3229/3237/1 3230/3238/1 3231/3239/1 3232/3240/1 +f 3233/3241/1 3234/3242/1 3235/3243/1 3236/3244/1 +f 3237/3245/1 3238/3246/1 3239/3247/1 3240/3248/1 +f 3241/3249/1 3242/3250/1 3243/3251/1 3244/3252/1 +f 3245/3253/1 3246/3254/1 3247/3255/1 3248/3256/1 +f 3249/3257/1 3250/3258/1 3251/3259/1 3252/3260/1 +f 3253/3261/1 3254/3262/1 3255/3263/1 3256/3264/1 +f 3257/3265/1 3258/3266/1 3259/3267/1 3260/3268/1 +f 3261/3269/1 3262/3270/1 3263/3271/1 3264/3272/1 +f 3265/3273/1 3266/3274/1 3267/3275/1 3268/3276/1 +f 3269/3277/1 3270/3278/1 3271/3279/1 3272/3280/1 +f 3273/3281/1 3274/3282/1 3275/3283/1 3276/3284/1 +f 3277/3285/1 3278/3286/1 3279/3287/1 3280/3288/1 +f 3281/3289/1 3282/3290/1 3283/3291/1 3284/3292/1 +f 3285/3293/1 3286/3294/1 3287/3295/1 3288/3296/1 +f 3289/3297/1 3290/3298/1 3291/3299/1 3292/3300/1 +f 3293/3301/1 3294/3302/1 3295/3303/1 3296/3304/1 +f 3297/3305/1 3298/3306/1 3299/3307/1 3300/3308/1 +f 3301/3309/1 3302/3310/1 3303/3311/1 3304/3312/1 +f 3305/3313/1 3306/3314/1 3307/3315/1 3308/3316/1 +f 3309/3317/1 3310/3318/1 3311/3319/1 3312/3320/1 +f 3313/3321/1 3314/3322/1 3315/3323/1 3316/3324/1 +f 3317/3325/1 3318/3326/1 3319/3327/1 3320/3328/1 +f 3321/3329/1 3322/3330/1 3323/3331/1 3324/3332/1 +f 3325/3333/1 3326/3334/1 3327/3335/1 3328/3336/1 +f 3329/3337/1 3330/3338/1 3331/3339/1 3332/3340/1 +f 3333/3341/1 3334/3342/1 3335/3343/1 3336/3344/1 +f 3337/3345/1 3338/3346/1 3339/3347/1 3340/3348/1 +f 3341/3349/1 3342/3350/1 3343/3351/1 3344/3352/1 +f 3345/3353/1 3346/3354/1 3347/3355/1 3348/3356/1 +f 3349/3357/1 3350/3358/1 3351/3359/1 3352/3360/1 +f 3353/3361/1 3354/3362/1 3355/3363/1 3356/3364/1 +f 3357/3365/1 3358/3366/1 3359/3367/1 3360/3368/1 +f 3361/3369/1 3362/3370/1 3363/3371/1 3364/3372/1 +f 3365/3373/1 3366/3374/1 3367/3375/1 3368/3376/1 +f 3369/3377/1 3370/3378/1 3371/3379/1 3372/3380/1 +f 3373/3381/1 3374/3382/1 3375/3383/1 3376/3384/1 +f 3377/3385/1 3378/3386/1 3379/3387/1 3380/3388/1 +f 3381/3389/1 3382/3390/1 3383/3391/1 3384/3392/1 +f 3385/3393/1 3386/3394/1 3387/3395/1 3388/3396/1 +f 3389/3397/1 3390/3398/1 3391/3399/1 3392/3400/1 +f 3393/3401/1 3394/3402/1 3395/3403/1 3396/3404/1 +f 3397/3405/1 3398/3406/1 3399/3407/1 3400/3408/1 +f 3401/3409/1 3402/3410/1 3403/3411/1 3404/3412/1 +f 3405/3413/1 3406/3414/1 3407/3415/1 3408/3416/1 +f 3409/3417/1 3410/3418/1 3411/3419/1 3412/3420/1 +f 3413/3421/1 3414/3422/1 3415/3423/1 3416/3424/1 +f 3417/3425/1 3418/3426/1 3419/3427/1 3420/3428/1 +f 3421/3429/1 3422/3430/1 3423/3431/1 3424/3432/1 +f 3425/3433/1 3426/3434/1 3427/3435/1 3428/3436/1 +f 3429/3437/1 3430/3438/1 3431/3439/1 3432/3440/1 +f 3433/3441/1 3434/3442/1 3435/3443/1 3436/3444/1 +f 3437/3445/1 3438/3446/1 3439/3447/1 3440/3448/1 +f 3441/3449/1 3442/3450/1 3443/3451/1 3444/3452/1 +f 3445/3453/1 3446/3454/1 3447/3455/1 3448/3456/1 +f 3449/3457/1 3450/3458/1 3451/3459/1 3452/3460/1 +f 3453/3461/1 3454/3462/1 3455/3463/1 3456/3464/1 +f 3457/3465/1 3458/3466/1 3459/3467/1 3460/3468/1 +f 3461/3469/1 3462/3470/1 3463/3471/1 3464/3472/1 +f 3465/3473/1 3466/3474/1 3467/3475/1 3468/3476/1 +f 3469/3477/1 3470/3478/1 3471/3479/1 3472/3480/1 +f 3473/3481/1 3474/3482/1 3475/3483/1 3476/3484/1 +f 3477/3485/1 3478/3486/1 3479/3487/1 3480/3488/1 +f 3481/3489/1 3482/3490/1 3483/3491/1 3484/3492/1 +f 3485/3493/1 3486/3494/1 3487/3495/1 3488/3496/1 +f 3489/3497/1 3490/3498/1 3491/3499/1 3492/3500/1 +f 3493/3501/1 3494/3502/1 3495/3503/1 3496/3504/1 +f 3497/3505/1 3498/3506/1 3499/3507/1 3500/3508/1 +f 3501/3509/1 3502/3510/1 3503/3511/1 3504/3512/1 +f 3505/3513/1 3506/3514/1 3507/3515/1 3508/3516/1 +f 3509/3517/1 3510/3518/1 3511/3519/1 3512/3520/1 +f 3513/3521/1 3514/3522/1 3515/3523/1 3516/3524/1 +f 3517/3525/1 3518/3526/1 3519/3527/1 3520/3528/1 +f 3521/3529/1 3522/3530/1 3523/3531/1 3524/3532/1 +f 3525/3533/1 3526/3534/1 3527/3535/1 3528/3536/1 +f 3529/3537/1 3530/3538/1 3531/3539/1 3532/3540/1 +f 3533/3541/1 3534/3542/1 3535/3543/1 3536/3544/1 +f 3537/3545/1 3538/3546/1 3539/3547/1 3540/3548/1 +f 3541/3549/1 3542/3550/1 3543/3551/1 3544/3552/1 +f 3545/3553/1 3546/3554/1 3547/3555/1 3548/3556/1 +f 3549/3557/1 3550/3558/1 3551/3559/1 3552/3560/1 +f 3553/3561/1 3554/3562/1 3555/3563/1 3556/3564/1 +f 3557/3565/1 3558/3566/1 3559/3567/1 3560/3568/1 +f 3561/3569/1 3562/3570/1 3563/3571/1 3564/3572/1 +f 3565/3573/1 3566/3574/1 3567/3575/1 3568/3576/1 +f 3569/3577/1 3570/3578/1 3571/3579/1 3572/3580/1 +f 3573/3581/1 3574/3582/1 3575/3583/1 3576/3584/1 +f 3577/3585/1 3578/3586/1 3579/3587/1 3580/3588/1 +f 3581/3589/1 3582/3590/1 3583/3591/1 3584/3592/1 +f 3585/3593/1 3586/3594/1 3587/3595/1 3588/3596/1 +f 3589/3597/1 3590/3598/1 3591/3599/1 3592/3600/1 +f 3593/3601/1 3594/3602/1 3595/3603/1 3596/3604/1 +f 3597/3605/1 3598/3606/1 3599/3607/1 3600/3608/1 +f 3601/3609/1 3602/3610/1 3603/3611/1 3604/3612/1 +f 3605/3613/1 3606/3614/1 3607/3615/1 3608/3616/1 +f 3609/3617/1 3610/3618/1 3611/3619/1 3612/3620/1 +f 3613/3621/1 3614/3622/1 3615/3623/1 3616/3624/1 +f 3617/3625/1 3618/3626/1 3619/3627/1 3620/3628/1 +f 3621/3629/1 3622/3630/1 3623/3631/1 3624/3632/1 +f 3625/3633/1 3626/3634/1 3627/3635/1 3628/3636/1 +f 3629/3637/1 3630/3638/1 3631/3639/1 3632/3640/1 +f 3633/3641/1 3634/3642/1 3635/3643/1 3636/3644/1 +f 3637/3645/1 3638/3646/1 3639/3647/1 3640/3648/1 +f 3641/3649/1 3642/3650/1 3643/3651/1 3644/3652/1 +f 3645/3653/1 3646/3654/1 3647/3655/1 3648/3656/1 +f 3649/3657/1 3650/3658/1 3651/3659/1 3652/3660/1 +f 3653/3661/1 3654/3662/1 3655/3663/1 3656/3664/1 +f 3657/3665/1 3658/3666/1 3659/3667/1 3660/3668/1 +f 3661/3669/1 3662/3670/1 3663/3671/1 3664/3672/1 +f 3665/3673/1 3666/3674/1 3667/3675/1 3668/3676/1 +f 3669/3677/1 3670/3678/1 3671/3679/1 3672/3680/1 +f 3673/3681/1 3674/3682/1 3675/3683/1 3676/3684/1 +f 3677/3685/1 3678/3686/1 3679/3687/1 3680/3688/1 +f 3681/3689/1 3682/3690/1 3683/3691/1 3684/3692/1 +f 3685/3693/1 3686/3694/1 3687/3695/1 3688/3696/1 +f 3689/3697/1 3690/3698/1 3691/3699/1 3692/3700/1 +f 3693/3701/1 3694/3702/1 3695/3703/1 3696/3704/1 +f 3697/3705/1 3698/3706/1 3699/3707/1 3700/3708/1 +f 3701/3709/1 3702/3710/1 3703/3711/1 3704/3712/1 +f 3705/3713/1 3706/3714/1 3707/3715/1 3708/3716/1 +f 3709/3717/1 3710/3718/1 3711/3719/1 3712/3720/1 +f 3713/3721/1 3714/3722/1 3715/3723/1 3716/3724/1 +f 3717/3725/1 3718/3726/1 3719/3727/1 3720/3728/1 +f 3721/3729/1 3722/3730/1 3723/3731/1 3724/3732/1 +f 3725/3733/1 3726/3734/1 3727/3735/1 3728/3736/1 +f 3729/3737/1 3730/3738/1 3731/3739/1 3732/3740/1 +f 3733/3741/1 3734/3742/1 3735/3743/1 3736/3744/1 +f 3737/3745/1 3738/3746/1 3739/3747/1 3740/3748/1 +f 3741/3749/1 3742/3750/1 3743/3751/1 3744/3752/1 +f 3745/3753/1 3746/3754/1 3747/3755/1 3748/3756/1 +f 3749/3757/1 3750/3758/1 3751/3759/1 3752/3760/1 +f 3753/3761/1 3754/3762/1 3755/3763/1 3756/3764/1 +f 3757/3765/1 3758/3766/1 3759/3767/1 3760/3768/1 +f 3761/3769/1 3762/3770/1 3763/3771/1 3764/3772/1 +f 3765/3773/1 3766/3774/1 3767/3775/1 3768/3776/1 +f 3769/3777/1 3770/3778/1 3771/3779/1 3772/3780/1 +f 3773/3781/1 3774/3782/1 3775/3783/1 3776/3784/1 +f 3777/3785/1 3778/3786/1 3779/3787/1 3780/3788/1 +f 3781/3789/1 3782/3790/1 3783/3791/1 3784/3792/1 +f 3785/3793/1 3786/3794/1 3787/3795/1 3788/3796/1 +f 3789/3797/1 3790/3798/1 3791/3799/1 3792/3800/1 +f 3793/3801/1 3794/3802/1 3795/3803/1 3796/3804/1 +f 3797/3805/1 3798/3806/1 3799/3807/1 3800/3808/1 +f 3801/3809/1 3802/3810/1 3803/3811/1 3804/3812/1 +f 3805/3813/1 3806/3814/1 3807/3815/1 3808/3816/1 +f 3809/3817/1 3810/3818/1 3811/3819/1 3812/3820/1 +f 3813/3821/1 3814/3822/1 3815/3823/1 3816/3824/1 +f 3817/3825/1 3818/3826/1 3819/3827/1 3820/3828/1 +f 3821/3829/1 3822/3830/1 3823/3831/1 3824/3832/1 +f 3825/3833/1 3826/3834/1 3827/3835/1 3828/3836/1 +f 3829/3837/1 3830/3838/1 3831/3839/1 3832/3840/1 +f 3833/3841/1 3834/3842/1 3835/3843/1 3836/3844/1 +f 3837/3845/1 3838/3846/1 3839/3847/1 3840/3848/1 +f 3841/3849/1 3842/3850/1 3843/3851/1 3844/3852/1 +f 3845/3853/1 3846/3854/1 3847/3855/1 3848/3856/1 +f 3849/3857/1 3850/3858/1 3851/3859/1 3852/3860/1 +f 3853/3861/1 3854/3862/1 3855/3863/1 3856/3864/1 +f 3857/3865/1 3858/3866/1 3859/3867/1 3860/3868/1 +f 3861/3869/1 3862/3870/1 3863/3871/1 3864/3872/1 +f 3865/3873/1 3866/3874/1 3867/3875/1 3868/3876/1 +f 3869/3877/1 3870/3878/1 3871/3879/1 3872/3880/1 +f 3873/3881/1 3874/3882/1 3875/3883/1 3876/3884/1 +f 3877/3885/1 3878/3886/1 3879/3887/1 3880/3888/1 +f 3881/3889/1 3882/3890/1 3883/3891/1 3884/3892/1 +f 3885/3893/1 3886/3894/1 3887/3895/1 3888/3896/1 +f 3889/3897/1 3890/3898/1 3891/3899/1 3892/3900/1 +f 3893/3901/1 3894/3902/1 3895/3903/1 3896/3904/1 +f 3897/3905/1 3898/3906/1 3899/3907/1 3900/3908/1 +f 3901/3909/1 3902/3910/1 3903/3911/1 3904/3912/1 +f 3905/3913/1 3906/3914/1 3907/3915/1 3908/3916/1 +f 3909/3917/1 3910/3918/1 3911/3919/1 3912/3920/1 +f 3913/3921/1 3914/3922/1 3915/3923/1 3916/3924/1 +f 3917/3925/1 3918/3926/1 3919/3927/1 3920/3928/1 +f 3921/3929/1 3922/3930/1 3923/3931/1 3924/3932/1 +f 3925/3933/1 3926/3934/1 3927/3935/1 3928/3936/1 +f 3929/3937/1 3930/3938/1 3931/3939/1 3932/3940/1 +f 3933/3941/1 3934/3942/1 3935/3943/1 3936/3944/1 +f 3937/3945/1 3938/3946/1 3939/3947/1 3940/3948/1 +f 3941/3949/1 3942/3950/1 3943/3951/1 3944/3952/1 +f 3945/3953/1 3946/3954/1 3947/3955/1 3948/3956/1 +f 3949/3957/1 3950/3958/1 3951/3959/1 3952/3960/1 +f 3953/3961/1 3954/3962/1 3955/3963/1 3956/3964/1 +f 3957/3965/1 3958/3966/1 3959/3967/1 3960/3968/1 +f 3961/3969/1 3962/3970/1 3963/3971/1 3964/3972/1 +f 3965/3973/1 3966/3974/1 3967/3975/1 3968/3976/1 +f 3969/3977/1 3970/3978/1 3971/3979/1 3972/3980/1 +f 3973/3981/1 3974/3982/1 3975/3983/1 3976/3984/1 +f 3977/3985/1 3978/3986/1 3979/3987/1 3980/3988/1 +f 3981/3989/1 3982/3990/1 3983/3991/1 3984/3992/1 +f 3985/3993/1 3986/3994/1 3987/3995/1 3988/3996/1 +f 3989/3997/1 3990/3998/1 3991/3999/1 3992/4000/1 +f 3993/4001/1 3994/4002/1 3995/4003/1 3996/4004/1 +f 3997/4005/1 3998/4006/1 3999/4007/1 4000/4008/1 +f 4001/4009/1 4002/4010/1 4003/4011/1 4004/4012/1 +f 4005/4013/1 4006/4014/1 4007/4015/1 4008/4016/1 +f 4009/4017/1 4010/4018/1 4011/4019/1 4012/4020/1 +f 4013/4021/1 4014/4022/1 4015/4023/1 4016/4024/1 +f 4017/4025/1 4018/4026/1 4019/4027/1 4020/4028/1 +f 4021/4029/1 4022/4030/1 4023/4031/1 4024/4032/1 +f 4025/4033/1 4026/4034/1 4027/4035/1 4028/4036/1 +f 4029/4037/1 4030/4038/1 4031/4039/1 4032/4040/1 +f 4033/4041/1 4034/4042/1 4035/4043/1 4036/4044/1 +f 4037/4045/1 4038/4046/1 4039/4047/1 4040/4048/1 +f 4041/4049/1 4042/4050/1 4043/4051/1 4044/4052/1 +f 4045/4053/1 4046/4054/1 4047/4055/1 4048/4056/1 +f 4049/4057/1 4050/4058/1 4051/4059/1 4052/4060/1 +f 4053/4061/1 4054/4062/1 4055/4063/1 4056/4064/1 +f 4057/4065/1 4058/4066/1 4059/4067/1 4060/4068/1 +f 4061/4069/1 4062/4070/1 4063/4071/1 4064/4072/1 +f 4065/4073/1 4066/4074/1 4067/4075/1 4068/4076/1 +f 4069/4077/1 4070/4078/1 4071/4079/1 4072/4080/1 +f 4073/4081/1 4074/4082/1 4075/4083/1 4076/4084/1 +f 4077/4085/1 4078/4086/1 4079/4087/1 4080/4088/1 +f 4081/4089/1 4082/4090/1 4083/4091/1 4084/4092/1 +f 4085/4093/1 4086/4094/1 4087/4095/1 4088/4096/1 +f 4089/4097/1 4090/4098/1 4091/4099/1 4092/4100/1 +f 4093/4101/1 4094/4102/1 4095/4103/1 4096/4104/1 +f 4097/4105/1 4098/4106/1 4099/4107/1 4100/4108/1 +f 4101/4109/1 4102/4110/1 4103/4111/1 4104/4112/1 +f 4105/4113/1 4106/4114/1 4107/4115/1 4108/4116/1 +f 4109/4117/1 4110/4118/1 4111/4119/1 4112/4120/1 +f 4113/4121/1 4114/4122/1 4115/4123/1 4116/4124/1 +f 4117/4125/1 4118/4126/1 4119/4127/1 4120/4128/1 +f 4121/4129/1 4122/4130/1 4123/4131/1 4124/4132/1 +f 4125/4133/1 4126/4134/1 4127/4135/1 4128/4136/1 +f 4129/4137/1 4130/4138/1 4131/4139/1 4132/4140/1 +f 4133/4141/1 4134/4142/1 4135/4143/1 4136/4144/1 +f 4137/4145/1 4138/4146/1 4139/4147/1 4140/4148/1 +f 4141/4149/1 4142/4150/1 4143/4151/1 4144/4152/1 +f 4145/4153/1 4146/4154/1 4147/4155/1 4148/4156/1 +f 4149/4157/1 4150/4158/1 4151/4159/1 4152/4160/1 +f 4153/4161/1 4154/4162/1 4155/4163/1 4156/4164/1 +f 4157/4165/1 4158/4166/1 4159/4167/1 4160/4168/1 +f 4161/4169/1 4162/4170/1 4163/4171/1 4164/4172/1 +f 4165/4173/1 4166/4174/1 4167/4175/1 4168/4176/1 +f 4169/4177/1 4170/4178/1 4171/4179/1 4172/4180/1 +f 4173/4181/1 4174/4182/1 4175/4183/1 4176/4184/1 +f 4177/4185/1 4178/4186/1 4179/4187/1 4180/4188/1 +f 4181/4189/1 4182/4190/1 4183/4191/1 4184/4192/1 +f 4185/4193/1 4186/4194/1 4187/4195/1 4188/4196/1 +f 4189/4197/1 4190/4198/1 4191/4199/1 4192/4200/1 +f 4193/4201/1 4194/4202/1 4195/4203/1 4196/4204/1 +f 4197/4205/1 4198/4206/1 4199/4207/1 4200/4208/1 +f 4201/4209/1 4202/4210/1 4203/4211/1 4204/4212/1 +f 4205/4213/1 4206/4214/1 4207/4215/1 4208/4216/1 +f 4209/4217/1 4210/4218/1 4211/4219/1 4212/4220/1 +f 4213/4221/1 4214/4222/1 4215/4223/1 4216/4224/1 +f 4217/4225/1 4218/4226/1 4219/4227/1 4220/4228/1 +f 4221/4229/1 4222/4230/1 4223/4231/1 4224/4232/1 +f 4225/4233/1 4226/4234/1 4227/4235/1 4228/4236/1 +f 4229/4237/1 4230/4238/1 4231/4239/1 4232/4240/1 +f 4233/4241/1 4234/4242/1 4235/4243/1 4236/4244/1 +f 4237/4245/1 4238/4246/1 4239/4247/1 4240/4248/1 +f 4241/4249/1 4242/4250/1 4243/4251/1 4244/4252/1 +f 4245/4253/1 4246/4254/1 4247/4255/1 4248/4256/1 +f 4249/4257/1 4250/4258/1 4251/4259/1 4252/4260/1 +f 4253/4261/1 4254/4262/1 4255/4263/1 4256/4264/1 +f 4257/4265/1 4258/4266/1 4259/4267/1 4260/4268/1 +f 4261/4269/1 4262/4270/1 4263/4271/1 4264/4272/1 +f 4265/4273/1 4266/4274/1 4267/4275/1 4268/4276/1 +f 4269/4277/1 4270/4278/1 4271/4279/1 4272/4280/1 +f 4273/4281/1 4274/4282/1 4275/4283/1 4276/4284/1 +f 4277/4285/1 4278/4286/1 4279/4287/1 4280/4288/1 +f 4281/4289/1 4282/4290/1 4283/4291/1 4284/4292/1 +f 4285/4293/1 4286/4294/1 4287/4295/1 4288/4296/1 +f 4289/4297/1 4290/4298/1 4291/4299/1 4292/4300/1 +f 4293/4301/1 4294/4302/1 4295/4303/1 4296/4304/1 +f 4297/4305/1 4298/4306/1 4299/4307/1 4300/4308/1 +f 4301/4309/1 4302/4310/1 4303/4311/1 4304/4312/1 +f 4305/4313/1 4306/4314/1 4307/4315/1 4308/4316/1 +f 4309/4317/1 4310/4318/1 4311/4319/1 4312/4320/1 +f 4313/4321/1 4314/4322/1 4315/4323/1 4316/4324/1 +f 4317/4325/1 4318/4326/1 4319/4327/1 4320/4328/1 +f 4321/4329/1 4322/4330/1 4323/4331/1 4324/4332/1 +f 4325/4333/1 4326/4334/1 4327/4335/1 4328/4336/1 +f 4329/4337/1 4330/4338/1 4331/4339/1 4332/4340/1 +f 4333/4341/1 4334/4342/1 4335/4343/1 4336/4344/1 +f 4337/4345/1 4338/4346/1 4339/4347/1 4340/4348/1 +f 4341/4349/1 4342/4350/1 4343/4351/1 4344/4352/1 +f 4345/4353/1 4346/4354/1 4347/4355/1 4348/4356/1 +f 4349/4357/1 4350/4358/1 4351/4359/1 4352/4360/1 +f 4353/4361/1 4354/4362/1 4355/4363/1 4356/4364/1 +f 4357/4365/1 4358/4366/1 4359/4367/1 4360/4368/1 +f 4361/4369/1 4362/4370/1 4363/4371/1 4364/4372/1 +f 4365/4373/1 4366/4374/1 4367/4375/1 4368/4376/1 +f 4369/4377/1 4370/4378/1 4371/4379/1 4372/4380/1 +f 4373/4381/1 4374/4382/1 4375/4383/1 4376/4384/1 +f 4377/4385/1 4378/4386/1 4379/4387/1 4380/4388/1 +f 4381/4389/1 4382/4390/1 4383/4391/1 4384/4392/1 +f 4385/4393/1 4386/4394/1 4387/4395/1 4388/4396/1 +f 4389/4397/1 4390/4398/1 4391/4399/1 4392/4400/1 +f 4393/4401/1 4394/4402/1 4395/4403/1 4396/4404/1 +f 4397/4405/1 4398/4406/1 4399/4407/1 4400/4408/1 +f 4401/4409/1 4402/4410/1 4403/4411/1 4404/4412/1 +f 4405/4413/1 4406/4414/1 4407/4415/1 4408/4416/1 +f 4409/4417/1 4410/4418/1 4411/4419/1 4412/4420/1 +f 4413/4421/1 4414/4422/1 4415/4423/1 4416/4424/1 +f 4417/4425/1 4418/4426/1 4419/4427/1 4420/4428/1 +f 4421/4429/1 4422/4430/1 4423/4431/1 4424/4432/1 +f 4425/4433/1 4426/4434/1 4427/4435/1 4428/4436/1 +f 4429/4437/1 4430/4438/1 4431/4439/1 4432/4440/1 +f 4433/4441/1 4434/4442/1 4435/4443/1 4436/4444/1 +f 4437/4445/1 4438/4446/1 4439/4447/1 4440/4448/1 +f 4441/4449/1 4442/4450/1 4443/4451/1 4444/4452/1 +f 4445/4453/1 4446/4454/1 4447/4455/1 4448/4456/1 +f 4449/4457/1 4450/4458/1 4451/4459/1 4452/4460/1 +f 4453/4461/1 4454/4462/1 4455/4463/1 4456/4464/1 +f 4457/4465/1 4458/4466/1 4459/4467/1 4460/4468/1 +f 4461/4469/1 4462/4470/1 4463/4471/1 4464/4472/1 +f 4465/4473/1 4466/4474/1 4467/4475/1 4468/4476/1 +f 4469/4477/1 4470/4478/1 4471/4479/1 4472/4480/1 +f 4473/4481/1 4474/4482/1 4475/4483/1 4476/4484/1 +f 4477/4485/1 4478/4486/1 4479/4487/1 4480/4488/1 +f 4481/4489/1 4482/4490/1 4483/4491/1 4484/4492/1 +f 4485/4493/1 4486/4494/1 4487/4495/1 4488/4496/1 +f 4489/4497/1 4490/4498/1 4491/4499/1 4492/4500/1 +f 4493/4501/1 4494/4502/1 4495/4503/1 4496/4504/1 +f 4497/4505/1 4498/4506/1 4499/4507/1 4500/4508/1 +f 4501/4509/1 4502/4510/1 4503/4511/1 4504/4512/1 +f 4505/4513/1 4506/4514/1 4507/4515/1 4508/4516/1 +f 4509/4517/1 4510/4518/1 4511/4519/1 4512/4520/1 +f 4513/4521/1 4514/4522/1 4515/4523/1 4516/4524/1 +f 4517/4525/1 4518/4526/1 4519/4527/1 4520/4528/1 +f 4521/4529/1 4522/4530/1 4523/4531/1 4524/4532/1 +f 4525/4533/1 4526/4534/1 4527/4535/1 4528/4536/1 +f 4529/4537/1 4530/4538/1 4531/4539/1 4532/4540/1 +f 4533/4541/1 4534/4542/1 4535/4543/1 4536/4544/1 +f 4537/4545/1 4538/4546/1 4539/4547/1 4540/4548/1 +f 4541/4549/1 4542/4550/1 4543/4551/1 4544/4552/1 +f 4545/4553/1 4546/4554/1 4547/4555/1 4548/4556/1 +f 4549/4557/1 4550/4558/1 4551/4559/1 4552/4560/1 +f 4553/4561/1 4554/4562/1 4555/4563/1 4556/4564/1 +f 4557/4565/1 4558/4566/1 4559/4567/1 4560/4568/1 +f 4561/4569/1 4562/4570/1 4563/4571/1 4564/4572/1 +f 4565/4573/1 4566/4574/1 4567/4575/1 4568/4576/1 +f 4569/4577/1 4570/4578/1 4571/4579/1 4572/4580/1 +f 4573/4581/1 4574/4582/1 4575/4583/1 4576/4584/1 +f 4577/4585/1 4578/4586/1 4579/4587/1 4580/4588/1 +f 4581/4589/1 4582/4590/1 4583/4591/1 4584/4592/1 +f 4585/4593/1 4586/4594/1 4587/4595/1 4588/4596/1 +f 4589/4597/1 4590/4598/1 4591/4599/1 4592/4600/1 +f 4593/4601/1 4594/4602/1 4595/4603/1 4596/4604/1 +f 4597/4605/1 4598/4606/1 4599/4607/1 4600/4608/1 +f 4601/4609/1 4602/4610/1 4603/4611/1 4604/4612/1 +f 4605/4613/1 4606/4614/1 4607/4615/1 4608/4616/1 +f 4609/4617/1 4610/4618/1 4611/4619/1 4612/4620/1 +f 4613/4621/1 4614/4622/1 4615/4623/1 4616/4624/1 +f 4617/4625/1 4618/4626/1 4619/4627/1 4620/4628/1 +f 4621/4629/1 4622/4630/1 4623/4631/1 4624/4632/1 +f 4625/4633/1 4626/4634/1 4627/4635/1 4628/4636/1 +f 4629/4637/1 4630/4638/1 4631/4639/1 4632/4640/1 +f 4633/4641/1 4634/4642/1 4635/4643/1 4636/4644/1 +f 4637/4645/1 4638/4646/1 4639/4647/1 4640/4648/1 +f 4641/4649/1 4642/4650/1 4643/4651/1 4644/4652/1 +f 4645/4653/1 4646/4654/1 4647/4655/1 4648/4656/1 +f 4649/4657/1 4650/4658/1 4651/4659/1 4652/4660/1 +f 4653/4661/1 4654/4662/1 4655/4663/1 4656/4664/1 +f 4657/4665/1 4658/4666/1 4659/4667/1 4660/4668/1 +f 4661/4669/1 4662/4670/1 4663/4671/1 4664/4672/1 +f 4665/4673/1 4666/4674/1 4667/4675/1 4668/4676/1 +f 4669/4677/1 4670/4678/1 4671/4679/1 4672/4680/1 +f 4673/4681/1 4674/4682/1 4675/4683/1 4676/4684/1 +f 4677/4685/1 4678/4686/1 4679/4687/1 4680/4688/1 +f 4681/4689/1 4682/4690/1 4683/4691/1 4684/4692/1 +f 4685/4693/1 4686/4694/1 4687/4695/1 4688/4696/1 +f 4689/4697/1 4690/4698/1 4691/4699/1 4692/4700/1 +f 4693/4701/1 4694/4702/1 4695/4703/1 4696/4704/1 +f 4697/4705/1 4698/4706/1 4699/4707/1 4700/4708/1 +f 4701/4709/1 4702/4710/1 4703/4711/1 4704/4712/1 +f 4705/4713/1 4706/4714/1 4707/4715/1 4708/4716/1 +f 4709/4717/1 4710/4718/1 4711/4719/1 4712/4720/1 +f 4713/4721/1 4714/4722/1 4715/4723/1 4716/4724/1 +f 4717/4725/1 4718/4726/1 4719/4727/1 4720/4728/1 +f 4721/4729/1 4722/4730/1 4723/4731/1 4724/4732/1 +f 4725/4733/1 4726/4734/1 4727/4735/1 4728/4736/1 +f 4729/4737/1 4730/4738/1 4731/4739/1 4732/4740/1 +f 4733/4741/1 4734/4742/1 4735/4743/1 4736/4744/1 +f 4737/4745/1 4738/4746/1 4739/4747/1 4740/4748/1 +f 4741/4749/1 4742/4750/1 4743/4751/1 4744/4752/1 +f 4745/4753/1 4746/4754/1 4747/4755/1 4748/4756/1 +f 4749/4757/1 4750/4758/1 4751/4759/1 4752/4760/1 +f 4753/4761/1 4754/4762/1 4755/4763/1 4756/4764/1 +f 4757/4765/1 4758/4766/1 4759/4767/1 4760/4768/1 +f 4761/4769/1 4762/4770/1 4763/4771/1 4764/4772/1 +f 4765/4773/1 4766/4774/1 4767/4775/1 4768/4776/1 +f 4769/4777/1 4770/4778/1 4771/4779/1 4772/4780/1 +f 4773/4781/1 4774/4782/1 4775/4783/1 4776/4784/1 +f 4777/4785/1 4778/4786/1 4779/4787/1 4780/4788/1 +f 4781/4789/1 4782/4790/1 4783/4791/1 4784/4792/1 +f 4785/4793/1 4786/4794/1 4787/4795/1 4788/4796/1 +f 4789/4797/1 4790/4798/1 4791/4799/1 4792/4800/1 +f 4793/4801/1 4794/4802/1 4795/4803/1 4796/4804/1 +f 4797/4805/1 4798/4806/1 4799/4807/1 4800/4808/1 +f 4801/4809/1 4802/4810/1 4803/4811/1 4804/4812/1 +f 4805/4813/1 4806/4814/1 4807/4815/1 4808/4816/1 +f 4809/4817/1 4810/4818/1 4811/4819/1 4812/4820/1 +f 4813/4821/1 4814/4822/1 4815/4823/1 4816/4824/1 +f 4817/4825/1 4818/4826/1 4819/4827/1 4820/4828/1 +f 4821/4829/1 4822/4830/1 4823/4831/1 4824/4832/1 +f 4825/4833/1 4826/4834/1 4827/4835/1 4828/4836/1 +f 4829/4837/1 4830/4838/1 4831/4839/1 4832/4840/1 +f 4833/4841/1 4834/4842/1 4835/4843/1 4836/4844/1 +f 4837/4845/1 4838/4846/1 4839/4847/1 4840/4848/1 +f 4841/4849/1 4842/4850/1 4843/4851/1 4844/4852/1 +f 4845/4853/1 4846/4854/1 4847/4855/1 4848/4856/1 +f 4849/4857/1 4850/4858/1 4851/4859/1 4852/4860/1 +f 4853/4861/1 4854/4862/1 4855/4863/1 4856/4864/1 +f 4857/4865/1 4858/4866/1 4859/4867/1 4860/4868/1 +f 4861/4869/1 4862/4870/1 4863/4871/1 4864/4872/1 +f 4865/4873/1 4866/4874/1 4867/4875/1 4868/4876/1 +f 4869/4877/1 4870/4878/1 4871/4879/1 4872/4880/1 +f 4873/4881/1 4874/4882/1 4875/4883/1 4876/4884/1 +f 4877/4885/1 4878/4886/1 4879/4887/1 4880/4888/1 +f 4881/4889/1 4882/4890/1 4883/4891/1 4884/4892/1 +f 4885/4893/1 4886/4894/1 4887/4895/1 4888/4896/1 +f 4889/4897/1 4890/4898/1 4891/4899/1 4892/4900/1 +f 4893/4901/1 4894/4902/1 4895/4903/1 4896/4904/1 +f 4897/4905/1 4898/4906/1 4899/4907/1 4900/4908/1 +f 4901/4909/1 4902/4910/1 4903/4911/1 4904/4912/1 +f 4905/4913/1 4906/4914/1 4907/4915/1 4908/4916/1 +f 4909/4917/1 4910/4918/1 4911/4919/1 4912/4920/1 +f 4913/4921/1 4914/4922/1 4915/4923/1 4916/4924/1 +f 4917/4925/1 4918/4926/1 4919/4927/1 4920/4928/1 +f 4921/4929/1 4922/4930/1 4923/4931/1 4924/4932/1 +f 4925/4933/1 4926/4934/1 4927/4935/1 4928/4936/1 +f 4929/4937/1 4930/4938/1 4931/4939/1 4932/4940/1 +f 4933/4941/1 4934/4942/1 4935/4943/1 4936/4944/1 +f 4937/4945/1 4938/4946/1 4939/4947/1 4940/4948/1 +f 4941/4949/1 4942/4950/1 4943/4951/1 4944/4952/1 +f 4945/4953/1 4946/4954/1 4947/4955/1 4948/4956/1 +f 4949/4957/1 4950/4958/1 4951/4959/1 4952/4960/1 +f 4953/4961/1 4954/4962/1 4955/4963/1 4956/4964/1 +f 4957/4965/1 4958/4966/1 4959/4967/1 4960/4968/1 +f 4961/4969/1 4962/4970/1 4963/4971/1 4964/4972/1 +f 4965/4973/1 4966/4974/1 4967/4975/1 4968/4976/1 +f 4969/4977/1 4970/4978/1 4971/4979/1 4972/4980/1 +f 4973/4981/1 4974/4982/1 4975/4983/1 4976/4984/1 +f 4977/4985/1 4978/4986/1 4979/4987/1 4980/4988/1 +f 4981/4989/1 4982/4990/1 4983/4991/1 4984/4992/1 +f 4985/4993/1 4986/4994/1 4987/4995/1 4988/4996/1 +f 4989/4997/1 4990/4998/1 4991/4999/1 4992/5000/1 +f 4993/5001/1 4994/5002/1 4995/5003/1 4996/5004/1 +f 4997/5005/1 4998/5006/1 4999/5007/1 5000/5008/1 +f 5001/5009/1 5002/5010/1 5003/5011/1 5004/5012/1 +f 5005/5013/1 5006/5014/1 5007/5015/1 5008/5016/1 +f 5009/5017/1 5010/5018/1 5011/5019/1 5012/5020/1 +f 5013/5021/1 5014/5022/1 5015/5023/1 5016/5024/1 +f 5017/5025/1 5018/5026/1 5019/5027/1 5020/5028/1 +f 5021/5029/1 5022/5030/1 5023/5031/1 5024/5032/1 +f 5025/5033/1 5026/5034/1 5027/5035/1 5028/5036/1 +f 5029/5037/1 5030/5038/1 5031/5039/1 5032/5040/1 +f 5033/5041/1 5034/5042/1 5035/5043/1 5036/5044/1 +f 5037/5045/1 5038/5046/1 5039/5047/1 5040/5048/1 +f 5041/5049/1 5042/5050/1 5043/5051/1 5044/5052/1 +f 5045/5053/1 5046/5054/1 5047/5055/1 5048/5056/1 +f 5049/5057/1 5050/5058/1 5051/5059/1 5052/5060/1 +f 5053/5061/1 5054/5062/1 5055/5063/1 5056/5064/1 +f 5057/5065/1 5058/5066/1 5059/5067/1 5060/5068/1 +f 5061/5069/1 5062/5070/1 5063/5071/1 5064/5072/1 +f 5065/5073/1 5066/5074/1 5067/5075/1 5068/5076/1 +f 5069/5077/1 5070/5078/1 5071/5079/1 5072/5080/1 +f 5073/5081/1 5074/5082/1 5075/5083/1 5076/5084/1 +f 5077/5085/1 5078/5086/1 5079/5087/1 5080/5088/1 +f 5081/5089/1 5082/5090/1 5083/5091/1 5084/5092/1 +f 5085/5093/1 5086/5094/1 5087/5095/1 5088/5096/1 +f 5089/5097/1 5090/5098/1 5091/5099/1 5092/5100/1 +f 5093/5101/1 5094/5102/1 5095/5103/1 5096/5104/1 +f 5097/5105/1 5098/5106/1 5099/5107/1 5100/5108/1 +f 5101/5109/1 5102/5110/1 5103/5111/1 5104/5112/1 +f 5105/5113/1 5106/5114/1 5107/5115/1 5108/5116/1 +f 5109/5117/1 5110/5118/1 5111/5119/1 5112/5120/1 +f 5113/5121/1 5114/5122/1 5115/5123/1 5116/5124/1 +f 5117/5125/1 5118/5126/1 5119/5127/1 5120/5128/1 +f 5121/5129/1 5122/5130/1 5123/5131/1 5124/5132/1 +f 5125/5133/1 5126/5134/1 5127/5135/1 5128/5136/1 +f 5129/5137/1 5130/5138/1 5131/5139/1 5132/5140/1 +f 5133/5141/1 5134/5142/1 5135/5143/1 5136/5144/1 +f 5137/5145/1 5138/5146/1 5139/5147/1 5140/5148/1 +f 5141/5149/1 5142/5150/1 5143/5151/1 5144/5152/1 +f 5145/5153/1 5146/5154/1 5147/5155/1 5148/5156/1 +f 5149/5157/1 5150/5158/1 5151/5159/1 5152/5160/1 +f 5153/5161/1 5154/5162/1 5155/5163/1 5156/5164/1 +f 5157/5165/1 5158/5166/1 5159/5167/1 5160/5168/1 +f 5161/5169/1 5162/5170/1 5163/5171/1 5164/5172/1 +f 5165/5173/1 5166/5174/1 5167/5175/1 5168/5176/1 +f 5169/5177/1 5170/5178/1 5171/5179/1 5172/5180/1 +f 5173/5181/1 5174/5182/1 5175/5183/1 5176/5184/1 +f 5177/5185/1 5178/5186/1 5179/5187/1 5180/5188/1 +f 5181/5189/1 5182/5190/1 5183/5191/1 5184/5192/1 +f 5185/5193/1 5186/5194/1 5187/5195/1 5188/5196/1 +f 5189/5197/1 5190/5198/1 5191/5199/1 5192/5200/1 +f 5193/5201/1 5194/5202/1 5195/5203/1 5196/5204/1 +f 5197/5205/1 5198/5206/1 5199/5207/1 5200/5208/1 +f 5201/5209/1 5202/5210/1 5203/5211/1 5204/5212/1 +f 5205/5213/1 5206/5214/1 5207/5215/1 5208/5216/1 +f 5209/5217/1 5210/5218/1 5211/5219/1 5212/5220/1 +f 5213/5221/1 5214/5222/1 5215/5223/1 5216/5224/1 +f 5217/5225/1 5218/5226/1 5219/5227/1 5220/5228/1 +f 5221/5229/1 5222/5230/1 5223/5231/1 5224/5232/1 +f 5225/5233/1 5226/5234/1 5227/5235/1 5228/5236/1 +f 5229/5237/1 5230/5238/1 5231/5239/1 5232/5240/1 +f 5233/5241/1 5234/5242/1 5235/5243/1 5236/5244/1 +f 5237/5245/1 5238/5246/1 5239/5247/1 5240/5248/1 +f 5241/5249/1 5242/5250/1 5243/5251/1 5244/5252/1 +f 5245/5253/1 5246/5254/1 5247/5255/1 5248/5256/1 +f 5249/5257/1 5250/5258/1 5251/5259/1 5252/5260/1 +f 5253/5261/1 5254/5262/1 5255/5263/1 5256/5264/1 +f 5257/5265/1 5258/5266/1 5259/5267/1 5260/5268/1 +f 5261/5269/1 5262/5270/1 5263/5271/1 5264/5272/1 +f 5265/5273/1 5266/5274/1 5267/5275/1 5268/5276/1 +f 5269/5277/1 5270/5278/1 5271/5279/1 5272/5280/1 +f 5273/5281/1 5274/5282/1 5275/5283/1 5276/5284/1 +f 5277/5285/1 5278/5286/1 5279/5287/1 5280/5288/1 +f 5281/5289/1 5282/5290/1 5283/5291/1 5284/5292/1 +f 5285/5293/1 5286/5294/1 5287/5295/1 5288/5296/1 +f 5289/5297/1 5290/5298/1 5291/5299/1 5292/5300/1 +f 5293/5301/1 5294/5302/1 5295/5303/1 5296/5304/1 +f 5297/5305/1 5298/5306/1 5299/5307/1 5300/5308/1 +f 5301/5309/1 5302/5310/1 5303/5311/1 5304/5312/1 +f 5305/5313/1 5306/5314/1 5307/5315/1 5308/5316/1 +f 5309/5317/1 5310/5318/1 5311/5319/1 5312/5320/1 +f 5313/5321/1 5314/5322/1 5315/5323/1 5316/5324/1 +f 5317/5325/1 5318/5326/1 5319/5327/1 5320/5328/1 +f 5321/5329/1 5322/5330/1 5323/5331/1 5324/5332/1 +f 5325/5333/1 5326/5334/1 5327/5335/1 5328/5336/1 +f 5329/5337/1 5330/5338/1 5331/5339/1 5332/5340/1 +f 5333/5341/1 5334/5342/1 5335/5343/1 5336/5344/1 +f 5337/5345/1 5338/5346/1 5339/5347/1 5340/5348/1 +f 5341/5349/1 5342/5350/1 5343/5351/1 5344/5352/1 +f 5345/5353/1 5346/5354/1 5347/5355/1 5348/5356/1 +f 5349/5357/1 5350/5358/1 5351/5359/1 5352/5360/1 +f 5353/5361/1 5354/5362/1 5355/5363/1 5356/5364/1 +f 5357/5365/1 5358/5366/1 5359/5367/1 5360/5368/1 +f 5361/5369/1 5362/5370/1 5363/5371/1 5364/5372/1 +f 5365/5373/1 5366/5374/1 5367/5375/1 5368/5376/1 +f 5369/5377/1 5370/5378/1 5371/5379/1 5372/5380/1 +f 5373/5381/1 5374/5382/1 5375/5383/1 5376/5384/1 +f 5377/5385/1 5378/5386/1 5379/5387/1 5380/5388/1 +f 5381/5389/1 5382/5390/1 5383/5391/1 5384/5392/1 +f 5385/5393/1 5386/5394/1 5387/5395/1 5388/5396/1 +f 5389/5397/1 5390/5398/1 5391/5399/1 5392/5400/1 +f 5393/5401/1 5394/5402/1 5395/5403/1 5396/5404/1 +f 5397/5405/1 5398/5406/1 5399/5407/1 5400/5408/1 +f 5401/5409/1 5402/5410/1 5403/5411/1 5404/5412/1 +f 5405/5413/1 5406/5414/1 5407/5415/1 5408/5416/1 +f 5409/5417/1 5410/5418/1 5411/5419/1 5412/5420/1 +f 5413/5421/1 5414/5422/1 5415/5423/1 5416/5424/1 +f 5417/5425/1 5418/5426/1 5419/5427/1 5420/5428/1 +f 5421/5429/1 5422/5430/1 5423/5431/1 5424/5432/1 +f 5425/5433/1 5426/5434/1 5427/5435/1 5428/5436/1 +f 5429/5437/1 5430/5438/1 5431/5439/1 5432/5440/1 +f 5433/5441/1 5434/5442/1 5435/5443/1 5436/5444/1 +f 5437/5445/1 5438/5446/1 5439/5447/1 5440/5448/1 +f 5441/5449/1 5442/5450/1 5443/5451/1 5444/5452/1 +f 5445/5453/1 5446/5454/1 5447/5455/1 5448/5456/1 +f 5449/5457/1 5450/5458/1 5451/5459/1 5452/5460/1 +f 5453/5461/1 5454/5462/1 5455/5463/1 5456/5464/1 +f 5457/5465/1 5458/5466/1 5459/5467/1 5460/5468/1 +f 5461/5469/1 5462/5470/1 5463/5471/1 5464/5472/1 +f 5465/5473/1 5466/5474/1 5467/5475/1 5468/5476/1 +f 5469/5477/1 5470/5478/1 5471/5479/1 5472/5480/1 +f 5473/5481/1 5474/5482/1 5475/5483/1 5476/5484/1 +f 5477/5485/1 5478/5486/1 5479/5487/1 5480/5488/1 +f 5481/5489/1 5482/5490/1 5483/5491/1 5484/5492/1 +f 5485/5493/1 5486/5494/1 5487/5495/1 5488/5496/1 +f 5489/5497/1 5490/5498/1 5491/5499/1 5492/5500/1 +f 5493/5501/1 5494/5502/1 5495/5503/1 5496/5504/1 +f 5497/5505/1 5498/5506/1 5499/5507/1 5500/5508/1 +f 5501/5509/1 5502/5510/1 5503/5511/1 5504/5512/1 +f 5505/5513/1 5506/5514/1 5507/5515/1 5508/5516/1 +f 5509/5517/1 5510/5518/1 5511/5519/1 5512/5520/1 +f 5513/5521/1 5514/5522/1 5515/5523/1 5516/5524/1 +f 5517/5525/1 5518/5526/1 5519/5527/1 5520/5528/1 +f 5521/5529/1 5522/5530/1 5523/5531/1 5524/5532/1 +f 5525/5533/1 5526/5534/1 5527/5535/1 5528/5536/1 +f 5529/5537/1 5530/5538/1 5531/5539/1 5532/5540/1 +f 5533/5541/1 5534/5542/1 5535/5543/1 5536/5544/1 +f 5537/5545/1 5538/5546/1 5539/5547/1 5540/5548/1 +f 5541/5549/1 5542/5550/1 5543/5551/1 5544/5552/1 +f 5545/5553/1 5546/5554/1 5547/5555/1 5548/5556/1 +f 5549/5557/1 5550/5558/1 5551/5559/1 5552/5560/1 +f 5553/5561/1 5554/5562/1 5555/5563/1 5556/5564/1 +f 5557/5565/1 5558/5566/1 5559/5567/1 5560/5568/1 +f 5561/5569/1 5562/5570/1 5563/5571/1 5564/5572/1 +f 5565/5573/1 5566/5574/1 5567/5575/1 5568/5576/1 +f 5569/5577/1 5570/5578/1 5571/5579/1 5572/5580/1 +f 5573/5581/1 5574/5582/1 5575/5583/1 5576/5584/1 +f 5577/5585/1 5578/5586/1 5579/5587/1 5580/5588/1 +f 5581/5589/1 5582/5590/1 5583/5591/1 5584/5592/1 +f 5585/5593/1 5586/5594/1 5587/5595/1 5588/5596/1 +f 5589/5597/1 5590/5598/1 5591/5599/1 5592/5600/1 +f 5593/5601/1 5594/5602/1 5595/5603/1 5596/5604/1 +f 5597/5605/1 5598/5606/1 5599/5607/1 5600/5608/1 +f 5601/5609/1 5602/5610/1 5603/5611/1 5604/5612/1 +f 5605/5613/1 5606/5614/1 5607/5615/1 5608/5616/1 +f 5609/5617/1 5610/5618/1 5611/5619/1 5612/5620/1 +f 5613/5621/1 5614/5622/1 5615/5623/1 5616/5624/1 +f 5617/5625/1 5618/5626/1 5619/5627/1 5620/5628/1 +f 5621/5629/1 5622/5630/1 5623/5631/1 5624/5632/1 +f 5625/5633/1 5626/5634/1 5627/5635/1 5628/5636/1 +f 5629/5637/1 5630/5638/1 5631/5639/1 5632/5640/1 +f 5633/5641/1 5634/5642/1 5635/5643/1 5636/5644/1 +f 5637/5645/1 5638/5646/1 5639/5647/1 5640/5648/1 +f 5641/5649/1 5642/5650/1 5643/5651/1 5644/5652/1 +f 5645/5653/1 5646/5654/1 5647/5655/1 5648/5656/1 +f 5649/5657/1 5650/5658/1 5651/5659/1 5652/5660/1 +f 5653/5661/1 5654/5662/1 5655/5663/1 5656/5664/1 +f 5657/5665/1 5658/5666/1 5659/5667/1 5660/5668/1 +f 5661/5669/1 5662/5670/1 5663/5671/1 5664/5672/1 +f 5665/5673/1 5666/5674/1 5667/5675/1 5668/5676/1 +f 5669/5677/1 5670/5678/1 5671/5679/1 5672/5680/1 +f 5673/5681/1 5674/5682/1 5675/5683/1 5676/5684/1 +f 5677/5685/1 5678/5686/1 5679/5687/1 5680/5688/1 +f 5681/5689/1 5682/5690/1 5683/5691/1 5684/5692/1 +f 5685/5693/1 5686/5694/1 5687/5695/1 5688/5696/1 +f 5689/5697/1 5690/5698/1 5691/5699/1 5692/5700/1 +f 5693/5701/1 5694/5702/1 5695/5703/1 5696/5704/1 +f 5697/5705/1 5698/5706/1 5699/5707/1 5700/5708/1 +f 5701/5709/1 5702/5710/1 5703/5711/1 5704/5712/1 +f 5705/5713/1 5706/5714/1 5707/5715/1 5708/5716/1 +f 5709/5717/1 5710/5718/1 5711/5719/1 5712/5720/1 +f 5713/5721/1 5714/5722/1 5715/5723/1 5716/5724/1 +f 5717/5725/1 5718/5726/1 5719/5727/1 5720/5728/1 +f 5721/5729/1 5722/5730/1 5723/5731/1 5724/5732/1 +f 5725/5733/1 5726/5734/1 5727/5735/1 5728/5736/1 +f 5729/5737/1 5730/5738/1 5731/5739/1 5732/5740/1 +f 5733/5741/1 5734/5742/1 5735/5743/1 5736/5744/1 +f 5737/5745/1 5738/5746/1 5739/5747/1 5740/5748/1 +f 5741/5749/1 5742/5750/1 5743/5751/1 5744/5752/1 +f 5745/5753/1 5746/5754/1 5747/5755/1 5748/5756/1 +f 5749/5757/1 5750/5758/1 5751/5759/1 5752/5760/1 +f 5753/5761/1 5754/5762/1 5755/5763/1 5756/5764/1 +f 5757/5765/1 5758/5766/1 5759/5767/1 5760/5768/1 +f 5761/5769/1 5762/5770/1 5763/5771/1 5764/5772/1 +f 5765/5773/1 5766/5774/1 5767/5775/1 5768/5776/1 +f 5769/5777/1 5770/5778/1 5771/5779/1 5772/5780/1 +f 5773/5781/1 5774/5782/1 5775/5783/1 5776/5784/1 +f 5777/5785/1 5778/5786/1 5779/5787/1 5780/5788/1 +f 5781/5789/1 5782/5790/1 5783/5791/1 5784/5792/1 +f 5785/5793/1 5786/5794/1 5787/5795/1 5788/5796/1 +f 5789/5797/1 5790/5798/1 5791/5799/1 5792/5800/1 +f 5793/5801/1 5794/5802/1 5795/5803/1 5796/5804/1 +f 5797/5805/1 5798/5806/1 5799/5807/1 5800/5808/1 +f 5801/5809/1 5802/5810/1 5803/5811/1 5804/5812/1 +f 5805/5813/1 5806/5814/1 5807/5815/1 5808/5816/1 +f 5809/5817/1 5810/5818/1 5811/5819/1 5812/5820/1 +f 5813/5821/1 5814/5822/1 5815/5823/1 5816/5824/1 +f 5817/5825/1 5818/5826/1 5819/5827/1 5820/5828/1 +f 5821/5829/1 5822/5830/1 5823/5831/1 5824/5832/1 +f 5825/5833/1 5826/5834/1 5827/5835/1 5828/5836/1 +f 5829/5837/1 5830/5838/1 5831/5839/1 5832/5840/1 +f 5833/5841/1 5834/5842/1 5835/5843/1 5836/5844/1 +f 5837/5845/1 5838/5846/1 5839/5847/1 5840/5848/1 +f 5841/5849/1 5842/5850/1 5843/5851/1 5844/5852/1 +f 5845/5853/1 5846/5854/1 5847/5855/1 5848/5856/1 +f 5849/5857/1 5850/5858/1 5851/5859/1 5852/5860/1 +f 5853/5861/1 5854/5862/1 5855/5863/1 5856/5864/1 +f 5857/5865/1 5858/5866/1 5859/5867/1 5860/5868/1 +f 5861/5869/1 5862/5870/1 5863/5871/1 5864/5872/1 +f 5865/5873/1 5866/5874/1 5867/5875/1 5868/5876/1 +f 5869/5877/1 5870/5878/1 5871/5879/1 5872/5880/1 +f 5873/5881/1 5874/5882/1 5875/5883/1 5876/5884/1 +f 5877/5885/1 5878/5886/1 5879/5887/1 5880/5888/1 +f 5881/5889/1 5882/5890/1 5883/5891/1 5884/5892/1 +f 5885/5893/1 5886/5894/1 5887/5895/1 5888/5896/1 +f 5889/5897/1 5890/5898/1 5891/5899/1 5892/5900/1 +f 5893/5901/1 5894/5902/1 5895/5903/1 5896/5904/1 +f 5897/5905/1 5898/5906/1 5899/5907/1 5900/5908/1 +f 5901/5909/1 5902/5910/1 5903/5911/1 5904/5912/1 +f 5905/5913/1 5906/5914/1 5907/5915/1 5908/5916/1 +f 5909/5917/1 5910/5918/1 5911/5919/1 5912/5920/1 +f 5913/5921/1 5914/5922/1 5915/5923/1 5916/5924/1 +f 5917/5925/1 5918/5926/1 5919/5927/1 5920/5928/1 +f 5921/5929/1 5922/5930/1 5923/5931/1 5924/5932/1 +f 5925/5933/1 5926/5934/1 5927/5935/1 5928/5936/1 +f 5929/5937/1 5930/5938/1 5931/5939/1 5932/5940/1 +f 5933/5941/1 5934/5942/1 5935/5943/1 5936/5944/1 +f 5937/5945/1 5938/5946/1 5939/5947/1 5940/5948/1 +f 5941/5949/1 5942/5950/1 5943/5951/1 5944/5952/1 +f 5945/5953/1 5946/5954/1 5947/5955/1 5948/5956/1 +f 5949/5957/1 5950/5958/1 5951/5959/1 5952/5960/1 +f 5953/5961/1 5954/5962/1 5955/5963/1 5956/5964/1 +f 5957/5965/1 5958/5966/1 5959/5967/1 5960/5968/1 +f 5961/5969/1 5962/5970/1 5963/5971/1 5964/5972/1 +f 5965/5973/1 5966/5974/1 5967/5975/1 5968/5976/1 +f 5969/5977/1 5970/5978/1 5971/5979/1 5972/5980/1 +f 5973/5981/1 5974/5982/1 5975/5983/1 5976/5984/1 +f 5977/5985/1 5978/5986/1 5979/5987/1 5980/5988/1 +f 5981/5989/1 5982/5990/1 5983/5991/1 5984/5992/1 +f 5985/5993/1 5986/5994/1 5987/5995/1 5988/5996/1 +f 5989/5997/1 5990/5998/1 5991/5999/1 5992/6000/1 +f 5993/6001/1 5994/6002/1 5995/6003/1 5996/6004/1 +f 5997/6005/1 5998/6006/1 5999/6007/1 6000/6008/1 +f 6001/6009/1 6002/6010/1 6003/6011/1 6004/6012/1 +f 6005/6013/1 6006/6014/1 6007/6015/1 6008/6016/1 +f 6009/6017/1 6010/6018/1 6011/6019/1 6012/6020/1 +f 6013/6021/1 6014/6022/1 6015/6023/1 6016/6024/1 +f 6017/6025/1 6018/6026/1 6019/6027/1 6020/6028/1 +f 6021/6029/1 6022/6030/1 6023/6031/1 6024/6032/1 +f 6025/6033/1 6026/6034/1 6027/6035/1 6028/6036/1 +f 6029/6037/1 6030/6038/1 6031/6039/1 6032/6040/1 +f 6033/6041/1 6034/6042/1 6035/6043/1 6036/6044/1 +f 6037/6045/1 6038/6046/1 6039/6047/1 6040/6048/1 +f 6041/6049/1 6042/6050/1 6043/6051/1 6044/6052/1 +f 6045/6053/1 6046/6054/1 6047/6055/1 6048/6056/1 +f 6049/6057/1 6050/6058/1 6051/6059/1 6052/6060/1 +f 6053/6061/1 6054/6062/1 6055/6063/1 6056/6064/1 +f 6057/6065/1 6058/6066/1 6059/6067/1 6060/6068/1 +f 6061/6069/1 6062/6070/1 6063/6071/1 6064/6072/1 +f 6065/6073/1 6066/6074/1 6067/6075/1 6068/6076/1 +f 6069/6077/1 6070/6078/1 6071/6079/1 6072/6080/1 +f 6073/6081/1 6074/6082/1 6075/6083/1 6076/6084/1 +f 6077/6085/1 6078/6086/1 6079/6087/1 6080/6088/1 +f 6081/6089/1 6082/6090/1 6083/6091/1 6084/6092/1 +f 6085/6093/1 6086/6094/1 6087/6095/1 6088/6096/1 +f 6089/6097/1 6090/6098/1 6091/6099/1 6092/6100/1 +f 6093/6101/1 6094/6102/1 6095/6103/1 6096/6104/1 +f 6097/6105/1 6098/6106/1 6099/6107/1 6100/6108/1 +f 6101/6109/1 6102/6110/1 6103/6111/1 6104/6112/1 +f 6105/6113/1 6106/6114/1 6107/6115/1 6108/6116/1 +f 6109/6117/1 6110/6118/1 6111/6119/1 6112/6120/1 +f 6113/6121/1 6114/6122/1 6115/6123/1 6116/6124/1 +f 6117/6125/1 6118/6126/1 6119/6127/1 6120/6128/1 +f 6121/6129/1 6122/6130/1 6123/6131/1 6124/6132/1 +f 6125/6133/1 6126/6134/1 6127/6135/1 6128/6136/1 +f 6129/6137/1 6130/6138/1 6131/6139/1 6132/6140/1 +f 6133/6141/1 6134/6142/1 6135/6143/1 6136/6144/1 +f 6137/6145/1 6138/6146/1 6139/6147/1 6140/6148/1 +f 6141/6149/1 6142/6150/1 6143/6151/1 6144/6152/1 +f 6145/6153/1 6146/6154/1 6147/6155/1 6148/6156/1 +f 6149/6157/1 6150/6158/1 6151/6159/1 6152/6160/1 +f 6153/6161/1 6154/6162/1 6155/6163/1 6156/6164/1 +f 6157/6165/1 6158/6166/1 6159/6167/1 6160/6168/1 +f 6161/6169/1 6162/6170/1 6163/6171/1 6164/6172/1 +f 6165/6173/1 6166/6174/1 6167/6175/1 6168/6176/1 +f 6169/6177/1 6170/6178/1 6171/6179/1 6172/6180/1 +f 6173/6181/1 6174/6182/1 6175/6183/1 6176/6184/1 +f 6177/6185/1 6178/6186/1 6179/6187/1 6180/6188/1 +f 6181/6189/1 6182/6190/1 6183/6191/1 6184/6192/1 +f 6185/6193/1 6186/6194/1 6187/6195/1 6188/6196/1 +f 6189/6197/1 6190/6198/1 6191/6199/1 6192/6200/1 +f 6193/6201/1 6194/6202/1 6195/6203/1 6196/6204/1 +f 6197/6205/1 6198/6206/1 6199/6207/1 6200/6208/1 +f 6201/6209/1 6202/6210/1 6203/6211/1 6204/6212/1 +f 6205/6213/1 6206/6214/1 6207/6215/1 6208/6216/1 +f 6209/6217/1 6210/6218/1 6211/6219/1 6212/6220/1 +f 6213/6221/1 6214/6222/1 6215/6223/1 6216/6224/1 +f 6217/6225/1 6218/6226/1 6219/6227/1 6220/6228/1 +f 6221/6229/1 6222/6230/1 6223/6231/1 6224/6232/1 +f 6225/6233/1 6226/6234/1 6227/6235/1 6228/6236/1 +f 6229/6237/1 6230/6238/1 6231/6239/1 6232/6240/1 +f 6233/6241/1 6234/6242/1 6235/6243/1 6236/6244/1 +f 6237/6245/1 6238/6246/1 6239/6247/1 6240/6248/1 +f 6241/6249/1 6242/6250/1 6243/6251/1 6244/6252/1 +f 6245/6253/1 6246/6254/1 6247/6255/1 6248/6256/1 +f 6249/6257/1 6250/6258/1 6251/6259/1 6252/6260/1 +f 6253/6261/1 6254/6262/1 6255/6263/1 6256/6264/1 +f 6257/6265/1 6258/6266/1 6259/6267/1 6260/6268/1 +f 6261/6269/1 6262/6270/1 6263/6271/1 6264/6272/1 +f 6265/6273/1 6266/6274/1 6267/6275/1 6268/6276/1 +f 6269/6277/1 6270/6278/1 6271/6279/1 6272/6280/1 +f 6273/6281/1 6274/6282/1 6275/6283/1 6276/6284/1 +f 6277/6285/1 6278/6286/1 6279/6287/1 6280/6288/1 +f 6281/6289/1 6282/6290/1 6283/6291/1 6284/6292/1 +f 6285/6293/1 6286/6294/1 6287/6295/1 6288/6296/1 +f 6289/6297/1 6290/6298/1 6291/6299/1 6292/6300/1 +f 6293/6301/1 6294/6302/1 6295/6303/1 6296/6304/1 +f 6297/6305/1 6298/6306/1 6299/6307/1 6300/6308/1 +f 6301/6309/1 6302/6310/1 6303/6311/1 6304/6312/1 +f 6305/6313/1 6306/6314/1 6307/6315/1 6308/6316/1 +f 6309/6317/1 6310/6318/1 6311/6319/1 6312/6320/1 +f 6313/6321/1 6314/6322/1 6315/6323/1 6316/6324/1 +f 6317/6325/1 6318/6326/1 6319/6327/1 6320/6328/1 +f 6321/6329/1 6322/6330/1 6323/6331/1 6324/6332/1 +f 6325/6333/1 6326/6334/1 6327/6335/1 6328/6336/1 +f 6329/6337/1 6330/6338/1 6331/6339/1 6332/6340/1 +f 6333/6341/1 6334/6342/1 6335/6343/1 6336/6344/1 +f 6337/6345/1 6338/6346/1 6339/6347/1 6340/6348/1 +f 6341/6349/1 6342/6350/1 6343/6351/1 6344/6352/1 +f 6345/6353/1 6346/6354/1 6347/6355/1 6348/6356/1 +f 6349/6357/1 6350/6358/1 6351/6359/1 6352/6360/1 +f 6353/6361/1 6354/6362/1 6355/6363/1 6356/6364/1 +f 6357/6365/1 6358/6366/1 6359/6367/1 6360/6368/1 +f 6361/6369/1 6362/6370/1 6363/6371/1 6364/6372/1 +f 6365/6373/1 6366/6374/1 6367/6375/1 6368/6376/1 +f 6369/6377/1 6370/6378/1 6371/6379/1 6372/6380/1 +f 6373/6381/1 6374/6382/1 6375/6383/1 6376/6384/1 +f 6377/6385/1 6378/6386/1 6379/6387/1 6380/6388/1 +f 6381/6389/1 6382/6390/1 6383/6391/1 6384/6392/1 +f 6385/6393/1 6386/6394/1 6387/6395/1 6388/6396/1 +f 6389/6397/1 6390/6398/1 6391/6399/1 6392/6400/1 +f 6393/6401/1 6394/6402/1 6395/6403/1 6396/6404/1 +f 6397/6405/1 6398/6406/1 6399/6407/1 6400/6408/1 +f 6401/6409/1 6402/6410/1 6403/6411/1 6404/6412/1 +f 6405/6413/1 6406/6414/1 6407/6415/1 6408/6416/1 +f 6409/6417/1 6410/6418/1 6411/6419/1 6412/6420/1 +f 6413/6421/1 6414/6422/1 6415/6423/1 6416/6424/1 +f 6417/6425/1 6418/6426/1 6419/6427/1 6420/6428/1 +f 6421/6429/1 6422/6430/1 6423/6431/1 6424/6432/1 +f 6425/6433/1 6426/6434/1 6427/6435/1 6428/6436/1 +f 6429/6437/1 6430/6438/1 6431/6439/1 6432/6440/1 +f 6433/6441/1 6434/6442/1 6435/6443/1 6436/6444/1 +f 6437/6445/1 6438/6446/1 6439/6447/1 6440/6448/1 +f 6441/6449/1 6442/6450/1 6443/6451/1 6444/6452/1 +f 6445/6453/1 6446/6454/1 6447/6455/1 6448/6456/1 +f 6449/6457/1 6450/6458/1 6451/6459/1 6452/6460/1 +f 6453/6461/1 6454/6462/1 6455/6463/1 6456/6464/1 +f 6457/6465/1 6458/6466/1 6459/6467/1 6460/6468/1 +f 6461/6469/1 6462/6470/1 6463/6471/1 6464/6472/1 +f 6465/6473/1 6466/6474/1 6467/6475/1 6468/6476/1 +f 6469/6477/1 6470/6478/1 6471/6479/1 6472/6480/1 +f 6473/6481/1 6474/6482/1 6475/6483/1 6476/6484/1 +f 6477/6485/1 6478/6486/1 6479/6487/1 6480/6488/1 +f 6481/6489/1 6482/6490/1 6483/6491/1 6484/6492/1 +f 6485/6493/1 6486/6494/1 6487/6495/1 6488/6496/1 +f 6489/6497/1 6490/6498/1 6491/6499/1 6492/6500/1 +f 6493/6501/1 6494/6502/1 6495/6503/1 6496/6504/1 +f 6497/6505/1 6498/6506/1 6499/6507/1 6500/6508/1 +f 6501/6509/1 6502/6510/1 6503/6511/1 6504/6512/1 +f 6505/6513/1 6506/6514/1 6507/6515/1 6508/6516/1 +f 6509/6517/1 6510/6518/1 6511/6519/1 6512/6520/1 +f 6513/6521/1 6514/6522/1 6515/6523/1 6516/6524/1 +f 6517/6525/1 6518/6526/1 6519/6527/1 6520/6528/1 +f 6521/6529/1 6522/6530/1 6523/6531/1 6524/6532/1 +f 6525/6533/1 6526/6534/1 6527/6535/1 6528/6536/1 +f 6529/6537/1 6530/6538/1 6531/6539/1 6532/6540/1 +f 6533/6541/1 6534/6542/1 6535/6543/1 6536/6544/1 +f 6537/6545/1 6538/6546/1 6539/6547/1 6540/6548/1 +f 6541/6549/1 6542/6550/1 6543/6551/1 6544/6552/1 +f 6545/6553/1 6546/6554/1 6547/6555/1 6548/6556/1 +f 6549/6557/1 6550/6558/1 6551/6559/1 6552/6560/1 +f 6553/6561/1 6554/6562/1 6555/6563/1 6556/6564/1 +f 6557/6565/1 6558/6566/1 6559/6567/1 6560/6568/1 +f 6561/6569/1 6562/6570/1 6563/6571/1 6564/6572/1 +f 6565/6573/1 6566/6574/1 6567/6575/1 6568/6576/1 +f 6569/6577/1 6570/6578/1 6571/6579/1 6572/6580/1 +f 6573/6581/1 6574/6582/1 6575/6583/1 6576/6584/1 +f 6577/6585/1 6578/6586/1 6579/6587/1 6580/6588/1 +f 6581/6589/1 6582/6590/1 6583/6591/1 6584/6592/1 +f 6585/6593/1 6586/6594/1 6587/6595/1 6588/6596/1 +f 6589/6597/1 6590/6598/1 6591/6599/1 6592/6600/1 +f 6593/6601/1 6594/6602/1 6595/6603/1 6596/6604/1 +f 6597/6605/1 6598/6606/1 6599/6607/1 6600/6608/1 +f 6601/6609/1 6602/6610/1 6603/6611/1 6604/6612/1 +f 6605/6613/1 6606/6614/1 6607/6615/1 6608/6616/1 +f 6609/6617/1 6610/6618/1 6611/6619/1 6612/6620/1 +f 6613/6621/1 6614/6622/1 6615/6623/1 6616/6624/1 +f 6617/6625/1 6618/6626/1 6619/6627/1 6620/6628/1 +f 6621/6629/1 6622/6630/1 6623/6631/1 6624/6632/1 +f 6625/6633/1 6626/6634/1 6627/6635/1 6628/6636/1 +f 6629/6637/1 6630/6638/1 6631/6639/1 6632/6640/1 +f 6633/6641/1 6634/6642/1 6635/6643/1 6636/6644/1 +f 6637/6645/1 6638/6646/1 6639/6647/1 6640/6648/1 +f 6641/6649/1 6642/6650/1 6643/6651/1 6644/6652/1 +f 6645/6653/1 6646/6654/1 6647/6655/1 6648/6656/1 +f 6649/6657/1 6650/6658/1 6651/6659/1 6652/6660/1 +f 6653/6661/1 6654/6662/1 6655/6663/1 6656/6664/1 +f 6657/6665/1 6658/6666/1 6659/6667/1 6660/6668/1 +f 6661/6669/1 6662/6670/1 6663/6671/1 6664/6672/1 +f 6665/6673/1 6666/6674/1 6667/6675/1 6668/6676/1 +f 6669/6677/1 6670/6678/1 6671/6679/1 6672/6680/1 +f 6673/6681/1 6674/6682/1 6675/6683/1 6676/6684/1 +f 6677/6685/1 6678/6686/1 6679/6687/1 6680/6688/1 +f 6681/6689/1 6682/6690/1 6683/6691/1 6684/6692/1 +f 6685/6693/1 6686/6694/1 6687/6695/1 6688/6696/1 +f 6689/6697/1 6690/6698/1 6691/6699/1 6692/6700/1 +f 6693/6701/1 6694/6702/1 6695/6703/1 6696/6704/1 +f 6697/6705/1 6698/6706/1 6699/6707/1 6700/6708/1 +f 6701/6709/1 6702/6710/1 6703/6711/1 6704/6712/1 +f 6705/6713/1 6706/6714/1 6707/6715/1 6708/6716/1 +f 6709/6717/1 6710/6718/1 6711/6719/1 6712/6720/1 +f 6713/6721/1 6714/6722/1 6715/6723/1 6716/6724/1 +f 6717/6725/1 6718/6726/1 6719/6727/1 6720/6728/1 +f 6721/6729/1 6722/6730/1 6723/6731/1 6724/6732/1 +f 6725/6733/1 6726/6734/1 6727/6735/1 6728/6736/1 +f 6729/6737/1 6730/6738/1 6731/6739/1 6732/6740/1 +f 6733/6741/1 6734/6742/1 6735/6743/1 6736/6744/1 +f 6737/6745/1 6738/6746/1 6739/6747/1 6740/6748/1 +f 6741/6749/1 6742/6750/1 6743/6751/1 6744/6752/1 +f 6745/6753/1 6746/6754/1 6747/6755/1 6748/6756/1 +f 6749/6757/1 6750/6758/1 6751/6759/1 6752/6760/1 +f 6753/6761/1 6754/6762/1 6755/6763/1 6756/6764/1 +f 6757/6765/1 6758/6766/1 6759/6767/1 6760/6768/1 +f 6761/6769/1 6762/6770/1 6763/6771/1 6764/6772/1 +f 6765/6773/1 6766/6774/1 6767/6775/1 6768/6776/1 +f 6769/6777/1 6770/6778/1 6771/6779/1 6772/6780/1 +f 6773/6781/1 6774/6782/1 6775/6783/1 6776/6784/1 +f 6777/6785/1 6778/6786/1 6779/6787/1 6780/6788/1 +f 6781/6789/1 6782/6790/1 6783/6791/1 6784/6792/1 +f 6785/6793/1 6786/6794/1 6787/6795/1 6788/6796/1 +f 6789/6797/1 6790/6798/1 6791/6799/1 6792/6800/1 +f 6793/6801/1 6794/6802/1 6795/6803/1 6796/6804/1 +f 6797/6805/1 6798/6806/1 6799/6807/1 6800/6808/1 +f 6801/6809/1 6802/6810/1 6803/6811/1 6804/6812/1 +f 6805/6813/1 6806/6814/1 6807/6815/1 6808/6816/1 +f 6809/6817/1 6810/6818/1 6811/6819/1 6812/6820/1 +f 6813/6821/1 6814/6822/1 6815/6823/1 6816/6824/1 +f 6817/6825/1 6818/6826/1 6819/6827/1 6820/6828/1 +f 6821/6829/1 6822/6830/1 6823/6831/1 6824/6832/1 +f 6825/6833/1 6826/6834/1 6827/6835/1 6828/6836/1 +f 6829/6837/1 6830/6838/1 6831/6839/1 6832/6840/1 +f 6833/6841/1 6834/6842/1 6835/6843/1 6836/6844/1 +f 6837/6845/1 6838/6846/1 6839/6847/1 6840/6848/1 +f 6841/6849/1 6842/6850/1 6843/6851/1 6844/6852/1 +f 6845/6853/1 6846/6854/1 6847/6855/1 6848/6856/1 +f 6849/6857/1 6850/6858/1 6851/6859/1 6852/6860/1 +f 6853/6861/1 6854/6862/1 6855/6863/1 6856/6864/1 +f 6857/6865/1 6858/6866/1 6859/6867/1 6860/6868/1 +f 6861/6869/1 6862/6870/1 6863/6871/1 6864/6872/1 +f 6865/6873/1 6866/6874/1 6867/6875/1 6868/6876/1 +f 6869/6877/1 6870/6878/1 6871/6879/1 6872/6880/1 +f 6873/6881/1 6874/6882/1 6875/6883/1 6876/6884/1 +f 6877/6885/1 6878/6886/1 6879/6887/1 6880/6888/1 +f 6881/6889/1 6882/6890/1 6883/6891/1 6884/6892/1 +f 6885/6893/1 6886/6894/1 6887/6895/1 6888/6896/1 +f 6889/6897/1 6890/6898/1 6891/6899/1 6892/6900/1 +f 6893/6901/1 6894/6902/1 6895/6903/1 6896/6904/1 +f 6897/6905/1 6898/6906/1 6899/6907/1 6900/6908/1 +f 6901/6909/1 6902/6910/1 6903/6911/1 6904/6912/1 +f 6905/6913/1 6906/6914/1 6907/6915/1 6908/6916/1 +f 6909/6917/1 6910/6918/1 6911/6919/1 6912/6920/1 +f 6913/6921/1 6914/6922/1 6915/6923/1 6916/6924/1 +f 6917/6925/1 6918/6926/1 6919/6927/1 6920/6928/1 +f 6921/6929/1 6922/6930/1 6923/6931/1 6924/6932/1 +f 6925/6933/1 6926/6934/1 6927/6935/1 6928/6936/1 +f 6929/6937/1 6930/6938/1 6931/6939/1 6932/6940/1 +f 6933/6941/1 6934/6942/1 6935/6943/1 6936/6944/1 +f 6937/6945/1 6938/6946/1 6939/6947/1 6940/6948/1 +f 6941/6949/1 6942/6950/1 6943/6951/1 6944/6952/1 +f 6945/6953/1 6946/6954/1 6947/6955/1 6948/6956/1 +f 6949/6957/1 6950/6958/1 6951/6959/1 6952/6960/1 +f 6953/6961/1 6954/6962/1 6955/6963/1 6956/6964/1 +f 6957/6965/1 6958/6966/1 6959/6967/1 6960/6968/1 +f 6961/6969/1 6962/6970/1 6963/6971/1 6964/6972/1 +f 6965/6973/1 6966/6974/1 6967/6975/1 6968/6976/1 +f 6969/6977/1 6970/6978/1 6971/6979/1 6972/6980/1 +f 6973/6981/1 6974/6982/1 6975/6983/1 6976/6984/1 +f 6977/6985/1 6978/6986/1 6979/6987/1 6980/6988/1 +f 6981/6989/1 6982/6990/1 6983/6991/1 6984/6992/1 +f 6985/6993/1 6986/6994/1 6987/6995/1 6988/6996/1 +f 6989/6997/1 6990/6998/1 6991/6999/1 6992/7000/1 +f 6993/7001/1 6994/7002/1 6995/7003/1 6996/7004/1 +f 6997/7005/1 6998/7006/1 6999/7007/1 7000/7008/1 +f 7001/7009/1 7002/7010/1 7003/7011/1 7004/7012/1 +f 7005/7013/1 7006/7014/1 7007/7015/1 7008/7016/1 +f 7009/7017/1 7010/7018/1 7011/7019/1 7012/7020/1 +f 7013/7021/1 7014/7022/1 7015/7023/1 7016/7024/1 +f 7017/7025/1 7018/7026/1 7019/7027/1 7020/7028/1 +f 7021/7029/1 7022/7030/1 7023/7031/1 7024/7032/1 +f 7025/7033/1 7026/7034/1 7027/7035/1 7028/7036/1 +f 7029/7037/1 7030/7038/1 7031/7039/1 7032/7040/1 +f 7033/7041/1 7034/7042/1 7035/7043/1 7036/7044/1 +f 7037/7045/1 7038/7046/1 7039/7047/1 7040/7048/1 +f 7041/7049/1 7042/7050/1 7043/7051/1 7044/7052/1 +f 7045/7053/1 7046/7054/1 7047/7055/1 7048/7056/1 +f 7049/7057/1 7050/7058/1 7051/7059/1 7052/7060/1 +f 7053/7061/1 7054/7062/1 7055/7063/1 7056/7064/1 +f 7057/7065/1 7058/7066/1 7059/7067/1 7060/7068/1 +f 7061/7069/1 7062/7070/1 7063/7071/1 7064/7072/1 +f 7065/7073/1 7066/7074/1 7067/7075/1 7068/7076/1 +f 7069/7077/1 7070/7078/1 7071/7079/1 7072/7080/1 +f 7073/7081/1 7074/7082/1 7075/7083/1 7076/7084/1 +f 7077/7085/1 7078/7086/1 7079/7087/1 7080/7088/1 +f 7081/7089/1 7082/7090/1 7083/7091/1 7084/7092/1 +f 7085/7093/1 7086/7094/1 7087/7095/1 7088/7096/1 +f 7089/7097/1 7090/7098/1 7091/7099/1 7092/7100/1 +f 7093/7101/1 7094/7102/1 7095/7103/1 7096/7104/1 +f 7097/7105/1 7098/7106/1 7099/7107/1 7100/7108/1 +f 7101/7109/1 7102/7110/1 7103/7111/1 7104/7112/1 +f 7105/7113/1 7106/7114/1 7107/7115/1 7108/7116/1 +f 7109/7117/1 7110/7118/1 7111/7119/1 7112/7120/1 +f 7113/7121/1 7114/7122/1 7115/7123/1 7116/7124/1 +f 7117/7125/1 7118/7126/1 7119/7127/1 7120/7128/1 +f 7121/7129/1 7122/7130/1 7123/7131/1 7124/7132/1 +f 7125/7133/1 7126/7134/1 7127/7135/1 7128/7136/1 +f 7129/7137/1 7130/7138/1 7131/7139/1 7132/7140/1 +f 7133/7141/1 7134/7142/1 7135/7143/1 7136/7144/1 +f 7137/7145/1 7138/7146/1 7139/7147/1 7140/7148/1 +f 7141/7149/1 7142/7150/1 7143/7151/1 7144/7152/1 +f 7145/7153/1 7146/7154/1 7147/7155/1 7148/7156/1 +f 7149/7157/1 7150/7158/1 7151/7159/1 7152/7160/1 +f 7153/7161/1 7154/7162/1 7155/7163/1 7156/7164/1 +f 7157/7165/1 7158/7166/1 7159/7167/1 7160/7168/1 +f 7161/7169/1 7162/7170/1 7163/7171/1 7164/7172/1 +f 7165/7173/1 7166/7174/1 7167/7175/1 7168/7176/1 +f 7169/7177/1 7170/7178/1 7171/7179/1 7172/7180/1 +f 7173/7181/1 7174/7182/1 7175/7183/1 7176/7184/1 +f 7177/7185/1 7178/7186/1 7179/7187/1 7180/7188/1 +f 7181/7189/1 7182/7190/1 7183/7191/1 7184/7192/1 +f 7185/7193/1 7186/7194/1 7187/7195/1 7188/7196/1 +f 7189/7197/1 7190/7198/1 7191/7199/1 7192/7200/1 +f 7193/7201/1 7194/7202/1 7195/7203/1 7196/7204/1 +f 7197/7205/1 7198/7206/1 7199/7207/1 7200/7208/1 +f 7201/7209/1 7202/7210/1 7203/7211/1 7204/7212/1 +f 7205/7213/1 7206/7214/1 7207/7215/1 7208/7216/1 +f 7209/7217/1 7210/7218/1 7211/7219/1 7212/7220/1 +f 7213/7221/1 7214/7222/1 7215/7223/1 7216/7224/1 +f 7217/7225/1 7218/7226/1 7219/7227/1 7220/7228/1 +f 7221/7229/1 7222/7230/1 7223/7231/1 7224/7232/1 +f 7225/7233/1 7226/7234/1 7227/7235/1 7228/7236/1 +f 7229/7237/1 7230/7238/1 7231/7239/1 7232/7240/1 +f 7233/7241/1 7234/7242/1 7235/7243/1 7236/7244/1 +f 7237/7245/1 7238/7246/1 7239/7247/1 7240/7248/1 +f 7241/7249/1 7242/7250/1 7243/7251/1 7244/7252/1 +f 7245/7253/1 7246/7254/1 7247/7255/1 7248/7256/1 +f 7249/7257/1 7250/7258/1 7251/7259/1 7252/7260/1 +f 7253/7261/1 7254/7262/1 7255/7263/1 7256/7264/1 +f 7257/7265/1 7258/7266/1 7259/7267/1 7260/7268/1 +f 7261/7269/1 7262/7270/1 7263/7271/1 7264/7272/1 +f 7265/7273/1 7266/7274/1 7267/7275/1 7268/7276/1 +f 7269/7277/1 7270/7278/1 7271/7279/1 7272/7280/1 +f 7273/7281/1 7274/7282/1 7275/7283/1 7276/7284/1 +f 7277/7285/1 7278/7286/1 7279/7287/1 7280/7288/1 +f 7281/7289/1 7282/7290/1 7283/7291/1 7284/7292/1 +f 7285/7293/1 7286/7294/1 7287/7295/1 7288/7296/1 +f 7289/7297/1 7290/7298/1 7291/7299/1 7292/7300/1 +f 7293/7301/1 7294/7302/1 7295/7303/1 7296/7304/1 +f 7297/7305/1 7298/7306/1 7299/7307/1 7300/7308/1 +f 7301/7309/1 7302/7310/1 7303/7311/1 7304/7312/1 +f 7305/7313/1 7306/7314/1 7307/7315/1 7308/7316/1 +f 7309/7317/1 7310/7318/1 7311/7319/1 7312/7320/1 +f 7313/7321/1 7314/7322/1 7315/7323/1 7316/7324/1 +f 7317/7325/1 7318/7326/1 7319/7327/1 7320/7328/1 +f 7321/7329/1 7322/7330/1 7323/7331/1 7324/7332/1 +f 7325/7333/1 7326/7334/1 7327/7335/1 7328/7336/1 +f 7329/7337/1 7330/7338/1 7331/7339/1 7332/7340/1 +f 7333/7341/1 7334/7342/1 7335/7343/1 7336/7344/1 +f 7337/7345/1 7338/7346/1 7339/7347/1 7340/7348/1 +f 7341/7349/1 7342/7350/1 7343/7351/1 7344/7352/1 +f 7345/7353/1 7346/7354/1 7347/7355/1 7348/7356/1 +f 7349/7357/1 7350/7358/1 7351/7359/1 7352/7360/1 +f 7353/7361/1 7354/7362/1 7355/7363/1 7356/7364/1 +f 7357/7365/1 7358/7366/1 7359/7367/1 7360/7368/1 +f 7361/7369/1 7362/7370/1 7363/7371/1 7364/7372/1 +f 7365/7373/1 7366/7374/1 7367/7375/1 7368/7376/1 +f 7369/7377/1 7370/7378/1 7371/7379/1 7372/7380/1 +f 7373/7381/1 7374/7382/1 7375/7383/1 7376/7384/1 +f 7377/7385/1 7378/7386/1 7379/7387/1 7380/7388/1 +f 7381/7389/1 7382/7390/1 7383/7391/1 7384/7392/1 +f 7385/7393/1 7386/7394/1 7387/7395/1 7388/7396/1 +f 7389/7397/1 7390/7398/1 7391/7399/1 7392/7400/1 +f 7393/7401/1 7394/7402/1 7395/7403/1 7396/7404/1 +f 7397/7405/1 7398/7406/1 7399/7407/1 7400/7408/1 +f 7401/7409/1 7402/7410/1 7403/7411/1 7404/7412/1 +f 7405/7413/1 7406/7414/1 7407/7415/1 7408/7416/1 +f 7409/7417/1 7410/7418/1 7411/7419/1 7412/7420/1 +f 7413/7421/1 7414/7422/1 7415/7423/1 7416/7424/1 +f 7417/7425/1 7418/7426/1 7419/7427/1 7420/7428/1 +f 7421/7429/1 7422/7430/1 7423/7431/1 7424/7432/1 +f 7425/7433/1 7426/7434/1 7427/7435/1 7428/7436/1 +f 7429/7437/1 7430/7438/1 7431/7439/1 7432/7440/1 +f 7433/7441/1 7434/7442/1 7435/7443/1 7436/7444/1 +f 7437/7445/1 7438/7446/1 7439/7447/1 7440/7448/1 +f 7441/7449/1 7442/7450/1 7443/7451/1 7444/7452/1 +f 7445/7453/1 7446/7454/1 7447/7455/1 7448/7456/1 +f 7449/7457/1 7450/7458/1 7451/7459/1 7452/7460/1 +f 7453/7461/1 7454/7462/1 7455/7463/1 7456/7464/1 +f 7457/7465/1 7458/7466/1 7459/7467/1 7460/7468/1 +f 7461/7469/1 7462/7470/1 7463/7471/1 7464/7472/1 +f 7465/7473/1 7466/7474/1 7467/7475/1 7468/7476/1 +f 7469/7477/1 7470/7478/1 7471/7479/1 7472/7480/1 +f 7473/7481/1 7474/7482/1 7475/7483/1 7476/7484/1 +f 7477/7485/1 7478/7486/1 7479/7487/1 7480/7488/1 +f 7481/7489/1 7482/7490/1 7483/7491/1 7484/7492/1 +f 7485/7493/1 7486/7494/1 7487/7495/1 7488/7496/1 +f 7489/7497/1 7490/7498/1 7491/7499/1 7492/7500/1 +f 7493/7501/1 7494/7502/1 7495/7503/1 7496/7504/1 +f 7497/7505/1 7498/7506/1 7499/7507/1 7500/7508/1 +f 7501/7509/1 7502/7510/1 7503/7511/1 7504/7512/1 +f 7505/7513/1 7506/7514/1 7507/7515/1 7508/7516/1 +f 7509/7517/1 7510/7518/1 7511/7519/1 7512/7520/1 +f 7513/7521/1 7514/7522/1 7515/7523/1 7516/7524/1 +f 7517/7525/1 7518/7526/1 7519/7527/1 7520/7528/1 +f 7521/7529/1 7522/7530/1 7523/7531/1 7524/7532/1 +f 7525/7533/1 7526/7534/1 7527/7535/1 7528/7536/1 +f 7529/7537/1 7530/7538/1 7531/7539/1 7532/7540/1 +f 7533/7541/1 7534/7542/1 7535/7543/1 7536/7544/1 +f 7537/7545/1 7538/7546/1 7539/7547/1 7540/7548/1 +f 7541/7549/1 7542/7550/1 7543/7551/1 7544/7552/1 +f 7545/7553/1 7546/7554/1 7547/7555/1 7548/7556/1 +f 7549/7557/1 7550/7558/1 7551/7559/1 7552/7560/1 +f 7553/7561/1 7554/7562/1 7555/7563/1 7556/7564/1 +f 7557/7565/1 7558/7566/1 7559/7567/1 7560/7568/1 +f 7561/7569/1 7562/7570/1 7563/7571/1 7564/7572/1 +f 7565/7573/1 7566/7574/1 7567/7575/1 7568/7576/1 +f 7569/7577/1 7570/7578/1 7571/7579/1 7572/7580/1 +f 7573/7581/1 7574/7582/1 7575/7583/1 7576/7584/1 +f 7577/7585/1 7578/7586/1 7579/7587/1 7580/7588/1 +f 7581/7589/1 7582/7590/1 7583/7591/1 7584/7592/1 +f 7585/7593/1 7586/7594/1 7587/7595/1 7588/7596/1 +f 7589/7597/1 7590/7598/1 7591/7599/1 7592/7600/1 +f 7593/7601/1 7594/7602/1 7595/7603/1 7596/7604/1 +f 7597/7605/1 7598/7606/1 7599/7607/1 7600/7608/1 +f 7601/7609/1 7602/7610/1 7603/7611/1 7604/7612/1 +f 7605/7613/1 7606/7614/1 7607/7615/1 7608/7616/1 +f 7609/7617/1 7610/7618/1 7611/7619/1 7612/7620/1 +f 7613/7621/1 7614/7622/1 7615/7623/1 7616/7624/1 +f 7617/7625/1 7618/7626/1 7619/7627/1 7620/7628/1 +f 7621/7629/1 7622/7630/1 7623/7631/1 7624/7632/1 +f 7625/7633/1 7626/7634/1 7627/7635/1 7628/7636/1 +f 7629/7637/1 7630/7638/1 7631/7639/1 7632/7640/1 +f 7633/7641/1 7634/7642/1 7635/7643/1 7636/7644/1 +f 7637/7645/1 7638/7646/1 7639/7647/1 7640/7648/1 +f 7641/7649/1 7642/7650/1 7643/7651/1 7644/7652/1 +f 7645/7653/1 7646/7654/1 7647/7655/1 7648/7656/1 +f 7649/7657/1 7650/7658/1 7651/7659/1 7652/7660/1 +f 7653/7661/1 7654/7662/1 7655/7663/1 7656/7664/1 +f 7657/7665/1 7658/7666/1 7659/7667/1 7660/7668/1 +f 7661/7669/1 7662/7670/1 7663/7671/1 7664/7672/1 +f 7665/7673/1 7666/7674/1 7667/7675/1 7668/7676/1 +f 7669/7677/1 7670/7678/1 7671/7679/1 7672/7680/1 +f 7673/7681/1 7674/7682/1 7675/7683/1 7676/7684/1 +f 7677/7685/1 7678/7686/1 7679/7687/1 7680/7688/1 +f 7681/7689/1 7682/7690/1 7683/7691/1 7684/7692/1 +f 7685/7693/1 7686/7694/1 7687/7695/1 7688/7696/1 +f 7689/7697/1 7690/7698/1 7691/7699/1 7692/7700/1 +f 7693/7701/1 7694/7702/1 7695/7703/1 7696/7704/1 +f 7697/7705/1 7698/7706/1 7699/7707/1 7700/7708/1 +f 7701/7709/1 7702/7710/1 7703/7711/1 7704/7712/1 +f 7705/7713/1 7706/7714/1 7707/7715/1 7708/7716/1 +f 7709/7717/1 7710/7718/1 7711/7719/1 7712/7720/1 +f 7713/7721/1 7714/7722/1 7715/7723/1 7716/7724/1 +f 7717/7725/1 7718/7726/1 7719/7727/1 7720/7728/1 +f 7721/7729/1 7722/7730/1 7723/7731/1 7724/7732/1 +f 7725/7733/1 7726/7734/1 7727/7735/1 7728/7736/1 +f 7729/7737/1 7730/7738/1 7731/7739/1 7732/7740/1 +f 7733/7741/1 7734/7742/1 7735/7743/1 7736/7744/1 +f 7737/7745/1 7738/7746/1 7739/7747/1 7740/7748/1 +f 7741/7749/1 7742/7750/1 7743/7751/1 7744/7752/1 +f 7745/7753/1 7746/7754/1 7747/7755/1 7748/7756/1 +f 7749/7757/1 7750/7758/1 7751/7759/1 7752/7760/1 +f 7753/7761/1 7754/7762/1 7755/7763/1 7756/7764/1 +f 7757/7765/1 7758/7766/1 7759/7767/1 7760/7768/1 +f 7761/7769/1 7762/7770/1 7763/7771/1 7764/7772/1 +f 7765/7773/1 7766/7774/1 7767/7775/1 7768/7776/1 +f 7769/7777/1 7770/7778/1 7771/7779/1 7772/7780/1 +f 7773/7781/1 7774/7782/1 7775/7783/1 7776/7784/1 +f 7777/7785/1 7778/7786/1 7779/7787/1 7780/7788/1 +f 7781/7789/1 7782/7790/1 7783/7791/1 7784/7792/1 +f 7785/7793/1 7786/7794/1 7787/7795/1 7788/7796/1 +f 7789/7797/1 7790/7798/1 7791/7799/1 7792/7800/1 +f 7793/7801/1 7794/7802/1 7795/7803/1 7796/7804/1 +f 7797/7805/1 7798/7806/1 7799/7807/1 7800/7808/1 +f 7801/7809/1 7802/7810/1 7803/7811/1 7804/7812/1 +f 7805/7813/1 7806/7814/1 7807/7815/1 7808/7816/1 +f 7809/7817/1 7810/7818/1 7811/7819/1 7812/7820/1 +f 7813/7821/1 7814/7822/1 7815/7823/1 7816/7824/1 +f 7817/7825/1 7818/7826/1 7819/7827/1 7820/7828/1 +f 7821/7829/1 7822/7830/1 7823/7831/1 7824/7832/1 +f 7825/7833/1 7826/7834/1 7827/7835/1 7828/7836/1 +f 7829/7837/1 7830/7838/1 7831/7839/1 7832/7840/1 +f 7833/7841/1 7834/7842/1 7835/7843/1 7836/7844/1 +f 7837/7845/1 7838/7846/1 7839/7847/1 7840/7848/1 +f 7841/7849/1 7842/7850/1 7843/7851/1 7844/7852/1 +f 7845/7853/1 7846/7854/1 7847/7855/1 7848/7856/1 +f 7849/7857/1 7850/7858/1 7851/7859/1 7852/7860/1 +f 7853/7861/1 7854/7862/1 7855/7863/1 7856/7864/1 +f 7857/7865/1 7858/7866/1 7859/7867/1 7860/7868/1 +f 7861/7869/1 7862/7870/1 7863/7871/1 7864/7872/1 +f 7865/7873/1 7866/7874/1 7867/7875/1 7868/7876/1 +f 7869/7877/1 7870/7878/1 7871/7879/1 7872/7880/1 +f 7873/7881/1 7874/7882/1 7875/7883/1 7876/7884/1 +f 7877/7885/1 7878/7886/1 7879/7887/1 7880/7888/1 +f 7881/7889/1 7882/7890/1 7883/7891/1 7884/7892/1 +f 7885/7893/1 7886/7894/1 7887/7895/1 7888/7896/1 +f 7889/7897/1 7890/7898/1 7891/7899/1 7892/7900/1 +f 7893/7901/1 7894/7902/1 7895/7903/1 7896/7904/1 +f 7897/7905/1 7898/7906/1 7899/7907/1 7900/7908/1 +f 7901/7909/1 7902/7910/1 7903/7911/1 7904/7912/1 +f 7905/7913/1 7906/7914/1 7907/7915/1 7908/7916/1 +f 7909/7917/1 7910/7918/1 7911/7919/1 7912/7920/1 +f 7913/7921/1 7914/7922/1 7915/7923/1 7916/7924/1 +f 7917/7925/1 7918/7926/1 7919/7927/1 7920/7928/1 +f 7921/7929/1 7922/7930/1 7923/7931/1 7924/7932/1 +f 7925/7933/1 7926/7934/1 7927/7935/1 7928/7936/1 +f 7929/7937/1 7930/7938/1 7931/7939/1 7932/7940/1 +f 7933/7941/1 7934/7942/1 7935/7943/1 7936/7944/1 +f 7937/7945/1 7938/7946/1 7939/7947/1 7940/7948/1 +f 7941/7949/1 7942/7950/1 7943/7951/1 7944/7952/1 +f 7945/7953/1 7946/7954/1 7947/7955/1 7948/7956/1 +f 7949/7957/1 7950/7958/1 7951/7959/1 7952/7960/1 +f 7953/7961/1 7954/7962/1 7955/7963/1 7956/7964/1 +f 7957/7965/1 7958/7966/1 7959/7967/1 7960/7968/1 +f 7961/7969/1 7962/7970/1 7963/7971/1 7964/7972/1 +f 7965/7973/1 7966/7974/1 7967/7975/1 7968/7976/1 +f 7969/7977/1 7970/7978/1 7971/7979/1 7972/7980/1 +f 7973/7981/1 7974/7982/1 7975/7983/1 7976/7984/1 +f 7977/7985/1 7978/7986/1 7979/7987/1 7980/7988/1 +f 7981/7989/1 7982/7990/1 7983/7991/1 7984/7992/1 +f 7985/7993/1 7986/7994/1 7987/7995/1 7988/7996/1 +f 7989/7997/1 7990/7998/1 7991/7999/1 7992/8000/1 +f 7993/8001/1 7994/8002/1 7995/8003/1 7996/8004/1 +f 7997/8005/1 7998/8006/1 7999/8007/1 8000/8008/1 +f 8001/8009/1 8002/8010/1 8003/8011/1 8004/8012/1 +f 8005/8013/1 8006/8014/1 8007/8015/1 8008/8016/1 +f 8009/8017/1 8010/8018/1 8011/8019/1 8012/8020/1 +f 8013/8021/1 8014/8022/1 8015/8023/1 8016/8024/1 +f 8017/8025/1 8018/8026/1 8019/8027/1 8020/8028/1 +f 8021/8029/1 8022/8030/1 8023/8031/1 8024/8032/1 +f 8025/8033/1 8026/8034/1 8027/8035/1 8028/8036/1 +f 8029/8037/1 8030/8038/1 8031/8039/1 8032/8040/1 +f 8033/8041/1 8034/8042/1 8035/8043/1 8036/8044/1 +f 8037/8045/1 8038/8046/1 8039/8047/1 8040/8048/1 +f 8041/8049/1 8042/8050/1 8043/8051/1 8044/8052/1 +f 8045/8053/1 8046/8054/1 8047/8055/1 8048/8056/1 +f 8049/8057/1 8050/8058/1 8051/8059/1 8052/8060/1 +f 8053/8061/1 8054/8062/1 8055/8063/1 8056/8064/1 +f 8057/8065/1 8058/8066/1 8059/8067/1 8060/8068/1 +f 8061/8069/1 8062/8070/1 8063/8071/1 8064/8072/1 +f 8065/8073/1 8066/8074/1 8067/8075/1 8068/8076/1 +f 8069/8077/1 8070/8078/1 8071/8079/1 8072/8080/1 +f 8073/8081/1 8074/8082/1 8075/8083/1 8076/8084/1 +f 8077/8085/1 8078/8086/1 8079/8087/1 8080/8088/1 +f 8081/8089/1 8082/8090/1 8083/8091/1 8084/8092/1 +f 8085/8093/1 8086/8094/1 8087/8095/1 8088/8096/1 +f 8089/8097/1 8090/8098/1 8091/8099/1 8092/8100/1 +f 8093/8101/1 8094/8102/1 8095/8103/1 8096/8104/1 +f 8097/8105/1 8098/8106/1 8099/8107/1 8100/8108/1 +f 8101/8109/1 8102/8110/1 8103/8111/1 8104/8112/1 +f 8105/8113/1 8106/8114/1 8107/8115/1 8108/8116/1 +f 8109/8117/1 8110/8118/1 8111/8119/1 8112/8120/1 +f 8113/8121/1 8114/8122/1 8115/8123/1 8116/8124/1 +f 8117/8125/1 8118/8126/1 8119/8127/1 8120/8128/1 +f 8121/8129/1 8122/8130/1 8123/8131/1 8124/8132/1 +f 8125/8133/1 8126/8134/1 8127/8135/1 8128/8136/1 +f 8129/8137/1 8130/8138/1 8131/8139/1 8132/8140/1 +f 8133/8141/1 8134/8142/1 8135/8143/1 8136/8144/1 +f 8137/8145/1 8138/8146/1 8139/8147/1 8140/8148/1 +f 8141/8149/1 8142/8150/1 8143/8151/1 8144/8152/1 +f 8145/8153/1 8146/8154/1 8147/8155/1 8148/8156/1 +f 8149/8157/1 8150/8158/1 8151/8159/1 8152/8160/1 +f 8153/8161/1 8154/8162/1 8155/8163/1 8156/8164/1 +f 8157/8165/1 8158/8166/1 8159/8167/1 8160/8168/1 +f 8161/8169/1 8162/8170/1 8163/8171/1 8164/8172/1 +f 8165/8173/1 8166/8174/1 8167/8175/1 8168/8176/1 +f 8169/8177/1 8170/8178/1 8171/8179/1 8172/8180/1 +f 8173/8181/1 8174/8182/1 8175/8183/1 8176/8184/1 +f 8177/8185/1 8178/8186/1 8179/8187/1 8180/8188/1 +f 8181/8189/1 8182/8190/1 8183/8191/1 8184/8192/1 +f 8185/8193/1 8186/8194/1 8187/8195/1 8188/8196/1 +f 8189/8197/1 8190/8198/1 8191/8199/1 8192/8200/1 +f 8193/8201/1 8194/8202/1 8195/8203/1 8196/8204/1 +f 8197/8205/1 8198/8206/1 8199/8207/1 8200/8208/1 +f 8201/8209/1 8202/8210/1 8203/8211/1 8204/8212/1 +f 8205/8213/1 8206/8214/1 8207/8215/1 8208/8216/1 +f 8209/8217/1 8210/8218/1 8211/8219/1 8212/8220/1 +f 8213/8221/1 8214/8222/1 8215/8223/1 8216/8224/1 +f 8217/8225/1 8218/8226/1 8219/8227/1 8220/8228/1 +f 8221/8229/1 8222/8230/1 8223/8231/1 8224/8232/1 +f 8225/8233/1 8226/8234/1 8227/8235/1 8228/8236/1 +f 8229/8237/1 8230/8238/1 8231/8239/1 8232/8240/1 +f 8233/8241/1 8234/8242/1 8235/8243/1 8236/8244/1 +f 8237/8245/1 8238/8246/1 8239/8247/1 8240/8248/1 +f 8241/8249/1 8242/8250/1 8243/8251/1 8244/8252/1 +f 8245/8253/1 8246/8254/1 8247/8255/1 8248/8256/1 +f 8249/8257/1 8250/8258/1 8251/8259/1 8252/8260/1 +f 8253/8261/1 8254/8262/1 8255/8263/1 8256/8264/1 +f 8257/8265/1 8258/8266/1 8259/8267/1 8260/8268/1 +f 8261/8269/1 8262/8270/1 8263/8271/1 8264/8272/1 +f 8265/8273/1 8266/8274/1 8267/8275/1 8268/8276/1 +f 8269/8277/1 8270/8278/1 8271/8279/1 8272/8280/1 +f 8273/8281/1 8274/8282/1 8275/8283/1 8276/8284/1 +f 8277/8285/1 8278/8286/1 8279/8287/1 8280/8288/1 +f 8281/8289/1 8282/8290/1 8283/8291/1 8284/8292/1 +f 8285/8293/1 8286/8294/1 8287/8295/1 8288/8296/1 +f 8289/8297/1 8290/8298/1 8291/8299/1 8292/8300/1 +f 8293/8301/1 8294/8302/1 8295/8303/1 8296/8304/1 +f 8297/8305/1 8298/8306/1 8299/8307/1 8300/8308/1 +f 8301/8309/1 8302/8310/1 8303/8311/1 8304/8312/1 +f 8305/8313/1 8306/8314/1 8307/8315/1 8308/8316/1 +f 8309/8317/1 8310/8318/1 8311/8319/1 8312/8320/1 +f 8313/8321/1 8314/8322/1 8315/8323/1 8316/8324/1 +f 8317/8325/1 8318/8326/1 8319/8327/1 8320/8328/1 +f 8321/8329/1 8322/8330/1 8323/8331/1 8324/8332/1 +f 8325/8333/1 8326/8334/1 8327/8335/1 8328/8336/1 +f 8329/8337/1 8330/8338/1 8331/8339/1 8332/8340/1 +f 8333/8341/1 8334/8342/1 8335/8343/1 8336/8344/1 +f 8337/8345/1 8338/8346/1 8339/8347/1 8340/8348/1 +f 8341/8349/1 8342/8350/1 8343/8351/1 8344/8352/1 +f 8345/8353/1 8346/8354/1 8347/8355/1 8348/8356/1 +f 8349/8357/1 8350/8358/1 8351/8359/1 8352/8360/1 +f 8353/8361/1 8354/8362/1 8355/8363/1 8356/8364/1 +f 8357/8365/1 8358/8366/1 8359/8367/1 8360/8368/1 +f 8361/8369/1 8362/8370/1 8363/8371/1 8364/8372/1 +f 8365/8373/1 8366/8374/1 8367/8375/1 8368/8376/1 +f 8369/8377/1 8370/8378/1 8371/8379/1 8372/8380/1 +f 8373/8381/1 8374/8382/1 8375/8383/1 8376/8384/1 +f 8377/8385/1 8378/8386/1 8379/8387/1 8380/8388/1 +f 8381/8389/1 8382/8390/1 8383/8391/1 8384/8392/1 +f 8385/8393/1 8386/8394/1 8387/8395/1 8388/8396/1 +f 8389/8397/1 8390/8398/1 8391/8399/1 8392/8400/1 +f 8393/8401/1 8394/8402/1 8395/8403/1 8396/8404/1 +f 8397/8405/1 8398/8406/1 8399/8407/1 8400/8408/1 +f 8401/8409/1 8402/8410/1 8403/8411/1 8404/8412/1 +f 8405/8413/1 8406/8414/1 8407/8415/1 8408/8416/1 +f 8409/8417/1 8410/8418/1 8411/8419/1 8412/8420/1 +f 8413/8421/1 8414/8422/1 8415/8423/1 8416/8424/1 +f 8417/8425/1 8418/8426/1 8419/8427/1 8420/8428/1 +f 8421/8429/1 8422/8430/1 8423/8431/1 8424/8432/1 +f 8425/8433/1 8426/8434/1 8427/8435/1 8428/8436/1 +f 8429/8437/1 8430/8438/1 8431/8439/1 8432/8440/1 +f 8433/8441/1 8434/8442/1 8435/8443/1 8436/8444/1 +f 8437/8445/1 8438/8446/1 8439/8447/1 8440/8448/1 +f 8441/8449/1 8442/8450/1 8443/8451/1 8444/8452/1 +f 8445/8453/1 8446/8454/1 8447/8455/1 8448/8456/1 +f 8449/8457/1 8450/8458/1 8451/8459/1 8452/8460/1 +f 8453/8461/1 8454/8462/1 8455/8463/1 8456/8464/1 +f 8457/8465/1 8458/8466/1 8459/8467/1 8460/8468/1 +f 8461/8469/1 8462/8470/1 8463/8471/1 8464/8472/1 +f 8465/8473/1 8466/8474/1 8467/8475/1 8468/8476/1 +f 8469/8477/1 8470/8478/1 8471/8479/1 8472/8480/1 +f 8473/8481/1 8474/8482/1 8475/8483/1 8476/8484/1 +f 8477/8485/1 8478/8486/1 8479/8487/1 8480/8488/1 +f 8481/8489/1 8482/8490/1 8483/8491/1 8484/8492/1 +f 8485/8493/1 8486/8494/1 8487/8495/1 8488/8496/1 +f 8489/8497/1 8490/8498/1 8491/8499/1 8492/8500/1 +f 8493/8501/1 8494/8502/1 8495/8503/1 8496/8504/1 +f 8497/8505/1 8498/8506/1 8499/8507/1 8500/8508/1 +f 8501/8509/1 8502/8510/1 8503/8511/1 8504/8512/1 +f 8505/8513/1 8506/8514/1 8507/8515/1 8508/8516/1 +f 8509/8517/1 8510/8518/1 8511/8519/1 8512/8520/1 +f 8513/8521/1 8514/8522/1 8515/8523/1 8516/8524/1 +f 8517/8525/1 8518/8526/1 8519/8527/1 8520/8528/1 +f 8521/8529/1 8522/8530/1 8523/8531/1 8524/8532/1 +f 8525/8533/1 8526/8534/1 8527/8535/1 8528/8536/1 +f 8529/8537/1 8530/8538/1 8531/8539/1 8532/8540/1 +f 8533/8541/1 8534/8542/1 8535/8543/1 8536/8544/1 +f 8537/8545/1 8538/8546/1 8539/8547/1 8540/8548/1 +f 8541/8549/1 8542/8550/1 8543/8551/1 8544/8552/1 +f 8545/8553/1 8546/8554/1 8547/8555/1 8548/8556/1 +f 8549/8557/1 8550/8558/1 8551/8559/1 8552/8560/1 +f 8553/8561/1 8554/8562/1 8555/8563/1 8556/8564/1 +f 8557/8565/1 8558/8566/1 8559/8567/1 8560/8568/1 +f 8561/8569/1 8562/8570/1 8563/8571/1 8564/8572/1 +f 8565/8573/1 8566/8574/1 8567/8575/1 8568/8576/1 +f 8569/8577/1 8570/8578/1 8571/8579/1 8572/8580/1 +f 8573/8581/1 8574/8582/1 8575/8583/1 8576/8584/1 +f 8577/8585/1 8578/8586/1 8579/8587/1 8580/8588/1 +f 8581/8589/1 8582/8590/1 8583/8591/1 8584/8592/1 +f 8585/8593/1 8586/8594/1 8587/8595/1 8588/8596/1 +f 8589/8597/1 8590/8598/1 8591/8599/1 8592/8600/1 +f 8593/8601/1 8594/8602/1 8595/8603/1 8596/8604/1 +f 8597/8605/1 8598/8606/1 8599/8607/1 8600/8608/1 +f 8601/8609/1 8602/8610/1 8603/8611/1 8604/8612/1 +f 8605/8613/1 8606/8614/1 8607/8615/1 8608/8616/1 +f 8609/8617/1 8610/8618/1 8611/8619/1 8612/8620/1 +f 8613/8621/1 8614/8622/1 8615/8623/1 8616/8624/1 +f 8617/8625/1 8618/8626/1 8619/8627/1 8620/8628/1 +f 8621/8629/1 8622/8630/1 8623/8631/1 8624/8632/1 +f 8625/8633/1 8626/8634/1 8627/8635/1 8628/8636/1 +f 8629/8637/1 8630/8638/1 8631/8639/1 8632/8640/1 +f 8633/8641/1 8634/8642/1 8635/8643/1 8636/8644/1 +f 8637/8645/1 8638/8646/1 8639/8647/1 8640/8648/1 +f 8641/8649/1 8642/8650/1 8643/8651/1 8644/8652/1 +f 8645/8653/1 8646/8654/1 8647/8655/1 8648/8656/1 +f 8649/8657/1 8650/8658/1 8651/8659/1 8652/8660/1 +f 8653/8661/1 8654/8662/1 8655/8663/1 8656/8664/1 +f 8657/8665/1 8658/8666/1 8659/8667/1 8660/8668/1 +f 8661/8669/1 8662/8670/1 8663/8671/1 8664/8672/1 +f 8665/8673/1 8666/8674/1 8667/8675/1 8668/8676/1 +f 8669/8677/1 8670/8678/1 8671/8679/1 8672/8680/1 +f 8673/8681/1 8674/8682/1 8675/8683/1 8676/8684/1 +f 8677/8685/1 8678/8686/1 8679/8687/1 8680/8688/1 +f 8681/8689/1 8682/8690/1 8683/8691/1 8684/8692/1 +f 8685/8693/1 8686/8694/1 8687/8695/1 8688/8696/1 +f 8689/8697/1 8690/8698/1 8691/8699/1 8692/8700/1 +f 8693/8701/1 8694/8702/1 8695/8703/1 8696/8704/1 +f 8697/8705/1 8698/8706/1 8699/8707/1 8700/8708/1 +f 8701/8709/1 8702/8710/1 8703/8711/1 8704/8712/1 +f 8705/8713/1 8706/8714/1 8707/8715/1 8708/8716/1 +f 8709/8717/1 8710/8718/1 8711/8719/1 8712/8720/1 +f 8713/8721/1 8714/8722/1 8715/8723/1 8716/8724/1 +f 8717/8725/1 8718/8726/1 8719/8727/1 8720/8728/1 +f 8721/8729/1 8722/8730/1 8723/8731/1 8724/8732/1 +f 8725/8733/1 8726/8734/1 8727/8735/1 8728/8736/1 +f 8729/8737/1 8730/8738/1 8731/8739/1 8732/8740/1 +f 8733/8741/1 8734/8742/1 8735/8743/1 8736/8744/1 +f 8737/8745/1 8738/8746/1 8739/8747/1 8740/8748/1 +f 8741/8749/1 8742/8750/1 8743/8751/1 8744/8752/1 +f 8745/8753/1 8746/8754/1 8747/8755/1 8748/8756/1 +f 8749/8757/1 8750/8758/1 8751/8759/1 8752/8760/1 +f 8753/8761/1 8754/8762/1 8755/8763/1 8756/8764/1 +f 8757/8765/1 8758/8766/1 8759/8767/1 8760/8768/1 +f 8761/8769/1 8762/8770/1 8763/8771/1 8764/8772/1 +f 8765/8773/1 8766/8774/1 8767/8775/1 8768/8776/1 +f 8769/8777/1 8770/8778/1 8771/8779/1 8772/8780/1 +f 8773/8781/1 8774/8782/1 8775/8783/1 8776/8784/1 +f 8777/8785/1 8778/8786/1 8779/8787/1 8780/8788/1 +f 8781/8789/1 8782/8790/1 8783/8791/1 8784/8792/1 +f 8785/8793/1 8786/8794/1 8787/8795/1 8788/8796/1 +f 8789/8797/1 8790/8798/1 8791/8799/1 8792/8800/1 +f 8793/8801/1 8794/8802/1 8795/8803/1 8796/8804/1 +f 8797/8805/1 8798/8806/1 8799/8807/1 8800/8808/1 +f 8801/8809/1 8802/8810/1 8803/8811/1 8804/8812/1 +f 8805/8813/1 8806/8814/1 8807/8815/1 8808/8816/1 +f 8809/8817/1 8810/8818/1 8811/8819/1 8812/8820/1 +f 8813/8821/1 8814/8822/1 8815/8823/1 8816/8824/1 +f 8817/8825/1 8818/8826/1 8819/8827/1 8820/8828/1 +f 8821/8829/1 8822/8830/1 8823/8831/1 8824/8832/1 +f 8825/8833/1 8826/8834/1 8827/8835/1 8828/8836/1 +f 8829/8837/1 8830/8838/1 8831/8839/1 8832/8840/1 +f 8833/8841/1 8834/8842/1 8835/8843/1 8836/8844/1 +f 8837/8845/1 8838/8846/1 8839/8847/1 8840/8848/1 +f 8841/8849/1 8842/8850/1 8843/8851/1 8844/8852/1 +f 8845/8853/1 8846/8854/1 8847/8855/1 8848/8856/1 +f 8849/8857/1 8850/8858/1 8851/8859/1 8852/8860/1 +f 8853/8861/1 8854/8862/1 8855/8863/1 8856/8864/1 +f 8857/8865/1 8858/8866/1 8859/8867/1 8860/8868/1 +f 8861/8869/1 8862/8870/1 8863/8871/1 8864/8872/1 +f 8865/8873/1 8866/8874/1 8867/8875/1 8868/8876/1 +f 8869/8877/1 8870/8878/1 8871/8879/1 8872/8880/1 +f 8873/8881/1 8874/8882/1 8875/8883/1 8876/8884/1 +f 8877/8885/1 8878/8886/1 8879/8887/1 8880/8888/1 +f 8881/8889/1 8882/8890/1 8883/8891/1 8884/8892/1 +f 8885/8893/1 8886/8894/1 8887/8895/1 8888/8896/1 +f 8889/8897/1 8890/8898/1 8891/8899/1 8892/8900/1 +f 8893/8901/1 8894/8902/1 8895/8903/1 8896/8904/1 +f 8897/8905/1 8898/8906/1 8899/8907/1 8900/8908/1 +f 8901/8909/1 8902/8910/1 8903/8911/1 8904/8912/1 +f 8905/8913/1 8906/8914/1 8907/8915/1 8908/8916/1 +f 8909/8917/1 8910/8918/1 8911/8919/1 8912/8920/1 +f 8913/8921/1 8914/8922/1 8915/8923/1 8916/8924/1 +f 8917/8925/1 8918/8926/1 8919/8927/1 8920/8928/1 +f 8921/8929/1 8922/8930/1 8923/8931/1 8924/8932/1 +f 8925/8933/1 8926/8934/1 8927/8935/1 8928/8936/1 +f 8929/8937/1 8930/8938/1 8931/8939/1 8932/8940/1 +f 8933/8941/1 8934/8942/1 8935/8943/1 8936/8944/1 +f 8937/8945/1 8938/8946/1 8939/8947/1 8940/8948/1 +f 8941/8949/1 8942/8950/1 8943/8951/1 8944/8952/1 +f 8945/8953/1 8946/8954/1 8947/8955/1 8948/8956/1 +f 8949/8957/1 8950/8958/1 8951/8959/1 8952/8960/1 +f 8953/8961/1 8954/8962/1 8955/8963/1 8956/8964/1 +f 8957/8965/1 8958/8966/1 8959/8967/1 8960/8968/1 +f 8961/8969/1 8962/8970/1 8963/8971/1 8964/8972/1 +f 8965/8973/1 8966/8974/1 8967/8975/1 8968/8976/1 +f 8969/8977/1 8970/8978/1 8971/8979/1 8972/8980/1 +f 8973/8981/1 8974/8982/1 8975/8983/1 8976/8984/1 +f 8977/8985/1 8978/8986/1 8979/8987/1 8980/8988/1 +f 8981/8989/1 8982/8990/1 8983/8991/1 8984/8992/1 +f 8985/8993/1 8986/8994/1 8987/8995/1 8988/8996/1 +f 8989/8997/1 8990/8998/1 8991/8999/1 8992/9000/1 +f 8993/9001/1 8994/9002/1 8995/9003/1 8996/9004/1 +f 8997/9005/1 8998/9006/1 8999/9007/1 9000/9008/1 +f 9001/9009/1 9002/9010/1 9003/9011/1 9004/9012/1 +f 9005/9013/1 9006/9014/1 9007/9015/1 9008/9016/1 +f 9009/9017/1 9010/9018/1 9011/9019/1 9012/9020/1 +f 9013/9021/1 9014/9022/1 9015/9023/1 9016/9024/1 +f 9017/9025/1 9018/9026/1 9019/9027/1 9020/9028/1 +f 9021/9029/1 9022/9030/1 9023/9031/1 9024/9032/1 +f 9025/9033/1 9026/9034/1 9027/9035/1 9028/9036/1 +f 9029/9037/1 9030/9038/1 9031/9039/1 9032/9040/1 +f 9033/9041/1 9034/9042/1 9035/9043/1 9036/9044/1 +f 9037/9045/1 9038/9046/1 9039/9047/1 9040/9048/1 +f 9041/9049/1 9042/9050/1 9043/9051/1 9044/9052/1 +f 9045/9053/1 9046/9054/1 9047/9055/1 9048/9056/1 +f 9049/9057/1 9050/9058/1 9051/9059/1 9052/9060/1 +f 9053/9061/1 9054/9062/1 9055/9063/1 9056/9064/1 +f 9057/9065/1 9058/9066/1 9059/9067/1 9060/9068/1 +f 9061/9069/1 9062/9070/1 9063/9071/1 9064/9072/1 +f 9065/9073/1 9066/9074/1 9067/9075/1 9068/9076/1 +f 9069/9077/1 9070/9078/1 9071/9079/1 9072/9080/1 +f 9073/9081/1 9074/9082/1 9075/9083/1 9076/9084/1 +f 9077/9085/1 9078/9086/1 9079/9087/1 9080/9088/1 +f 9081/9089/1 9082/9090/1 9083/9091/1 9084/9092/1 +f 9085/9093/1 9086/9094/1 9087/9095/1 9088/9096/1 +f 9089/9097/1 9090/9098/1 9091/9099/1 9092/9100/1 +f 9093/9101/1 9094/9102/1 9095/9103/1 9096/9104/1 +f 9097/9105/1 9098/9106/1 9099/9107/1 9100/9108/1 +f 9101/9109/1 9102/9110/1 9103/9111/1 9104/9112/1 +f 9105/9113/1 9106/9114/1 9107/9115/1 9108/9116/1 +f 9109/9117/1 9110/9118/1 9111/9119/1 9112/9120/1 +f 9113/9121/1 9114/9122/1 9115/9123/1 9116/9124/1 +f 9117/9125/1 9118/9126/1 9119/9127/1 9120/9128/1 +f 9121/9129/1 9122/9130/1 9123/9131/1 9124/9132/1 +f 9125/9133/1 9126/9134/1 9127/9135/1 9128/9136/1 +f 9129/9137/1 9130/9138/1 9131/9139/1 9132/9140/1 +f 9133/9141/1 9134/9142/1 9135/9143/1 9136/9144/1 +f 9137/9145/1 9138/9146/1 9139/9147/1 9140/9148/1 +f 9141/9149/1 9142/9150/1 9143/9151/1 9144/9152/1 +f 9145/9153/1 9146/9154/1 9147/9155/1 9148/9156/1 +f 9149/9157/1 9150/9158/1 9151/9159/1 9152/9160/1 +f 9153/9161/1 9154/9162/1 9155/9163/1 9156/9164/1 +f 9157/9165/1 9158/9166/1 9159/9167/1 9160/9168/1 +f 9161/9169/1 9162/9170/1 9163/9171/1 9164/9172/1 +f 9165/9173/1 9166/9174/1 9167/9175/1 9168/9176/1 +f 9169/9177/1 9170/9178/1 9171/9179/1 9172/9180/1 +f 9173/9181/1 9174/9182/1 9175/9183/1 9176/9184/1 +f 9177/9185/1 9178/9186/1 9179/9187/1 9180/9188/1 +f 9181/9189/1 9182/9190/1 9183/9191/1 9184/9192/1 +f 9185/9193/1 9186/9194/1 9187/9195/1 9188/9196/1 +f 9189/9197/1 9190/9198/1 9191/9199/1 9192/9200/1 +f 9193/9201/1 9194/9202/1 9195/9203/1 9196/9204/1 +f 9197/9205/1 9198/9206/1 9199/9207/1 9200/9208/1 +f 9201/9209/1 9202/9210/1 9203/9211/1 9204/9212/1 +f 9205/9213/1 9206/9214/1 9207/9215/1 9208/9216/1 +f 9209/9217/1 9210/9218/1 9211/9219/1 9212/9220/1 +f 9213/9221/1 9214/9222/1 9215/9223/1 9216/9224/1 +f 9217/9225/1 9218/9226/1 9219/9227/1 9220/9228/1 +f 9221/9229/1 9222/9230/1 9223/9231/1 9224/9232/1 +f 9225/9233/1 9226/9234/1 9227/9235/1 9228/9236/1 +f 9229/9237/1 9230/9238/1 9231/9239/1 9232/9240/1 +f 9233/9241/1 9234/9242/1 9235/9243/1 9236/9244/1 +f 9237/9245/1 9238/9246/1 9239/9247/1 9240/9248/1 +f 9241/9249/1 9242/9250/1 9243/9251/1 9244/9252/1 +f 9245/9253/1 9246/9254/1 9247/9255/1 9248/9256/1 +f 9249/9257/1 9250/9258/1 9251/9259/1 9252/9260/1 +f 9253/9261/1 9254/9262/1 9255/9263/1 9256/9264/1 +f 9257/9265/1 9258/9266/1 9259/9267/1 9260/9268/1 +f 9261/9269/1 9262/9270/1 9263/9271/1 9264/9272/1 +f 9265/9273/1 9266/9274/1 9267/9275/1 9268/9276/1 +f 9269/9277/1 9270/9278/1 9271/9279/1 9272/9280/1 +f 9273/9281/1 9274/9282/1 9275/9283/1 9276/9284/1 +f 9277/9285/1 9278/9286/1 9279/9287/1 9280/9288/1 +f 9281/9289/1 9282/9290/1 9283/9291/1 9284/9292/1 +f 9285/9293/1 9286/9294/1 9287/9295/1 9288/9296/1 +f 9289/9297/1 9290/9298/1 9291/9299/1 9292/9300/1 +f 9293/9301/1 9294/9302/1 9295/9303/1 9296/9304/1 +f 9297/9305/1 9298/9306/1 9299/9307/1 9300/9308/1 +f 9301/9309/1 9302/9310/1 9303/9311/1 9304/9312/1 +f 9305/9313/1 9306/9314/1 9307/9315/1 9308/9316/1 +f 9309/9317/1 9310/9318/1 9311/9319/1 9312/9320/1 +f 9313/9321/1 9314/9322/1 9315/9323/1 9316/9324/1 +f 9317/9325/1 9318/9326/1 9319/9327/1 9320/9328/1 +f 9321/9329/1 9322/9330/1 9323/9331/1 9324/9332/1 +f 9325/9333/1 9326/9334/1 9327/9335/1 9328/9336/1 +f 9329/9337/1 9330/9338/1 9331/9339/1 9332/9340/1 +f 9333/9341/1 9334/9342/1 9335/9343/1 9336/9344/1 +f 9337/9345/1 9338/9346/1 9339/9347/1 9340/9348/1 +f 9341/9349/1 9342/9350/1 9343/9351/1 9344/9352/1 +f 9345/9353/1 9346/9354/1 9347/9355/1 9348/9356/1 +f 9349/9357/1 9350/9358/1 9351/9359/1 9352/9360/1 +f 9353/9361/1 9354/9362/1 9355/9363/1 9356/9364/1 +f 9357/9365/1 9358/9366/1 9359/9367/1 9360/9368/1 +f 9361/9369/1 9362/9370/1 9363/9371/1 9364/9372/1 +f 9365/9373/1 9366/9374/1 9367/9375/1 9368/9376/1 +f 9369/9377/1 9370/9378/1 9371/9379/1 9372/9380/1 +f 9373/9381/1 9374/9382/1 9375/9383/1 9376/9384/1 +f 9377/9385/1 9378/9386/1 9379/9387/1 9380/9388/1 +f 9381/9389/1 9382/9390/1 9383/9391/1 9384/9392/1 +f 9385/9393/1 9386/9394/1 9387/9395/1 9388/9396/1 +f 9389/9397/1 9390/9398/1 9391/9399/1 9392/9400/1 +f 9393/9401/1 9394/9402/1 9395/9403/1 9396/9404/1 +f 9397/9405/1 9398/9406/1 9399/9407/1 9400/9408/1 +f 9401/9409/1 9402/9410/1 9403/9411/1 9404/9412/1 +f 9405/9413/1 9406/9414/1 9407/9415/1 9408/9416/1 +f 9409/9417/1 9410/9418/1 9411/9419/1 9412/9420/1 +f 9413/9421/1 9414/9422/1 9415/9423/1 9416/9424/1 +f 9417/9425/1 9418/9426/1 9419/9427/1 9420/9428/1 +f 9421/9429/1 9422/9430/1 9423/9431/1 9424/9432/1 +f 9425/9433/1 9426/9434/1 9427/9435/1 9428/9436/1 +f 9429/9437/1 9430/9438/1 9431/9439/1 9432/9440/1 +f 9433/9441/1 9434/9442/1 9435/9443/1 9436/9444/1 +f 9437/9445/1 9438/9446/1 9439/9447/1 9440/9448/1 +f 9441/9449/1 9442/9450/1 9443/9451/1 9444/9452/1 +f 9445/9453/1 9446/9454/1 9447/9455/1 9448/9456/1 +f 9449/9457/1 9450/9458/1 9451/9459/1 9452/9460/1 +f 9453/9461/1 9454/9462/1 9455/9463/1 9456/9464/1 +f 9457/9465/1 9458/9466/1 9459/9467/1 9460/9468/1 +f 9461/9469/1 9462/9470/1 9463/9471/1 9464/9472/1 +f 9465/9473/1 9466/9474/1 9467/9475/1 9468/9476/1 +f 9469/9477/1 9470/9478/1 9471/9479/1 9472/9480/1 +f 9473/9481/1 9474/9482/1 9475/9483/1 9476/9484/1 +f 9477/9485/1 9478/9486/1 9479/9487/1 9480/9488/1 +f 9481/9489/1 9482/9490/1 9483/9491/1 9484/9492/1 +f 9485/9493/1 9486/9494/1 9487/9495/1 9488/9496/1 +f 9489/9497/1 9490/9498/1 9491/9499/1 9492/9500/1 +f 9493/9501/1 9494/9502/1 9495/9503/1 9496/9504/1 +f 9497/9505/1 9498/9506/1 9499/9507/1 9500/9508/1 +f 9501/9509/1 9502/9510/1 9503/9511/1 9504/9512/1 +f 9505/9513/1 9506/9514/1 9507/9515/1 9508/9516/1 +f 9509/9517/1 9510/9518/1 9511/9519/1 9512/9520/1 +f 9513/9521/1 9514/9522/1 9515/9523/1 9516/9524/1 +f 9517/9525/1 9518/9526/1 9519/9527/1 9520/9528/1 +f 9521/9529/1 9522/9530/1 9523/9531/1 9524/9532/1 +f 9525/9533/1 9526/9534/1 9527/9535/1 9528/9536/1 +f 9529/9537/1 9530/9538/1 9531/9539/1 9532/9540/1 +f 9533/9541/1 9534/9542/1 9535/9543/1 9536/9544/1 +f 9537/9545/1 9538/9546/1 9539/9547/1 9540/9548/1 +f 9541/9549/1 9542/9550/1 9543/9551/1 9544/9552/1 +f 9545/9553/1 9546/9554/1 9547/9555/1 9548/9556/1 +f 9549/9557/1 9550/9558/1 9551/9559/1 9552/9560/1 +f 9553/9561/1 9554/9562/1 9555/9563/1 9556/9564/1 +f 9557/9565/1 9558/9566/1 9559/9567/1 9560/9568/1 +f 9561/9569/1 9562/9570/1 9563/9571/1 9564/9572/1 +f 9565/9573/1 9566/9574/1 9567/9575/1 9568/9576/1 +f 9569/9577/1 9570/9578/1 9571/9579/1 9572/9580/1 +f 9573/9581/1 9574/9582/1 9575/9583/1 9576/9584/1 +f 9577/9585/1 9578/9586/1 9579/9587/1 9580/9588/1 +f 9581/9589/1 9582/9590/1 9583/9591/1 9584/9592/1 +f 9585/9593/1 9586/9594/1 9587/9595/1 9588/9596/1 +f 9589/9597/1 9590/9598/1 9591/9599/1 9592/9600/1 +f 9593/9601/1 9594/9602/1 9595/9603/1 9596/9604/1 +f 9597/9605/1 9598/9606/1 9599/9607/1 9600/9608/1 +f 9601/9609/1 9602/9610/1 9603/9611/1 9604/9612/1 +f 9605/9613/1 9606/9614/1 9607/9615/1 9608/9616/1 +f 9609/9617/1 9610/9618/1 9611/9619/1 9612/9620/1 +f 9613/9621/1 9614/9622/1 9615/9623/1 9616/9624/1 +f 9617/9625/1 9618/9626/1 9619/9627/1 9620/9628/1 +f 9621/9629/1 9622/9630/1 9623/9631/1 9624/9632/1 +f 9625/9633/1 9626/9634/1 9627/9635/1 9628/9636/1 +f 9629/9637/1 9630/9638/1 9631/9639/1 9632/9640/1 +f 9633/9641/1 9634/9642/1 9635/9643/1 9636/9644/1 +f 9637/9645/1 9638/9646/1 9639/9647/1 9640/9648/1 +f 9641/9649/1 9642/9650/1 9643/9651/1 9644/9652/1 +f 9645/9653/1 9646/9654/1 9647/9655/1 9648/9656/1 +f 9649/9657/1 9650/9658/1 9651/9659/1 9652/9660/1 +f 9653/9661/1 9654/9662/1 9655/9663/1 9656/9664/1 +f 9657/9665/1 9658/9666/1 9659/9667/1 9660/9668/1 +f 9661/9669/1 9662/9670/1 9663/9671/1 9664/9672/1 +f 9665/9673/1 9666/9674/1 9667/9675/1 9668/9676/1 +f 9669/9677/1 9670/9678/1 9671/9679/1 9672/9680/1 +f 9673/9681/1 9674/9682/1 9675/9683/1 9676/9684/1 +f 9677/9685/1 9678/9686/1 9679/9687/1 9680/9688/1 +f 9681/9689/1 9682/9690/1 9683/9691/1 9684/9692/1 +f 9685/9693/1 9686/9694/1 9687/9695/1 9688/9696/1 +f 9689/9697/1 9690/9698/1 9691/9699/1 9692/9700/1 +f 9693/9701/1 9694/9702/1 9695/9703/1 9696/9704/1 +f 9697/9705/1 9698/9706/1 9699/9707/1 9700/9708/1 +f 9701/9709/1 9702/9710/1 9703/9711/1 9704/9712/1 +f 9705/9713/1 9706/9714/1 9707/9715/1 9708/9716/1 +f 9709/9717/1 9710/9718/1 9711/9719/1 9712/9720/1 +f 9713/9721/1 9714/9722/1 9715/9723/1 9716/9724/1 +f 9717/9725/1 9718/9726/1 9719/9727/1 9720/9728/1 +f 9721/9729/1 9722/9730/1 9723/9731/1 9724/9732/1 +f 9725/9733/1 9726/9734/1 9727/9735/1 9728/9736/1 +f 9729/9737/1 9730/9738/1 9731/9739/1 9732/9740/1 +f 9733/9741/1 9734/9742/1 9735/9743/1 9736/9744/1 +f 9737/9745/1 9738/9746/1 9739/9747/1 9740/9748/1 +f 9741/9749/1 9742/9750/1 9743/9751/1 9744/9752/1 +f 9745/9753/1 9746/9754/1 9747/9755/1 9748/9756/1 +f 9749/9757/1 9750/9758/1 9751/9759/1 9752/9760/1 +f 9753/9761/1 9754/9762/1 9755/9763/1 9756/9764/1 +f 9757/9765/1 9758/9766/1 9759/9767/1 9760/9768/1 +f 9761/9769/1 9762/9770/1 9763/9771/1 9764/9772/1 +f 9765/9773/1 9766/9774/1 9767/9775/1 9768/9776/1 +f 9769/9777/1 9770/9778/1 9771/9779/1 9772/9780/1 +f 9773/9781/1 9774/9782/1 9775/9783/1 9776/9784/1 +f 9777/9785/1 9778/9786/1 9779/9787/1 9780/9788/1 +f 9781/9789/1 9782/9790/1 9783/9791/1 9784/9792/1 +f 9785/9793/1 9786/9794/1 9787/9795/1 9788/9796/1 +f 9789/9797/1 9790/9798/1 9791/9799/1 9792/9800/1 +f 9793/9801/1 9794/9802/1 9795/9803/1 9796/9804/1 +f 9797/9805/1 9798/9806/1 9799/9807/1 9800/9808/1 +f 9801/9809/1 9802/9810/1 9803/9811/1 9804/9812/1 +f 9805/9813/1 9806/9814/1 9807/9815/1 9808/9816/1 +f 9809/9817/1 9810/9818/1 9811/9819/1 9812/9820/1 +f 9813/9821/1 9814/9822/1 9815/9823/1 9816/9824/1 +f 9817/9825/1 9818/9826/1 9819/9827/1 9820/9828/1 +f 9821/9829/1 9822/9830/1 9823/9831/1 9824/9832/1 +f 9825/9833/1 9826/9834/1 9827/9835/1 9828/9836/1 +f 9829/9837/1 9830/9838/1 9831/9839/1 9832/9840/1 +f 9833/9841/1 9834/9842/1 9835/9843/1 9836/9844/1 +f 9837/9845/1 9838/9846/1 9839/9847/1 9840/9848/1 +f 9841/9849/1 9842/9850/1 9843/9851/1 9844/9852/1 +f 9845/9853/1 9846/9854/1 9847/9855/1 9848/9856/1 +f 9849/9857/1 9850/9858/1 9851/9859/1 9852/9860/1 +f 9853/9861/1 9854/9862/1 9855/9863/1 9856/9864/1 +f 9857/9865/1 9858/9866/1 9859/9867/1 9860/9868/1 +f 9861/9869/1 9862/9870/1 9863/9871/1 9864/9872/1 +f 9865/9873/1 9866/9874/1 9867/9875/1 9868/9876/1 +f 9869/9877/1 9870/9878/1 9871/9879/1 9872/9880/1 +f 9873/9881/1 9874/9882/1 9875/9883/1 9876/9884/1 +f 9877/9885/1 9878/9886/1 9879/9887/1 9880/9888/1 +f 9881/9889/1 9882/9890/1 9883/9891/1 9884/9892/1 +f 9885/9893/1 9886/9894/1 9887/9895/1 9888/9896/1 +f 9889/9897/1 9890/9898/1 9891/9899/1 9892/9900/1 +f 9893/9901/1 9894/9902/1 9895/9903/1 9896/9904/1 +f 9897/9905/1 9898/9906/1 9899/9907/1 9900/9908/1 +f 9901/9909/1 9902/9910/1 9903/9911/1 9904/9912/1 +f 9905/9913/1 9906/9914/1 9907/9915/1 9908/9916/1 +f 9909/9917/1 9910/9918/1 9911/9919/1 9912/9920/1 +f 9913/9921/1 9914/9922/1 9915/9923/1 9916/9924/1 +f 9917/9925/1 9918/9926/1 9919/9927/1 9920/9928/1 +f 9921/9929/1 9922/9930/1 9923/9931/1 9924/9932/1 +f 9925/9933/1 9926/9934/1 9927/9935/1 9928/9936/1 +f 9929/9937/1 9930/9938/1 9931/9939/1 9932/9940/1 +f 9933/9941/1 9934/9942/1 9935/9943/1 9936/9944/1 +f 9937/9945/1 9938/9946/1 9939/9947/1 9940/9948/1 +f 9941/9949/1 9942/9950/1 9943/9951/1 9944/9952/1 +f 9945/9953/1 9946/9954/1 9947/9955/1 9948/9956/1 +f 9949/9957/1 9950/9958/1 9951/9959/1 9952/9960/1 +f 9953/9961/1 9954/9962/1 9955/9963/1 9956/9964/1 +f 9957/9965/1 9958/9966/1 9959/9967/1 9960/9968/1 +f 9961/9969/1 9962/9970/1 9963/9971/1 9964/9972/1 +f 9965/9973/1 9966/9974/1 9967/9975/1 9968/9976/1 +f 9969/9977/1 9970/9978/1 9971/9979/1 9972/9980/1 +f 9973/9981/1 9974/9982/1 9975/9983/1 9976/9984/1 +f 9977/9985/1 9978/9986/1 9979/9987/1 9980/9988/1 +f 9981/9989/1 9982/9990/1 9983/9991/1 9984/9992/1 +f 9985/9993/1 9986/9994/1 9987/9995/1 9988/9996/1 +f 9989/9997/1 9990/9998/1 9991/9999/1 9992/10000/1 +f 9993/10001/1 9994/10002/1 9995/10003/1 9996/10004/1 +f 9997/10005/1 9998/10006/1 9999/10007/1 10000/10008/1 +f 10001/10009/1 10002/10010/1 10003/10011/1 10004/10012/1 +f 10005/10013/1 10006/10014/1 10007/10015/1 10008/10016/1 +f 10009/10017/1 10010/10018/1 10011/10019/1 10012/10020/1 +f 10013/10021/1 10014/10022/1 10015/10023/1 10016/10024/1 +f 10017/10025/1 10018/10026/1 10019/10027/1 10020/10028/1 +f 10021/10029/1 10022/10030/1 10023/10031/1 10024/10032/1 +f 10025/10033/1 10026/10034/1 10027/10035/1 10028/10036/1 +f 10029/10037/1 10030/10038/1 10031/10039/1 10032/10040/1 +f 10033/10041/1 10034/10042/1 10035/10043/1 10036/10044/1 +f 10037/10045/1 10038/10046/1 10039/10047/1 10040/10048/1 +f 10041/10049/1 10042/10050/1 10043/10051/1 10044/10052/1 +f 10045/10053/1 10046/10054/1 10047/10055/1 10048/10056/1 +f 10049/10057/1 10050/10058/1 10051/10059/1 10052/10060/1 +f 10053/10061/1 10054/10062/1 10055/10063/1 10056/10064/1 +f 10057/10065/1 10058/10066/1 10059/10067/1 10060/10068/1 +f 10061/10069/1 10062/10070/1 10063/10071/1 10064/10072/1 +f 10065/10073/1 10066/10074/1 10067/10075/1 10068/10076/1 +f 10069/10077/1 10070/10078/1 10071/10079/1 10072/10080/1 +f 10073/10081/1 10074/10082/1 10075/10083/1 10076/10084/1 +f 10077/10085/1 10078/10086/1 10079/10087/1 10080/10088/1 +f 10081/10089/1 10082/10090/1 10083/10091/1 10084/10092/1 +f 10085/10093/1 10086/10094/1 10087/10095/1 10088/10096/1 +f 10089/10097/1 10090/10098/1 10091/10099/1 10092/10100/1 +f 10093/10101/1 10094/10102/1 10095/10103/1 10096/10104/1 +f 10097/10105/1 10098/10106/1 10099/10107/1 10100/10108/1 +f 10101/10109/1 10102/10110/1 10103/10111/1 10104/10112/1 +f 10105/10113/1 10106/10114/1 10107/10115/1 10108/10116/1 +f 10109/10117/1 10110/10118/1 10111/10119/1 10112/10120/1 +f 10113/10121/1 10114/10122/1 10115/10123/1 10116/10124/1 +f 10117/10125/1 10118/10126/1 10119/10127/1 10120/10128/1 +f 10121/10129/1 10122/10130/1 10123/10131/1 10124/10132/1 +f 10125/10133/1 10126/10134/1 10127/10135/1 10128/10136/1 +f 10129/10137/1 10130/10138/1 10131/10139/1 10132/10140/1 +f 10133/10141/1 10134/10142/1 10135/10143/1 10136/10144/1 +f 10137/10145/1 10138/10146/1 10139/10147/1 10140/10148/1 +f 10141/10149/1 10142/10150/1 10143/10151/1 10144/10152/1 +f 10145/10153/1 10146/10154/1 10147/10155/1 10148/10156/1 +f 10149/10157/1 10150/10158/1 10151/10159/1 10152/10160/1 +f 10153/10161/1 10154/10162/1 10155/10163/1 10156/10164/1 +f 10157/10165/1 10158/10166/1 10159/10167/1 10160/10168/1 +f 10161/10169/1 10162/10170/1 10163/10171/1 10164/10172/1 +f 10165/10173/1 10166/10174/1 10167/10175/1 10168/10176/1 +f 10169/10177/1 10170/10178/1 10171/10179/1 10172/10180/1 +f 10173/10181/1 10174/10182/1 10175/10183/1 10176/10184/1 +f 10177/10185/1 10178/10186/1 10179/10187/1 10180/10188/1 +f 10181/10189/1 10182/10190/1 10183/10191/1 10184/10192/1 +f 10185/10193/1 10186/10194/1 10187/10195/1 10188/10196/1 +f 10189/10197/1 10190/10198/1 10191/10199/1 10192/10200/1 +f 10193/10201/1 10194/10202/1 10195/10203/1 10196/10204/1 +f 10197/10205/1 10198/10206/1 10199/10207/1 10200/10208/1 +f 10201/10209/1 10202/10210/1 10203/10211/1 10204/10212/1 +f 10205/10213/1 10206/10214/1 10207/10215/1 10208/10216/1 +f 10209/10217/1 10210/10218/1 10211/10219/1 10212/10220/1 +f 10213/10221/1 10214/10222/1 10215/10223/1 10216/10224/1 +f 10217/10225/1 10218/10226/1 10219/10227/1 10220/10228/1 +f 10221/10229/1 10222/10230/1 10223/10231/1 10224/10232/1 +f 10225/10233/1 10226/10234/1 10227/10235/1 10228/10236/1 +f 10229/10237/1 10230/10238/1 10231/10239/1 10232/10240/1 +f 10233/10241/1 10234/10242/1 10235/10243/1 10236/10244/1 +f 10237/10245/1 10238/10246/1 10239/10247/1 10240/10248/1 +f 10241/10249/1 10242/10250/1 10243/10251/1 10244/10252/1 +f 10245/10253/1 10246/10254/1 10247/10255/1 10248/10256/1 +f 10249/10257/1 10250/10258/1 10251/10259/1 10252/10260/1 +f 10253/10261/1 10254/10262/1 10255/10263/1 10256/10264/1 +f 10257/10265/1 10258/10266/1 10259/10267/1 10260/10268/1 +f 10261/10269/1 10262/10270/1 10263/10271/1 10264/10272/1 +f 10265/10273/1 10266/10274/1 10267/10275/1 10268/10276/1 +f 10269/10277/1 10270/10278/1 10271/10279/1 10272/10280/1 +f 10273/10281/1 10274/10282/1 10275/10283/1 10276/10284/1 +f 10277/10285/1 10278/10286/1 10279/10287/1 10280/10288/1 +f 10281/10289/1 10282/10290/1 10283/10291/1 10284/10292/1 +f 10285/10293/1 10286/10294/1 10287/10295/1 10288/10296/1 +f 10289/10297/1 10290/10298/1 10291/10299/1 10292/10300/1 +f 10293/10301/1 10294/10302/1 10295/10303/1 10296/10304/1 +f 10297/10305/1 10298/10306/1 10299/10307/1 10300/10308/1 +f 10301/10309/1 10302/10310/1 10303/10311/1 10304/10312/1 +f 10305/10313/1 10306/10314/1 10307/10315/1 10308/10316/1 +f 10309/10317/1 10310/10318/1 10311/10319/1 10312/10320/1 +f 10313/10321/1 10314/10322/1 10315/10323/1 10316/10324/1 +f 10317/10325/1 10318/10326/1 10319/10327/1 10320/10328/1 +f 10321/10329/1 10322/10330/1 10323/10331/1 10324/10332/1 +f 10325/10333/1 10326/10334/1 10327/10335/1 10328/10336/1 +f 10329/10337/1 10330/10338/1 10331/10339/1 10332/10340/1 +f 10333/10341/1 10334/10342/1 10335/10343/1 10336/10344/1 +f 10337/10345/1 10338/10346/1 10339/10347/1 10340/10348/1 +f 10341/10349/1 10342/10350/1 10343/10351/1 10344/10352/1 +f 10345/10353/1 10346/10354/1 10347/10355/1 10348/10356/1 +f 10349/10357/1 10350/10358/1 10351/10359/1 10352/10360/1 +f 10353/10361/1 10354/10362/1 10355/10363/1 10356/10364/1 +f 10357/10365/1 10358/10366/1 10359/10367/1 10360/10368/1 +f 10361/10369/1 10362/10370/1 10363/10371/1 10364/10372/1 +f 10365/10373/1 10366/10374/1 10367/10375/1 10368/10376/1 +f 10369/10377/1 10370/10378/1 10371/10379/1 10372/10380/1 +f 10373/10381/1 10374/10382/1 10375/10383/1 10376/10384/1 +f 10377/10385/1 10378/10386/1 10379/10387/1 10380/10388/1 +f 10381/10389/1 10382/10390/1 10383/10391/1 10384/10392/1 +f 10385/10393/1 10386/10394/1 10387/10395/1 10388/10396/1 +f 10389/10397/1 10390/10398/1 10391/10399/1 10392/10400/1 +f 10393/10401/1 10394/10402/1 10395/10403/1 10396/10404/1 +f 10397/10405/1 10398/10406/1 10399/10407/1 10400/10408/1 +f 10401/10409/1 10402/10410/1 10403/10411/1 10404/10412/1 +f 10405/10413/1 10406/10414/1 10407/10415/1 10408/10416/1 +f 10409/10417/1 10410/10418/1 10411/10419/1 10412/10420/1 +f 10413/10421/1 10414/10422/1 10415/10423/1 10416/10424/1 +f 10417/10425/1 10418/10426/1 10419/10427/1 10420/10428/1 +f 10421/10429/1 10422/10430/1 10423/10431/1 10424/10432/1 +f 10425/10433/1 10426/10434/1 10427/10435/1 10428/10436/1 +f 10429/10437/1 10430/10438/1 10431/10439/1 10432/10440/1 +f 10433/10441/1 10434/10442/1 10435/10443/1 10436/10444/1 +f 10437/10445/1 10438/10446/1 10439/10447/1 10440/10448/1 +f 10441/10449/1 10442/10450/1 10443/10451/1 10444/10452/1 +f 10445/10453/1 10446/10454/1 10447/10455/1 10448/10456/1 +f 10449/10457/1 10450/10458/1 10451/10459/1 10452/10460/1 +f 10453/10461/1 10454/10462/1 10455/10463/1 10456/10464/1 +f 10457/10465/1 10458/10466/1 10459/10467/1 10460/10468/1 +f 10461/10469/1 10462/10470/1 10463/10471/1 10464/10472/1 +f 10465/10473/1 10466/10474/1 10467/10475/1 10468/10476/1 +f 10469/10477/1 10470/10478/1 10471/10479/1 10472/10480/1 +f 10473/10481/1 10474/10482/1 10475/10483/1 10476/10484/1 +f 10477/10485/1 10478/10486/1 10479/10487/1 10480/10488/1 +f 10481/10489/1 10482/10490/1 10483/10491/1 10484/10492/1 +f 10485/10493/1 10486/10494/1 10487/10495/1 10488/10496/1 +f 10489/10497/1 10490/10498/1 10491/10499/1 10492/10500/1 +f 10493/10501/1 10494/10502/1 10495/10503/1 10496/10504/1 +f 10497/10505/1 10498/10506/1 10499/10507/1 10500/10508/1 +f 10501/10509/1 10502/10510/1 10503/10511/1 10504/10512/1 +f 10505/10513/1 10506/10514/1 10507/10515/1 10508/10516/1 +f 10509/10517/1 10510/10518/1 10511/10519/1 10512/10520/1 +f 10513/10521/1 10514/10522/1 10515/10523/1 10516/10524/1 +f 10517/10525/1 10518/10526/1 10519/10527/1 10520/10528/1 +f 10521/10529/1 10522/10530/1 10523/10531/1 10524/10532/1 +f 10525/10533/1 10526/10534/1 10527/10535/1 10528/10536/1 +f 10529/10537/1 10530/10538/1 10531/10539/1 10532/10540/1 +f 10533/10541/1 10534/10542/1 10535/10543/1 10536/10544/1 +f 10537/10545/1 10538/10546/1 10539/10547/1 10540/10548/1 +f 10541/10549/1 10542/10550/1 10543/10551/1 10544/10552/1 +f 10545/10553/1 10546/10554/1 10547/10555/1 10548/10556/1 +f 10549/10557/1 10550/10558/1 10551/10559/1 10552/10560/1 +f 10553/10561/1 10554/10562/1 10555/10563/1 10556/10564/1 +f 10557/10565/1 10558/10566/1 10559/10567/1 10560/10568/1 +f 10561/10569/1 10562/10570/1 10563/10571/1 10564/10572/1 +f 10565/10573/1 10566/10574/1 10567/10575/1 10568/10576/1 +f 10569/10577/1 10570/10578/1 10571/10579/1 10572/10580/1 +f 10573/10581/1 10574/10582/1 10575/10583/1 10576/10584/1 +f 10577/10585/1 10578/10586/1 10579/10587/1 10580/10588/1 +f 10581/10589/1 10582/10590/1 10583/10591/1 10584/10592/1 +f 10585/10593/1 10586/10594/1 10587/10595/1 10588/10596/1 +f 10589/10597/1 10590/10598/1 10591/10599/1 10592/10600/1 +f 10593/10601/1 10594/10602/1 10595/10603/1 10596/10604/1 +f 10597/10605/1 10598/10606/1 10599/10607/1 10600/10608/1 +f 10601/10609/1 10602/10610/1 10603/10611/1 10604/10612/1 +f 10605/10613/1 10606/10614/1 10607/10615/1 10608/10616/1 +f 10609/10617/1 10610/10618/1 10611/10619/1 10612/10620/1 +f 10613/10621/1 10614/10622/1 10615/10623/1 10616/10624/1 +f 10617/10625/1 10618/10626/1 10619/10627/1 10620/10628/1 +f 10621/10629/1 10622/10630/1 10623/10631/1 10624/10632/1 +f 10625/10633/1 10626/10634/1 10627/10635/1 10628/10636/1 +f 10629/10637/1 10630/10638/1 10631/10639/1 10632/10640/1 +f 10633/10641/1 10634/10642/1 10635/10643/1 10636/10644/1 +f 10637/10645/1 10638/10646/1 10639/10647/1 10640/10648/1 +f 10641/10649/1 10642/10650/1 10643/10651/1 10644/10652/1 +f 10645/10653/1 10646/10654/1 10647/10655/1 10648/10656/1 +f 10649/10657/1 10650/10658/1 10651/10659/1 10652/10660/1 +f 10653/10661/1 10654/10662/1 10655/10663/1 10656/10664/1 +f 10657/10665/1 10658/10666/1 10659/10667/1 10660/10668/1 +f 10661/10669/1 10662/10670/1 10663/10671/1 10664/10672/1 +f 10665/10673/1 10666/10674/1 10667/10675/1 10668/10676/1 +f 10669/10677/1 10670/10678/1 10671/10679/1 10672/10680/1 +f 10673/10681/1 10674/10682/1 10675/10683/1 10676/10684/1 +f 10677/10685/1 10678/10686/1 10679/10687/1 10680/10688/1 +f 10681/10689/1 10682/10690/1 10683/10691/1 10684/10692/1 +f 10685/10693/1 10686/10694/1 10687/10695/1 10688/10696/1 +f 10689/10697/1 10690/10698/1 10691/10699/1 10692/10700/1 +f 10693/10701/1 10694/10702/1 10695/10703/1 10696/10704/1 +f 10697/10705/1 10698/10706/1 10699/10707/1 10700/10708/1 +f 10701/10709/1 10702/10710/1 10703/10711/1 10704/10712/1 +f 10705/10713/1 10706/10714/1 10707/10715/1 10708/10716/1 +f 10709/10717/1 10710/10718/1 10711/10719/1 10712/10720/1 +f 10713/10721/1 10714/10722/1 10715/10723/1 10716/10724/1 +f 10717/10725/1 10718/10726/1 10719/10727/1 10720/10728/1 +f 10721/10729/1 10722/10730/1 10723/10731/1 10724/10732/1 +f 10725/10733/1 10726/10734/1 10727/10735/1 10728/10736/1 +f 10729/10737/1 10730/10738/1 10731/10739/1 10732/10740/1 +f 10733/10741/1 10734/10742/1 10735/10743/1 10736/10744/1 +f 10737/10745/1 10738/10746/1 10739/10747/1 10740/10748/1 +f 10741/10749/1 10742/10750/1 10743/10751/1 10744/10752/1 +f 10745/10753/1 10746/10754/1 10747/10755/1 10748/10756/1 +f 10749/10757/1 10750/10758/1 10751/10759/1 10752/10760/1 +f 10753/10761/1 10754/10762/1 10755/10763/1 10756/10764/1 +f 10757/10765/1 10758/10766/1 10759/10767/1 10760/10768/1 +f 10761/10769/1 10762/10770/1 10763/10771/1 10764/10772/1 +f 10765/10773/1 10766/10774/1 10767/10775/1 10768/10776/1 +f 10769/10777/1 10770/10778/1 10771/10779/1 10772/10780/1 +f 10773/10781/1 10774/10782/1 10775/10783/1 10776/10784/1 +f 10777/10785/1 10778/10786/1 10779/10787/1 10780/10788/1 +f 10781/10789/1 10782/10790/1 10783/10791/1 10784/10792/1 +f 10785/10793/1 10786/10794/1 10787/10795/1 10788/10796/1 +f 10789/10797/1 10790/10798/1 10791/10799/1 10792/10800/1 +f 10793/10801/1 10794/10802/1 10795/10803/1 10796/10804/1 +f 10797/10805/1 10798/10806/1 10799/10807/1 10800/10808/1 +f 10801/10809/1 10802/10810/1 10803/10811/1 10804/10812/1 +f 10805/10813/1 10806/10814/1 10807/10815/1 10808/10816/1 +f 10809/10817/1 10810/10818/1 10811/10819/1 10812/10820/1 +f 10813/10821/1 10814/10822/1 10815/10823/1 10816/10824/1 +f 10817/10825/1 10818/10826/1 10819/10827/1 10820/10828/1 +f 10821/10829/1 10822/10830/1 10823/10831/1 10824/10832/1 +f 10825/10833/1 10826/10834/1 10827/10835/1 10828/10836/1 +f 10829/10837/1 10830/10838/1 10831/10839/1 10832/10840/1 +f 10833/10841/1 10834/10842/1 10835/10843/1 10836/10844/1 +f 10837/10845/1 10838/10846/1 10839/10847/1 10840/10848/1 +f 10841/10849/1 10842/10850/1 10843/10851/1 10844/10852/1 +f 10845/10853/1 10846/10854/1 10847/10855/1 10848/10856/1 +f 10849/10857/1 10850/10858/1 10851/10859/1 10852/10860/1 +f 10853/10861/1 10854/10862/1 10855/10863/1 10856/10864/1 +f 10857/10865/1 10858/10866/1 10859/10867/1 10860/10868/1 +f 10861/10869/1 10862/10870/1 10863/10871/1 10864/10872/1 +f 10865/10873/1 10866/10874/1 10867/10875/1 10868/10876/1 +f 10869/10877/1 10870/10878/1 10871/10879/1 10872/10880/1 +f 10873/10881/1 10874/10882/1 10875/10883/1 10876/10884/1 +f 10877/10885/1 10878/10886/1 10879/10887/1 10880/10888/1 +f 10881/10889/1 10882/10890/1 10883/10891/1 10884/10892/1 +f 10885/10893/1 10886/10894/1 10887/10895/1 10888/10896/1 +f 10889/10897/1 10890/10898/1 10891/10899/1 10892/10900/1 +f 10893/10901/1 10894/10902/1 10895/10903/1 10896/10904/1 +f 10897/10905/1 10898/10906/1 10899/10907/1 10900/10908/1 +f 10901/10909/1 10902/10910/1 10903/10911/1 10904/10912/1 +f 10905/10913/1 10906/10914/1 10907/10915/1 10908/10916/1 +f 10909/10917/1 10910/10918/1 10911/10919/1 10912/10920/1 +f 10913/10921/1 10914/10922/1 10915/10923/1 10916/10924/1 +f 10917/10925/1 10918/10926/1 10919/10927/1 10920/10928/1 +f 10921/10929/1 10922/10930/1 10923/10931/1 10924/10932/1 +f 10925/10933/1 10926/10934/1 10927/10935/1 10928/10936/1 +f 10929/10937/1 10930/10938/1 10931/10939/1 10932/10940/1 +f 10933/10941/1 10934/10942/1 10935/10943/1 10936/10944/1 +f 10937/10945/1 10938/10946/1 10939/10947/1 10940/10948/1 +f 10941/10949/1 10942/10950/1 10943/10951/1 10944/10952/1 +f 10945/10953/1 10946/10954/1 10947/10955/1 10948/10956/1 +f 10949/10957/1 10950/10958/1 10951/10959/1 10952/10960/1 +f 10953/10961/1 10954/10962/1 10955/10963/1 10956/10964/1 +f 10957/10965/1 10958/10966/1 10959/10967/1 10960/10968/1 +f 10961/10969/1 10962/10970/1 10963/10971/1 10964/10972/1 +f 10965/10973/1 10966/10974/1 10967/10975/1 10968/10976/1 +f 10969/10977/1 10970/10978/1 10971/10979/1 10972/10980/1 +f 10973/10981/1 10974/10982/1 10975/10983/1 10976/10984/1 +f 10977/10985/1 10978/10986/1 10979/10987/1 10980/10988/1 +f 10981/10989/1 10982/10990/1 10983/10991/1 10984/10992/1 +f 10985/10993/1 10986/10994/1 10987/10995/1 10988/10996/1 +f 10989/10997/1 10990/10998/1 10991/10999/1 10992/11000/1 +f 10993/11001/1 10994/11002/1 10995/11003/1 10996/11004/1 +f 10997/11005/1 10998/11006/1 10999/11007/1 11000/11008/1 +f 11001/11009/1 11002/11010/1 11003/11011/1 11004/11012/1 +f 11005/11013/1 11006/11014/1 11007/11015/1 11008/11016/1 +f 11009/11017/1 11010/11018/1 11011/11019/1 11012/11020/1 +f 11013/11021/1 11014/11022/1 11015/11023/1 11016/11024/1 +f 11017/11025/1 11018/11026/1 11019/11027/1 11020/11028/1 +f 11021/11029/1 11022/11030/1 11023/11031/1 11024/11032/1 +f 11025/11033/1 11026/11034/1 11027/11035/1 11028/11036/1 +f 11029/11037/1 11030/11038/1 11031/11039/1 11032/11040/1 +f 11033/11041/1 11034/11042/1 11035/11043/1 11036/11044/1 +f 11037/11045/1 11038/11046/1 11039/11047/1 11040/11048/1 +f 11041/11049/1 11042/11050/1 11043/11051/1 11044/11052/1 +f 11045/11053/1 11046/11054/1 11047/11055/1 11048/11056/1 +f 11049/11057/1 11050/11058/1 11051/11059/1 11052/11060/1 +f 11053/11061/1 11054/11062/1 11055/11063/1 11056/11064/1 +f 11057/11065/1 11058/11066/1 11059/11067/1 11060/11068/1 +f 11061/11069/1 11062/11070/1 11063/11071/1 11064/11072/1 +f 11065/11073/1 11066/11074/1 11067/11075/1 11068/11076/1 +f 11069/11077/1 11070/11078/1 11071/11079/1 11072/11080/1 +f 11073/11081/1 11074/11082/1 11075/11083/1 11076/11084/1 +f 11077/11085/1 11078/11086/1 11079/11087/1 11080/11088/1 +f 11081/11089/1 11082/11090/1 11083/11091/1 11084/11092/1 +f 11085/11093/1 11086/11094/1 11087/11095/1 11088/11096/1 +f 11089/11097/1 11090/11098/1 11091/11099/1 11092/11100/1 +f 11093/11101/1 11094/11102/1 11095/11103/1 11096/11104/1 +f 11097/11105/1 11098/11106/1 11099/11107/1 11100/11108/1 +f 11101/11109/1 11102/11110/1 11103/11111/1 11104/11112/1 +f 11105/11113/1 11106/11114/1 11107/11115/1 11108/11116/1 +f 11109/11117/1 11110/11118/1 11111/11119/1 11112/11120/1 +f 11113/11121/1 11114/11122/1 11115/11123/1 11116/11124/1 +f 11117/11125/1 11118/11126/1 11119/11127/1 11120/11128/1 +f 11121/11129/1 11122/11130/1 11123/11131/1 11124/11132/1 +f 11125/11133/1 11126/11134/1 11127/11135/1 11128/11136/1 +f 11129/11137/1 11130/11138/1 11131/11139/1 11132/11140/1 +f 11133/11141/1 11134/11142/1 11135/11143/1 11136/11144/1 +f 11137/11145/1 11138/11146/1 11139/11147/1 11140/11148/1 +f 11141/11149/1 11142/11150/1 11143/11151/1 11144/11152/1 +f 11145/11153/1 11146/11154/1 11147/11155/1 11148/11156/1 +f 11149/11157/1 11150/11158/1 11151/11159/1 11152/11160/1 +f 11153/11161/1 11154/11162/1 11155/11163/1 11156/11164/1 +f 11157/11165/1 11158/11166/1 11159/11167/1 11160/11168/1 +f 11161/11169/1 11162/11170/1 11163/11171/1 11164/11172/1 +f 11165/11173/1 11166/11174/1 11167/11175/1 11168/11176/1 +f 11169/11177/1 11170/11178/1 11171/11179/1 11172/11180/1 +f 11173/11181/1 11174/11182/1 11175/11183/1 11176/11184/1 +f 11177/11185/1 11178/11186/1 11179/11187/1 11180/11188/1 +f 11181/11189/1 11182/11190/1 11183/11191/1 11184/11192/1 +f 11185/11193/1 11186/11194/1 11187/11195/1 11188/11196/1 +f 11189/11197/1 11190/11198/1 11191/11199/1 11192/11200/1 +f 11193/11201/1 11194/11202/1 11195/11203/1 11196/11204/1 +f 11197/11205/1 11198/11206/1 11199/11207/1 11200/11208/1 +f 11201/11209/1 11202/11210/1 11203/11211/1 11204/11212/1 +f 11205/11213/1 11206/11214/1 11207/11215/1 11208/11216/1 +f 11209/11217/1 11210/11218/1 11211/11219/1 11212/11220/1 +f 11213/11221/1 11214/11222/1 11215/11223/1 11216/11224/1 +f 11217/11225/1 11218/11226/1 11219/11227/1 11220/11228/1 +f 11221/11229/1 11222/11230/1 11223/11231/1 11224/11232/1 +f 11225/11233/1 11226/11234/1 11227/11235/1 11228/11236/1 +f 11229/11237/1 11230/11238/1 11231/11239/1 11232/11240/1 +f 11233/11241/1 11234/11242/1 11235/11243/1 11236/11244/1 +f 11237/11245/1 11238/11246/1 11239/11247/1 11240/11248/1 +f 11241/11249/1 11242/11250/1 11243/11251/1 11244/11252/1 +f 11245/11253/1 11246/11254/1 11247/11255/1 11248/11256/1 +f 11249/11257/1 11250/11258/1 11251/11259/1 11252/11260/1 +f 11253/11261/1 11254/11262/1 11255/11263/1 11256/11264/1 +f 11257/11265/1 11258/11266/1 11259/11267/1 11260/11268/1 +f 11261/11269/1 11262/11270/1 11263/11271/1 11264/11272/1 +f 11265/11273/1 11266/11274/1 11267/11275/1 11268/11276/1 +f 11269/11277/1 11270/11278/1 11271/11279/1 11272/11280/1 +f 11273/11281/1 11274/11282/1 11275/11283/1 11276/11284/1 +f 11277/11285/1 11278/11286/1 11279/11287/1 11280/11288/1 +f 11281/11289/1 11282/11290/1 11283/11291/1 11284/11292/1 +f 11285/11293/1 11286/11294/1 11287/11295/1 11288/11296/1 +f 11289/11297/1 11290/11298/1 11291/11299/1 11292/11300/1 +f 11293/11301/1 11294/11302/1 11295/11303/1 11296/11304/1 +f 11297/11305/1 11298/11306/1 11299/11307/1 11300/11308/1 +f 11301/11309/1 11302/11310/1 11303/11311/1 11304/11312/1 +f 11305/11313/1 11306/11314/1 11307/11315/1 11308/11316/1 +f 11309/11317/1 11310/11318/1 11311/11319/1 11312/11320/1 +f 11313/11321/1 11314/11322/1 11315/11323/1 11316/11324/1 +f 11317/11325/1 11318/11326/1 11319/11327/1 11320/11328/1 +f 11321/11329/1 11322/11330/1 11323/11331/1 11324/11332/1 +f 11325/11333/1 11326/11334/1 11327/11335/1 11328/11336/1 +f 11329/11337/1 11330/11338/1 11331/11339/1 11332/11340/1 +f 11333/11341/1 11334/11342/1 11335/11343/1 11336/11344/1 +f 11337/11345/1 11338/11346/1 11339/11347/1 11340/11348/1 +f 11341/11349/1 11342/11350/1 11343/11351/1 11344/11352/1 +f 11345/11353/1 11346/11354/1 11347/11355/1 11348/11356/1 +f 11349/11357/1 11350/11358/1 11351/11359/1 11352/11360/1 +f 11353/11361/1 11354/11362/1 11355/11363/1 11356/11364/1 +f 11357/11365/1 11358/11366/1 11359/11367/1 11360/11368/1 +f 11361/11369/1 11362/11370/1 11363/11371/1 11364/11372/1 +f 11365/11373/1 11366/11374/1 11367/11375/1 11368/11376/1 +f 11369/11377/1 11370/11378/1 11371/11379/1 11372/11380/1 +f 11373/11381/1 11374/11382/1 11375/11383/1 11376/11384/1 +f 11377/11385/1 11378/11386/1 11379/11387/1 11380/11388/1 +f 11381/11389/1 11382/11390/1 11383/11391/1 11384/11392/1 +f 11385/11393/1 11386/11394/1 11387/11395/1 11388/11396/1 +f 11389/11397/1 11390/11398/1 11391/11399/1 11392/11400/1 +f 11393/11401/1 11394/11402/1 11395/11403/1 11396/11404/1 +f 11397/11405/1 11398/11406/1 11399/11407/1 11400/11408/1 +f 11401/11409/1 11402/11410/1 11403/11411/1 11404/11412/1 +f 11405/11413/1 11406/11414/1 11407/11415/1 11408/11416/1 +f 11409/11417/1 11410/11418/1 11411/11419/1 11412/11420/1 +f 11413/11421/1 11414/11422/1 11415/11423/1 11416/11424/1 +f 11417/11425/1 11418/11426/1 11419/11427/1 11420/11428/1 +f 11421/11429/1 11422/11430/1 11423/11431/1 11424/11432/1 +f 11425/11433/1 11426/11434/1 11427/11435/1 11428/11436/1 +f 11429/11437/1 11430/11438/1 11431/11439/1 11432/11440/1 +f 11433/11441/1 11434/11442/1 11435/11443/1 11436/11444/1 +f 11437/11445/1 11438/11446/1 11439/11447/1 11440/11448/1 +f 11441/11449/1 11442/11450/1 11443/11451/1 11444/11452/1 +f 11445/11453/1 11446/11454/1 11447/11455/1 11448/11456/1 +f 11449/11457/1 11450/11458/1 11451/11459/1 11452/11460/1 +f 11453/11461/1 11454/11462/1 11455/11463/1 11456/11464/1 +f 11457/11465/1 11458/11466/1 11459/11467/1 11460/11468/1 +f 11461/11469/1 11462/11470/1 11463/11471/1 11464/11472/1 +f 11465/11473/1 11466/11474/1 11467/11475/1 11468/11476/1 +f 11469/11477/1 11470/11478/1 11471/11479/1 11472/11480/1 +f 11473/11481/1 11474/11482/1 11475/11483/1 11476/11484/1 +f 11477/11485/1 11478/11486/1 11479/11487/1 11480/11488/1 +f 11481/11489/1 11482/11490/1 11483/11491/1 11484/11492/1 +f 11485/11493/1 11486/11494/1 11487/11495/1 11488/11496/1 +f 11489/11497/1 11490/11498/1 11491/11499/1 11492/11500/1 +f 11493/11501/1 11494/11502/1 11495/11503/1 11496/11504/1 +f 11497/11505/1 11498/11506/1 11499/11507/1 11500/11508/1 +f 11501/11509/1 11502/11510/1 11503/11511/1 11504/11512/1 +f 11505/11513/1 11506/11514/1 11507/11515/1 11508/11516/1 +f 11509/11517/1 11510/11518/1 11511/11519/1 11512/11520/1 +f 11513/11521/1 11514/11522/1 11515/11523/1 11516/11524/1 +f 11517/11525/1 11518/11526/1 11519/11527/1 11520/11528/1 +f 11521/11529/1 11522/11530/1 11523/11531/1 11524/11532/1 +f 11525/11533/1 11526/11534/1 11527/11535/1 11528/11536/1 +f 11529/11537/1 11530/11538/1 11531/11539/1 11532/11540/1 +f 11533/11541/1 11534/11542/1 11535/11543/1 11536/11544/1 +f 11537/11545/1 11538/11546/1 11539/11547/1 11540/11548/1 +f 11541/11549/1 11542/11550/1 11543/11551/1 11544/11552/1 +f 11545/11553/1 11546/11554/1 11547/11555/1 11548/11556/1 +f 11549/11557/1 11550/11558/1 11551/11559/1 11552/11560/1 +f 11553/11561/1 11554/11562/1 11555/11563/1 11556/11564/1 +f 11557/11565/1 11558/11566/1 11559/11567/1 11560/11568/1 +f 11561/11569/1 11562/11570/1 11563/11571/1 11564/11572/1 +f 11565/11573/1 11566/11574/1 11567/11575/1 11568/11576/1 +f 11569/11577/1 11570/11578/1 11571/11579/1 11572/11580/1 +f 11573/11581/1 11574/11582/1 11575/11583/1 11576/11584/1 +f 11577/11585/1 11578/11586/1 11579/11587/1 11580/11588/1 +f 11581/11589/1 11582/11590/1 11583/11591/1 11584/11592/1 +f 11585/11593/1 11586/11594/1 11587/11595/1 11588/11596/1 +f 11589/11597/1 11590/11598/1 11591/11599/1 11592/11600/1 +f 11593/11601/1 11594/11602/1 11595/11603/1 11596/11604/1 +f 11597/11605/1 11598/11606/1 11599/11607/1 11600/11608/1 +f 11601/11609/1 11602/11610/1 11603/11611/1 11604/11612/1 +f 11605/11613/1 11606/11614/1 11607/11615/1 11608/11616/1 +f 11609/11617/1 11610/11618/1 11611/11619/1 11612/11620/1 +f 11613/11621/1 11614/11622/1 11615/11623/1 11616/11624/1 +f 11617/11625/1 11618/11626/1 11619/11627/1 11620/11628/1 +f 11621/11629/1 11622/11630/1 11623/11631/1 11624/11632/1 +f 11625/11633/1 11626/11634/1 11627/11635/1 11628/11636/1 +f 11629/11637/1 11630/11638/1 11631/11639/1 11632/11640/1 +f 11633/11641/1 11634/11642/1 11635/11643/1 11636/11644/1 +f 11637/11645/1 11638/11646/1 11639/11647/1 11640/11648/1 +f 11641/11649/1 11642/11650/1 11643/11651/1 11644/11652/1 +f 11645/11653/1 11646/11654/1 11647/11655/1 11648/11656/1 +f 11649/11657/1 11650/11658/1 11651/11659/1 11652/11660/1 +f 11653/11661/1 11654/11662/1 11655/11663/1 11656/11664/1 +f 11657/11665/1 11658/11666/1 11659/11667/1 11660/11668/1 +f 11661/11669/1 11662/11670/1 11663/11671/1 11664/11672/1 +f 11665/11673/1 11666/11674/1 11667/11675/1 11668/11676/1 +f 11669/11677/1 11670/11678/1 11671/11679/1 11672/11680/1 +f 11673/11681/1 11674/11682/1 11675/11683/1 11676/11684/1 +f 11677/11685/1 11678/11686/1 11679/11687/1 11680/11688/1 +f 11681/11689/1 11682/11690/1 11683/11691/1 11684/11692/1 +f 11685/11693/1 11686/11694/1 11687/11695/1 11688/11696/1 +f 11689/11697/1 11690/11698/1 11691/11699/1 11692/11700/1 +f 11693/11701/1 11694/11702/1 11695/11703/1 11696/11704/1 +f 11697/11705/1 11698/11706/1 11699/11707/1 11700/11708/1 +f 11701/11709/1 11702/11710/1 11703/11711/1 11704/11712/1 +f 11705/11713/1 11706/11714/1 11707/11715/1 11708/11716/1 +f 11709/11717/1 11710/11718/1 11711/11719/1 11712/11720/1 +f 11713/11721/1 11714/11722/1 11715/11723/1 11716/11724/1 +f 11717/11725/1 11718/11726/1 11719/11727/1 11720/11728/1 +f 11721/11729/1 11722/11730/1 11723/11731/1 11724/11732/1 +f 11725/11733/1 11726/11734/1 11727/11735/1 11728/11736/1 +f 11729/11737/1 11730/11738/1 11731/11739/1 11732/11740/1 +f 11733/11741/1 11734/11742/1 11735/11743/1 11736/11744/1 +f 11737/11745/1 11738/11746/1 11739/11747/1 11740/11748/1 +f 11741/11749/1 11742/11750/1 11743/11751/1 11744/11752/1 +f 11745/11753/1 11746/11754/1 11747/11755/1 11748/11756/1 +f 11749/11757/1 11750/11758/1 11751/11759/1 11752/11760/1 +f 11753/11761/1 11754/11762/1 11755/11763/1 11756/11764/1 +f 11757/11765/1 11758/11766/1 11759/11767/1 11760/11768/1 +f 11761/11769/1 11762/11770/1 11763/11771/1 11764/11772/1 +f 11765/11773/1 11766/11774/1 11767/11775/1 11768/11776/1 +f 11769/11777/1 11770/11778/1 11771/11779/1 11772/11780/1 +f 11773/11781/1 11774/11782/1 11775/11783/1 11776/11784/1 +f 11777/11785/1 11778/11786/1 11779/11787/1 11780/11788/1 +f 11781/11789/1 11782/11790/1 11783/11791/1 11784/11792/1 +f 11785/11793/1 11786/11794/1 11787/11795/1 11788/11796/1 +f 11789/11797/1 11790/11798/1 11791/11799/1 11792/11800/1 +f 11793/11801/1 11794/11802/1 11795/11803/1 11796/11804/1 +f 11797/11805/1 11798/11806/1 11799/11807/1 11800/11808/1 +f 11801/11809/1 11802/11810/1 11803/11811/1 11804/11812/1 +f 11805/11813/1 11806/11814/1 11807/11815/1 11808/11816/1 +f 11809/11817/1 11810/11818/1 11811/11819/1 11812/11820/1 +f 11813/11821/1 11814/11822/1 11815/11823/1 11816/11824/1 +f 11817/11825/1 11818/11826/1 11819/11827/1 11820/11828/1 +f 11821/11829/1 11822/11830/1 11823/11831/1 11824/11832/1 +f 11825/11833/1 11826/11834/1 11827/11835/1 11828/11836/1 +f 11829/11837/1 11830/11838/1 11831/11839/1 11832/11840/1 +f 11833/11841/1 11834/11842/1 11835/11843/1 11836/11844/1 +f 11837/11845/1 11838/11846/1 11839/11847/1 11840/11848/1 +f 11841/11849/1 11842/11850/1 11843/11851/1 11844/11852/1 +f 11845/11853/1 11846/11854/1 11847/11855/1 11848/11856/1 +f 11849/11857/1 11850/11858/1 11851/11859/1 11852/11860/1 +f 11853/11861/1 11854/11862/1 11855/11863/1 11856/11864/1 +f 11857/11865/1 11858/11866/1 11859/11867/1 11860/11868/1 +f 11861/11869/1 11862/11870/1 11863/11871/1 11864/11872/1 +f 11865/11873/1 11866/11874/1 11867/11875/1 11868/11876/1 +f 11869/11877/1 11870/11878/1 11871/11879/1 11872/11880/1 +f 11873/11881/1 11874/11882/1 11875/11883/1 11876/11884/1 +f 11877/11885/1 11878/11886/1 11879/11887/1 11880/11888/1 +f 11881/11889/1 11882/11890/1 11883/11891/1 11884/11892/1 +f 11885/11893/1 11886/11894/1 11887/11895/1 11888/11896/1 +f 11889/11897/1 11890/11898/1 11891/11899/1 11892/11900/1 +f 11893/11901/1 11894/11902/1 11895/11903/1 11896/11904/1 +f 11897/11905/1 11898/11906/1 11899/11907/1 11900/11908/1 +f 11901/11909/1 11902/11910/1 11903/11911/1 11904/11912/1 +f 11905/11913/1 11906/11914/1 11907/11915/1 11908/11916/1 +f 11909/11917/1 11910/11918/1 11911/11919/1 11912/11920/1 +f 11913/11921/1 11914/11922/1 11915/11923/1 11916/11924/1 +f 11917/11925/1 11918/11926/1 11919/11927/1 11920/11928/1 +f 11921/11929/1 11922/11930/1 11923/11931/1 11924/11932/1 +f 11925/11933/1 11926/11934/1 11927/11935/1 11928/11936/1 +f 11929/11937/1 11930/11938/1 11931/11939/1 11932/11940/1 +f 11933/11941/1 11934/11942/1 11935/11943/1 11936/11944/1 +f 11937/11945/1 11938/11946/1 11939/11947/1 11940/11948/1 +f 11941/11949/1 11942/11950/1 11943/11951/1 11944/11952/1 +f 11945/11953/1 11946/11954/1 11947/11955/1 11948/11956/1 +f 11949/11957/1 11950/11958/1 11951/11959/1 11952/11960/1 +f 11953/11961/1 11954/11962/1 11955/11963/1 11956/11964/1 +f 11957/11965/1 11958/11966/1 11959/11967/1 11960/11968/1 +f 11961/11969/1 11962/11970/1 11963/11971/1 11964/11972/1 +f 11965/11973/1 11966/11974/1 11967/11975/1 11968/11976/1 +f 11969/11977/1 11970/11978/1 11971/11979/1 11972/11980/1 +f 11973/11981/1 11974/11982/1 11975/11983/1 11976/11984/1 +f 11977/11985/1 11978/11986/1 11979/11987/1 11980/11988/1 +f 11981/11989/1 11982/11990/1 11983/11991/1 11984/11992/1 +f 11985/11993/1 11986/11994/1 11987/11995/1 11988/11996/1 +f 11989/11997/1 11990/11998/1 11991/11999/1 11992/12000/1 +f 11993/12001/1 11994/12002/1 11995/12003/1 11996/12004/1 +f 11997/12005/1 11998/12006/1 11999/12007/1 12000/12008/1 +f 12001/12009/1 12002/12010/1 12003/12011/1 12004/12012/1 +f 12005/12013/1 12006/12014/1 12007/12015/1 12008/12016/1 +f 12009/12017/1 12010/12018/1 12011/12019/1 12012/12020/1 +f 12013/12021/1 12014/12022/1 12015/12023/1 12016/12024/1 +f 12017/12025/1 12018/12026/1 12019/12027/1 12020/12028/1 +f 12021/12029/1 12022/12030/1 12023/12031/1 12024/12032/1 +f 12025/12033/1 12026/12034/1 12027/12035/1 12028/12036/1 +f 12029/12037/1 12030/12038/1 12031/12039/1 12032/12040/1 +f 12033/12041/1 12034/12042/1 12035/12043/1 12036/12044/1 +f 12037/12045/1 12038/12046/1 12039/12047/1 12040/12048/1 +f 12041/12049/1 12042/12050/1 12043/12051/1 12044/12052/1 +f 12045/12053/1 12046/12054/1 12047/12055/1 12048/12056/1 +f 12049/12057/1 12050/12058/1 12051/12059/1 12052/12060/1 +f 12053/12061/1 12054/12062/1 12055/12063/1 12056/12064/1 +f 12057/12065/1 12058/12066/1 12059/12067/1 12060/12068/1 +f 12061/12069/1 12062/12070/1 12063/12071/1 12064/12072/1 +f 12065/12073/1 12066/12074/1 12067/12075/1 12068/12076/1 +f 12069/12077/1 12070/12078/1 12071/12079/1 12072/12080/1 +f 12073/12081/1 12074/12082/1 12075/12083/1 12076/12084/1 +f 12077/12085/1 12078/12086/1 12079/12087/1 12080/12088/1 +f 12081/12089/1 12082/12090/1 12083/12091/1 12084/12092/1 +f 12085/12093/1 12086/12094/1 12087/12095/1 12088/12096/1 +f 12089/12097/1 12090/12098/1 12091/12099/1 12092/12100/1 +f 12093/12101/1 12094/12102/1 12095/12103/1 12096/12104/1 +f 12097/12105/1 12098/12106/1 12099/12107/1 12100/12108/1 +f 12101/12109/1 12102/12110/1 12103/12111/1 12104/12112/1 +f 12105/12113/1 12106/12114/1 12107/12115/1 12108/12116/1 +f 12109/12117/1 12110/12118/1 12111/12119/1 12112/12120/1 +f 12113/12121/1 12114/12122/1 12115/12123/1 12116/12124/1 +f 12117/12125/1 12118/12126/1 12119/12127/1 12120/12128/1 +f 12121/12129/1 12122/12130/1 12123/12131/1 12124/12132/1 +f 12125/12133/1 12126/12134/1 12127/12135/1 12128/12136/1 +f 12129/12137/1 12130/12138/1 12131/12139/1 12132/12140/1 +f 12133/12141/1 12134/12142/1 12135/12143/1 12136/12144/1 +f 12137/12145/1 12138/12146/1 12139/12147/1 12140/12148/1 +f 12141/12149/1 12142/12150/1 12143/12151/1 12144/12152/1 +f 12145/12153/1 12146/12154/1 12147/12155/1 12148/12156/1 +f 12149/12157/1 12150/12158/1 12151/12159/1 12152/12160/1 +f 12153/12161/1 12154/12162/1 12155/12163/1 12156/12164/1 +f 12157/12165/1 12158/12166/1 12159/12167/1 12160/12168/1 +f 12161/12169/1 12162/12170/1 12163/12171/1 12164/12172/1 +f 12165/12173/1 12166/12174/1 12167/12175/1 12168/12176/1 +f 12169/12177/1 12170/12178/1 12171/12179/1 12172/12180/1 +f 12173/12181/1 12174/12182/1 12175/12183/1 12176/12184/1 +f 12177/12185/1 12178/12186/1 12179/12187/1 12180/12188/1 +f 12181/12189/1 12182/12190/1 12183/12191/1 12184/12192/1 +f 12185/12193/1 12186/12194/1 12187/12195/1 12188/12196/1 +f 12189/12197/1 12190/12198/1 12191/12199/1 12192/12200/1 +f 12193/12201/1 12194/12202/1 12195/12203/1 12196/12204/1 +f 12197/12205/1 12198/12206/1 12199/12207/1 12200/12208/1 +f 12201/12209/1 12202/12210/1 12203/12211/1 12204/12212/1 +f 12205/12213/1 12206/12214/1 12207/12215/1 12208/12216/1 +f 12209/12217/1 12210/12218/1 12211/12219/1 12212/12220/1 +f 12213/12221/1 12214/12222/1 12215/12223/1 12216/12224/1 +f 12217/12225/1 12218/12226/1 12219/12227/1 12220/12228/1 +f 12221/12229/1 12222/12230/1 12223/12231/1 12224/12232/1 +f 12225/12233/1 12226/12234/1 12227/12235/1 12228/12236/1 +f 12229/12237/1 12230/12238/1 12231/12239/1 12232/12240/1 +f 12233/12241/1 12234/12242/1 12235/12243/1 12236/12244/1 +f 12237/12245/1 12238/12246/1 12239/12247/1 12240/12248/1 +f 12241/12249/1 12242/12250/1 12243/12251/1 12244/12252/1 +f 12245/12253/1 12246/12254/1 12247/12255/1 12248/12256/1 +f 12249/12257/1 12250/12258/1 12251/12259/1 12252/12260/1 +f 12253/12261/1 12254/12262/1 12255/12263/1 12256/12264/1 +f 12257/12265/1 12258/12266/1 12259/12267/1 12260/12268/1 +f 12261/12269/1 12262/12270/1 12263/12271/1 12264/12272/1 +f 12265/12273/1 12266/12274/1 12267/12275/1 12268/12276/1 +f 12269/12277/1 12270/12278/1 12271/12279/1 12272/12280/1 +f 12273/12281/1 12274/12282/1 12275/12283/1 12276/12284/1 +f 12277/12285/1 12278/12286/1 12279/12287/1 12280/12288/1 +f 12281/12289/1 12282/12290/1 12283/12291/1 12284/12292/1 +f 12285/12293/1 12286/12294/1 12287/12295/1 12288/12296/1 +f 12289/12297/1 12290/12298/1 12291/12299/1 12292/12300/1 +f 12293/12301/1 12294/12302/1 12295/12303/1 12296/12304/1 +f 12297/12305/1 12298/12306/1 12299/12307/1 12300/12308/1 +f 12301/12309/1 12302/12310/1 12303/12311/1 12304/12312/1 +f 12305/12313/1 12306/12314/1 12307/12315/1 12308/12316/1 +f 12309/12317/1 12310/12318/1 12311/12319/1 12312/12320/1 +f 12313/12321/1 12314/12322/1 12315/12323/1 12316/12324/1 +f 12317/12325/1 12318/12326/1 12319/12327/1 12320/12328/1 +f 12321/12329/1 12322/12330/1 12323/12331/1 12324/12332/1 +f 12325/12333/1 12326/12334/1 12327/12335/1 12328/12336/1 +f 12329/12337/1 12330/12338/1 12331/12339/1 12332/12340/1 +f 12333/12341/1 12334/12342/1 12335/12343/1 12336/12344/1 +f 12337/12345/1 12338/12346/1 12339/12347/1 12340/12348/1 +f 12341/12349/1 12342/12350/1 12343/12351/1 12344/12352/1 +f 12345/12353/1 12346/12354/1 12347/12355/1 12348/12356/1 +f 12349/12357/1 12350/12358/1 12351/12359/1 12352/12360/1 +f 12353/12361/1 12354/12362/1 12355/12363/1 12356/12364/1 +f 12357/12365/1 12358/12366/1 12359/12367/1 12360/12368/1 +f 12361/12369/1 12362/12370/1 12363/12371/1 12364/12372/1 +f 12365/12373/1 12366/12374/1 12367/12375/1 12368/12376/1 +f 12369/12377/1 12370/12378/1 12371/12379/1 12372/12380/1 +f 12373/12381/1 12374/12382/1 12375/12383/1 12376/12384/1 +f 12377/12385/1 12378/12386/1 12379/12387/1 12380/12388/1 +f 12381/12389/1 12382/12390/1 12383/12391/1 12384/12392/1 +f 12385/12393/1 12386/12394/1 12387/12395/1 12388/12396/1 +f 12389/12397/1 12390/12398/1 12391/12399/1 12392/12400/1 +f 12393/12401/1 12394/12402/1 12395/12403/1 12396/12404/1 +f 12397/12405/1 12398/12406/1 12399/12407/1 12400/12408/1 +f 12401/12409/1 12402/12410/1 12403/12411/1 12404/12412/1 +f 12405/12413/1 12406/12414/1 12407/12415/1 12408/12416/1 +f 12409/12417/1 12410/12418/1 12411/12419/1 12412/12420/1 +f 12413/12421/1 12414/12422/1 12415/12423/1 12416/12424/1 +f 12417/12425/1 12418/12426/1 12419/12427/1 12420/12428/1 +f 12421/12429/1 12422/12430/1 12423/12431/1 12424/12432/1 +f 12425/12433/1 12426/12434/1 12427/12435/1 12428/12436/1 +f 12429/12437/1 12430/12438/1 12431/12439/1 12432/12440/1 +f 12433/12441/1 12434/12442/1 12435/12443/1 12436/12444/1 +f 12437/12445/1 12438/12446/1 12439/12447/1 12440/12448/1 +f 12441/12449/1 12442/12450/1 12443/12451/1 12444/12452/1 +f 12445/12453/1 12446/12454/1 12447/12455/1 12448/12456/1 +f 12449/12457/1 12450/12458/1 12451/12459/1 12452/12460/1 +f 12453/12461/1 12454/12462/1 12455/12463/1 12456/12464/1 +f 12457/12465/1 12458/12466/1 12459/12467/1 12460/12468/1 +f 12461/12469/1 12462/12470/1 12463/12471/1 12464/12472/1 +f 12465/12473/1 12466/12474/1 12467/12475/1 12468/12476/1 +f 12469/12477/1 12470/12478/1 12471/12479/1 12472/12480/1 +f 12473/12481/1 12474/12482/1 12475/12483/1 12476/12484/1 +f 12477/12485/1 12478/12486/1 12479/12487/1 12480/12488/1 +f 12481/12489/1 12482/12490/1 12483/12491/1 12484/12492/1 +f 12485/12493/1 12486/12494/1 12487/12495/1 12488/12496/1 +f 12489/12497/1 12490/12498/1 12491/12499/1 12492/12500/1 +f 12493/12501/1 12494/12502/1 12495/12503/1 12496/12504/1 +f 12497/12505/1 12498/12506/1 12499/12507/1 12500/12508/1 +f 12501/12509/1 12502/12510/1 12503/12511/1 12504/12512/1 +f 12505/12513/1 12506/12514/1 12507/12515/1 12508/12516/1 +f 12509/12517/1 12510/12518/1 12511/12519/1 12512/12520/1 +f 12513/12521/1 12514/12522/1 12515/12523/1 12516/12524/1 +f 12517/12525/1 12518/12526/1 12519/12527/1 12520/12528/1 +f 12521/12529/1 12522/12530/1 12523/12531/1 12524/12532/1 +f 12525/12533/1 12526/12534/1 12527/12535/1 12528/12536/1 +f 12529/12537/1 12530/12538/1 12531/12539/1 12532/12540/1 +f 12533/12541/1 12534/12542/1 12535/12543/1 12536/12544/1 +f 12537/12545/1 12538/12546/1 12539/12547/1 12540/12548/1 +f 12541/12549/1 12542/12550/1 12543/12551/1 12544/12552/1 +f 12545/12553/1 12546/12554/1 12547/12555/1 12548/12556/1 +f 12549/12557/1 12550/12558/1 12551/12559/1 12552/12560/1 +f 12553/12561/1 12554/12562/1 12555/12563/1 12556/12564/1 +f 12557/12565/1 12558/12566/1 12559/12567/1 12560/12568/1 +f 12561/12569/1 12562/12570/1 12563/12571/1 12564/12572/1 +f 12565/12573/1 12566/12574/1 12567/12575/1 12568/12576/1 +f 12569/12577/1 12570/12578/1 12571/12579/1 12572/12580/1 +f 12573/12581/1 12574/12582/1 12575/12583/1 12576/12584/1 +f 12577/12585/1 12578/12586/1 12579/12587/1 12580/12588/1 +f 12581/12589/1 12582/12590/1 12583/12591/1 12584/12592/1 +f 12585/12593/1 12586/12594/1 12587/12595/1 12588/12596/1 +f 12589/12597/1 12590/12598/1 12591/12599/1 12592/12600/1 +f 12593/12601/1 12594/12602/1 12595/12603/1 12596/12604/1 +f 12597/12605/1 12598/12606/1 12599/12607/1 12600/12608/1 +f 12601/12609/1 12602/12610/1 12603/12611/1 12604/12612/1 +f 12605/12613/1 12606/12614/1 12607/12615/1 12608/12616/1 +f 12609/12617/1 12610/12618/1 12611/12619/1 12612/12620/1 +f 12613/12621/1 12614/12622/1 12615/12623/1 12616/12624/1 +f 12617/12625/1 12618/12626/1 12619/12627/1 12620/12628/1 +f 12621/12629/1 12622/12630/1 12623/12631/1 12624/12632/1 +f 12625/12633/1 12626/12634/1 12627/12635/1 12628/12636/1 +f 12629/12637/1 12630/12638/1 12631/12639/1 12632/12640/1 +f 12633/12641/1 12634/12642/1 12635/12643/1 12636/12644/1 +f 12637/12645/1 12638/12646/1 12639/12647/1 12640/12648/1 +f 12641/12649/1 12642/12650/1 12643/12651/1 12644/12652/1 +f 12645/12653/1 12646/12654/1 12647/12655/1 12648/12656/1 +f 12649/12657/1 12650/12658/1 12651/12659/1 12652/12660/1 +f 12653/12661/1 12654/12662/1 12655/12663/1 12656/12664/1 +f 12657/12665/1 12658/12666/1 12659/12667/1 12660/12668/1 +f 12661/12669/1 12662/12670/1 12663/12671/1 12664/12672/1 +f 12665/12673/1 12666/12674/1 12667/12675/1 12668/12676/1 +f 12669/12677/1 12670/12678/1 12671/12679/1 12672/12680/1 +f 12673/12681/1 12674/12682/1 12675/12683/1 12676/12684/1 +f 12677/12685/1 12678/12686/1 12679/12687/1 12680/12688/1 +f 12681/12689/1 12682/12690/1 12683/12691/1 12684/12692/1 +f 12685/12693/1 12686/12694/1 12687/12695/1 12688/12696/1 +f 12689/12697/1 12690/12698/1 12691/12699/1 12692/12700/1 +f 12693/12701/1 12694/12702/1 12695/12703/1 12696/12704/1 +f 12697/12705/1 12698/12706/1 12699/12707/1 12700/12708/1 +f 12701/12709/1 12702/12710/1 12703/12711/1 12704/12712/1 +f 12705/12713/1 12706/12714/1 12707/12715/1 12708/12716/1 +f 12709/12717/1 12710/12718/1 12711/12719/1 12712/12720/1 +f 12713/12721/1 12714/12722/1 12715/12723/1 12716/12724/1 +f 12717/12725/1 12718/12726/1 12719/12727/1 12720/12728/1 +f 12721/12729/1 12722/12730/1 12723/12731/1 12724/12732/1 +f 12725/12733/1 12726/12734/1 12727/12735/1 12728/12736/1 +f 12729/12737/1 12730/12738/1 12731/12739/1 12732/12740/1 +f 12733/12741/1 12734/12742/1 12735/12743/1 12736/12744/1 +f 12737/12745/1 12738/12746/1 12739/12747/1 12740/12748/1 +f 12741/12749/1 12742/12750/1 12743/12751/1 12744/12752/1 +f 12745/12753/1 12746/12754/1 12747/12755/1 12748/12756/1 +f 12749/12757/1 12750/12758/1 12751/12759/1 12752/12760/1 +f 12753/12761/1 12754/12762/1 12755/12763/1 12756/12764/1 +f 12757/12765/1 12758/12766/1 12759/12767/1 12760/12768/1 +f 12761/12769/1 12762/12770/1 12763/12771/1 12764/12772/1 +f 12765/12773/1 12766/12774/1 12767/12775/1 12768/12776/1 +f 12769/12777/1 12770/12778/1 12771/12779/1 12772/12780/1 +f 12773/12781/1 12774/12782/1 12775/12783/1 12776/12784/1 +f 12777/12785/1 12778/12786/1 12779/12787/1 12780/12788/1 +f 12781/12789/1 12782/12790/1 12783/12791/1 12784/12792/1 +f 12785/12793/1 12786/12794/1 12787/12795/1 12788/12796/1 +f 12789/12797/1 12790/12798/1 12791/12799/1 12792/12800/1 +f 12793/12801/1 12794/12802/1 12795/12803/1 12796/12804/1 +f 12797/12805/1 12798/12806/1 12799/12807/1 12800/12808/1 +f 12801/12809/1 12802/12810/1 12803/12811/1 12804/12812/1 +f 12805/12813/1 12806/12814/1 12807/12815/1 12808/12816/1 +f 12809/12817/1 12810/12818/1 12811/12819/1 12812/12820/1 +f 12813/12821/1 12814/12822/1 12815/12823/1 12816/12824/1 +f 12817/12825/1 12818/12826/1 12819/12827/1 12820/12828/1 +f 12821/12829/1 12822/12830/1 12823/12831/1 12824/12832/1 +f 12825/12833/1 12826/12834/1 12827/12835/1 12828/12836/1 +f 12829/12837/1 12830/12838/1 12831/12839/1 12832/12840/1 +f 12833/12841/1 12834/12842/1 12835/12843/1 12836/12844/1 +f 12837/12845/1 12838/12846/1 12839/12847/1 12840/12848/1 +f 12841/12849/1 12842/12850/1 12843/12851/1 12844/12852/1 +f 12845/12853/1 12846/12854/1 12847/12855/1 12848/12856/1 +f 12849/12857/1 12850/12858/1 12851/12859/1 12852/12860/1 +f 12853/12861/1 12854/12862/1 12855/12863/1 12856/12864/1 +f 12857/12865/1 12858/12866/1 12859/12867/1 12860/12868/1 +f 12861/12869/1 12862/12870/1 12863/12871/1 12864/12872/1 +f 12865/12873/1 12866/12874/1 12867/12875/1 12868/12876/1 +f 12869/12877/1 12870/12878/1 12871/12879/1 12872/12880/1 +f 12873/12881/1 12874/12882/1 12875/12883/1 12876/12884/1 +f 12877/12885/1 12878/12886/1 12879/12887/1 12880/12888/1 +f 12881/12889/1 12882/12890/1 12883/12891/1 12884/12892/1 +f 12885/12893/1 12886/12894/1 12887/12895/1 12888/12896/1 +f 12889/12897/1 12890/12898/1 12891/12899/1 12892/12900/1 +f 12893/12901/1 12894/12902/1 12895/12903/1 12896/12904/1 +f 12897/12905/1 12898/12906/1 12899/12907/1 12900/12908/1 +f 12901/12909/1 12902/12910/1 12903/12911/1 12904/12912/1 +f 12905/12913/1 12906/12914/1 12907/12915/1 12908/12916/1 +f 12909/12917/1 12910/12918/1 12911/12919/1 12912/12920/1 +f 12913/12921/1 12914/12922/1 12915/12923/1 12916/12924/1 +f 12917/12925/1 12918/12926/1 12919/12927/1 12920/12928/1 +f 12921/12929/1 12922/12930/1 12923/12931/1 12924/12932/1 +f 12925/12933/1 12926/12934/1 12927/12935/1 12928/12936/1 +f 12929/12937/1 12930/12938/1 12931/12939/1 12932/12940/1 +f 12933/12941/1 12934/12942/1 12935/12943/1 12936/12944/1 +f 12937/12945/1 12938/12946/1 12939/12947/1 12940/12948/1 +f 12941/12949/1 12942/12950/1 12943/12951/1 12944/12952/1 +f 12945/12953/1 12946/12954/1 12947/12955/1 12948/12956/1 +f 12949/12957/1 12950/12958/1 12951/12959/1 12952/12960/1 +f 12953/12961/1 12954/12962/1 12955/12963/1 12956/12964/1 +f 12957/12965/1 12958/12966/1 12959/12967/1 12960/12968/1 +f 12961/12969/1 12962/12970/1 12963/12971/1 12964/12972/1 +f 12965/12973/1 12966/12974/1 12967/12975/1 12968/12976/1 +f 12969/12977/1 12970/12978/1 12971/12979/1 12972/12980/1 +f 12973/12981/1 12974/12982/1 12975/12983/1 12976/12984/1 +f 12977/12985/1 12978/12986/1 12979/12987/1 12980/12988/1 +f 12981/12989/1 12982/12990/1 12983/12991/1 12984/12992/1 +f 12985/12993/1 12986/12994/1 12987/12995/1 12988/12996/1 +f 12989/12997/1 12990/12998/1 12991/12999/1 12992/13000/1 +f 12993/13001/1 12994/13002/1 12995/13003/1 12996/13004/1 +f 12997/13005/1 12998/13006/1 12999/13007/1 13000/13008/1 +f 13001/13009/1 13002/13010/1 13003/13011/1 13004/13012/1 +f 13005/13013/1 13006/13014/1 13007/13015/1 13008/13016/1 +f 13009/13017/1 13010/13018/1 13011/13019/1 13012/13020/1 +f 13013/13021/1 13014/13022/1 13015/13023/1 13016/13024/1 +f 13017/13025/1 13018/13026/1 13019/13027/1 13020/13028/1 +f 13021/13029/1 13022/13030/1 13023/13031/1 13024/13032/1 +f 13025/13033/1 13026/13034/1 13027/13035/1 13028/13036/1 +f 13029/13037/1 13030/13038/1 13031/13039/1 13032/13040/1 +f 13033/13041/1 13034/13042/1 13035/13043/1 13036/13044/1 +f 13037/13045/1 13038/13046/1 13039/13047/1 13040/13048/1 +f 13041/13049/1 13042/13050/1 13043/13051/1 13044/13052/1 +f 13045/13053/1 13046/13054/1 13047/13055/1 13048/13056/1 +f 13049/13057/1 13050/13058/1 13051/13059/1 13052/13060/1 +f 13053/13061/1 13054/13062/1 13055/13063/1 13056/13064/1 +f 13057/13065/1 13058/13066/1 13059/13067/1 13060/13068/1 +f 13061/13069/1 13062/13070/1 13063/13071/1 13064/13072/1 +f 13065/13073/1 13066/13074/1 13067/13075/1 13068/13076/1 +f 13069/13077/1 13070/13078/1 13071/13079/1 13072/13080/1 +f 13073/13081/1 13074/13082/1 13075/13083/1 13076/13084/1 +f 13077/13085/1 13078/13086/1 13079/13087/1 13080/13088/1 +f 13081/13089/1 13082/13090/1 13083/13091/1 13084/13092/1 +f 13085/13093/1 13086/13094/1 13087/13095/1 13088/13096/1 +f 13089/13097/1 13090/13098/1 13091/13099/1 13092/13100/1 +f 13093/13101/1 13094/13102/1 13095/13103/1 13096/13104/1 +f 13097/13105/1 13098/13106/1 13099/13107/1 13100/13108/1 +f 13101/13109/1 13102/13110/1 13103/13111/1 13104/13112/1 +f 13105/13113/1 13106/13114/1 13107/13115/1 13108/13116/1 +f 13109/13117/1 13110/13118/1 13111/13119/1 13112/13120/1 +f 13113/13121/1 13114/13122/1 13115/13123/1 13116/13124/1 +f 13117/13125/1 13118/13126/1 13119/13127/1 13120/13128/1 +f 13121/13129/1 13122/13130/1 13123/13131/1 13124/13132/1 +f 13125/13133/1 13126/13134/1 13127/13135/1 13128/13136/1 +f 13129/13137/1 13130/13138/1 13131/13139/1 13132/13140/1 +f 13133/13141/1 13134/13142/1 13135/13143/1 13136/13144/1 +f 13137/13145/1 13138/13146/1 13139/13147/1 13140/13148/1 +f 13141/13149/1 13142/13150/1 13143/13151/1 13144/13152/1 +f 13145/13153/1 13146/13154/1 13147/13155/1 13148/13156/1 +f 13149/13157/1 13150/13158/1 13151/13159/1 13152/13160/1 +f 13153/13161/1 13154/13162/1 13155/13163/1 13156/13164/1 +f 13157/13165/1 13158/13166/1 13159/13167/1 13160/13168/1 +f 13161/13169/1 13162/13170/1 13163/13171/1 13164/13172/1 +f 13165/13173/1 13166/13174/1 13167/13175/1 13168/13176/1 +f 13169/13177/1 13170/13178/1 13171/13179/1 13172/13180/1 +f 13173/13181/1 13174/13182/1 13175/13183/1 13176/13184/1 +f 13177/13185/1 13178/13186/1 13179/13187/1 13180/13188/1 +f 13181/13189/1 13182/13190/1 13183/13191/1 13184/13192/1 +f 13185/13193/1 13186/13194/1 13187/13195/1 13188/13196/1 +f 13189/13197/1 13190/13198/1 13191/13199/1 13192/13200/1 +f 13193/13201/1 13194/13202/1 13195/13203/1 13196/13204/1 +f 13197/13205/1 13198/13206/1 13199/13207/1 13200/13208/1 +f 13201/13209/1 13202/13210/1 13203/13211/1 13204/13212/1 +f 13205/13213/1 13206/13214/1 13207/13215/1 13208/13216/1 +f 13209/13217/1 13210/13218/1 13211/13219/1 13212/13220/1 +f 13213/13221/1 13214/13222/1 13215/13223/1 13216/13224/1 +f 13217/13225/1 13218/13226/1 13219/13227/1 13220/13228/1 +f 13221/13229/1 13222/13230/1 13223/13231/1 13224/13232/1 +f 13225/13233/1 13226/13234/1 13227/13235/1 13228/13236/1 +f 13229/13237/1 13230/13238/1 13231/13239/1 13232/13240/1 +f 13233/13241/1 13234/13242/1 13235/13243/1 13236/13244/1 +f 13237/13245/1 13238/13246/1 13239/13247/1 13240/13248/1 +f 13241/13249/1 13242/13250/1 13243/13251/1 13244/13252/1 +f 13245/13253/1 13246/13254/1 13247/13255/1 13248/13256/1 +f 13249/13257/1 13250/13258/1 13251/13259/1 13252/13260/1 +f 13253/13261/1 13254/13262/1 13255/13263/1 13256/13264/1 +f 13257/13265/1 13258/13266/1 13259/13267/1 13260/13268/1 +f 13261/13269/1 13262/13270/1 13263/13271/1 13264/13272/1 +f 13265/13273/1 13266/13274/1 13267/13275/1 13268/13276/1 +f 13269/13277/1 13270/13278/1 13271/13279/1 13272/13280/1 +f 13273/13281/1 13274/13282/1 13275/13283/1 13276/13284/1 +f 13277/13285/1 13278/13286/1 13279/13287/1 13280/13288/1 +f 13281/13289/1 13282/13290/1 13283/13291/1 13284/13292/1 +f 13285/13293/1 13286/13294/1 13287/13295/1 13288/13296/1 +f 13289/13297/1 13290/13298/1 13291/13299/1 13292/13300/1 +f 13293/13301/1 13294/13302/1 13295/13303/1 13296/13304/1 +f 13297/13305/1 13298/13306/1 13299/13307/1 13300/13308/1 +f 13301/13309/1 13302/13310/1 13303/13311/1 13304/13312/1 +f 13305/13313/1 13306/13314/1 13307/13315/1 13308/13316/1 +f 13309/13317/1 13310/13318/1 13311/13319/1 13312/13320/1 +f 13313/13321/1 13314/13322/1 13315/13323/1 13316/13324/1 +f 13317/13325/1 13318/13326/1 13319/13327/1 13320/13328/1 +f 13321/13329/1 13322/13330/1 13323/13331/1 13324/13332/1 +f 13325/13333/1 13326/13334/1 13327/13335/1 13328/13336/1 +f 13329/13337/1 13330/13338/1 13331/13339/1 13332/13340/1 +f 13333/13341/1 13334/13342/1 13335/13343/1 13336/13344/1 +f 13337/13345/1 13338/13346/1 13339/13347/1 13340/13348/1 +f 13341/13349/1 13342/13350/1 13343/13351/1 13344/13352/1 +f 13345/13353/1 13346/13354/1 13347/13355/1 13348/13356/1 +f 13349/13357/1 13350/13358/1 13351/13359/1 13352/13360/1 +f 13353/13361/1 13354/13362/1 13355/13363/1 13356/13364/1 +f 13357/13365/1 13358/13366/1 13359/13367/1 13360/13368/1 +f 13361/13369/1 13362/13370/1 13363/13371/1 13364/13372/1 +f 13365/13373/1 13366/13374/1 13367/13375/1 13368/13376/1 +f 13369/13377/1 13370/13378/1 13371/13379/1 13372/13380/1 +f 13373/13381/1 13374/13382/1 13375/13383/1 13376/13384/1 +f 13377/13385/1 13378/13386/1 13379/13387/1 13380/13388/1 +f 13381/13389/1 13382/13390/1 13383/13391/1 13384/13392/1 +f 13385/13393/1 13386/13394/1 13387/13395/1 13388/13396/1 +f 13389/13397/1 13390/13398/1 13391/13399/1 13392/13400/1 +f 13393/13401/1 13394/13402/1 13395/13403/1 13396/13404/1 +f 13397/13405/1 13398/13406/1 13399/13407/1 13400/13408/1 +f 13401/13409/1 13402/13410/1 13403/13411/1 13404/13412/1 +f 13405/13413/1 13406/13414/1 13407/13415/1 13408/13416/1 +f 13409/13417/1 13410/13418/1 13411/13419/1 13412/13420/1 +f 13413/13421/1 13414/13422/1 13415/13423/1 13416/13424/1 +f 13417/13425/1 13418/13426/1 13419/13427/1 13420/13428/1 +f 13421/13429/1 13422/13430/1 13423/13431/1 13424/13432/1 +f 13425/13433/1 13426/13434/1 13427/13435/1 13428/13436/1 +f 13429/13437/1 13430/13438/1 13431/13439/1 13432/13440/1 +f 13433/13441/1 13434/13442/1 13435/13443/1 13436/13444/1 +f 13437/13445/1 13438/13446/1 13439/13447/1 13440/13448/1 +f 13441/13449/1 13442/13450/1 13443/13451/1 13444/13452/1 +f 13445/13453/1 13446/13454/1 13447/13455/1 13448/13456/1 +f 13449/13457/1 13450/13458/1 13451/13459/1 13452/13460/1 +f 13453/13461/1 13454/13462/1 13455/13463/1 13456/13464/1 +f 13457/13465/1 13458/13466/1 13459/13467/1 13460/13468/1 +f 13461/13469/1 13462/13470/1 13463/13471/1 13464/13472/1 +f 13465/13473/1 13466/13474/1 13467/13475/1 13468/13476/1 +f 13469/13477/1 13470/13478/1 13471/13479/1 13472/13480/1 +f 13473/13481/1 13474/13482/1 13475/13483/1 13476/13484/1 +f 13477/13485/1 13478/13486/1 13479/13487/1 13480/13488/1 +f 13481/13489/1 13482/13490/1 13483/13491/1 13484/13492/1 +f 13485/13493/1 13486/13494/1 13487/13495/1 13488/13496/1 +f 13489/13497/1 13490/13498/1 13491/13499/1 13492/13500/1 +f 13493/13501/1 13494/13502/1 13495/13503/1 13496/13504/1 +f 13497/13505/1 13498/13506/1 13499/13507/1 13500/13508/1 +f 13501/13509/1 13502/13510/1 13503/13511/1 13504/13512/1 +f 13505/13513/1 13506/13514/1 13507/13515/1 13508/13516/1 +f 13509/13517/1 13510/13518/1 13511/13519/1 13512/13520/1 +f 13513/13521/1 13514/13522/1 13515/13523/1 13516/13524/1 +f 13517/13525/1 13518/13526/1 13519/13527/1 13520/13528/1 +f 13521/13529/1 13522/13530/1 13523/13531/1 13524/13532/1 +f 13525/13533/1 13526/13534/1 13527/13535/1 13528/13536/1 +f 13529/13537/1 13530/13538/1 13531/13539/1 13532/13540/1 +f 13533/13541/1 13534/13542/1 13535/13543/1 13536/13544/1 +f 13537/13545/1 13538/13546/1 13539/13547/1 13540/13548/1 +f 13541/13549/1 13542/13550/1 13543/13551/1 13544/13552/1 +f 13545/13553/1 13546/13554/1 13547/13555/1 13548/13556/1 +f 13549/13557/1 13550/13558/1 13551/13559/1 13552/13560/1 +f 13553/13561/1 13554/13562/1 13555/13563/1 13556/13564/1 +f 13557/13565/1 13558/13566/1 13559/13567/1 13560/13568/1 +f 13561/13569/1 13562/13570/1 13563/13571/1 13564/13572/1 +f 13565/13573/1 13566/13574/1 13567/13575/1 13568/13576/1 +f 13569/13577/1 13570/13578/1 13571/13579/1 13572/13580/1 +f 13573/13581/1 13574/13582/1 13575/13583/1 13576/13584/1 +f 13577/13585/1 13578/13586/1 13579/13587/1 13580/13588/1 +f 13581/13589/1 13582/13590/1 13583/13591/1 13584/13592/1 +f 13585/13593/1 13586/13594/1 13587/13595/1 13588/13596/1 +f 13589/13597/1 13590/13598/1 13591/13599/1 13592/13600/1 +f 13593/13601/1 13594/13602/1 13595/13603/1 13596/13604/1 +f 13597/13605/1 13598/13606/1 13599/13607/1 13600/13608/1 +f 13601/13609/1 13602/13610/1 13603/13611/1 13604/13612/1 +f 13605/13613/1 13606/13614/1 13607/13615/1 13608/13616/1 +f 13609/13617/1 13610/13618/1 13611/13619/1 13612/13620/1 +f 13613/13621/1 13614/13622/1 13615/13623/1 13616/13624/1 +f 13617/13625/1 13618/13626/1 13619/13627/1 13620/13628/1 +f 13621/13629/1 13622/13630/1 13623/13631/1 13624/13632/1 +f 13625/13633/1 13626/13634/1 13627/13635/1 13628/13636/1 +f 13629/13637/1 13630/13638/1 13631/13639/1 13632/13640/1 +f 13633/13641/1 13634/13642/1 13635/13643/1 13636/13644/1 +f 13637/13645/1 13638/13646/1 13639/13647/1 13640/13648/1 +f 13641/13649/1 13642/13650/1 13643/13651/1 13644/13652/1 +f 13645/13653/1 13646/13654/1 13647/13655/1 13648/13656/1 +f 13649/13657/1 13650/13658/1 13651/13659/1 13652/13660/1 +f 13653/13661/1 13654/13662/1 13655/13663/1 13656/13664/1 +f 13657/13665/1 13658/13666/1 13659/13667/1 13660/13668/1 +f 13661/13669/1 13662/13670/1 13663/13671/1 13664/13672/1 +f 13665/13673/1 13666/13674/1 13667/13675/1 13668/13676/1 +f 13669/13677/1 13670/13678/1 13671/13679/1 13672/13680/1 +f 13673/13681/1 13674/13682/1 13675/13683/1 13676/13684/1 +f 13677/13685/1 13678/13686/1 13679/13687/1 13680/13688/1 +f 13681/13689/1 13682/13690/1 13683/13691/1 13684/13692/1 +f 13685/13693/1 13686/13694/1 13687/13695/1 13688/13696/1 +f 13689/13697/1 13690/13698/1 13691/13699/1 13692/13700/1 +f 13693/13701/1 13694/13702/1 13695/13703/1 13696/13704/1 +f 13697/13705/1 13698/13706/1 13699/13707/1 13700/13708/1 +f 13701/13709/1 13702/13710/1 13703/13711/1 13704/13712/1 +f 13705/13713/1 13706/13714/1 13707/13715/1 13708/13716/1 +f 13709/13717/1 13710/13718/1 13711/13719/1 13712/13720/1 +f 13713/13721/1 13714/13722/1 13715/13723/1 13716/13724/1 +f 13717/13725/1 13718/13726/1 13719/13727/1 13720/13728/1 +f 13721/13729/1 13722/13730/1 13723/13731/1 13724/13732/1 +f 13725/13733/1 13726/13734/1 13727/13735/1 13728/13736/1 +f 13729/13737/1 13730/13738/1 13731/13739/1 13732/13740/1 +f 13733/13741/1 13734/13742/1 13735/13743/1 13736/13744/1 +f 13737/13745/1 13738/13746/1 13739/13747/1 13740/13748/1 +f 13741/13749/1 13742/13750/1 13743/13751/1 13744/13752/1 +f 13745/13753/1 13746/13754/1 13747/13755/1 13748/13756/1 +f 13749/13757/1 13750/13758/1 13751/13759/1 13752/13760/1 +f 13753/13761/1 13754/13762/1 13755/13763/1 13756/13764/1 +f 13757/13765/1 13758/13766/1 13759/13767/1 13760/13768/1 +f 13761/13769/1 13762/13770/1 13763/13771/1 13764/13772/1 +f 13765/13773/1 13766/13774/1 13767/13775/1 13768/13776/1 +f 13769/13777/1 13770/13778/1 13771/13779/1 13772/13780/1 +f 13773/13781/1 13774/13782/1 13775/13783/1 13776/13784/1 +f 13777/13785/1 13778/13786/1 13779/13787/1 13780/13788/1 +f 13781/13789/1 13782/13790/1 13783/13791/1 13784/13792/1 +f 13785/13793/1 13786/13794/1 13787/13795/1 13788/13796/1 +f 13789/13797/1 13790/13798/1 13791/13799/1 13792/13800/1 +f 13793/13801/1 13794/13802/1 13795/13803/1 13796/13804/1 +f 13797/13805/1 13798/13806/1 13799/13807/1 13800/13808/1 +f 13801/13809/1 13802/13810/1 13803/13811/1 13804/13812/1 +f 13805/13813/1 13806/13814/1 13807/13815/1 13808/13816/1 +f 13809/13817/1 13810/13818/1 13811/13819/1 13812/13820/1 +f 13813/13821/1 13814/13822/1 13815/13823/1 13816/13824/1 +f 13817/13825/1 13818/13826/1 13819/13827/1 13820/13828/1 +f 13821/13829/1 13822/13830/1 13823/13831/1 13824/13832/1 +f 13825/13833/1 13826/13834/1 13827/13835/1 13828/13836/1 +f 13829/13837/1 13830/13838/1 13831/13839/1 13832/13840/1 +f 13833/13841/1 13834/13842/1 13835/13843/1 13836/13844/1 +f 13837/13845/1 13838/13846/1 13839/13847/1 13840/13848/1 +f 13841/13849/1 13842/13850/1 13843/13851/1 13844/13852/1 +f 13845/13853/1 13846/13854/1 13847/13855/1 13848/13856/1 +f 13849/13857/1 13850/13858/1 13851/13859/1 13852/13860/1 +f 13853/13861/1 13854/13862/1 13855/13863/1 13856/13864/1 +f 13857/13865/1 13858/13866/1 13859/13867/1 13860/13868/1 +f 13861/13869/1 13862/13870/1 13863/13871/1 13864/13872/1 +f 13865/13873/1 13866/13874/1 13867/13875/1 13868/13876/1 +f 13869/13877/1 13870/13878/1 13871/13879/1 13872/13880/1 +f 13873/13881/1 13874/13882/1 13875/13883/1 13876/13884/1 +f 13877/13885/1 13878/13886/1 13879/13887/1 13880/13888/1 +f 13881/13889/1 13882/13890/1 13883/13891/1 13884/13892/1 +f 13885/13893/1 13886/13894/1 13887/13895/1 13888/13896/1 +f 13889/13897/1 13890/13898/1 13891/13899/1 13892/13900/1 +f 13893/13901/1 13894/13902/1 13895/13903/1 13896/13904/1 +f 13897/13905/1 13898/13906/1 13899/13907/1 13900/13908/1 +f 13901/13909/1 13902/13910/1 13903/13911/1 13904/13912/1 +f 13905/13913/1 13906/13914/1 13907/13915/1 13908/13916/1 +f 13909/13917/1 13910/13918/1 13911/13919/1 13912/13920/1 +f 13913/13921/1 13914/13922/1 13915/13923/1 13916/13924/1 +f 13917/13925/1 13918/13926/1 13919/13927/1 13920/13928/1 +f 13921/13929/1 13922/13930/1 13923/13931/1 13924/13932/1 +f 13925/13933/1 13926/13934/1 13927/13935/1 13928/13936/1 +f 13929/13937/1 13930/13938/1 13931/13939/1 13932/13940/1 +f 13933/13941/1 13934/13942/1 13935/13943/1 13936/13944/1 +f 13937/13945/1 13938/13946/1 13939/13947/1 13940/13948/1 +f 13941/13949/1 13942/13950/1 13943/13951/1 13944/13952/1 +f 13945/13953/1 13946/13954/1 13947/13955/1 13948/13956/1 +f 13949/13957/1 13950/13958/1 13951/13959/1 13952/13960/1 +f 13953/13961/1 13954/13962/1 13955/13963/1 13956/13964/1 +f 13957/13965/1 13958/13966/1 13959/13967/1 13960/13968/1 +f 13961/13969/1 13962/13970/1 13963/13971/1 13964/13972/1 +f 13965/13973/1 13966/13974/1 13967/13975/1 13968/13976/1 +f 13969/13977/1 13970/13978/1 13971/13979/1 13972/13980/1 +f 13973/13981/1 13974/13982/1 13975/13983/1 13976/13984/1 +f 13977/13985/1 13978/13986/1 13979/13987/1 13980/13988/1 +f 13981/13989/1 13982/13990/1 13983/13991/1 13984/13992/1 +f 13985/13993/1 13986/13994/1 13987/13995/1 13988/13996/1 +f 13989/13997/1 13990/13998/1 13991/13999/1 13992/14000/1 +f 13993/14001/1 13994/14002/1 13995/14003/1 13996/14004/1 +f 13997/14005/1 13998/14006/1 13999/14007/1 14000/14008/1 +f 14001/14009/1 14002/14010/1 14003/14011/1 14004/14012/1 +f 14005/14013/1 14006/14014/1 14007/14015/1 14008/14016/1 +f 14009/14017/1 14010/14018/1 14011/14019/1 14012/14020/1 +f 14013/14021/1 14014/14022/1 14015/14023/1 14016/14024/1 +f 14017/14025/1 14018/14026/1 14019/14027/1 14020/14028/1 +f 14021/14029/1 14022/14030/1 14023/14031/1 14024/14032/1 +f 14025/14033/1 14026/14034/1 14027/14035/1 14028/14036/1 +f 14029/14037/1 14030/14038/1 14031/14039/1 14032/14040/1 +f 14033/14041/1 14034/14042/1 14035/14043/1 14036/14044/1 +f 14037/14045/1 14038/14046/1 14039/14047/1 14040/14048/1 +f 14041/14049/1 14042/14050/1 14043/14051/1 14044/14052/1 +f 14045/14053/1 14046/14054/1 14047/14055/1 14048/14056/1 +f 14049/14057/1 14050/14058/1 14051/14059/1 14052/14060/1 +f 14053/14061/1 14054/14062/1 14055/14063/1 14056/14064/1 +f 14057/14065/1 14058/14066/1 14059/14067/1 14060/14068/1 +f 14061/14069/1 14062/14070/1 14063/14071/1 14064/14072/1 +f 14065/14073/1 14066/14074/1 14067/14075/1 14068/14076/1 +f 14069/14077/1 14070/14078/1 14071/14079/1 14072/14080/1 +f 14073/14081/1 14074/14082/1 14075/14083/1 14076/14084/1 +f 14077/14085/1 14078/14086/1 14079/14087/1 14080/14088/1 +f 14081/14089/1 14082/14090/1 14083/14091/1 14084/14092/1 +f 14085/14093/1 14086/14094/1 14087/14095/1 14088/14096/1 +f 14089/14097/1 14090/14098/1 14091/14099/1 14092/14100/1 +f 14093/14101/1 14094/14102/1 14095/14103/1 14096/14104/1 +f 14097/14105/1 14098/14106/1 14099/14107/1 14100/14108/1 +f 14101/14109/1 14102/14110/1 14103/14111/1 14104/14112/1 +f 14105/14113/1 14106/14114/1 14107/14115/1 14108/14116/1 +f 14109/14117/1 14110/14118/1 14111/14119/1 14112/14120/1 +f 14113/14121/1 14114/14122/1 14115/14123/1 14116/14124/1 +f 14117/14125/1 14118/14126/1 14119/14127/1 14120/14128/1 +f 14121/14129/1 14122/14130/1 14123/14131/1 14124/14132/1 +f 14125/14133/1 14126/14134/1 14127/14135/1 14128/14136/1 +f 14129/14137/1 14130/14138/1 14131/14139/1 14132/14140/1 +f 14133/14141/1 14134/14142/1 14135/14143/1 14136/14144/1 +f 14137/14145/1 14138/14146/1 14139/14147/1 14140/14148/1 +f 14141/14149/1 14142/14150/1 14143/14151/1 14144/14152/1 +f 14145/14153/1 14146/14154/1 14147/14155/1 14148/14156/1 +f 14149/14157/1 14150/14158/1 14151/14159/1 14152/14160/1 +f 14153/14161/1 14154/14162/1 14155/14163/1 14156/14164/1 +f 14157/14165/1 14158/14166/1 14159/14167/1 14160/14168/1 +f 14161/14169/1 14162/14170/1 14163/14171/1 14164/14172/1 +f 14165/14173/1 14166/14174/1 14167/14175/1 14168/14176/1 +f 14169/14177/1 14170/14178/1 14171/14179/1 14172/14180/1 +f 14173/14181/1 14174/14182/1 14175/14183/1 14176/14184/1 +f 14177/14185/1 14178/14186/1 14179/14187/1 14180/14188/1 +f 14181/14189/1 14182/14190/1 14183/14191/1 14184/14192/1 +f 14185/14193/1 14186/14194/1 14187/14195/1 14188/14196/1 +f 14189/14197/1 14190/14198/1 14191/14199/1 14192/14200/1 +f 14193/14201/1 14194/14202/1 14195/14203/1 14196/14204/1 +f 14197/14205/1 14198/14206/1 14199/14207/1 14200/14208/1 +f 14201/14209/1 14202/14210/1 14203/14211/1 14204/14212/1 +f 14205/14213/1 14206/14214/1 14207/14215/1 14208/14216/1 +f 14209/14217/1 14210/14218/1 14211/14219/1 14212/14220/1 +f 14213/14221/1 14214/14222/1 14215/14223/1 14216/14224/1 +f 14217/14225/1 14218/14226/1 14219/14227/1 14220/14228/1 +f 14221/14229/1 14222/14230/1 14223/14231/1 14224/14232/1 +f 14225/14233/1 14226/14234/1 14227/14235/1 14228/14236/1 +f 14229/14237/1 14230/14238/1 14231/14239/1 14232/14240/1 +f 14233/14241/1 14234/14242/1 14235/14243/1 14236/14244/1 +f 14237/14245/1 14238/14246/1 14239/14247/1 14240/14248/1 +f 14241/14249/1 14242/14250/1 14243/14251/1 14244/14252/1 +f 14245/14253/1 14246/14254/1 14247/14255/1 14248/14256/1 +f 14249/14257/1 14250/14258/1 14251/14259/1 14252/14260/1 +f 14253/14261/1 14254/14262/1 14255/14263/1 14256/14264/1 +f 14257/14265/1 14258/14266/1 14259/14267/1 14260/14268/1 +f 14261/14269/1 14262/14270/1 14263/14271/1 14264/14272/1 +f 14265/14273/1 14266/14274/1 14267/14275/1 14268/14276/1 +f 14269/14277/1 14270/14278/1 14271/14279/1 14272/14280/1 +f 14273/14281/1 14274/14282/1 14275/14283/1 14276/14284/1 +f 14277/14285/1 14278/14286/1 14279/14287/1 14280/14288/1 +f 14281/14289/1 14282/14290/1 14283/14291/1 14284/14292/1 +f 14285/14293/1 14286/14294/1 14287/14295/1 14288/14296/1 +f 14289/14297/1 14290/14298/1 14291/14299/1 14292/14300/1 +f 14293/14301/1 14294/14302/1 14295/14303/1 14296/14304/1 +f 14297/14305/1 14298/14306/1 14299/14307/1 14300/14308/1 +f 14301/14309/1 14302/14310/1 14303/14311/1 14304/14312/1 +f 14305/14313/1 14306/14314/1 14307/14315/1 14308/14316/1 +f 14309/14317/1 14310/14318/1 14311/14319/1 14312/14320/1 +f 14313/14321/1 14314/14322/1 14315/14323/1 14316/14324/1 +f 14317/14325/1 14318/14326/1 14319/14327/1 14320/14328/1 +f 14321/14329/1 14322/14330/1 14323/14331/1 14324/14332/1 +f 14325/14333/1 14326/14334/1 14327/14335/1 14328/14336/1 +f 14329/14337/1 14330/14338/1 14331/14339/1 14332/14340/1 +f 14333/14341/1 14334/14342/1 14335/14343/1 14336/14344/1 +f 14337/14345/1 14338/14346/1 14339/14347/1 14340/14348/1 +f 14341/14349/1 14342/14350/1 14343/14351/1 14344/14352/1 +f 14345/14353/1 14346/14354/1 14347/14355/1 14348/14356/1 +f 14349/14357/1 14350/14358/1 14351/14359/1 14352/14360/1 +f 14353/14361/1 14354/14362/1 14355/14363/1 14356/14364/1 +f 14357/14365/1 14358/14366/1 14359/14367/1 14360/14368/1 +f 14361/14369/1 14362/14370/1 14363/14371/1 14364/14372/1 +f 14365/14373/1 14366/14374/1 14367/14375/1 14368/14376/1 +f 14369/14377/1 14370/14378/1 14371/14379/1 14372/14380/1 +f 14373/14381/1 14374/14382/1 14375/14383/1 14376/14384/1 +f 14377/14385/1 14378/14386/1 14379/14387/1 14380/14388/1 +f 14381/14389/1 14382/14390/1 14383/14391/1 14384/14392/1 +f 14385/14393/1 14386/14394/1 14387/14395/1 14388/14396/1 +f 14389/14397/1 14390/14398/1 14391/14399/1 14392/14400/1 +f 14393/14401/1 14394/14402/1 14395/14403/1 14396/14404/1 +f 14397/14405/1 14398/14406/1 14399/14407/1 14400/14408/1 +f 14401/14409/1 14402/14410/1 14403/14411/1 14404/14412/1 +f 14405/14413/1 14406/14414/1 14407/14415/1 14408/14416/1 +f 14409/14417/1 14410/14418/1 14411/14419/1 14412/14420/1 +f 14413/14421/1 14414/14422/1 14415/14423/1 14416/14424/1 +f 14417/14425/1 14418/14426/1 14419/14427/1 14420/14428/1 +f 14421/14429/1 14422/14430/1 14423/14431/1 14424/14432/1 +f 14425/14433/1 14426/14434/1 14427/14435/1 14428/14436/1 +f 14429/14437/1 14430/14438/1 14431/14439/1 14432/14440/1 +f 14433/14441/1 14434/14442/1 14435/14443/1 14436/14444/1 +f 14437/14445/1 14438/14446/1 14439/14447/1 14440/14448/1 +f 14441/14449/1 14442/14450/1 14443/14451/1 14444/14452/1 +f 14445/14453/1 14446/14454/1 14447/14455/1 14448/14456/1 +f 14449/14457/1 14450/14458/1 14451/14459/1 14452/14460/1 +f 14453/14461/1 14454/14462/1 14455/14463/1 14456/14464/1 +f 14457/14465/1 14458/14466/1 14459/14467/1 14460/14468/1 +f 14461/14469/1 14462/14470/1 14463/14471/1 14464/14472/1 +f 14465/14473/1 14466/14474/1 14467/14475/1 14468/14476/1 +f 14469/14477/1 14470/14478/1 14471/14479/1 14472/14480/1 +f 14473/14481/1 14474/14482/1 14475/14483/1 14476/14484/1 +f 14477/14485/1 14478/14486/1 14479/14487/1 14480/14488/1 +f 14481/14489/1 14482/14490/1 14483/14491/1 14484/14492/1 +f 14485/14493/1 14486/14494/1 14487/14495/1 14488/14496/1 +f 14489/14497/1 14490/14498/1 14491/14499/1 14492/14500/1 +f 14493/14501/1 14494/14502/1 14495/14503/1 14496/14504/1 +f 14497/14505/1 14498/14506/1 14499/14507/1 14500/14508/1 +f 14501/14509/1 14502/14510/1 14503/14511/1 14504/14512/1 +f 14505/14513/1 14506/14514/1 14507/14515/1 14508/14516/1 +f 14509/14517/1 14510/14518/1 14511/14519/1 14512/14520/1 +f 14513/14521/1 14514/14522/1 14515/14523/1 14516/14524/1 +f 14517/14525/1 14518/14526/1 14519/14527/1 14520/14528/1 +f 14521/14529/1 14522/14530/1 14523/14531/1 14524/14532/1 +f 14525/14533/1 14526/14534/1 14527/14535/1 14528/14536/1 +f 14529/14537/1 14530/14538/1 14531/14539/1 14532/14540/1 +f 14533/14541/1 14534/14542/1 14535/14543/1 14536/14544/1 +f 14537/14545/1 14538/14546/1 14539/14547/1 14540/14548/1 +f 14541/14549/1 14542/14550/1 14543/14551/1 14544/14552/1 +f 14545/14553/1 14546/14554/1 14547/14555/1 14548/14556/1 +f 14549/14557/1 14550/14558/1 14551/14559/1 14552/14560/1 +f 14553/14561/1 14554/14562/1 14555/14563/1 14556/14564/1 +f 14557/14565/1 14558/14566/1 14559/14567/1 14560/14568/1 +f 14561/14569/1 14562/14570/1 14563/14571/1 14564/14572/1 +f 14565/14573/1 14566/14574/1 14567/14575/1 14568/14576/1 +f 14569/14577/1 14570/14578/1 14571/14579/1 14572/14580/1 +f 14573/14581/1 14574/14582/1 14575/14583/1 14576/14584/1 +f 14577/14585/1 14578/14586/1 14579/14587/1 14580/14588/1 +f 14581/14589/1 14582/14590/1 14583/14591/1 14584/14592/1 +f 14585/14593/1 14586/14594/1 14587/14595/1 14588/14596/1 +f 14589/14597/1 14590/14598/1 14591/14599/1 14592/14600/1 +f 14593/14601/1 14594/14602/1 14595/14603/1 14596/14604/1 +f 14597/14605/1 14598/14606/1 14599/14607/1 14600/14608/1 +f 14601/14609/1 14602/14610/1 14603/14611/1 14604/14612/1 +f 14605/14613/1 14606/14614/1 14607/14615/1 14608/14616/1 +f 14609/14617/1 14610/14618/1 14611/14619/1 14612/14620/1 +f 14613/14621/1 14614/14622/1 14615/14623/1 14616/14624/1 +f 14617/14625/1 14618/14626/1 14619/14627/1 14620/14628/1 +f 14621/14629/1 14622/14630/1 14623/14631/1 14624/14632/1 +f 14625/14633/1 14626/14634/1 14627/14635/1 14628/14636/1 +f 14629/14637/1 14630/14638/1 14631/14639/1 14632/14640/1 +f 14633/14641/1 14634/14642/1 14635/14643/1 14636/14644/1 +f 14637/14645/1 14638/14646/1 14639/14647/1 14640/14648/1 +f 14641/14649/1 14642/14650/1 14643/14651/1 14644/14652/1 +f 14645/14653/1 14646/14654/1 14647/14655/1 14648/14656/1 +f 14649/14657/1 14650/14658/1 14651/14659/1 14652/14660/1 +f 14653/14661/1 14654/14662/1 14655/14663/1 14656/14664/1 +f 14657/14665/1 14658/14666/1 14659/14667/1 14660/14668/1 +f 14661/14669/1 14662/14670/1 14663/14671/1 14664/14672/1 +f 14665/14673/1 14666/14674/1 14667/14675/1 14668/14676/1 +f 14669/14677/1 14670/14678/1 14671/14679/1 14672/14680/1 +f 14673/14681/1 14674/14682/1 14675/14683/1 14676/14684/1 +f 14677/14685/1 14678/14686/1 14679/14687/1 14680/14688/1 +f 14681/14689/1 14682/14690/1 14683/14691/1 14684/14692/1 +f 14685/14693/1 14686/14694/1 14687/14695/1 14688/14696/1 +f 14689/14697/1 14690/14698/1 14691/14699/1 14692/14700/1 +f 14693/14701/1 14694/14702/1 14695/14703/1 14696/14704/1 +f 14697/14705/1 14698/14706/1 14699/14707/1 14700/14708/1 +f 14701/14709/1 14702/14710/1 14703/14711/1 14704/14712/1 +f 14705/14713/1 14706/14714/1 14707/14715/1 14708/14716/1 +f 14709/14717/1 14710/14718/1 14711/14719/1 14712/14720/1 +f 14713/14721/1 14714/14722/1 14715/14723/1 14716/14724/1 +f 14717/14725/1 14718/14726/1 14719/14727/1 14720/14728/1 +f 14721/14729/1 14722/14730/1 14723/14731/1 14724/14732/1 +f 14725/14733/1 14726/14734/1 14727/14735/1 14728/14736/1 +f 14729/14737/1 14730/14738/1 14731/14739/1 14732/14740/1 +f 14733/14741/1 14734/14742/1 14735/14743/1 14736/14744/1 +f 14737/14745/1 14738/14746/1 14739/14747/1 14740/14748/1 +f 14741/14749/1 14742/14750/1 14743/14751/1 14744/14752/1 +f 14745/14753/1 14746/14754/1 14747/14755/1 14748/14756/1 +f 14749/14757/1 14750/14758/1 14751/14759/1 14752/14760/1 +f 14753/14761/1 14754/14762/1 14755/14763/1 14756/14764/1 +f 14757/14765/1 14758/14766/1 14759/14767/1 14760/14768/1 +f 14761/14769/1 14762/14770/1 14763/14771/1 14764/14772/1 +f 14765/14773/1 14766/14774/1 14767/14775/1 14768/14776/1 +f 14769/14777/1 14770/14778/1 14771/14779/1 14772/14780/1 +f 14773/14781/1 14774/14782/1 14775/14783/1 14776/14784/1 +f 14777/14785/1 14778/14786/1 14779/14787/1 14780/14788/1 +f 14781/14789/1 14782/14790/1 14783/14791/1 14784/14792/1 +f 14785/14793/1 14786/14794/1 14787/14795/1 14788/14796/1 +f 14789/14797/1 14790/14798/1 14791/14799/1 14792/14800/1 +f 14793/14801/1 14794/14802/1 14795/14803/1 14796/14804/1 +f 14797/14805/1 14798/14806/1 14799/14807/1 14800/14808/1 +f 14801/14809/1 14802/14810/1 14803/14811/1 14804/14812/1 +f 14805/14813/1 14806/14814/1 14807/14815/1 14808/14816/1 +f 14809/14817/1 14810/14818/1 14811/14819/1 14812/14820/1 +f 14813/14821/1 14814/14822/1 14815/14823/1 14816/14824/1 +f 14817/14825/1 14818/14826/1 14819/14827/1 14820/14828/1 +f 14821/14829/1 14822/14830/1 14823/14831/1 14824/14832/1 +f 14825/14833/1 14826/14834/1 14827/14835/1 14828/14836/1 +f 14829/14837/1 14830/14838/1 14831/14839/1 14832/14840/1 +f 14833/14841/1 14834/14842/1 14835/14843/1 14836/14844/1 +f 14837/14845/1 14838/14846/1 14839/14847/1 14840/14848/1 +f 14841/14849/1 14842/14850/1 14843/14851/1 14844/14852/1 +f 14845/14853/1 14846/14854/1 14847/14855/1 14848/14856/1 +f 14849/14857/1 14850/14858/1 14851/14859/1 14852/14860/1 +f 14853/14861/1 14854/14862/1 14855/14863/1 14856/14864/1 +f 14857/14865/1 14858/14866/1 14859/14867/1 14860/14868/1 +f 14861/14869/1 14862/14870/1 14863/14871/1 14864/14872/1 +f 14865/14873/1 14866/14874/1 14867/14875/1 14868/14876/1 +f 14869/14877/1 14870/14878/1 14871/14879/1 14872/14880/1 +f 14873/14881/1 14874/14882/1 14875/14883/1 14876/14884/1 +f 14877/14885/1 14878/14886/1 14879/14887/1 14880/14888/1 +f 14881/14889/1 14882/14890/1 14883/14891/1 14884/14892/1 +f 14885/14893/1 14886/14894/1 14887/14895/1 14888/14896/1 +f 14889/14897/1 14890/14898/1 14891/14899/1 14892/14900/1 +f 14893/14901/1 14894/14902/1 14895/14903/1 14896/14904/1 +f 14897/14905/1 14898/14906/1 14899/14907/1 14900/14908/1 +f 14901/14909/1 14902/14910/1 14903/14911/1 14904/14912/1 +f 14905/14913/1 14906/14914/1 14907/14915/1 14908/14916/1 +f 14909/14917/1 14910/14918/1 14911/14919/1 14912/14920/1 +f 14913/14921/1 14914/14922/1 14915/14923/1 14916/14924/1 +f 14917/14925/1 14918/14926/1 14919/14927/1 14920/14928/1 +f 14921/14929/1 14922/14930/1 14923/14931/1 14924/14932/1 +f 14925/14933/1 14926/14934/1 14927/14935/1 14928/14936/1 +f 14929/14937/1 14930/14938/1 14931/14939/1 14932/14940/1 +f 14933/14941/1 14934/14942/1 14935/14943/1 14936/14944/1 +f 14937/14945/1 14938/14946/1 14939/14947/1 14940/14948/1 +f 14941/14949/1 14942/14950/1 14943/14951/1 14944/14952/1 +f 14945/14953/1 14946/14954/1 14947/14955/1 14948/14956/1 +f 14949/14957/1 14950/14958/1 14951/14959/1 14952/14960/1 +f 14953/14961/1 14954/14962/1 14955/14963/1 14956/14964/1 +f 14957/14965/1 14958/14966/1 14959/14967/1 14960/14968/1 +f 14961/14969/1 14962/14970/1 14963/14971/1 14964/14972/1 +f 14965/14973/1 14966/14974/1 14967/14975/1 14968/14976/1 +f 14969/14977/1 14970/14978/1 14971/14979/1 14972/14980/1 +f 14973/14981/1 14974/14982/1 14975/14983/1 14976/14984/1 +f 14977/14985/1 14978/14986/1 14979/14987/1 14980/14988/1 +f 14981/14989/1 14982/14990/1 14983/14991/1 14984/14992/1 +f 14985/14993/1 14986/14994/1 14987/14995/1 14988/14996/1 +f 14989/14997/1 14990/14998/1 14991/14999/1 14992/15000/1 +f 14993/15001/1 14994/15002/1 14995/15003/1 14996/15004/1 +f 14997/15005/1 14998/15006/1 14999/15007/1 15000/15008/1 +f 15001/15009/1 15002/15010/1 15003/15011/1 15004/15012/1 +f 15005/15013/1 15006/15014/1 15007/15015/1 15008/15016/1 +f 15009/15017/1 15010/15018/1 15011/15019/1 15012/15020/1 +f 15013/15021/1 15014/15022/1 15015/15023/1 15016/15024/1 +f 15017/15025/1 15018/15026/1 15019/15027/1 15020/15028/1 +f 15021/15029/1 15022/15030/1 15023/15031/1 15024/15032/1 +f 15025/15033/1 15026/15034/1 15027/15035/1 15028/15036/1 +f 15029/15037/1 15030/15038/1 15031/15039/1 15032/15040/1 +f 15033/15041/1 15034/15042/1 15035/15043/1 15036/15044/1 +f 15037/15045/1 15038/15046/1 15039/15047/1 15040/15048/1 +f 15041/15049/1 15042/15050/1 15043/15051/1 15044/15052/1 +f 15045/15053/1 15046/15054/1 15047/15055/1 15048/15056/1 +f 15049/15057/1 15050/15058/1 15051/15059/1 15052/15060/1 +f 15053/15061/1 15054/15062/1 15055/15063/1 15056/15064/1 +f 15057/15065/1 15058/15066/1 15059/15067/1 15060/15068/1 +f 15061/15069/1 15062/15070/1 15063/15071/1 15064/15072/1 +f 15065/15073/1 15066/15074/1 15067/15075/1 15068/15076/1 +f 15069/15077/1 15070/15078/1 15071/15079/1 15072/15080/1 +f 15073/15081/1 15074/15082/1 15075/15083/1 15076/15084/1 +f 15077/15085/1 15078/15086/1 15079/15087/1 15080/15088/1 +f 15081/15089/1 15082/15090/1 15083/15091/1 15084/15092/1 +f 15085/15093/1 15086/15094/1 15087/15095/1 15088/15096/1 +f 15089/15097/1 15090/15098/1 15091/15099/1 15092/15100/1 +f 15093/15101/1 15094/15102/1 15095/15103/1 15096/15104/1 +f 15097/15105/1 15098/15106/1 15099/15107/1 15100/15108/1 +f 15101/15109/1 15102/15110/1 15103/15111/1 15104/15112/1 +f 15105/15113/1 15106/15114/1 15107/15115/1 15108/15116/1 +f 15109/15117/1 15110/15118/1 15111/15119/1 15112/15120/1 +f 15113/15121/1 15114/15122/1 15115/15123/1 15116/15124/1 +f 15117/15125/1 15118/15126/1 15119/15127/1 15120/15128/1 +f 15121/15129/1 15122/15130/1 15123/15131/1 15124/15132/1 +f 15125/15133/1 15126/15134/1 15127/15135/1 15128/15136/1 +f 15129/15137/1 15130/15138/1 15131/15139/1 15132/15140/1 +f 15133/15141/1 15134/15142/1 15135/15143/1 15136/15144/1 +f 15137/15145/1 15138/15146/1 15139/15147/1 15140/15148/1 +f 15141/15149/1 15142/15150/1 15143/15151/1 15144/15152/1 +f 15145/15153/1 15146/15154/1 15147/15155/1 15148/15156/1 +f 15149/15157/1 15150/15158/1 15151/15159/1 15152/15160/1 +f 15153/15161/1 15154/15162/1 15155/15163/1 15156/15164/1 +f 15157/15165/1 15158/15166/1 15159/15167/1 15160/15168/1 +f 15161/15169/1 15162/15170/1 15163/15171/1 15164/15172/1 +f 15165/15173/1 15166/15174/1 15167/15175/1 15168/15176/1 +f 15169/15177/1 15170/15178/1 15171/15179/1 15172/15180/1 +f 15173/15181/1 15174/15182/1 15175/15183/1 15176/15184/1 +f 15177/15185/1 15178/15186/1 15179/15187/1 15180/15188/1 +f 15181/15189/1 15182/15190/1 15183/15191/1 15184/15192/1 +f 15185/15193/1 15186/15194/1 15187/15195/1 15188/15196/1 +f 15189/15197/1 15190/15198/1 15191/15199/1 15192/15200/1 +f 15193/15201/1 15194/15202/1 15195/15203/1 15196/15204/1 +f 15197/15205/1 15198/15206/1 15199/15207/1 15200/15208/1 +f 15201/15209/1 15202/15210/1 15203/15211/1 15204/15212/1 +f 15205/15213/1 15206/15214/1 15207/15215/1 15208/15216/1 +f 15209/15217/1 15210/15218/1 15211/15219/1 15212/15220/1 +f 15213/15221/1 15214/15222/1 15215/15223/1 15216/15224/1 +f 15217/15225/1 15218/15226/1 15219/15227/1 15220/15228/1 +f 15221/15229/1 15222/15230/1 15223/15231/1 15224/15232/1 +f 15225/15233/1 15226/15234/1 15227/15235/1 15228/15236/1 +f 15229/15237/1 15230/15238/1 15231/15239/1 15232/15240/1 +f 15233/15241/1 15234/15242/1 15235/15243/1 15236/15244/1 +f 15237/15245/1 15238/15246/1 15239/15247/1 15240/15248/1 +f 15241/15249/1 15242/15250/1 15243/15251/1 15244/15252/1 +f 15245/15253/1 15246/15254/1 15247/15255/1 15248/15256/1 +f 15249/15257/1 15250/15258/1 15251/15259/1 15252/15260/1 +f 15253/15261/1 15254/15262/1 15255/15263/1 15256/15264/1 +f 15257/15265/1 15258/15266/1 15259/15267/1 15260/15268/1 +f 15261/15269/1 15262/15270/1 15263/15271/1 15264/15272/1 +f 15265/15273/1 15266/15274/1 15267/15275/1 15268/15276/1 +f 15269/15277/1 15270/15278/1 15271/15279/1 15272/15280/1 +f 15273/15281/1 15274/15282/1 15275/15283/1 15276/15284/1 +f 15277/15285/1 15278/15286/1 15279/15287/1 15280/15288/1 +f 15281/15289/1 15282/15290/1 15283/15291/1 15284/15292/1 +f 15285/15293/1 15286/15294/1 15287/15295/1 15288/15296/1 +f 15289/15297/1 15290/15298/1 15291/15299/1 15292/15300/1 +f 15293/15301/1 15294/15302/1 15295/15303/1 15296/15304/1 +f 15297/15305/1 15298/15306/1 15299/15307/1 15300/15308/1 +f 15301/15309/1 15302/15310/1 15303/15311/1 15304/15312/1 +f 15305/15313/1 15306/15314/1 15307/15315/1 15308/15316/1 +f 15309/15317/1 15310/15318/1 15311/15319/1 15312/15320/1 +f 15313/15321/1 15314/15322/1 15315/15323/1 15316/15324/1 +f 15317/15325/1 15318/15326/1 15319/15327/1 15320/15328/1 +f 15321/15329/1 15322/15330/1 15323/15331/1 15324/15332/1 +f 15325/15333/1 15326/15334/1 15327/15335/1 15328/15336/1 +f 15329/15337/1 15330/15338/1 15331/15339/1 15332/15340/1 +f 15333/15341/1 15334/15342/1 15335/15343/1 15336/15344/1 +f 15337/15345/1 15338/15346/1 15339/15347/1 15340/15348/1 +f 15341/15349/1 15342/15350/1 15343/15351/1 15344/15352/1 +f 15345/15353/1 15346/15354/1 15347/15355/1 15348/15356/1 +f 15349/15357/1 15350/15358/1 15351/15359/1 15352/15360/1 +f 15353/15361/1 15354/15362/1 15355/15363/1 15356/15364/1 +f 15357/15365/1 15358/15366/1 15359/15367/1 15360/15368/1 +f 15361/15369/1 15362/15370/1 15363/15371/1 15364/15372/1 +f 15365/15373/1 15366/15374/1 15367/15375/1 15368/15376/1 +f 15369/15377/1 15370/15378/1 15371/15379/1 15372/15380/1 +f 15373/15381/1 15374/15382/1 15375/15383/1 15376/15384/1 +f 15377/15385/1 15378/15386/1 15379/15387/1 15380/15388/1 +f 15381/15389/1 15382/15390/1 15383/15391/1 15384/15392/1 +f 15385/15393/1 15386/15394/1 15387/15395/1 15388/15396/1 +f 15389/15397/1 15390/15398/1 15391/15399/1 15392/15400/1 +f 15393/15401/1 15394/15402/1 15395/15403/1 15396/15404/1 +f 15397/15405/1 15398/15406/1 15399/15407/1 15400/15408/1 +f 15401/15409/1 15402/15410/1 15403/15411/1 15404/15412/1 +f 15405/15413/1 15406/15414/1 15407/15415/1 15408/15416/1 +f 15409/15417/1 15410/15418/1 15411/15419/1 15412/15420/1 +f 15413/15421/1 15414/15422/1 15415/15423/1 15416/15424/1 +f 15417/15425/1 15418/15426/1 15419/15427/1 15420/15428/1 +f 15421/15429/1 15422/15430/1 15423/15431/1 15424/15432/1 +f 15425/15433/1 15426/15434/1 15427/15435/1 15428/15436/1 +f 15429/15437/1 15430/15438/1 15431/15439/1 15432/15440/1 +f 15433/15441/1 15434/15442/1 15435/15443/1 15436/15444/1 +f 15437/15445/1 15438/15446/1 15439/15447/1 15440/15448/1 +f 15441/15449/1 15442/15450/1 15443/15451/1 15444/15452/1 +f 15445/15453/1 15446/15454/1 15447/15455/1 15448/15456/1 +f 15449/15457/1 15450/15458/1 15451/15459/1 15452/15460/1 +f 15453/15461/1 15454/15462/1 15455/15463/1 15456/15464/1 +f 15457/15465/1 15458/15466/1 15459/15467/1 15460/15468/1 +f 15461/15469/1 15462/15470/1 15463/15471/1 15464/15472/1 +f 15465/15473/1 15466/15474/1 15467/15475/1 15468/15476/1 +f 15469/15477/1 15470/15478/1 15471/15479/1 15472/15480/1 +f 15473/15481/1 15474/15482/1 15475/15483/1 15476/15484/1 +f 15477/15485/1 15478/15486/1 15479/15487/1 15480/15488/1 +f 15481/15489/1 15482/15490/1 15483/15491/1 15484/15492/1 +f 15485/15493/1 15486/15494/1 15487/15495/1 15488/15496/1 +f 15489/15497/1 15490/15498/1 15491/15499/1 15492/15500/1 +f 15493/15501/1 15494/15502/1 15495/15503/1 15496/15504/1 +f 15497/15505/1 15498/15506/1 15499/15507/1 15500/15508/1 +f 15501/15509/1 15502/15510/1 15503/15511/1 15504/15512/1 +f 15505/15513/1 15506/15514/1 15507/15515/1 15508/15516/1 +f 15509/15517/1 15510/15518/1 15511/15519/1 15512/15520/1 +f 15513/15521/1 15514/15522/1 15515/15523/1 15516/15524/1 +f 15517/15525/1 15518/15526/1 15519/15527/1 15520/15528/1 +f 15521/15529/1 15522/15530/1 15523/15531/1 15524/15532/1 +f 15525/15533/1 15526/15534/1 15527/15535/1 15528/15536/1 +f 15529/15537/1 15530/15538/1 15531/15539/1 15532/15540/1 +f 15533/15541/1 15534/15542/1 15535/15543/1 15536/15544/1 +f 15537/15545/1 15538/15546/1 15539/15547/1 15540/15548/1 +f 15541/15549/1 15542/15550/1 15543/15551/1 15544/15552/1 +f 15545/15553/1 15546/15554/1 15547/15555/1 15548/15556/1 +f 15549/15557/1 15550/15558/1 15551/15559/1 15552/15560/1 +f 15553/15561/1 15554/15562/1 15555/15563/1 15556/15564/1 +f 15557/15565/1 15558/15566/1 15559/15567/1 15560/15568/1 +f 15561/15569/1 15562/15570/1 15563/15571/1 15564/15572/1 +f 15565/15573/1 15566/15574/1 15567/15575/1 15568/15576/1 +f 15569/15577/1 15570/15578/1 15571/15579/1 15572/15580/1 +f 15573/15581/1 15574/15582/1 15575/15583/1 15576/15584/1 +f 15577/15585/1 15578/15586/1 15579/15587/1 15580/15588/1 +f 15581/15589/1 15582/15590/1 15583/15591/1 15584/15592/1 +f 15585/15593/1 15586/15594/1 15587/15595/1 15588/15596/1 +f 15589/15597/1 15590/15598/1 15591/15599/1 15592/15600/1 +f 15593/15601/1 15594/15602/1 15595/15603/1 15596/15604/1 +f 15597/15605/1 15598/15606/1 15599/15607/1 15600/15608/1 +f 15601/15609/1 15602/15610/1 15603/15611/1 15604/15612/1 +f 15605/15613/1 15606/15614/1 15607/15615/1 15608/15616/1 +f 15609/15617/1 15610/15618/1 15611/15619/1 15612/15620/1 +f 15613/15621/1 15614/15622/1 15615/15623/1 15616/15624/1 +f 15617/15625/1 15618/15626/1 15619/15627/1 15620/15628/1 +f 15621/15629/1 15622/15630/1 15623/15631/1 15624/15632/1 +f 15625/15633/1 15626/15634/1 15627/15635/1 15628/15636/1 +f 15629/15637/1 15630/15638/1 15631/15639/1 15632/15640/1 +f 15633/15641/1 15634/15642/1 15635/15643/1 15636/15644/1 +f 15637/15645/1 15638/15646/1 15639/15647/1 15640/15648/1 +f 15641/15649/1 15642/15650/1 15643/15651/1 15644/15652/1 +f 15645/15653/1 15646/15654/1 15647/15655/1 15648/15656/1 +f 15649/15657/1 15650/15658/1 15651/15659/1 15652/15660/1 +f 15653/15661/1 15654/15662/1 15655/15663/1 15656/15664/1 +f 15657/15665/1 15658/15666/1 15659/15667/1 15660/15668/1 +f 15661/15669/1 15662/15670/1 15663/15671/1 15664/15672/1 +f 15665/15673/1 15666/15674/1 15667/15675/1 15668/15676/1 +f 15669/15677/1 15670/15678/1 15671/15679/1 15672/15680/1 +f 15673/15681/1 15674/15682/1 15675/15683/1 15676/15684/1 +f 15677/15685/1 15678/15686/1 15679/15687/1 15680/15688/1 +f 15681/15689/1 15682/15690/1 15683/15691/1 15684/15692/1 +f 15685/15693/1 15686/15694/1 15687/15695/1 15688/15696/1 +f 15689/15697/1 15690/15698/1 15691/15699/1 15692/15700/1 +f 15693/15701/1 15694/15702/1 15695/15703/1 15696/15704/1 +f 15697/15705/1 15698/15706/1 15699/15707/1 15700/15708/1 +f 15701/15709/1 15702/15710/1 15703/15711/1 15704/15712/1 +f 15705/15713/1 15706/15714/1 15707/15715/1 15708/15716/1 +f 15709/15717/1 15710/15718/1 15711/15719/1 15712/15720/1 +f 15713/15721/1 15714/15722/1 15715/15723/1 15716/15724/1 +f 15717/15725/1 15718/15726/1 15719/15727/1 15720/15728/1 +f 15721/15729/1 15722/15730/1 15723/15731/1 15724/15732/1 +f 15725/15733/1 15726/15734/1 15727/15735/1 15728/15736/1 +f 15729/15737/1 15730/15738/1 15731/15739/1 15732/15740/1 +f 15733/15741/1 15734/15742/1 15735/15743/1 15736/15744/1 +f 15737/15745/1 15738/15746/1 15739/15747/1 15740/15748/1 +f 15741/15749/1 15742/15750/1 15743/15751/1 15744/15752/1 +f 15745/15753/1 15746/15754/1 15747/15755/1 15748/15756/1 +f 15749/15757/1 15750/15758/1 15751/15759/1 15752/15760/1 +f 15753/15761/1 15754/15762/1 15755/15763/1 15756/15764/1 +f 15757/15765/1 15758/15766/1 15759/15767/1 15760/15768/1 +f 15761/15769/1 15762/15770/1 15763/15771/1 15764/15772/1 +f 15765/15773/1 15766/15774/1 15767/15775/1 15768/15776/1 +f 15769/15777/1 15770/15778/1 15771/15779/1 15772/15780/1 +f 15773/15781/1 15774/15782/1 15775/15783/1 15776/15784/1 +f 15777/15785/1 15778/15786/1 15779/15787/1 15780/15788/1 +f 15781/15789/1 15782/15790/1 15783/15791/1 15784/15792/1 +f 15785/15793/1 15786/15794/1 15787/15795/1 15788/15796/1 +f 15789/15797/1 15790/15798/1 15791/15799/1 15792/15800/1 +f 15793/15801/1 15794/15802/1 15795/15803/1 15796/15804/1 +f 15797/15805/1 15798/15806/1 15799/15807/1 15800/15808/1 +f 15801/15809/1 15802/15810/1 15803/15811/1 15804/15812/1 +f 15805/15813/1 15806/15814/1 15807/15815/1 15808/15816/1 +f 15809/15817/1 15810/15818/1 15811/15819/1 15812/15820/1 +f 15813/15821/1 15814/15822/1 15815/15823/1 15816/15824/1 +f 15817/15825/1 15818/15826/1 15819/15827/1 15820/15828/1 +f 15821/15829/1 15822/15830/1 15823/15831/1 15824/15832/1 +f 15825/15833/1 15826/15834/1 15827/15835/1 15828/15836/1 +f 15829/15837/1 15830/15838/1 15831/15839/1 15832/15840/1 +f 15833/15841/1 15834/15842/1 15835/15843/1 15836/15844/1 +f 15837/15845/1 15838/15846/1 15839/15847/1 15840/15848/1 +f 15841/15849/1 15842/15850/1 15843/15851/1 15844/15852/1 +f 15845/15853/1 15846/15854/1 15847/15855/1 15848/15856/1 +f 15849/15857/1 15850/15858/1 15851/15859/1 15852/15860/1 +f 15853/15861/1 15854/15862/1 15855/15863/1 15856/15864/1 +f 15857/15865/1 15858/15866/1 15859/15867/1 15860/15868/1 +f 15861/15869/1 15862/15870/1 15863/15871/1 15864/15872/1 +f 15865/15873/1 15866/15874/1 15867/15875/1 15868/15876/1 +f 15869/15877/1 15870/15878/1 15871/15879/1 15872/15880/1 +f 15873/15881/1 15874/15882/1 15875/15883/1 15876/15884/1 +f 15877/15885/1 15878/15886/1 15879/15887/1 15880/15888/1 +f 15881/15889/1 15882/15890/1 15883/15891/1 15884/15892/1 +f 15885/15893/1 15886/15894/1 15887/15895/1 15888/15896/1 +f 15889/15897/1 15890/15898/1 15891/15899/1 15892/15900/1 +f 15893/15901/1 15894/15902/1 15895/15903/1 15896/15904/1 +f 15897/15905/1 15898/15906/1 15899/15907/1 15900/15908/1 +f 15901/15909/1 15902/15910/1 15903/15911/1 15904/15912/1 +f 15905/15913/1 15906/15914/1 15907/15915/1 15908/15916/1 +f 15909/15917/1 15910/15918/1 15911/15919/1 15912/15920/1 +f 15913/15921/1 15914/15922/1 15915/15923/1 15916/15924/1 +f 15917/15925/1 15918/15926/1 15919/15927/1 15920/15928/1 +f 15921/15929/1 15922/15930/1 15923/15931/1 15924/15932/1 +f 15925/15933/1 15926/15934/1 15927/15935/1 15928/15936/1 +f 15929/15937/1 15930/15938/1 15931/15939/1 15932/15940/1 +f 15933/15941/1 15934/15942/1 15935/15943/1 15936/15944/1 +f 15937/15945/1 15938/15946/1 15939/15947/1 15940/15948/1 +f 15941/15949/1 15942/15950/1 15943/15951/1 15944/15952/1 +f 15945/15953/1 15946/15954/1 15947/15955/1 15948/15956/1 +f 15949/15957/1 15950/15958/1 15951/15959/1 15952/15960/1 +f 15953/15961/1 15954/15962/1 15955/15963/1 15956/15964/1 +f 15957/15965/1 15958/15966/1 15959/15967/1 15960/15968/1 +f 15961/15969/1 15962/15970/1 15963/15971/1 15964/15972/1 +f 15965/15973/1 15966/15974/1 15967/15975/1 15968/15976/1 +f 15969/15977/1 15970/15978/1 15971/15979/1 15972/15980/1 +f 15973/15981/1 15974/15982/1 15975/15983/1 15976/15984/1 +f 15977/15985/1 15978/15986/1 15979/15987/1 15980/15988/1 +f 15981/15989/1 15982/15990/1 15983/15991/1 15984/15992/1 +f 15985/15993/1 15986/15994/1 15987/15995/1 15988/15996/1 +f 15989/15997/1 15990/15998/1 15991/15999/1 15992/16000/1 +f 15993/16001/1 15994/16002/1 15995/16003/1 15996/16004/1 +f 15997/16005/1 15998/16006/1 15999/16007/1 16000/16008/1 +f 16001/16009/1 16002/16010/1 16003/16011/1 16004/16012/1 +f 16005/16013/1 16006/16014/1 16007/16015/1 16008/16016/1 +f 16009/16017/1 16010/16018/1 16011/16019/1 16012/16020/1 +f 16013/16021/1 16014/16022/1 16015/16023/1 16016/16024/1 +f 16017/16025/1 16018/16026/1 16019/16027/1 16020/16028/1 +f 16021/16029/1 16022/16030/1 16023/16031/1 16024/16032/1 +f 16025/16033/1 16026/16034/1 16027/16035/1 16028/16036/1 +f 16029/16037/1 16030/16038/1 16031/16039/1 16032/16040/1 +f 16033/16041/1 16034/16042/1 16035/16043/1 16036/16044/1 +f 16037/16045/1 16038/16046/1 16039/16047/1 16040/16048/1 +f 16041/16049/1 16042/16050/1 16043/16051/1 16044/16052/1 +f 16045/16053/1 16046/16054/1 16047/16055/1 16048/16056/1 +f 16049/16057/1 16050/16058/1 16051/16059/1 16052/16060/1 +f 16053/16061/1 16054/16062/1 16055/16063/1 16056/16064/1 +f 16057/16065/1 16058/16066/1 16059/16067/1 16060/16068/1 +f 16061/16069/1 16062/16070/1 16063/16071/1 16064/16072/1 +f 16065/16073/1 16066/16074/1 16067/16075/1 16068/16076/1 +f 16069/16077/1 16070/16078/1 16071/16079/1 16072/16080/1 +f 16073/16081/1 16074/16082/1 16075/16083/1 16076/16084/1 +f 16077/16085/1 16078/16086/1 16079/16087/1 16080/16088/1 +f 16081/16089/1 16082/16090/1 16083/16091/1 16084/16092/1 +f 16085/16093/1 16086/16094/1 16087/16095/1 16088/16096/1 +f 16089/16097/1 16090/16098/1 16091/16099/1 16092/16100/1 +f 16093/16101/1 16094/16102/1 16095/16103/1 16096/16104/1 +f 16097/16105/1 16098/16106/1 16099/16107/1 16100/16108/1 +f 16101/16109/1 16102/16110/1 16103/16111/1 16104/16112/1 +f 16105/16113/1 16106/16114/1 16107/16115/1 16108/16116/1 +f 16109/16117/1 16110/16118/1 16111/16119/1 16112/16120/1 +f 16113/16121/1 16114/16122/1 16115/16123/1 16116/16124/1 +f 16117/16125/1 16118/16126/1 16119/16127/1 16120/16128/1 +f 16121/16129/1 16122/16130/1 16123/16131/1 16124/16132/1 +f 16125/16133/1 16126/16134/1 16127/16135/1 16128/16136/1 +f 16129/16137/1 16130/16138/1 16131/16139/1 16132/16140/1 +f 16133/16141/1 16134/16142/1 16135/16143/1 16136/16144/1 +f 16137/16145/1 16138/16146/1 16139/16147/1 16140/16148/1 +f 16141/16149/1 16142/16150/1 16143/16151/1 16144/16152/1 +f 16145/16153/1 16146/16154/1 16147/16155/1 16148/16156/1 +f 16149/16157/1 16150/16158/1 16151/16159/1 16152/16160/1 +f 16153/16161/1 16154/16162/1 16155/16163/1 16156/16164/1 +f 16157/16165/1 16158/16166/1 16159/16167/1 16160/16168/1 +f 16161/16169/1 16162/16170/1 16163/16171/1 16164/16172/1 +f 16165/16173/1 16166/16174/1 16167/16175/1 16168/16176/1 +f 16169/16177/1 16170/16178/1 16171/16179/1 16172/16180/1 +f 16173/16181/1 16174/16182/1 16175/16183/1 16176/16184/1 +f 16177/16185/1 16178/16186/1 16179/16187/1 16180/16188/1 +f 16181/16189/1 16182/16190/1 16183/16191/1 16184/16192/1 +f 16185/16193/1 16186/16194/1 16187/16195/1 16188/16196/1 +f 16189/16197/1 16190/16198/1 16191/16199/1 16192/16200/1 +f 16193/16201/1 16194/16202/1 16195/16203/1 16196/16204/1 +f 16197/16205/1 16198/16206/1 16199/16207/1 16200/16208/1 +f 16201/16209/1 16202/16210/1 16203/16211/1 16204/16212/1 +f 16205/16213/1 16206/16214/1 16207/16215/1 16208/16216/1 +f 16209/16217/1 16210/16218/1 16211/16219/1 16212/16220/1 +f 16213/16221/1 16214/16222/1 16215/16223/1 16216/16224/1 +f 16217/16225/1 16218/16226/1 16219/16227/1 16220/16228/1 +f 16221/16229/1 16222/16230/1 16223/16231/1 16224/16232/1 +f 16225/16233/1 16226/16234/1 16227/16235/1 16228/16236/1 +f 16229/16237/1 16230/16238/1 16231/16239/1 16232/16240/1 +f 16233/16241/1 16234/16242/1 16235/16243/1 16236/16244/1 +f 16237/16245/1 16238/16246/1 16239/16247/1 16240/16248/1 +f 16241/16249/1 16242/16250/1 16243/16251/1 16244/16252/1 +f 16245/16253/1 16246/16254/1 16247/16255/1 16248/16256/1 +f 16249/16257/1 16250/16258/1 16251/16259/1 16252/16260/1 +f 16253/16261/1 16254/16262/1 16255/16263/1 16256/16264/1 +f 16257/16265/1 16258/16266/1 16259/16267/1 16260/16268/1 +f 16261/16269/1 16262/16270/1 16263/16271/1 16264/16272/1 +f 16265/16273/1 16266/16274/1 16267/16275/1 16268/16276/1 +f 16269/16277/1 16270/16278/1 16271/16279/1 16272/16280/1 +f 16273/16281/1 16274/16282/1 16275/16283/1 16276/16284/1 +f 16277/16285/1 16278/16286/1 16279/16287/1 16280/16288/1 +f 16281/16289/1 16282/16290/1 16283/16291/1 16284/16292/1 +f 16285/16293/1 16286/16294/1 16287/16295/1 16288/16296/1 +f 16289/16297/1 16290/16298/1 16291/16299/1 16292/16300/1 +f 16293/16301/1 16294/16302/1 16295/16303/1 16296/16304/1 +f 16297/16305/1 16298/16306/1 16299/16307/1 16300/16308/1 +f 16301/16309/1 16302/16310/1 16303/16311/1 16304/16312/1 +f 16305/16313/1 16306/16314/1 16307/16315/1 16308/16316/1 +f 16309/16317/1 16310/16318/1 16311/16319/1 16312/16320/1 +f 16313/16321/1 16314/16322/1 16315/16323/1 16316/16324/1 +f 16317/16325/1 16318/16326/1 16319/16327/1 16320/16328/1 +f 16321/16329/1 16322/16330/1 16323/16331/1 16324/16332/1 +f 16325/16333/1 16326/16334/1 16327/16335/1 16328/16336/1 +f 16329/16337/1 16330/16338/1 16331/16339/1 16332/16340/1 +f 16333/16341/1 16334/16342/1 16335/16343/1 16336/16344/1 +f 16337/16345/1 16338/16346/1 16339/16347/1 16340/16348/1 +f 16341/16349/1 16342/16350/1 16343/16351/1 16344/16352/1 +f 16345/16353/1 16346/16354/1 16347/16355/1 16348/16356/1 +f 16349/16357/1 16350/16358/1 16351/16359/1 16352/16360/1 +f 16353/16361/1 16354/16362/1 16355/16363/1 16356/16364/1 +f 16357/16365/1 16358/16366/1 16359/16367/1 16360/16368/1 +f 16361/16369/1 16362/16370/1 16363/16371/1 16364/16372/1 +f 16365/16373/1 16366/16374/1 16367/16375/1 16368/16376/1 +f 16369/16377/1 16370/16378/1 16371/16379/1 16372/16380/1 +f 16373/16381/1 16374/16382/1 16375/16383/1 16376/16384/1 +f 16377/16385/1 16378/16386/1 16379/16387/1 16380/16388/1 +f 16381/16389/1 16382/16390/1 16383/16391/1 16384/16392/1 +f 16385/16393/1 16386/16394/1 16387/16395/1 16388/16396/1 +f 16389/16397/1 16390/16398/1 16391/16399/1 16392/16400/1 +f 16393/16401/1 16394/16402/1 16395/16403/1 16396/16404/1 +f 16397/16405/1 16398/16406/1 16399/16407/1 16400/16408/1 +f 16401/16409/1 16402/16410/1 16403/16411/1 16404/16412/1 +f 16405/16413/1 16406/16414/1 16407/16415/1 16408/16416/1 +f 16409/16417/1 16410/16418/1 16411/16419/1 16412/16420/1 +f 16413/16421/1 16414/16422/1 16415/16423/1 16416/16424/1 +f 16417/16425/1 16418/16426/1 16419/16427/1 16420/16428/1 +f 16421/16429/1 16422/16430/1 16423/16431/1 16424/16432/1 +f 16425/16433/1 16426/16434/1 16427/16435/1 16428/16436/1 +f 16429/16437/1 16430/16438/1 16431/16439/1 16432/16440/1 +f 16433/16441/1 16434/16442/1 16435/16443/1 16436/16444/1 +f 16437/16445/1 16438/16446/1 16439/16447/1 16440/16448/1 +f 16441/16449/1 16442/16450/1 16443/16451/1 16444/16452/1 +f 16445/16453/1 16446/16454/1 16447/16455/1 16448/16456/1 +f 16449/16457/1 16450/16458/1 16451/16459/1 16452/16460/1 +f 16453/16461/1 16454/16462/1 16455/16463/1 16456/16464/1 +f 16457/16465/1 16458/16466/1 16459/16467/1 16460/16468/1 +f 16461/16469/1 16462/16470/1 16463/16471/1 16464/16472/1 +f 16465/16473/1 16466/16474/1 16467/16475/1 16468/16476/1 +f 16469/16477/1 16470/16478/1 16471/16479/1 16472/16480/1 +f 16473/16481/1 16474/16482/1 16475/16483/1 16476/16484/1 +f 16477/16485/1 16478/16486/1 16479/16487/1 16480/16488/1 +f 16481/16489/1 16482/16490/1 16483/16491/1 16484/16492/1 +f 16485/16493/1 16486/16494/1 16487/16495/1 16488/16496/1 +f 16489/16497/1 16490/16498/1 16491/16499/1 16492/16500/1 +f 16493/16501/1 16494/16502/1 16495/16503/1 16496/16504/1 +f 16497/16505/1 16498/16506/1 16499/16507/1 16500/16508/1 +f 16501/16509/1 16502/16510/1 16503/16511/1 16504/16512/1 +f 16505/16513/1 16506/16514/1 16507/16515/1 16508/16516/1 +f 16509/16517/1 16510/16518/1 16511/16519/1 16512/16520/1 +f 16513/16521/1 16514/16522/1 16515/16523/1 16516/16524/1 +f 16517/16525/1 16518/16526/1 16519/16527/1 16520/16528/1 +f 16521/16529/1 16522/16530/1 16523/16531/1 16524/16532/1 +f 16525/16533/1 16526/16534/1 16527/16535/1 16528/16536/1 +f 16529/16537/1 16530/16538/1 16531/16539/1 16532/16540/1 +f 16533/16541/1 16534/16542/1 16535/16543/1 16536/16544/1 +f 16537/16545/1 16538/16546/1 16539/16547/1 16540/16548/1 +f 16541/16549/1 16542/16550/1 16543/16551/1 16544/16552/1 +f 16545/16553/1 16546/16554/1 16547/16555/1 16548/16556/1 +f 16549/16557/1 16550/16558/1 16551/16559/1 16552/16560/1 +f 16553/16561/1 16554/16562/1 16555/16563/1 16556/16564/1 +f 16557/16565/1 16558/16566/1 16559/16567/1 16560/16568/1 +f 16561/16569/1 16562/16570/1 16563/16571/1 16564/16572/1 +f 16565/16573/1 16566/16574/1 16567/16575/1 16568/16576/1 +f 16569/16577/1 16570/16578/1 16571/16579/1 16572/16580/1 +f 16573/16581/1 16574/16582/1 16575/16583/1 16576/16584/1 +f 16577/16585/1 16578/16586/1 16579/16587/1 16580/16588/1 +f 16581/16589/1 16582/16590/1 16583/16591/1 16584/16592/1 +f 16585/16593/1 16586/16594/1 16587/16595/1 16588/16596/1 +f 16589/16597/1 16590/16598/1 16591/16599/1 16592/16600/1 +f 16593/16601/1 16594/16602/1 16595/16603/1 16596/16604/1 +f 16597/16605/1 16598/16606/1 16599/16607/1 16600/16608/1 +f 16601/16609/1 16602/16610/1 16603/16611/1 16604/16612/1 +f 16605/16613/1 16606/16614/1 16607/16615/1 16608/16616/1 +f 16609/16617/1 16610/16618/1 16611/16619/1 16612/16620/1 +f 16613/16621/1 16614/16622/1 16615/16623/1 16616/16624/1 +f 16617/16625/1 16618/16626/1 16619/16627/1 16620/16628/1 +f 16621/16629/1 16622/16630/1 16623/16631/1 16624/16632/1 +f 16625/16633/1 16626/16634/1 16627/16635/1 16628/16636/1 +f 16629/16637/1 16630/16638/1 16631/16639/1 16632/16640/1 +f 16633/16641/1 16634/16642/1 16635/16643/1 16636/16644/1 +f 16637/16645/1 16638/16646/1 16639/16647/1 16640/16648/1 +f 16641/16649/1 16642/16650/1 16643/16651/1 16644/16652/1 +f 16645/16653/1 16646/16654/1 16647/16655/1 16648/16656/1 +f 16649/16657/1 16650/16658/1 16651/16659/1 16652/16660/1 +f 16653/16661/1 16654/16662/1 16655/16663/1 16656/16664/1 +f 16657/16665/1 16658/16666/1 16659/16667/1 16660/16668/1 +f 16661/16669/1 16662/16670/1 16663/16671/1 16664/16672/1 +f 16665/16673/1 16666/16674/1 16667/16675/1 16668/16676/1 +f 16669/16677/1 16670/16678/1 16671/16679/1 16672/16680/1 +f 16673/16681/1 16674/16682/1 16675/16683/1 16676/16684/1 +f 16677/16685/1 16678/16686/1 16679/16687/1 16680/16688/1 +f 16681/16689/1 16682/16690/1 16683/16691/1 16684/16692/1 +f 16685/16693/1 16686/16694/1 16687/16695/1 16688/16696/1 +f 16689/16697/1 16690/16698/1 16691/16699/1 16692/16700/1 +f 16693/16701/1 16694/16702/1 16695/16703/1 16696/16704/1 +f 16697/16705/1 16698/16706/1 16699/16707/1 16700/16708/1 +f 16701/16709/1 16702/16710/1 16703/16711/1 16704/16712/1 +f 16705/16713/1 16706/16714/1 16707/16715/1 16708/16716/1 +f 16709/16717/1 16710/16718/1 16711/16719/1 16712/16720/1 +f 16713/16721/1 16714/16722/1 16715/16723/1 16716/16724/1 +f 16717/16725/1 16718/16726/1 16719/16727/1 16720/16728/1 +f 16721/16729/1 16722/16730/1 16723/16731/1 16724/16732/1 +f 16725/16733/1 16726/16734/1 16727/16735/1 16728/16736/1 +f 16729/16737/1 16730/16738/1 16731/16739/1 16732/16740/1 +f 16733/16741/1 16734/16742/1 16735/16743/1 16736/16744/1 +f 16737/16745/1 16738/16746/1 16739/16747/1 16740/16748/1 +f 16741/16749/1 16742/16750/1 16743/16751/1 16744/16752/1 +f 16745/16753/1 16746/16754/1 16747/16755/1 16748/16756/1 +f 16749/16757/1 16750/16758/1 16751/16759/1 16752/16760/1 +f 16753/16761/1 16754/16762/1 16755/16763/1 16756/16764/1 +f 16757/16765/1 16758/16766/1 16759/16767/1 16760/16768/1 +f 16761/16769/1 16762/16770/1 16763/16771/1 16764/16772/1 +f 16765/16773/1 16766/16774/1 16767/16775/1 16768/16776/1 +f 16769/16777/1 16770/16778/1 16771/16779/1 16772/16780/1 +f 16773/16781/1 16774/16782/1 16775/16783/1 16776/16784/1 +f 16777/16785/1 16778/16786/1 16779/16787/1 16780/16788/1 +f 16781/16789/1 16782/16790/1 16783/16791/1 16784/16792/1 +f 16785/16793/1 16786/16794/1 16787/16795/1 16788/16796/1 +f 16789/16797/1 16790/16798/1 16791/16799/1 16792/16800/1 +f 16793/16801/1 16794/16802/1 16795/16803/1 16796/16804/1 +f 16797/16805/1 16798/16806/1 16799/16807/1 16800/16808/1 +f 16801/16809/1 16802/16810/1 16803/16811/1 16804/16812/1 +f 16805/16813/1 16806/16814/1 16807/16815/1 16808/16816/1 +f 16809/16817/1 16810/16818/1 16811/16819/1 16812/16820/1 +f 16813/16821/1 16814/16822/1 16815/16823/1 16816/16824/1 +f 16817/16825/1 16818/16826/1 16819/16827/1 16820/16828/1 +f 16821/16829/1 16822/16830/1 16823/16831/1 16824/16832/1 +f 16825/16833/1 16826/16834/1 16827/16835/1 16828/16836/1 +f 16829/16837/1 16830/16838/1 16831/16839/1 16832/16840/1 +f 16833/16841/1 16834/16842/1 16835/16843/1 16836/16844/1 +f 16837/16845/1 16838/16846/1 16839/16847/1 16840/16848/1 +f 16841/16849/1 16842/16850/1 16843/16851/1 16844/16852/1 +f 16845/16853/1 16846/16854/1 16847/16855/1 16848/16856/1 +f 16849/16857/1 16850/16858/1 16851/16859/1 16852/16860/1 +f 16853/16861/1 16854/16862/1 16855/16863/1 16856/16864/1 +f 16857/16865/1 16858/16866/1 16859/16867/1 16860/16868/1 +f 16861/16869/1 16862/16870/1 16863/16871/1 16864/16872/1 +f 16865/16873/1 16866/16874/1 16867/16875/1 16868/16876/1 +f 16869/16877/1 16870/16878/1 16871/16879/1 16872/16880/1 +f 16873/16881/1 16874/16882/1 16875/16883/1 16876/16884/1 +f 16877/16885/1 16878/16886/1 16879/16887/1 16880/16888/1 +f 16881/16889/1 16882/16890/1 16883/16891/1 16884/16892/1 +f 16885/16893/1 16886/16894/1 16887/16895/1 16888/16896/1 +f 16889/16897/1 16890/16898/1 16891/16899/1 16892/16900/1 +f 16893/16901/1 16894/16902/1 16895/16903/1 16896/16904/1 +f 16897/16905/1 16898/16906/1 16899/16907/1 16900/16908/1 +f 16901/16909/1 16902/16910/1 16903/16911/1 16904/16912/1 +f 16905/16913/1 16906/16914/1 16907/16915/1 16908/16916/1 +f 16909/16917/1 16910/16918/1 16911/16919/1 16912/16920/1 +f 16913/16921/1 16914/16922/1 16915/16923/1 16916/16924/1 +f 16917/16925/1 16918/16926/1 16919/16927/1 16920/16928/1 +f 16921/16929/1 16922/16930/1 16923/16931/1 16924/16932/1 +f 16925/16933/1 16926/16934/1 16927/16935/1 16928/16936/1 +f 16929/16937/1 16930/16938/1 16931/16939/1 16932/16940/1 +f 16933/16941/1 16934/16942/1 16935/16943/1 16936/16944/1 +f 16937/16945/1 16938/16946/1 16939/16947/1 16940/16948/1 +f 16941/16949/1 16942/16950/1 16943/16951/1 16944/16952/1 +f 16945/16953/1 16946/16954/1 16947/16955/1 16948/16956/1 +f 16949/16957/1 16950/16958/1 16951/16959/1 16952/16960/1 +f 16953/16961/1 16954/16962/1 16955/16963/1 16956/16964/1 +f 16957/16965/1 16958/16966/1 16959/16967/1 16960/16968/1 +f 16961/16969/1 16962/16970/1 16963/16971/1 16964/16972/1 +f 16965/16973/1 16966/16974/1 16967/16975/1 16968/16976/1 +f 16969/16977/1 16970/16978/1 16971/16979/1 16972/16980/1 +f 16973/16981/1 16974/16982/1 16975/16983/1 16976/16984/1 +f 16977/16985/1 16978/16986/1 16979/16987/1 16980/16988/1 +f 16981/16989/1 16982/16990/1 16983/16991/1 16984/16992/1 +f 16985/16993/1 16986/16994/1 16987/16995/1 16988/16996/1 +f 16989/16997/1 16990/16998/1 16991/16999/1 16992/17000/1 +f 16993/17001/1 16994/17002/1 16995/17003/1 16996/17004/1 +f 16997/17005/1 16998/17006/1 16999/17007/1 17000/17008/1 +f 17001/17009/1 17002/17010/1 17003/17011/1 17004/17012/1 +f 17005/17013/1 17006/17014/1 17007/17015/1 17008/17016/1 +f 17009/17017/1 17010/17018/1 17011/17019/1 17012/17020/1 +f 17013/17021/1 17014/17022/1 17015/17023/1 17016/17024/1 +f 17017/17025/1 17018/17026/1 17019/17027/1 17020/17028/1 +f 17021/17029/1 17022/17030/1 17023/17031/1 17024/17032/1 +f 17025/17033/1 17026/17034/1 17027/17035/1 17028/17036/1 +f 17029/17037/1 17030/17038/1 17031/17039/1 17032/17040/1 +f 17033/17041/1 17034/17042/1 17035/17043/1 17036/17044/1 +f 17037/17045/1 17038/17046/1 17039/17047/1 17040/17048/1 +f 17041/17049/1 17042/17050/1 17043/17051/1 17044/17052/1 +f 17045/17053/1 17046/17054/1 17047/17055/1 17048/17056/1 +f 17049/17057/1 17050/17058/1 17051/17059/1 17052/17060/1 +f 17053/17061/1 17054/17062/1 17055/17063/1 17056/17064/1 +f 17057/17065/1 17058/17066/1 17059/17067/1 17060/17068/1 +f 17061/17069/1 17062/17070/1 17063/17071/1 17064/17072/1 +f 17065/17073/1 17066/17074/1 17067/17075/1 17068/17076/1 +f 17069/17077/1 17070/17078/1 17071/17079/1 17072/17080/1 +f 17073/17081/1 17074/17082/1 17075/17083/1 17076/17084/1 +f 17077/17085/1 17078/17086/1 17079/17087/1 17080/17088/1 +f 17081/17089/1 17082/17090/1 17083/17091/1 17084/17092/1 +f 17085/17093/1 17086/17094/1 17087/17095/1 17088/17096/1 +f 17089/17097/1 17090/17098/1 17091/17099/1 17092/17100/1 +f 17093/17101/1 17094/17102/1 17095/17103/1 17096/17104/1 +f 17097/17105/1 17098/17106/1 17099/17107/1 17100/17108/1 +f 17101/17109/1 17102/17110/1 17103/17111/1 17104/17112/1 +f 17105/17113/1 17106/17114/1 17107/17115/1 17108/17116/1 +f 17109/17117/1 17110/17118/1 17111/17119/1 17112/17120/1 +f 17113/17121/1 17114/17122/1 17115/17123/1 17116/17124/1 +f 17117/17125/1 17118/17126/1 17119/17127/1 17120/17128/1 +f 17121/17129/1 17122/17130/1 17123/17131/1 17124/17132/1 +f 17125/17133/1 17126/17134/1 17127/17135/1 17128/17136/1 +f 17129/17137/1 17130/17138/1 17131/17139/1 17132/17140/1 +f 17133/17141/1 17134/17142/1 17135/17143/1 17136/17144/1 +f 17137/17145/1 17138/17146/1 17139/17147/1 17140/17148/1 +f 17141/17149/1 17142/17150/1 17143/17151/1 17144/17152/1 +f 17145/17153/1 17146/17154/1 17147/17155/1 17148/17156/1 +f 17149/17157/1 17150/17158/1 17151/17159/1 17152/17160/1 +f 17153/17161/1 17154/17162/1 17155/17163/1 17156/17164/1 +f 17157/17165/1 17158/17166/1 17159/17167/1 17160/17168/1 +f 17161/17169/1 17162/17170/1 17163/17171/1 17164/17172/1 +f 17165/17173/1 17166/17174/1 17167/17175/1 17168/17176/1 +f 17169/17177/1 17170/17178/1 17171/17179/1 17172/17180/1 +f 17173/17181/1 17174/17182/1 17175/17183/1 17176/17184/1 +f 17177/17185/1 17178/17186/1 17179/17187/1 17180/17188/1 +f 17181/17189/1 17182/17190/1 17183/17191/1 17184/17192/1 +f 17185/17193/1 17186/17194/1 17187/17195/1 17188/17196/1 +f 17189/17197/1 17190/17198/1 17191/17199/1 17192/17200/1 +f 17193/17201/1 17194/17202/1 17195/17203/1 17196/17204/1 +f 17197/17205/1 17198/17206/1 17199/17207/1 17200/17208/1 +f 17201/17209/1 17202/17210/1 17203/17211/1 17204/17212/1 +f 17205/17213/1 17206/17214/1 17207/17215/1 17208/17216/1 +f 17209/17217/1 17210/17218/1 17211/17219/1 17212/17220/1 +f 17213/17221/1 17214/17222/1 17215/17223/1 17216/17224/1 +f 17217/17225/1 17218/17226/1 17219/17227/1 17220/17228/1 +f 17221/17229/1 17222/17230/1 17223/17231/1 17224/17232/1 +f 17225/17233/1 17226/17234/1 17227/17235/1 17228/17236/1 +f 17229/17237/1 17230/17238/1 17231/17239/1 17232/17240/1 +f 17233/17241/1 17234/17242/1 17235/17243/1 17236/17244/1 +f 17237/17245/1 17238/17246/1 17239/17247/1 17240/17248/1 +f 17241/17249/1 17242/17250/1 17243/17251/1 17244/17252/1 +f 17245/17253/1 17246/17254/1 17247/17255/1 17248/17256/1 +f 17249/17257/1 17250/17258/1 17251/17259/1 17252/17260/1 +f 17253/17261/1 17254/17262/1 17255/17263/1 17256/17264/1 +f 17257/17265/1 17258/17266/1 17259/17267/1 17260/17268/1 +f 17261/17269/1 17262/17270/1 17263/17271/1 17264/17272/1 +f 17265/17273/1 17266/17274/1 17267/17275/1 17268/17276/1 +f 17269/17277/1 17270/17278/1 17271/17279/1 17272/17280/1 +f 17273/17281/1 17274/17282/1 17275/17283/1 17276/17284/1 +f 17277/17285/1 17278/17286/1 17279/17287/1 17280/17288/1 +f 17281/17289/1 17282/17290/1 17283/17291/1 17284/17292/1 +f 17285/17293/1 17286/17294/1 17287/17295/1 17288/17296/1 +f 17289/17297/1 17290/17298/1 17291/17299/1 17292/17300/1 +f 17293/17301/1 17294/17302/1 17295/17303/1 17296/17304/1 +f 17297/17305/1 17298/17306/1 17299/17307/1 17300/17308/1 +f 17301/17309/1 17302/17310/1 17303/17311/1 17304/17312/1 +f 17305/17313/1 17306/17314/1 17307/17315/1 17308/17316/1 +f 17309/17317/1 17310/17318/1 17311/17319/1 17312/17320/1 +f 17313/17321/1 17314/17322/1 17315/17323/1 17316/17324/1 +f 17317/17325/1 17318/17326/1 17319/17327/1 17320/17328/1 +f 17321/17329/1 17322/17330/1 17323/17331/1 17324/17332/1 +f 17325/17333/1 17326/17334/1 17327/17335/1 17328/17336/1 +f 17329/17337/1 17330/17338/1 17331/17339/1 17332/17340/1 +f 17333/17341/1 17334/17342/1 17335/17343/1 17336/17344/1 +f 17337/17345/1 17338/17346/1 17339/17347/1 17340/17348/1 +f 17341/17349/1 17342/17350/1 17343/17351/1 17344/17352/1 +f 17345/17353/1 17346/17354/1 17347/17355/1 17348/17356/1 +f 17349/17357/1 17350/17358/1 17351/17359/1 17352/17360/1 +f 17353/17361/1 17354/17362/1 17355/17363/1 17356/17364/1 +f 17357/17365/1 17358/17366/1 17359/17367/1 17360/17368/1 +f 17361/17369/1 17362/17370/1 17363/17371/1 17364/17372/1 +f 17365/17373/1 17366/17374/1 17367/17375/1 17368/17376/1 +f 17369/17377/1 17370/17378/1 17371/17379/1 17372/17380/1 +f 17373/17381/1 17374/17382/1 17375/17383/1 17376/17384/1 +f 17377/17385/1 17378/17386/1 17379/17387/1 17380/17388/1 +f 17381/17389/1 17382/17390/1 17383/17391/1 17384/17392/1 +f 17385/17393/1 17386/17394/1 17387/17395/1 17388/17396/1 +f 17389/17397/1 17390/17398/1 17391/17399/1 17392/17400/1 +f 17393/17401/1 17394/17402/1 17395/17403/1 17396/17404/1 +f 17397/17405/1 17398/17406/1 17399/17407/1 17400/17408/1 +f 17401/17409/1 17402/17410/1 17403/17411/1 17404/17412/1 +f 17405/17413/1 17406/17414/1 17407/17415/1 17408/17416/1 +f 17409/17417/1 17410/17418/1 17411/17419/1 17412/17420/1 +f 17406/17414/1 17409/17417/1 17412/17420/1 17407/17415/1 +f 5127/5135/1 5124/5132/1 17409/17417/1 17406/17414/1 +f 5124/5132/1 5123/5131/1 17410/17418/1 17409/17417/1 +f 5158/5166/1 17405/17413/1 17408/17416/1 5159/5167/1 +f 5119/5127/1 5128/5136/1 17405/17413/1 5158/5166/1 +f 5128/5136/1 5127/5135/1 17406/17414/1 17405/17413/1 +f 5114/5122/1 17401/17409/1 17404/17412/1 5115/5123/1 +f 5159/5167/1 17408/17416/1 17401/17409/1 5114/5122/1 +f 17408/17416/1 17407/17415/1 17402/17410/1 17401/17409/1 +f 17394/17402/1 17397/17405/1 17400/17408/1 17395/17403/1 +f 5163/5171/1 5112/5120/1 17397/17405/1 17394/17402/1 +f 5112/5120/1 5111/5119/1 17398/17406/1 17397/17405/1 +f 5194/5202/1 17393/17401/1 17396/17404/1 5195/5203/1 +f 5107/5115/1 5164/5172/1 17393/17401/1 5194/5202/1 +f 5164/5172/1 5163/5171/1 17394/17402/1 17393/17401/1 +f 5102/5110/1 17389/17397/1 17392/17400/1 5103/5111/1 +f 5195/5203/1 17396/17404/1 17389/17397/1 5102/5110/1 +f 17396/17404/1 17395/17403/1 17390/17398/1 17389/17397/1 +f 17382/17390/1 17385/17393/1 17388/17396/1 17383/17391/1 +f 5199/5207/1 5100/5108/1 17385/17393/1 17382/17390/1 +f 5100/5108/1 5099/5107/1 17386/17394/1 17385/17393/1 +f 5230/5238/1 17381/17389/1 17384/17392/1 5231/5239/1 +f 5095/5103/1 5200/5208/1 17381/17389/1 5230/5238/1 +f 5200/5208/1 5199/5207/1 17382/17390/1 17381/17389/1 +f 5090/5098/1 17377/17385/1 17380/17388/1 5091/5099/1 +f 5231/5239/1 17384/17392/1 17377/17385/1 5090/5098/1 +f 17384/17392/1 17383/17391/1 17378/17386/1 17377/17385/1 +f 17370/17378/1 17373/17381/1 17376/17384/1 17371/17379/1 +f 5235/5243/1 5088/5096/1 17373/17381/1 17370/17378/1 +f 5088/5096/1 5087/5095/1 17374/17382/1 17373/17381/1 +f 5266/5274/1 17369/17377/1 17372/17380/1 5267/5275/1 +f 5083/5091/1 5236/5244/1 17369/17377/1 5266/5274/1 +f 5236/5244/1 5235/5243/1 17370/17378/1 17369/17377/1 +f 5078/5086/1 17365/17373/1 17368/17376/1 5079/5087/1 +f 5267/5275/1 17372/17380/1 17365/17373/1 5078/5086/1 +f 17372/17380/1 17371/17379/1 17366/17374/1 17365/17373/1 +f 17358/17366/1 17361/17369/1 17364/17372/1 17359/17367/1 +f 5271/5279/1 5076/5084/1 17361/17369/1 17358/17366/1 +f 5076/5084/1 5075/5083/1 17362/17370/1 17361/17369/1 +f 5302/5310/1 17357/17365/1 17360/17368/1 5303/5311/1 +f 5071/5079/1 5272/5280/1 17357/17365/1 5302/5310/1 +f 5272/5280/1 5271/5279/1 17358/17366/1 17357/17365/1 +f 5066/5074/1 17353/17361/1 17356/17364/1 5067/5075/1 +f 5303/5311/1 17360/17368/1 17353/17361/1 5066/5074/1 +f 17360/17368/1 17359/17367/1 17354/17362/1 17353/17361/1 +f 17346/17354/1 17349/17357/1 17352/17360/1 17347/17355/1 +f 5307/5315/1 5064/5072/1 17349/17357/1 17346/17354/1 +f 5064/5072/1 5063/5071/1 17350/17358/1 17349/17357/1 +f 5338/5346/1 17345/17353/1 17348/17356/1 5339/5347/1 +f 5059/5067/1 5308/5316/1 17345/17353/1 5338/5346/1 +f 5308/5316/1 5307/5315/1 17346/17354/1 17345/17353/1 +f 5054/5062/1 17341/17349/1 17344/17352/1 5055/5063/1 +f 5339/5347/1 17348/17356/1 17341/17349/1 5054/5062/1 +f 17348/17356/1 17347/17355/1 17342/17350/1 17341/17349/1 +f 17334/17342/1 17337/17345/1 17340/17348/1 17335/17343/1 +f 5343/5351/1 5052/5060/1 17337/17345/1 17334/17342/1 +f 5052/5060/1 5051/5059/1 17338/17346/1 17337/17345/1 +f 5374/5382/1 17333/17341/1 17336/17344/1 5375/5383/1 +f 5047/5055/1 5344/5352/1 17333/17341/1 5374/5382/1 +f 5344/5352/1 5343/5351/1 17334/17342/1 17333/17341/1 +f 5042/5050/1 17329/17337/1 17332/17340/1 5043/5051/1 +f 5375/5383/1 17336/17344/1 17329/17337/1 5042/5050/1 +f 17336/17344/1 17335/17343/1 17330/17338/1 17329/17337/1 +f 17322/17330/1 17325/17333/1 17328/17336/1 17323/17331/1 +f 5379/5387/1 5040/5048/1 17325/17333/1 17322/17330/1 +f 5040/5048/1 5039/5047/1 17326/17334/1 17325/17333/1 +f 5410/5418/1 17321/17329/1 17324/17332/1 5411/5419/1 +f 5035/5043/1 5380/5388/1 17321/17329/1 5410/5418/1 +f 5380/5388/1 5379/5387/1 17322/17330/1 17321/17329/1 +f 5030/5038/1 17317/17325/1 17320/17328/1 5031/5039/1 +f 5411/5419/1 17324/17332/1 17317/17325/1 5030/5038/1 +f 17324/17332/1 17323/17331/1 17318/17326/1 17317/17325/1 +f 17310/17318/1 17313/17321/1 17316/17324/1 17311/17319/1 +f 5415/5423/1 5028/5036/1 17313/17321/1 17310/17318/1 +f 5028/5036/1 5027/5035/1 17314/17322/1 17313/17321/1 +f 5446/5454/1 17309/17317/1 17312/17320/1 5447/5455/1 +f 5023/5031/1 5416/5424/1 17309/17317/1 5446/5454/1 +f 5416/5424/1 5415/5423/1 17310/17318/1 17309/17317/1 +f 5018/5026/1 17305/17313/1 17308/17316/1 5019/5027/1 +f 5447/5455/1 17312/17320/1 17305/17313/1 5018/5026/1 +f 17312/17320/1 17311/17319/1 17306/17314/1 17305/17313/1 +f 17298/17306/1 17301/17309/1 17304/17312/1 17299/17307/1 +f 5451/5459/1 5016/5024/1 17301/17309/1 17298/17306/1 +f 5016/5024/1 5015/5023/1 17302/17310/1 17301/17309/1 +f 5482/5490/1 17297/17305/1 17300/17308/1 5483/5491/1 +f 5011/5019/1 5452/5460/1 17297/17305/1 5482/5490/1 +f 5452/5460/1 5451/5459/1 17298/17306/1 17297/17305/1 +f 5006/5014/1 17293/17301/1 17296/17304/1 5007/5015/1 +f 5483/5491/1 17300/17308/1 17293/17301/1 5006/5014/1 +f 17300/17308/1 17299/17307/1 17294/17302/1 17293/17301/1 +f 17286/17294/1 17289/17297/1 17292/17300/1 17287/17295/1 +f 5487/5495/1 5004/5012/1 17289/17297/1 17286/17294/1 +f 5004/5012/1 5003/5011/1 17290/17298/1 17289/17297/1 +f 5518/5526/1 17285/17293/1 17288/17296/1 5519/5527/1 +f 4999/5007/1 5488/5496/1 17285/17293/1 5518/5526/1 +f 5488/5496/1 5487/5495/1 17286/17294/1 17285/17293/1 +f 4994/5002/1 17281/17289/1 17284/17292/1 4995/5003/1 +f 5519/5527/1 17288/17296/1 17281/17289/1 4994/5002/1 +f 17288/17296/1 17287/17295/1 17282/17290/1 17281/17289/1 +f 17274/17282/1 17277/17285/1 17280/17288/1 17275/17283/1 +f 5523/5531/1 4992/5000/1 17277/17285/1 17274/17282/1 +f 4992/5000/1 4991/4999/1 17278/17286/1 17277/17285/1 +f 5554/5562/1 17273/17281/1 17276/17284/1 5555/5563/1 +f 4987/4995/1 5524/5532/1 17273/17281/1 5554/5562/1 +f 5524/5532/1 5523/5531/1 17274/17282/1 17273/17281/1 +f 4982/4990/1 17269/17277/1 17272/17280/1 4983/4991/1 +f 5555/5563/1 17276/17284/1 17269/17277/1 4982/4990/1 +f 17276/17284/1 17275/17283/1 17270/17278/1 17269/17277/1 +f 17262/17270/1 17265/17273/1 17268/17276/1 17263/17271/1 +f 5559/5567/1 4980/4988/1 17265/17273/1 17262/17270/1 +f 4980/4988/1 4979/4987/1 17266/17274/1 17265/17273/1 +f 5590/5598/1 17261/17269/1 17264/17272/1 5591/5599/1 +f 4975/4983/1 5560/5568/1 17261/17269/1 5590/5598/1 +f 5560/5568/1 5559/5567/1 17262/17270/1 17261/17269/1 +f 4970/4978/1 17257/17265/1 17260/17268/1 4971/4979/1 +f 5591/5599/1 17264/17272/1 17257/17265/1 4970/4978/1 +f 17264/17272/1 17263/17271/1 17258/17266/1 17257/17265/1 +f 17250/17258/1 17253/17261/1 17256/17264/1 17251/17259/1 +f 5595/5603/1 4968/4976/1 17253/17261/1 17250/17258/1 +f 4968/4976/1 4967/4975/1 17254/17262/1 17253/17261/1 +f 5626/5634/1 17249/17257/1 17252/17260/1 5627/5635/1 +f 4963/4971/1 5596/5604/1 17249/17257/1 5626/5634/1 +f 5596/5604/1 5595/5603/1 17250/17258/1 17249/17257/1 +f 4958/4966/1 17245/17253/1 17248/17256/1 4959/4967/1 +f 5627/5635/1 17252/17260/1 17245/17253/1 4958/4966/1 +f 17252/17260/1 17251/17259/1 17246/17254/1 17245/17253/1 +f 17238/17246/1 17241/17249/1 17244/17252/1 17239/17247/1 +f 5631/5639/1 4956/4964/1 17241/17249/1 17238/17246/1 +f 4956/4964/1 4955/4963/1 17242/17250/1 17241/17249/1 +f 5662/5670/1 17237/17245/1 17240/17248/1 5663/5671/1 +f 4951/4959/1 5632/5640/1 17237/17245/1 5662/5670/1 +f 5632/5640/1 5631/5639/1 17238/17246/1 17237/17245/1 +f 4946/4954/1 17233/17241/1 17236/17244/1 4947/4955/1 +f 5663/5671/1 17240/17248/1 17233/17241/1 4946/4954/1 +f 17240/17248/1 17239/17247/1 17234/17242/1 17233/17241/1 +f 17226/17234/1 17229/17237/1 17232/17240/1 17227/17235/1 +f 5667/5675/1 4944/4952/1 17229/17237/1 17226/17234/1 +f 4944/4952/1 4943/4951/1 17230/17238/1 17229/17237/1 +f 5698/5706/1 17225/17233/1 17228/17236/1 5699/5707/1 +f 4939/4947/1 5668/5676/1 17225/17233/1 5698/5706/1 +f 5668/5676/1 5667/5675/1 17226/17234/1 17225/17233/1 +f 4934/4942/1 17221/17229/1 17224/17232/1 4935/4943/1 +f 5699/5707/1 17228/17236/1 17221/17229/1 4934/4942/1 +f 17228/17236/1 17227/17235/1 17222/17230/1 17221/17229/1 +f 17214/17222/1 17217/17225/1 17220/17228/1 17215/17223/1 +f 5703/5711/1 4932/4940/1 17217/17225/1 17214/17222/1 +f 4932/4940/1 4931/4939/1 17218/17226/1 17217/17225/1 +f 5734/5742/1 17213/17221/1 17216/17224/1 5735/5743/1 +f 4927/4935/1 5704/5712/1 17213/17221/1 5734/5742/1 +f 5704/5712/1 5703/5711/1 17214/17222/1 17213/17221/1 +f 4922/4930/1 17209/17217/1 17212/17220/1 4923/4931/1 +f 5735/5743/1 17216/17224/1 17209/17217/1 4922/4930/1 +f 17216/17224/1 17215/17223/1 17210/17218/1 17209/17217/1 +f 17202/17210/1 17205/17213/1 17208/17216/1 17203/17211/1 +f 5739/5747/1 4920/4928/1 17205/17213/1 17202/17210/1 +f 4920/4928/1 4919/4927/1 17206/17214/1 17205/17213/1 +f 5770/5778/1 17201/17209/1 17204/17212/1 5771/5779/1 +f 4915/4923/1 5740/5748/1 17201/17209/1 5770/5778/1 +f 5740/5748/1 5739/5747/1 17202/17210/1 17201/17209/1 +f 4910/4918/1 17197/17205/1 17200/17208/1 4911/4919/1 +f 5771/5779/1 17204/17212/1 17197/17205/1 4910/4918/1 +f 17204/17212/1 17203/17211/1 17198/17206/1 17197/17205/1 +f 17190/17198/1 17193/17201/1 17196/17204/1 17191/17199/1 +f 5775/5783/1 4908/4916/1 17193/17201/1 17190/17198/1 +f 4908/4916/1 4907/4915/1 17194/17202/1 17193/17201/1 +f 5806/5814/1 17189/17197/1 17192/17200/1 5807/5815/1 +f 4903/4911/1 5776/5784/1 17189/17197/1 5806/5814/1 +f 5776/5784/1 5775/5783/1 17190/17198/1 17189/17197/1 +f 4898/4906/1 17185/17193/1 17188/17196/1 4899/4907/1 +f 5807/5815/1 17192/17200/1 17185/17193/1 4898/4906/1 +f 17192/17200/1 17191/17199/1 17186/17194/1 17185/17193/1 +f 17178/17186/1 17181/17189/1 17184/17192/1 17179/17187/1 +f 5811/5819/1 4896/4904/1 17181/17189/1 17178/17186/1 +f 4896/4904/1 4895/4903/1 17182/17190/1 17181/17189/1 +f 5842/5850/1 17177/17185/1 17180/17188/1 5843/5851/1 +f 4891/4899/1 5812/5820/1 17177/17185/1 5842/5850/1 +f 5812/5820/1 5811/5819/1 17178/17186/1 17177/17185/1 +f 4886/4894/1 17173/17181/1 17176/17184/1 4887/4895/1 +f 5843/5851/1 17180/17188/1 17173/17181/1 4886/4894/1 +f 17180/17188/1 17179/17187/1 17174/17182/1 17173/17181/1 +f 17166/17174/1 17169/17177/1 17172/17180/1 17167/17175/1 +f 5847/5855/1 4884/4892/1 17169/17177/1 17166/17174/1 +f 4884/4892/1 4883/4891/1 17170/17178/1 17169/17177/1 +f 5878/5886/1 17165/17173/1 17168/17176/1 5879/5887/1 +f 4879/4887/1 5848/5856/1 17165/17173/1 5878/5886/1 +f 5848/5856/1 5847/5855/1 17166/17174/1 17165/17173/1 +f 4874/4882/1 17161/17169/1 17164/17172/1 4875/4883/1 +f 5879/5887/1 17168/17176/1 17161/17169/1 4874/4882/1 +f 17168/17176/1 17167/17175/1 17162/17170/1 17161/17169/1 +f 17154/17162/1 17157/17165/1 17160/17168/1 17155/17163/1 +f 5883/5891/1 4872/4880/1 17157/17165/1 17154/17162/1 +f 4872/4880/1 4871/4879/1 17158/17166/1 17157/17165/1 +f 5914/5922/1 17153/17161/1 17156/17164/1 5915/5923/1 +f 4867/4875/1 5884/5892/1 17153/17161/1 5914/5922/1 +f 5884/5892/1 5883/5891/1 17154/17162/1 17153/17161/1 +f 4862/4870/1 17149/17157/1 17152/17160/1 4863/4871/1 +f 5915/5923/1 17156/17164/1 17149/17157/1 4862/4870/1 +f 17156/17164/1 17155/17163/1 17150/17158/1 17149/17157/1 +f 17142/17150/1 17145/17153/1 17148/17156/1 17143/17151/1 +f 5919/5927/1 4860/4868/1 17145/17153/1 17142/17150/1 +f 4860/4868/1 4859/4867/1 17146/17154/1 17145/17153/1 +f 5950/5958/1 17141/17149/1 17144/17152/1 5951/5959/1 +f 4855/4863/1 5920/5928/1 17141/17149/1 5950/5958/1 +f 5920/5928/1 5919/5927/1 17142/17150/1 17141/17149/1 +f 4850/4858/1 17137/17145/1 17140/17148/1 4851/4859/1 +f 5951/5959/1 17144/17152/1 17137/17145/1 4850/4858/1 +f 17144/17152/1 17143/17151/1 17138/17146/1 17137/17145/1 +f 17130/17138/1 17133/17141/1 17136/17144/1 17131/17139/1 +f 5955/5963/1 4848/4856/1 17133/17141/1 17130/17138/1 +f 4848/4856/1 4847/4855/1 17134/17142/1 17133/17141/1 +f 5986/5994/1 17129/17137/1 17132/17140/1 5987/5995/1 +f 4843/4851/1 5956/5964/1 17129/17137/1 5986/5994/1 +f 5956/5964/1 5955/5963/1 17130/17138/1 17129/17137/1 +f 4838/4846/1 17125/17133/1 17128/17136/1 4839/4847/1 +f 5987/5995/1 17132/17140/1 17125/17133/1 4838/4846/1 +f 17132/17140/1 17131/17139/1 17126/17134/1 17125/17133/1 +f 17118/17126/1 17121/17129/1 17124/17132/1 17119/17127/1 +f 5991/5999/1 4836/4844/1 17121/17129/1 17118/17126/1 +f 4836/4844/1 4835/4843/1 17122/17130/1 17121/17129/1 +f 6022/6030/1 17117/17125/1 17120/17128/1 6023/6031/1 +f 4831/4839/1 5992/6000/1 17117/17125/1 6022/6030/1 +f 5992/6000/1 5991/5999/1 17118/17126/1 17117/17125/1 +f 4826/4834/1 17113/17121/1 17116/17124/1 4827/4835/1 +f 6023/6031/1 17120/17128/1 17113/17121/1 4826/4834/1 +f 17120/17128/1 17119/17127/1 17114/17122/1 17113/17121/1 +f 17106/17114/1 17109/17117/1 17112/17120/1 17107/17115/1 +f 6027/6035/1 4824/4832/1 17109/17117/1 17106/17114/1 +f 4824/4832/1 4823/4831/1 17110/17118/1 17109/17117/1 +f 6058/6066/1 17105/17113/1 17108/17116/1 6059/6067/1 +f 4819/4827/1 6028/6036/1 17105/17113/1 6058/6066/1 +f 6028/6036/1 6027/6035/1 17106/17114/1 17105/17113/1 +f 4814/4822/1 17101/17109/1 17104/17112/1 4815/4823/1 +f 6059/6067/1 17108/17116/1 17101/17109/1 4814/4822/1 +f 17108/17116/1 17107/17115/1 17102/17110/1 17101/17109/1 +f 17094/17102/1 17097/17105/1 17100/17108/1 17095/17103/1 +f 6063/6071/1 4812/4820/1 17097/17105/1 17094/17102/1 +f 4812/4820/1 4811/4819/1 17098/17106/1 17097/17105/1 +f 6094/6102/1 17093/17101/1 17096/17104/1 6095/6103/1 +f 4807/4815/1 6064/6072/1 17093/17101/1 6094/6102/1 +f 6064/6072/1 6063/6071/1 17094/17102/1 17093/17101/1 +f 4802/4810/1 17089/17097/1 17092/17100/1 4803/4811/1 +f 6095/6103/1 17096/17104/1 17089/17097/1 4802/4810/1 +f 17096/17104/1 17095/17103/1 17090/17098/1 17089/17097/1 +f 17082/17090/1 17085/17093/1 17088/17096/1 17083/17091/1 +f 6099/6107/1 4800/4808/1 17085/17093/1 17082/17090/1 +f 4800/4808/1 4799/4807/1 17086/17094/1 17085/17093/1 +f 6130/6138/1 17081/17089/1 17084/17092/1 6131/6139/1 +f 4795/4803/1 6100/6108/1 17081/17089/1 6130/6138/1 +f 6100/6108/1 6099/6107/1 17082/17090/1 17081/17089/1 +f 4790/4798/1 17077/17085/1 17080/17088/1 4791/4799/1 +f 6131/6139/1 17084/17092/1 17077/17085/1 4790/4798/1 +f 17084/17092/1 17083/17091/1 17078/17086/1 17077/17085/1 +f 17070/17078/1 17073/17081/1 17076/17084/1 17071/17079/1 +f 6135/6143/1 4788/4796/1 17073/17081/1 17070/17078/1 +f 4788/4796/1 4787/4795/1 17074/17082/1 17073/17081/1 +f 6166/6174/1 17069/17077/1 17072/17080/1 6167/6175/1 +f 4783/4791/1 6136/6144/1 17069/17077/1 6166/6174/1 +f 6136/6144/1 6135/6143/1 17070/17078/1 17069/17077/1 +f 4778/4786/1 17065/17073/1 17068/17076/1 4779/4787/1 +f 6167/6175/1 17072/17080/1 17065/17073/1 4778/4786/1 +f 17072/17080/1 17071/17079/1 17066/17074/1 17065/17073/1 +f 17058/17066/1 17061/17069/1 17064/17072/1 17059/17067/1 +f 6171/6179/1 4776/4784/1 17061/17069/1 17058/17066/1 +f 4776/4784/1 4775/4783/1 17062/17070/1 17061/17069/1 +f 6202/6210/1 17057/17065/1 17060/17068/1 6203/6211/1 +f 4771/4779/1 6172/6180/1 17057/17065/1 6202/6210/1 +f 6172/6180/1 6171/6179/1 17058/17066/1 17057/17065/1 +f 4766/4774/1 17053/17061/1 17056/17064/1 4767/4775/1 +f 6203/6211/1 17060/17068/1 17053/17061/1 4766/4774/1 +f 17060/17068/1 17059/17067/1 17054/17062/1 17053/17061/1 +f 17046/17054/1 17049/17057/1 17052/17060/1 17047/17055/1 +f 6207/6215/1 4764/4772/1 17049/17057/1 17046/17054/1 +f 4764/4772/1 4763/4771/1 17050/17058/1 17049/17057/1 +f 6238/6246/1 17045/17053/1 17048/17056/1 6239/6247/1 +f 4759/4767/1 6208/6216/1 17045/17053/1 6238/6246/1 +f 6208/6216/1 6207/6215/1 17046/17054/1 17045/17053/1 +f 4754/4762/1 17041/17049/1 17044/17052/1 4755/4763/1 +f 6239/6247/1 17048/17056/1 17041/17049/1 4754/4762/1 +f 17048/17056/1 17047/17055/1 17042/17050/1 17041/17049/1 +f 17034/17042/1 17037/17045/1 17040/17048/1 17035/17043/1 +f 6243/6251/1 4752/4760/1 17037/17045/1 17034/17042/1 +f 4752/4760/1 4751/4759/1 17038/17046/1 17037/17045/1 +f 6274/6282/1 17033/17041/1 17036/17044/1 6275/6283/1 +f 4747/4755/1 6244/6252/1 17033/17041/1 6274/6282/1 +f 6244/6252/1 6243/6251/1 17034/17042/1 17033/17041/1 +f 4742/4750/1 17029/17037/1 17032/17040/1 4743/4751/1 +f 6275/6283/1 17036/17044/1 17029/17037/1 4742/4750/1 +f 17036/17044/1 17035/17043/1 17030/17038/1 17029/17037/1 +f 17022/17030/1 17025/17033/1 17028/17036/1 17023/17031/1 +f 6279/6287/1 4740/4748/1 17025/17033/1 17022/17030/1 +f 4740/4748/1 4739/4747/1 17026/17034/1 17025/17033/1 +f 6310/6318/1 17021/17029/1 17024/17032/1 6311/6319/1 +f 4735/4743/1 6280/6288/1 17021/17029/1 6310/6318/1 +f 6280/6288/1 6279/6287/1 17022/17030/1 17021/17029/1 +f 4730/4738/1 17017/17025/1 17020/17028/1 4731/4739/1 +f 6311/6319/1 17024/17032/1 17017/17025/1 4730/4738/1 +f 17024/17032/1 17023/17031/1 17018/17026/1 17017/17025/1 +f 17010/17018/1 17013/17021/1 17016/17024/1 17011/17019/1 +f 6315/6323/1 4728/4736/1 17013/17021/1 17010/17018/1 +f 4728/4736/1 4727/4735/1 17014/17022/1 17013/17021/1 +f 6346/6354/1 17009/17017/1 17012/17020/1 6347/6355/1 +f 4723/4731/1 6316/6324/1 17009/17017/1 6346/6354/1 +f 6316/6324/1 6315/6323/1 17010/17018/1 17009/17017/1 +f 4718/4726/1 17005/17013/1 17008/17016/1 4719/4727/1 +f 6347/6355/1 17012/17020/1 17005/17013/1 4718/4726/1 +f 17012/17020/1 17011/17019/1 17006/17014/1 17005/17013/1 +f 16998/17006/1 17001/17009/1 17004/17012/1 16999/17007/1 +f 6351/6359/1 4716/4724/1 17001/17009/1 16998/17006/1 +f 4716/4724/1 4715/4723/1 17002/17010/1 17001/17009/1 +f 6382/6390/1 16997/17005/1 17000/17008/1 6383/6391/1 +f 4711/4719/1 6352/6360/1 16997/17005/1 6382/6390/1 +f 6352/6360/1 6351/6359/1 16998/17006/1 16997/17005/1 +f 4706/4714/1 16993/17001/1 16996/17004/1 4707/4715/1 +f 6383/6391/1 17000/17008/1 16993/17001/1 4706/4714/1 +f 17000/17008/1 16999/17007/1 16994/17002/1 16993/17001/1 +f 16986/16994/1 16989/16997/1 16992/17000/1 16987/16995/1 +f 6387/6395/1 4704/4712/1 16989/16997/1 16986/16994/1 +f 4704/4712/1 4703/4711/1 16990/16998/1 16989/16997/1 +f 6418/6426/1 16985/16993/1 16988/16996/1 6419/6427/1 +f 4699/4707/1 6388/6396/1 16985/16993/1 6418/6426/1 +f 6388/6396/1 6387/6395/1 16986/16994/1 16985/16993/1 +f 4694/4702/1 16981/16989/1 16984/16992/1 4695/4703/1 +f 6419/6427/1 16988/16996/1 16981/16989/1 4694/4702/1 +f 16988/16996/1 16987/16995/1 16982/16990/1 16981/16989/1 +f 16974/16982/1 16977/16985/1 16980/16988/1 16975/16983/1 +f 6423/6431/1 4692/4700/1 16977/16985/1 16974/16982/1 +f 4692/4700/1 4691/4699/1 16978/16986/1 16977/16985/1 +f 6454/6462/1 16973/16981/1 16976/16984/1 6455/6463/1 +f 4687/4695/1 6424/6432/1 16973/16981/1 6454/6462/1 +f 6424/6432/1 6423/6431/1 16974/16982/1 16973/16981/1 +f 4682/4690/1 16969/16977/1 16972/16980/1 4683/4691/1 +f 6455/6463/1 16976/16984/1 16969/16977/1 4682/4690/1 +f 16976/16984/1 16975/16983/1 16970/16978/1 16969/16977/1 +f 16962/16970/1 16965/16973/1 16968/16976/1 16963/16971/1 +f 6459/6467/1 4680/4688/1 16965/16973/1 16962/16970/1 +f 4680/4688/1 4679/4687/1 16966/16974/1 16965/16973/1 +f 6490/6498/1 16961/16969/1 16964/16972/1 6491/6499/1 +f 4675/4683/1 6460/6468/1 16961/16969/1 6490/6498/1 +f 6460/6468/1 6459/6467/1 16962/16970/1 16961/16969/1 +f 4670/4678/1 16957/16965/1 16960/16968/1 4671/4679/1 +f 6491/6499/1 16964/16972/1 16957/16965/1 4670/4678/1 +f 16964/16972/1 16963/16971/1 16958/16966/1 16957/16965/1 +f 16950/16958/1 16953/16961/1 16956/16964/1 16951/16959/1 +f 6495/6503/1 4668/4676/1 16953/16961/1 16950/16958/1 +f 4668/4676/1 4667/4675/1 16954/16962/1 16953/16961/1 +f 6526/6534/1 16949/16957/1 16952/16960/1 6527/6535/1 +f 4663/4671/1 6496/6504/1 16949/16957/1 6526/6534/1 +f 6496/6504/1 6495/6503/1 16950/16958/1 16949/16957/1 +f 4658/4666/1 16945/16953/1 16948/16956/1 4659/4667/1 +f 6527/6535/1 16952/16960/1 16945/16953/1 4658/4666/1 +f 16952/16960/1 16951/16959/1 16946/16954/1 16945/16953/1 +f 16938/16946/1 16941/16949/1 16944/16952/1 16939/16947/1 +f 6531/6539/1 4656/4664/1 16941/16949/1 16938/16946/1 +f 4656/4664/1 4655/4663/1 16942/16950/1 16941/16949/1 +f 6562/6570/1 16937/16945/1 16940/16948/1 6563/6571/1 +f 4651/4659/1 6532/6540/1 16937/16945/1 6562/6570/1 +f 6532/6540/1 6531/6539/1 16938/16946/1 16937/16945/1 +f 4646/4654/1 16933/16941/1 16936/16944/1 4647/4655/1 +f 6563/6571/1 16940/16948/1 16933/16941/1 4646/4654/1 +f 16940/16948/1 16939/16947/1 16934/16942/1 16933/16941/1 +f 16926/16934/1 16929/16937/1 16932/16940/1 16927/16935/1 +f 6567/6575/1 4644/4652/1 16929/16937/1 16926/16934/1 +f 4644/4652/1 4643/4651/1 16930/16938/1 16929/16937/1 +f 6598/6606/1 16925/16933/1 16928/16936/1 6599/6607/1 +f 4639/4647/1 6568/6576/1 16925/16933/1 6598/6606/1 +f 6568/6576/1 6567/6575/1 16926/16934/1 16925/16933/1 +f 4634/4642/1 16921/16929/1 16924/16932/1 4635/4643/1 +f 6599/6607/1 16928/16936/1 16921/16929/1 4634/4642/1 +f 16928/16936/1 16927/16935/1 16922/16930/1 16921/16929/1 +f 16914/16922/1 16917/16925/1 16920/16928/1 16915/16923/1 +f 6603/6611/1 4632/4640/1 16917/16925/1 16914/16922/1 +f 4632/4640/1 4631/4639/1 16918/16926/1 16917/16925/1 +f 6634/6642/1 16913/16921/1 16916/16924/1 6635/6643/1 +f 4627/4635/1 6604/6612/1 16913/16921/1 6634/6642/1 +f 6604/6612/1 6603/6611/1 16914/16922/1 16913/16921/1 +f 4622/4630/1 16909/16917/1 16912/16920/1 4623/4631/1 +f 6635/6643/1 16916/16924/1 16909/16917/1 4622/4630/1 +f 16916/16924/1 16915/16923/1 16910/16918/1 16909/16917/1 +f 16902/16910/1 16905/16913/1 16908/16916/1 16903/16911/1 +f 6639/6647/1 4620/4628/1 16905/16913/1 16902/16910/1 +f 4620/4628/1 4619/4627/1 16906/16914/1 16905/16913/1 +f 6670/6678/1 16901/16909/1 16904/16912/1 6671/6679/1 +f 4615/4623/1 6640/6648/1 16901/16909/1 6670/6678/1 +f 6640/6648/1 6639/6647/1 16902/16910/1 16901/16909/1 +f 4610/4618/1 16897/16905/1 16900/16908/1 4611/4619/1 +f 6671/6679/1 16904/16912/1 16897/16905/1 4610/4618/1 +f 16904/16912/1 16903/16911/1 16898/16906/1 16897/16905/1 +f 16890/16898/1 16893/16901/1 16896/16904/1 16891/16899/1 +f 6675/6683/1 4608/4616/1 16893/16901/1 16890/16898/1 +f 4608/4616/1 4607/4615/1 16894/16902/1 16893/16901/1 +f 6706/6714/1 16889/16897/1 16892/16900/1 6707/6715/1 +f 4603/4611/1 6676/6684/1 16889/16897/1 6706/6714/1 +f 6676/6684/1 6675/6683/1 16890/16898/1 16889/16897/1 +f 4598/4606/1 16885/16893/1 16888/16896/1 4599/4607/1 +f 6707/6715/1 16892/16900/1 16885/16893/1 4598/4606/1 +f 16892/16900/1 16891/16899/1 16886/16894/1 16885/16893/1 +f 16878/16886/1 16881/16889/1 16884/16892/1 16879/16887/1 +f 6711/6719/1 4596/4604/1 16881/16889/1 16878/16886/1 +f 4596/4604/1 4595/4603/1 16882/16890/1 16881/16889/1 +f 6742/6750/1 16877/16885/1 16880/16888/1 6743/6751/1 +f 4591/4599/1 6712/6720/1 16877/16885/1 6742/6750/1 +f 6712/6720/1 6711/6719/1 16878/16886/1 16877/16885/1 +f 4586/4594/1 16873/16881/1 16876/16884/1 4587/4595/1 +f 6743/6751/1 16880/16888/1 16873/16881/1 4586/4594/1 +f 16880/16888/1 16879/16887/1 16874/16882/1 16873/16881/1 +f 16866/16874/1 16869/16877/1 16872/16880/1 16867/16875/1 +f 6747/6755/1 4584/4592/1 16869/16877/1 16866/16874/1 +f 4584/4592/1 4583/4591/1 16870/16878/1 16869/16877/1 +f 6778/6786/1 16865/16873/1 16868/16876/1 6779/6787/1 +f 4579/4587/1 6748/6756/1 16865/16873/1 6778/6786/1 +f 6748/6756/1 6747/6755/1 16866/16874/1 16865/16873/1 +f 4574/4582/1 16861/16869/1 16864/16872/1 4575/4583/1 +f 6779/6787/1 16868/16876/1 16861/16869/1 4574/4582/1 +f 16868/16876/1 16867/16875/1 16862/16870/1 16861/16869/1 +f 16854/16862/1 16857/16865/1 16860/16868/1 16855/16863/1 +f 6783/6791/1 4572/4580/1 16857/16865/1 16854/16862/1 +f 4572/4580/1 4571/4579/1 16858/16866/1 16857/16865/1 +f 6814/6822/1 16853/16861/1 16856/16864/1 6815/6823/1 +f 4567/4575/1 6784/6792/1 16853/16861/1 6814/6822/1 +f 6784/6792/1 6783/6791/1 16854/16862/1 16853/16861/1 +f 4562/4570/1 16849/16857/1 16852/16860/1 4563/4571/1 +f 6815/6823/1 16856/16864/1 16849/16857/1 4562/4570/1 +f 16856/16864/1 16855/16863/1 16850/16858/1 16849/16857/1 +f 16842/16850/1 16845/16853/1 16848/16856/1 16843/16851/1 +f 6819/6827/1 4560/4568/1 16845/16853/1 16842/16850/1 +f 4560/4568/1 4559/4567/1 16846/16854/1 16845/16853/1 +f 6850/6858/1 16841/16849/1 16844/16852/1 6851/6859/1 +f 4555/4563/1 6820/6828/1 16841/16849/1 6850/6858/1 +f 6820/6828/1 6819/6827/1 16842/16850/1 16841/16849/1 +f 4550/4558/1 16837/16845/1 16840/16848/1 4551/4559/1 +f 6851/6859/1 16844/16852/1 16837/16845/1 4550/4558/1 +f 16844/16852/1 16843/16851/1 16838/16846/1 16837/16845/1 +f 16830/16838/1 16833/16841/1 16836/16844/1 16831/16839/1 +f 6855/6863/1 4548/4556/1 16833/16841/1 16830/16838/1 +f 4548/4556/1 4547/4555/1 16834/16842/1 16833/16841/1 +f 6886/6894/1 16829/16837/1 16832/16840/1 6887/6895/1 +f 4543/4551/1 6856/6864/1 16829/16837/1 6886/6894/1 +f 6856/6864/1 6855/6863/1 16830/16838/1 16829/16837/1 +f 4538/4546/1 16825/16833/1 16828/16836/1 4539/4547/1 +f 6887/6895/1 16832/16840/1 16825/16833/1 4538/4546/1 +f 16832/16840/1 16831/16839/1 16826/16834/1 16825/16833/1 +f 16818/16826/1 16821/16829/1 16824/16832/1 16819/16827/1 +f 6891/6899/1 4536/4544/1 16821/16829/1 16818/16826/1 +f 4536/4544/1 4535/4543/1 16822/16830/1 16821/16829/1 +f 6922/6930/1 16817/16825/1 16820/16828/1 6923/6931/1 +f 4531/4539/1 6892/6900/1 16817/16825/1 6922/6930/1 +f 6892/6900/1 6891/6899/1 16818/16826/1 16817/16825/1 +f 4526/4534/1 16813/16821/1 16816/16824/1 4527/4535/1 +f 6923/6931/1 16820/16828/1 16813/16821/1 4526/4534/1 +f 16820/16828/1 16819/16827/1 16814/16822/1 16813/16821/1 +f 16806/16814/1 16809/16817/1 16812/16820/1 16807/16815/1 +f 6927/6935/1 4524/4532/1 16809/16817/1 16806/16814/1 +f 4524/4532/1 4523/4531/1 16810/16818/1 16809/16817/1 +f 6958/6966/1 16805/16813/1 16808/16816/1 6959/6967/1 +f 4519/4527/1 6928/6936/1 16805/16813/1 6958/6966/1 +f 6928/6936/1 6927/6935/1 16806/16814/1 16805/16813/1 +f 4514/4522/1 16801/16809/1 16804/16812/1 4515/4523/1 +f 6959/6967/1 16808/16816/1 16801/16809/1 4514/4522/1 +f 16808/16816/1 16807/16815/1 16802/16810/1 16801/16809/1 +f 16794/16802/1 16797/16805/1 16800/16808/1 16795/16803/1 +f 6963/6971/1 4512/4520/1 16797/16805/1 16794/16802/1 +f 4512/4520/1 4511/4519/1 16798/16806/1 16797/16805/1 +f 6994/7002/1 16793/16801/1 16796/16804/1 6995/7003/1 +f 4507/4515/1 6964/6972/1 16793/16801/1 6994/7002/1 +f 6964/6972/1 6963/6971/1 16794/16802/1 16793/16801/1 +f 4502/4510/1 16789/16797/1 16792/16800/1 4503/4511/1 +f 6995/7003/1 16796/16804/1 16789/16797/1 4502/4510/1 +f 16796/16804/1 16795/16803/1 16790/16798/1 16789/16797/1 +f 16782/16790/1 16785/16793/1 16788/16796/1 16783/16791/1 +f 6999/7007/1 4500/4508/1 16785/16793/1 16782/16790/1 +f 4500/4508/1 4499/4507/1 16786/16794/1 16785/16793/1 +f 7030/7038/1 16781/16789/1 16784/16792/1 7031/7039/1 +f 4495/4503/1 7000/7008/1 16781/16789/1 7030/7038/1 +f 7000/7008/1 6999/7007/1 16782/16790/1 16781/16789/1 +f 4490/4498/1 16777/16785/1 16780/16788/1 4491/4499/1 +f 7031/7039/1 16784/16792/1 16777/16785/1 4490/4498/1 +f 16784/16792/1 16783/16791/1 16778/16786/1 16777/16785/1 +f 16770/16778/1 16773/16781/1 16776/16784/1 16771/16779/1 +f 7035/7043/1 4488/4496/1 16773/16781/1 16770/16778/1 +f 4488/4496/1 4487/4495/1 16774/16782/1 16773/16781/1 +f 7066/7074/1 16769/16777/1 16772/16780/1 7067/7075/1 +f 4483/4491/1 7036/7044/1 16769/16777/1 7066/7074/1 +f 7036/7044/1 7035/7043/1 16770/16778/1 16769/16777/1 +f 4478/4486/1 16765/16773/1 16768/16776/1 4479/4487/1 +f 7067/7075/1 16772/16780/1 16765/16773/1 4478/4486/1 +f 16772/16780/1 16771/16779/1 16766/16774/1 16765/16773/1 +f 16758/16766/1 16761/16769/1 16764/16772/1 16759/16767/1 +f 7071/7079/1 4476/4484/1 16761/16769/1 16758/16766/1 +f 4476/4484/1 4475/4483/1 16762/16770/1 16761/16769/1 +f 7102/7110/1 16757/16765/1 16760/16768/1 7103/7111/1 +f 4471/4479/1 7072/7080/1 16757/16765/1 7102/7110/1 +f 7072/7080/1 7071/7079/1 16758/16766/1 16757/16765/1 +f 4466/4474/1 16753/16761/1 16756/16764/1 4467/4475/1 +f 7103/7111/1 16760/16768/1 16753/16761/1 4466/4474/1 +f 16760/16768/1 16759/16767/1 16754/16762/1 16753/16761/1 +f 16746/16754/1 16749/16757/1 16752/16760/1 16747/16755/1 +f 7107/7115/1 4464/4472/1 16749/16757/1 16746/16754/1 +f 4464/4472/1 4463/4471/1 16750/16758/1 16749/16757/1 +f 7138/7146/1 16745/16753/1 16748/16756/1 7139/7147/1 +f 4459/4467/1 7108/7116/1 16745/16753/1 7138/7146/1 +f 7108/7116/1 7107/7115/1 16746/16754/1 16745/16753/1 +f 4454/4462/1 16741/16749/1 16744/16752/1 4455/4463/1 +f 7139/7147/1 16748/16756/1 16741/16749/1 4454/4462/1 +f 16748/16756/1 16747/16755/1 16742/16750/1 16741/16749/1 +f 16734/16742/1 16737/16745/1 16740/16748/1 16735/16743/1 +f 7143/7151/1 4452/4460/1 16737/16745/1 16734/16742/1 +f 4452/4460/1 4451/4459/1 16738/16746/1 16737/16745/1 +f 7174/7182/1 16733/16741/1 16736/16744/1 7175/7183/1 +f 4447/4455/1 7144/7152/1 16733/16741/1 7174/7182/1 +f 7144/7152/1 7143/7151/1 16734/16742/1 16733/16741/1 +f 4442/4450/1 16729/16737/1 16732/16740/1 4443/4451/1 +f 7175/7183/1 16736/16744/1 16729/16737/1 4442/4450/1 +f 16736/16744/1 16735/16743/1 16730/16738/1 16729/16737/1 +f 16722/16730/1 16725/16733/1 16728/16736/1 16723/16731/1 +f 7179/7187/1 4440/4448/1 16725/16733/1 16722/16730/1 +f 4440/4448/1 4439/4447/1 16726/16734/1 16725/16733/1 +f 7210/7218/1 16721/16729/1 16724/16732/1 7211/7219/1 +f 4435/4443/1 7180/7188/1 16721/16729/1 7210/7218/1 +f 7180/7188/1 7179/7187/1 16722/16730/1 16721/16729/1 +f 4430/4438/1 16717/16725/1 16720/16728/1 4431/4439/1 +f 7211/7219/1 16724/16732/1 16717/16725/1 4430/4438/1 +f 16724/16732/1 16723/16731/1 16718/16726/1 16717/16725/1 +f 16710/16718/1 16713/16721/1 16716/16724/1 16711/16719/1 +f 7215/7223/1 4428/4436/1 16713/16721/1 16710/16718/1 +f 4428/4436/1 4427/4435/1 16714/16722/1 16713/16721/1 +f 7246/7254/1 16709/16717/1 16712/16720/1 7247/7255/1 +f 4423/4431/1 7216/7224/1 16709/16717/1 7246/7254/1 +f 7216/7224/1 7215/7223/1 16710/16718/1 16709/16717/1 +f 4418/4426/1 16705/16713/1 16708/16716/1 4419/4427/1 +f 7247/7255/1 16712/16720/1 16705/16713/1 4418/4426/1 +f 16712/16720/1 16711/16719/1 16706/16714/1 16705/16713/1 +f 16698/16706/1 16701/16709/1 16704/16712/1 16699/16707/1 +f 7251/7259/1 4416/4424/1 16701/16709/1 16698/16706/1 +f 4416/4424/1 4415/4423/1 16702/16710/1 16701/16709/1 +f 7282/7290/1 16697/16705/1 16700/16708/1 7283/7291/1 +f 4411/4419/1 7252/7260/1 16697/16705/1 7282/7290/1 +f 7252/7260/1 7251/7259/1 16698/16706/1 16697/16705/1 +f 4406/4414/1 16693/16701/1 16696/16704/1 4407/4415/1 +f 7283/7291/1 16700/16708/1 16693/16701/1 4406/4414/1 +f 16700/16708/1 16699/16707/1 16694/16702/1 16693/16701/1 +f 16686/16694/1 16689/16697/1 16692/16700/1 16687/16695/1 +f 7287/7295/1 4404/4412/1 16689/16697/1 16686/16694/1 +f 4404/4412/1 4403/4411/1 16690/16698/1 16689/16697/1 +f 7318/7326/1 16685/16693/1 16688/16696/1 7319/7327/1 +f 4399/4407/1 7288/7296/1 16685/16693/1 7318/7326/1 +f 7288/7296/1 7287/7295/1 16686/16694/1 16685/16693/1 +f 4394/4402/1 16681/16689/1 16684/16692/1 4395/4403/1 +f 7319/7327/1 16688/16696/1 16681/16689/1 4394/4402/1 +f 16688/16696/1 16687/16695/1 16682/16690/1 16681/16689/1 +f 16674/16682/1 16677/16685/1 16680/16688/1 16675/16683/1 +f 7323/7331/1 4392/4400/1 16677/16685/1 16674/16682/1 +f 4392/4400/1 4391/4399/1 16678/16686/1 16677/16685/1 +f 7354/7362/1 16673/16681/1 16676/16684/1 7355/7363/1 +f 4387/4395/1 7324/7332/1 16673/16681/1 7354/7362/1 +f 7324/7332/1 7323/7331/1 16674/16682/1 16673/16681/1 +f 4382/4390/1 16669/16677/1 16672/16680/1 4383/4391/1 +f 7355/7363/1 16676/16684/1 16669/16677/1 4382/4390/1 +f 16676/16684/1 16675/16683/1 16670/16678/1 16669/16677/1 +f 16662/16670/1 16665/16673/1 16668/16676/1 16663/16671/1 +f 7359/7367/1 4380/4388/1 16665/16673/1 16662/16670/1 +f 4380/4388/1 4379/4387/1 16666/16674/1 16665/16673/1 +f 7390/7398/1 16661/16669/1 16664/16672/1 7391/7399/1 +f 4375/4383/1 7360/7368/1 16661/16669/1 7390/7398/1 +f 7360/7368/1 7359/7367/1 16662/16670/1 16661/16669/1 +f 4370/4378/1 16657/16665/1 16660/16668/1 4371/4379/1 +f 7391/7399/1 16664/16672/1 16657/16665/1 4370/4378/1 +f 16664/16672/1 16663/16671/1 16658/16666/1 16657/16665/1 +f 16650/16658/1 16653/16661/1 16656/16664/1 16651/16659/1 +f 7395/7403/1 4368/4376/1 16653/16661/1 16650/16658/1 +f 4368/4376/1 4367/4375/1 16654/16662/1 16653/16661/1 +f 7426/7434/1 16649/16657/1 16652/16660/1 7427/7435/1 +f 4363/4371/1 7396/7404/1 16649/16657/1 7426/7434/1 +f 7396/7404/1 7395/7403/1 16650/16658/1 16649/16657/1 +f 4358/4366/1 16645/16653/1 16648/16656/1 4359/4367/1 +f 7427/7435/1 16652/16660/1 16645/16653/1 4358/4366/1 +f 16652/16660/1 16651/16659/1 16646/16654/1 16645/16653/1 +f 16638/16646/1 16641/16649/1 16644/16652/1 16639/16647/1 +f 7431/7439/1 4356/4364/1 16641/16649/1 16638/16646/1 +f 4356/4364/1 4355/4363/1 16642/16650/1 16641/16649/1 +f 7462/7470/1 16637/16645/1 16640/16648/1 7463/7471/1 +f 4351/4359/1 7432/7440/1 16637/16645/1 7462/7470/1 +f 7432/7440/1 7431/7439/1 16638/16646/1 16637/16645/1 +f 4346/4354/1 16633/16641/1 16636/16644/1 4347/4355/1 +f 7463/7471/1 16640/16648/1 16633/16641/1 4346/4354/1 +f 16640/16648/1 16639/16647/1 16634/16642/1 16633/16641/1 +f 16626/16634/1 16629/16637/1 16632/16640/1 16627/16635/1 +f 7467/7475/1 4344/4352/1 16629/16637/1 16626/16634/1 +f 4344/4352/1 4343/4351/1 16630/16638/1 16629/16637/1 +f 7498/7506/1 16625/16633/1 16628/16636/1 7499/7507/1 +f 4339/4347/1 7468/7476/1 16625/16633/1 7498/7506/1 +f 7468/7476/1 7467/7475/1 16626/16634/1 16625/16633/1 +f 4334/4342/1 16621/16629/1 16624/16632/1 4335/4343/1 +f 7499/7507/1 16628/16636/1 16621/16629/1 4334/4342/1 +f 16628/16636/1 16627/16635/1 16622/16630/1 16621/16629/1 +f 16614/16622/1 16617/16625/1 16620/16628/1 16615/16623/1 +f 7503/7511/1 4332/4340/1 16617/16625/1 16614/16622/1 +f 4332/4340/1 4331/4339/1 16618/16626/1 16617/16625/1 +f 7534/7542/1 16613/16621/1 16616/16624/1 7535/7543/1 +f 4327/4335/1 7504/7512/1 16613/16621/1 7534/7542/1 +f 7504/7512/1 7503/7511/1 16614/16622/1 16613/16621/1 +f 4322/4330/1 16609/16617/1 16612/16620/1 4323/4331/1 +f 7535/7543/1 16616/16624/1 16609/16617/1 4322/4330/1 +f 16616/16624/1 16615/16623/1 16610/16618/1 16609/16617/1 +f 16602/16610/1 16605/16613/1 16608/16616/1 16603/16611/1 +f 7539/7547/1 4320/4328/1 16605/16613/1 16602/16610/1 +f 4320/4328/1 4319/4327/1 16606/16614/1 16605/16613/1 +f 7570/7578/1 16601/16609/1 16604/16612/1 7571/7579/1 +f 4315/4323/1 7540/7548/1 16601/16609/1 7570/7578/1 +f 7540/7548/1 7539/7547/1 16602/16610/1 16601/16609/1 +f 4310/4318/1 16597/16605/1 16600/16608/1 4311/4319/1 +f 7571/7579/1 16604/16612/1 16597/16605/1 4310/4318/1 +f 16604/16612/1 16603/16611/1 16598/16606/1 16597/16605/1 +f 16590/16598/1 16593/16601/1 16596/16604/1 16591/16599/1 +f 7575/7583/1 4308/4316/1 16593/16601/1 16590/16598/1 +f 4308/4316/1 4307/4315/1 16594/16602/1 16593/16601/1 +f 7606/7614/1 16589/16597/1 16592/16600/1 7607/7615/1 +f 4303/4311/1 7576/7584/1 16589/16597/1 7606/7614/1 +f 7576/7584/1 7575/7583/1 16590/16598/1 16589/16597/1 +f 4298/4306/1 16585/16593/1 16588/16596/1 4299/4307/1 +f 7607/7615/1 16592/16600/1 16585/16593/1 4298/4306/1 +f 16592/16600/1 16591/16599/1 16586/16594/1 16585/16593/1 +f 16578/16586/1 16581/16589/1 16584/16592/1 16579/16587/1 +f 7611/7619/1 4296/4304/1 16581/16589/1 16578/16586/1 +f 4296/4304/1 4295/4303/1 16582/16590/1 16581/16589/1 +f 7642/7650/1 16577/16585/1 16580/16588/1 7643/7651/1 +f 4291/4299/1 7612/7620/1 16577/16585/1 7642/7650/1 +f 7612/7620/1 7611/7619/1 16578/16586/1 16577/16585/1 +f 4286/4294/1 16573/16581/1 16576/16584/1 4287/4295/1 +f 7643/7651/1 16580/16588/1 16573/16581/1 4286/4294/1 +f 16580/16588/1 16579/16587/1 16574/16582/1 16573/16581/1 +f 16566/16574/1 16569/16577/1 16572/16580/1 16567/16575/1 +f 7647/7655/1 4284/4292/1 16569/16577/1 16566/16574/1 +f 4284/4292/1 4283/4291/1 16570/16578/1 16569/16577/1 +f 7678/7686/1 16565/16573/1 16568/16576/1 7679/7687/1 +f 4279/4287/1 7648/7656/1 16565/16573/1 7678/7686/1 +f 7648/7656/1 7647/7655/1 16566/16574/1 16565/16573/1 +f 4274/4282/1 16561/16569/1 16564/16572/1 4275/4283/1 +f 7679/7687/1 16568/16576/1 16561/16569/1 4274/4282/1 +f 16568/16576/1 16567/16575/1 16562/16570/1 16561/16569/1 +f 16554/16562/1 16557/16565/1 16560/16568/1 16555/16563/1 +f 7683/7691/1 4272/4280/1 16557/16565/1 16554/16562/1 +f 4272/4280/1 4271/4279/1 16558/16566/1 16557/16565/1 +f 7714/7722/1 16553/16561/1 16556/16564/1 7715/7723/1 +f 4267/4275/1 7684/7692/1 16553/16561/1 7714/7722/1 +f 7684/7692/1 7683/7691/1 16554/16562/1 16553/16561/1 +f 4262/4270/1 16549/16557/1 16552/16560/1 4263/4271/1 +f 7715/7723/1 16556/16564/1 16549/16557/1 4262/4270/1 +f 16556/16564/1 16555/16563/1 16550/16558/1 16549/16557/1 +f 16542/16550/1 16545/16553/1 16548/16556/1 16543/16551/1 +f 7719/7727/1 4260/4268/1 16545/16553/1 16542/16550/1 +f 4260/4268/1 4259/4267/1 16546/16554/1 16545/16553/1 +f 7750/7758/1 16541/16549/1 16544/16552/1 7751/7759/1 +f 4255/4263/1 7720/7728/1 16541/16549/1 7750/7758/1 +f 7720/7728/1 7719/7727/1 16542/16550/1 16541/16549/1 +f 4250/4258/1 16537/16545/1 16540/16548/1 4251/4259/1 +f 7751/7759/1 16544/16552/1 16537/16545/1 4250/4258/1 +f 16544/16552/1 16543/16551/1 16538/16546/1 16537/16545/1 +f 16530/16538/1 16533/16541/1 16536/16544/1 16531/16539/1 +f 7755/7763/1 4248/4256/1 16533/16541/1 16530/16538/1 +f 4248/4256/1 4247/4255/1 16534/16542/1 16533/16541/1 +f 7786/7794/1 16529/16537/1 16532/16540/1 7787/7795/1 +f 4243/4251/1 7756/7764/1 16529/16537/1 7786/7794/1 +f 7756/7764/1 7755/7763/1 16530/16538/1 16529/16537/1 +f 4238/4246/1 16525/16533/1 16528/16536/1 4239/4247/1 +f 7787/7795/1 16532/16540/1 16525/16533/1 4238/4246/1 +f 16532/16540/1 16531/16539/1 16526/16534/1 16525/16533/1 +f 16518/16526/1 16521/16529/1 16524/16532/1 16519/16527/1 +f 7791/7799/1 4236/4244/1 16521/16529/1 16518/16526/1 +f 4236/4244/1 4235/4243/1 16522/16530/1 16521/16529/1 +f 7822/7830/1 16517/16525/1 16520/16528/1 7823/7831/1 +f 4231/4239/1 7792/7800/1 16517/16525/1 7822/7830/1 +f 7792/7800/1 7791/7799/1 16518/16526/1 16517/16525/1 +f 4226/4234/1 16513/16521/1 16516/16524/1 4227/4235/1 +f 7823/7831/1 16520/16528/1 16513/16521/1 4226/4234/1 +f 16520/16528/1 16519/16527/1 16514/16522/1 16513/16521/1 +f 16506/16514/1 16509/16517/1 16512/16520/1 16507/16515/1 +f 7827/7835/1 4224/4232/1 16509/16517/1 16506/16514/1 +f 4224/4232/1 4223/4231/1 16510/16518/1 16509/16517/1 +f 7858/7866/1 16505/16513/1 16508/16516/1 7859/7867/1 +f 4219/4227/1 7828/7836/1 16505/16513/1 7858/7866/1 +f 7828/7836/1 7827/7835/1 16506/16514/1 16505/16513/1 +f 4214/4222/1 16501/16509/1 16504/16512/1 4215/4223/1 +f 7859/7867/1 16508/16516/1 16501/16509/1 4214/4222/1 +f 16508/16516/1 16507/16515/1 16502/16510/1 16501/16509/1 +f 16494/16502/1 16497/16505/1 16500/16508/1 16495/16503/1 +f 7863/7871/1 4212/4220/1 16497/16505/1 16494/16502/1 +f 4212/4220/1 4211/4219/1 16498/16506/1 16497/16505/1 +f 7894/7902/1 16493/16501/1 16496/16504/1 7895/7903/1 +f 4207/4215/1 7864/7872/1 16493/16501/1 7894/7902/1 +f 7864/7872/1 7863/7871/1 16494/16502/1 16493/16501/1 +f 4202/4210/1 16489/16497/1 16492/16500/1 4203/4211/1 +f 7895/7903/1 16496/16504/1 16489/16497/1 4202/4210/1 +f 16496/16504/1 16495/16503/1 16490/16498/1 16489/16497/1 +f 16482/16490/1 16485/16493/1 16488/16496/1 16483/16491/1 +f 7899/7907/1 4200/4208/1 16485/16493/1 16482/16490/1 +f 4200/4208/1 4199/4207/1 16486/16494/1 16485/16493/1 +f 7930/7938/1 16481/16489/1 16484/16492/1 7931/7939/1 +f 4195/4203/1 7900/7908/1 16481/16489/1 7930/7938/1 +f 7900/7908/1 7899/7907/1 16482/16490/1 16481/16489/1 +f 4190/4198/1 16477/16485/1 16480/16488/1 4191/4199/1 +f 7931/7939/1 16484/16492/1 16477/16485/1 4190/4198/1 +f 16484/16492/1 16483/16491/1 16478/16486/1 16477/16485/1 +f 16470/16478/1 16473/16481/1 16476/16484/1 16471/16479/1 +f 7935/7943/1 4188/4196/1 16473/16481/1 16470/16478/1 +f 4188/4196/1 4187/4195/1 16474/16482/1 16473/16481/1 +f 7966/7974/1 16469/16477/1 16472/16480/1 7967/7975/1 +f 4183/4191/1 7936/7944/1 16469/16477/1 7966/7974/1 +f 7936/7944/1 7935/7943/1 16470/16478/1 16469/16477/1 +f 4178/4186/1 16465/16473/1 16468/16476/1 4179/4187/1 +f 7967/7975/1 16472/16480/1 16465/16473/1 4178/4186/1 +f 16472/16480/1 16471/16479/1 16466/16474/1 16465/16473/1 +f 16458/16466/1 16461/16469/1 16464/16472/1 16459/16467/1 +f 7971/7979/1 4176/4184/1 16461/16469/1 16458/16466/1 +f 4176/4184/1 4175/4183/1 16462/16470/1 16461/16469/1 +f 8002/8010/1 16457/16465/1 16460/16468/1 8003/8011/1 +f 4171/4179/1 7972/7980/1 16457/16465/1 8002/8010/1 +f 7972/7980/1 7971/7979/1 16458/16466/1 16457/16465/1 +f 4166/4174/1 16453/16461/1 16456/16464/1 4167/4175/1 +f 8003/8011/1 16460/16468/1 16453/16461/1 4166/4174/1 +f 16460/16468/1 16459/16467/1 16454/16462/1 16453/16461/1 +f 16446/16454/1 16449/16457/1 16452/16460/1 16447/16455/1 +f 8007/8015/1 4164/4172/1 16449/16457/1 16446/16454/1 +f 4164/4172/1 4163/4171/1 16450/16458/1 16449/16457/1 +f 8038/8046/1 16445/16453/1 16448/16456/1 8039/8047/1 +f 4159/4167/1 8008/8016/1 16445/16453/1 8038/8046/1 +f 8008/8016/1 8007/8015/1 16446/16454/1 16445/16453/1 +f 4154/4162/1 16441/16449/1 16444/16452/1 4155/4163/1 +f 8039/8047/1 16448/16456/1 16441/16449/1 4154/4162/1 +f 16448/16456/1 16447/16455/1 16442/16450/1 16441/16449/1 +f 16434/16442/1 16437/16445/1 16440/16448/1 16435/16443/1 +f 8043/8051/1 4152/4160/1 16437/16445/1 16434/16442/1 +f 4152/4160/1 4151/4159/1 16438/16446/1 16437/16445/1 +f 8074/8082/1 16433/16441/1 16436/16444/1 8075/8083/1 +f 4147/4155/1 8044/8052/1 16433/16441/1 8074/8082/1 +f 8044/8052/1 8043/8051/1 16434/16442/1 16433/16441/1 +f 4142/4150/1 16429/16437/1 16432/16440/1 4143/4151/1 +f 8075/8083/1 16436/16444/1 16429/16437/1 4142/4150/1 +f 16436/16444/1 16435/16443/1 16430/16438/1 16429/16437/1 +f 16422/16430/1 16425/16433/1 16428/16436/1 16423/16431/1 +f 8079/8087/1 4140/4148/1 16425/16433/1 16422/16430/1 +f 4140/4148/1 4139/4147/1 16426/16434/1 16425/16433/1 +f 8110/8118/1 16421/16429/1 16424/16432/1 8111/8119/1 +f 4135/4143/1 8080/8088/1 16421/16429/1 8110/8118/1 +f 8080/8088/1 8079/8087/1 16422/16430/1 16421/16429/1 +f 4130/4138/1 16417/16425/1 16420/16428/1 4131/4139/1 +f 8111/8119/1 16424/16432/1 16417/16425/1 4130/4138/1 +f 16424/16432/1 16423/16431/1 16418/16426/1 16417/16425/1 +f 16410/16418/1 16413/16421/1 16416/16424/1 16411/16419/1 +f 8115/8123/1 4128/4136/1 16413/16421/1 16410/16418/1 +f 4128/4136/1 4127/4135/1 16414/16422/1 16413/16421/1 +f 8146/8154/1 16409/16417/1 16412/16420/1 8147/8155/1 +f 4123/4131/1 8116/8124/1 16409/16417/1 8146/8154/1 +f 8116/8124/1 8115/8123/1 16410/16418/1 16409/16417/1 +f 4118/4126/1 16405/16413/1 16408/16416/1 4119/4127/1 +f 8147/8155/1 16412/16420/1 16405/16413/1 4118/4126/1 +f 16412/16420/1 16411/16419/1 16406/16414/1 16405/16413/1 +f 16398/16406/1 16401/16409/1 16404/16412/1 16399/16407/1 +f 8151/8159/1 4116/4124/1 16401/16409/1 16398/16406/1 +f 4116/4124/1 4115/4123/1 16402/16410/1 16401/16409/1 +f 8182/8190/1 16397/16405/1 16400/16408/1 8183/8191/1 +f 4111/4119/1 8152/8160/1 16397/16405/1 8182/8190/1 +f 8152/8160/1 8151/8159/1 16398/16406/1 16397/16405/1 +f 4106/4114/1 16393/16401/1 16396/16404/1 4107/4115/1 +f 8183/8191/1 16400/16408/1 16393/16401/1 4106/4114/1 +f 16400/16408/1 16399/16407/1 16394/16402/1 16393/16401/1 +f 16386/16394/1 16389/16397/1 16392/16400/1 16387/16395/1 +f 8187/8195/1 4104/4112/1 16389/16397/1 16386/16394/1 +f 4104/4112/1 4103/4111/1 16390/16398/1 16389/16397/1 +f 8218/8226/1 16385/16393/1 16388/16396/1 8219/8227/1 +f 4099/4107/1 8188/8196/1 16385/16393/1 8218/8226/1 +f 8188/8196/1 8187/8195/1 16386/16394/1 16385/16393/1 +f 4094/4102/1 16381/16389/1 16384/16392/1 4095/4103/1 +f 8219/8227/1 16388/16396/1 16381/16389/1 4094/4102/1 +f 16388/16396/1 16387/16395/1 16382/16390/1 16381/16389/1 +f 16374/16382/1 16377/16385/1 16380/16388/1 16375/16383/1 +f 8223/8231/1 4092/4100/1 16377/16385/1 16374/16382/1 +f 4092/4100/1 4091/4099/1 16378/16386/1 16377/16385/1 +f 8254/8262/1 16373/16381/1 16376/16384/1 8255/8263/1 +f 4087/4095/1 8224/8232/1 16373/16381/1 8254/8262/1 +f 8224/8232/1 8223/8231/1 16374/16382/1 16373/16381/1 +f 4082/4090/1 16369/16377/1 16372/16380/1 4083/4091/1 +f 8255/8263/1 16376/16384/1 16369/16377/1 4082/4090/1 +f 16376/16384/1 16375/16383/1 16370/16378/1 16369/16377/1 +f 16362/16370/1 16365/16373/1 16368/16376/1 16363/16371/1 +f 8259/8267/1 4080/4088/1 16365/16373/1 16362/16370/1 +f 4080/4088/1 4079/4087/1 16366/16374/1 16365/16373/1 +f 8290/8298/1 16361/16369/1 16364/16372/1 8291/8299/1 +f 4075/4083/1 8260/8268/1 16361/16369/1 8290/8298/1 +f 8260/8268/1 8259/8267/1 16362/16370/1 16361/16369/1 +f 4070/4078/1 16357/16365/1 16360/16368/1 4071/4079/1 +f 8291/8299/1 16364/16372/1 16357/16365/1 4070/4078/1 +f 16364/16372/1 16363/16371/1 16358/16366/1 16357/16365/1 +f 16350/16358/1 16353/16361/1 16356/16364/1 16351/16359/1 +f 8295/8303/1 4068/4076/1 16353/16361/1 16350/16358/1 +f 4068/4076/1 4067/4075/1 16354/16362/1 16353/16361/1 +f 8326/8334/1 16349/16357/1 16352/16360/1 8327/8335/1 +f 4063/4071/1 8296/8304/1 16349/16357/1 8326/8334/1 +f 8296/8304/1 8295/8303/1 16350/16358/1 16349/16357/1 +f 4058/4066/1 16345/16353/1 16348/16356/1 4059/4067/1 +f 8327/8335/1 16352/16360/1 16345/16353/1 4058/4066/1 +f 16352/16360/1 16351/16359/1 16346/16354/1 16345/16353/1 +f 16338/16346/1 16341/16349/1 16344/16352/1 16339/16347/1 +f 8331/8339/1 4056/4064/1 16341/16349/1 16338/16346/1 +f 4056/4064/1 4055/4063/1 16342/16350/1 16341/16349/1 +f 8362/8370/1 16337/16345/1 16340/16348/1 8363/8371/1 +f 4051/4059/1 8332/8340/1 16337/16345/1 8362/8370/1 +f 8332/8340/1 8331/8339/1 16338/16346/1 16337/16345/1 +f 4046/4054/1 16333/16341/1 16336/16344/1 4047/4055/1 +f 8363/8371/1 16340/16348/1 16333/16341/1 4046/4054/1 +f 16340/16348/1 16339/16347/1 16334/16342/1 16333/16341/1 +f 16326/16334/1 16329/16337/1 16332/16340/1 16327/16335/1 +f 8367/8375/1 4044/4052/1 16329/16337/1 16326/16334/1 +f 4044/4052/1 4043/4051/1 16330/16338/1 16329/16337/1 +f 8398/8406/1 16325/16333/1 16328/16336/1 8399/8407/1 +f 4039/4047/1 8368/8376/1 16325/16333/1 8398/8406/1 +f 8368/8376/1 8367/8375/1 16326/16334/1 16325/16333/1 +f 4034/4042/1 16321/16329/1 16324/16332/1 4035/4043/1 +f 8399/8407/1 16328/16336/1 16321/16329/1 4034/4042/1 +f 16328/16336/1 16327/16335/1 16322/16330/1 16321/16329/1 +f 16314/16322/1 16317/16325/1 16320/16328/1 16315/16323/1 +f 8403/8411/1 4032/4040/1 16317/16325/1 16314/16322/1 +f 4032/4040/1 4031/4039/1 16318/16326/1 16317/16325/1 +f 8434/8442/1 16313/16321/1 16316/16324/1 8435/8443/1 +f 4027/4035/1 8404/8412/1 16313/16321/1 8434/8442/1 +f 8404/8412/1 8403/8411/1 16314/16322/1 16313/16321/1 +f 4022/4030/1 16309/16317/1 16312/16320/1 4023/4031/1 +f 8435/8443/1 16316/16324/1 16309/16317/1 4022/4030/1 +f 16316/16324/1 16315/16323/1 16310/16318/1 16309/16317/1 +f 16302/16310/1 16305/16313/1 16308/16316/1 16303/16311/1 +f 8439/8447/1 4020/4028/1 16305/16313/1 16302/16310/1 +f 4020/4028/1 4019/4027/1 16306/16314/1 16305/16313/1 +f 8470/8478/1 16301/16309/1 16304/16312/1 8471/8479/1 +f 4015/4023/1 8440/8448/1 16301/16309/1 8470/8478/1 +f 8440/8448/1 8439/8447/1 16302/16310/1 16301/16309/1 +f 4010/4018/1 16297/16305/1 16300/16308/1 4011/4019/1 +f 8471/8479/1 16304/16312/1 16297/16305/1 4010/4018/1 +f 16304/16312/1 16303/16311/1 16298/16306/1 16297/16305/1 +f 16290/16298/1 16293/16301/1 16296/16304/1 16291/16299/1 +f 8475/8483/1 4008/4016/1 16293/16301/1 16290/16298/1 +f 4008/4016/1 4007/4015/1 16294/16302/1 16293/16301/1 +f 8506/8514/1 16289/16297/1 16292/16300/1 8507/8515/1 +f 4003/4011/1 8476/8484/1 16289/16297/1 8506/8514/1 +f 8476/8484/1 8475/8483/1 16290/16298/1 16289/16297/1 +f 3998/4006/1 16285/16293/1 16288/16296/1 3999/4007/1 +f 8507/8515/1 16292/16300/1 16285/16293/1 3998/4006/1 +f 16292/16300/1 16291/16299/1 16286/16294/1 16285/16293/1 +f 16278/16286/1 16281/16289/1 16284/16292/1 16279/16287/1 +f 8511/8519/1 3996/4004/1 16281/16289/1 16278/16286/1 +f 3996/4004/1 3995/4003/1 16282/16290/1 16281/16289/1 +f 8542/8550/1 16277/16285/1 16280/16288/1 8543/8551/1 +f 3991/3999/1 8512/8520/1 16277/16285/1 8542/8550/1 +f 8512/8520/1 8511/8519/1 16278/16286/1 16277/16285/1 +f 3986/3994/1 16273/16281/1 16276/16284/1 3987/3995/1 +f 8543/8551/1 16280/16288/1 16273/16281/1 3986/3994/1 +f 16280/16288/1 16279/16287/1 16274/16282/1 16273/16281/1 +f 16266/16274/1 16269/16277/1 16272/16280/1 16267/16275/1 +f 8547/8555/1 3984/3992/1 16269/16277/1 16266/16274/1 +f 3984/3992/1 3983/3991/1 16270/16278/1 16269/16277/1 +f 8578/8586/1 16265/16273/1 16268/16276/1 8579/8587/1 +f 3979/3987/1 8548/8556/1 16265/16273/1 8578/8586/1 +f 8548/8556/1 8547/8555/1 16266/16274/1 16265/16273/1 +f 3974/3982/1 16261/16269/1 16264/16272/1 3975/3983/1 +f 8579/8587/1 16268/16276/1 16261/16269/1 3974/3982/1 +f 16268/16276/1 16267/16275/1 16262/16270/1 16261/16269/1 +f 16254/16262/1 16257/16265/1 16260/16268/1 16255/16263/1 +f 8583/8591/1 3972/3980/1 16257/16265/1 16254/16262/1 +f 3972/3980/1 3971/3979/1 16258/16266/1 16257/16265/1 +f 8614/8622/1 16253/16261/1 16256/16264/1 8615/8623/1 +f 3967/3975/1 8584/8592/1 16253/16261/1 8614/8622/1 +f 8584/8592/1 8583/8591/1 16254/16262/1 16253/16261/1 +f 3962/3970/1 16249/16257/1 16252/16260/1 3963/3971/1 +f 8615/8623/1 16256/16264/1 16249/16257/1 3962/3970/1 +f 16256/16264/1 16255/16263/1 16250/16258/1 16249/16257/1 +f 16242/16250/1 16245/16253/1 16248/16256/1 16243/16251/1 +f 8619/8627/1 3960/3968/1 16245/16253/1 16242/16250/1 +f 3960/3968/1 3959/3967/1 16246/16254/1 16245/16253/1 +f 8650/8658/1 16241/16249/1 16244/16252/1 8651/8659/1 +f 3955/3963/1 8620/8628/1 16241/16249/1 8650/8658/1 +f 8620/8628/1 8619/8627/1 16242/16250/1 16241/16249/1 +f 3950/3958/1 16237/16245/1 16240/16248/1 3951/3959/1 +f 8651/8659/1 16244/16252/1 16237/16245/1 3950/3958/1 +f 16244/16252/1 16243/16251/1 16238/16246/1 16237/16245/1 +f 16230/16238/1 16233/16241/1 16236/16244/1 16231/16239/1 +f 8655/8663/1 3948/3956/1 16233/16241/1 16230/16238/1 +f 3948/3956/1 3947/3955/1 16234/16242/1 16233/16241/1 +f 8686/8694/1 16229/16237/1 16232/16240/1 8687/8695/1 +f 3943/3951/1 8656/8664/1 16229/16237/1 8686/8694/1 +f 8656/8664/1 8655/8663/1 16230/16238/1 16229/16237/1 +f 3938/3946/1 16225/16233/1 16228/16236/1 3939/3947/1 +f 8687/8695/1 16232/16240/1 16225/16233/1 3938/3946/1 +f 16232/16240/1 16231/16239/1 16226/16234/1 16225/16233/1 +f 16218/16226/1 16221/16229/1 16224/16232/1 16219/16227/1 +f 8691/8699/1 3936/3944/1 16221/16229/1 16218/16226/1 +f 3936/3944/1 3935/3943/1 16222/16230/1 16221/16229/1 +f 8722/8730/1 16217/16225/1 16220/16228/1 8723/8731/1 +f 3931/3939/1 8692/8700/1 16217/16225/1 8722/8730/1 +f 8692/8700/1 8691/8699/1 16218/16226/1 16217/16225/1 +f 3926/3934/1 16213/16221/1 16216/16224/1 3927/3935/1 +f 8723/8731/1 16220/16228/1 16213/16221/1 3926/3934/1 +f 16220/16228/1 16219/16227/1 16214/16222/1 16213/16221/1 +f 16206/16214/1 16209/16217/1 16212/16220/1 16207/16215/1 +f 8727/8735/1 3924/3932/1 16209/16217/1 16206/16214/1 +f 3924/3932/1 3923/3931/1 16210/16218/1 16209/16217/1 +f 8758/8766/1 16205/16213/1 16208/16216/1 8759/8767/1 +f 3919/3927/1 8728/8736/1 16205/16213/1 8758/8766/1 +f 8728/8736/1 8727/8735/1 16206/16214/1 16205/16213/1 +f 3914/3922/1 16201/16209/1 16204/16212/1 3915/3923/1 +f 8759/8767/1 16208/16216/1 16201/16209/1 3914/3922/1 +f 16208/16216/1 16207/16215/1 16202/16210/1 16201/16209/1 +f 16194/16202/1 16197/16205/1 16200/16208/1 16195/16203/1 +f 8763/8771/1 3912/3920/1 16197/16205/1 16194/16202/1 +f 3912/3920/1 3911/3919/1 16198/16206/1 16197/16205/1 +f 8794/8802/1 16193/16201/1 16196/16204/1 8795/8803/1 +f 3907/3915/1 8764/8772/1 16193/16201/1 8794/8802/1 +f 8764/8772/1 8763/8771/1 16194/16202/1 16193/16201/1 +f 3902/3910/1 16189/16197/1 16192/16200/1 3903/3911/1 +f 8795/8803/1 16196/16204/1 16189/16197/1 3902/3910/1 +f 16196/16204/1 16195/16203/1 16190/16198/1 16189/16197/1 +f 16182/16190/1 16185/16193/1 16188/16196/1 16183/16191/1 +f 8799/8807/1 3900/3908/1 16185/16193/1 16182/16190/1 +f 3900/3908/1 3899/3907/1 16186/16194/1 16185/16193/1 +f 8830/8838/1 16181/16189/1 16184/16192/1 8831/8839/1 +f 3895/3903/1 8800/8808/1 16181/16189/1 8830/8838/1 +f 8800/8808/1 8799/8807/1 16182/16190/1 16181/16189/1 +f 3890/3898/1 16177/16185/1 16180/16188/1 3891/3899/1 +f 8831/8839/1 16184/16192/1 16177/16185/1 3890/3898/1 +f 16184/16192/1 16183/16191/1 16178/16186/1 16177/16185/1 +f 16170/16178/1 16173/16181/1 16176/16184/1 16171/16179/1 +f 8835/8843/1 3888/3896/1 16173/16181/1 16170/16178/1 +f 3888/3896/1 3887/3895/1 16174/16182/1 16173/16181/1 +f 8866/8874/1 16169/16177/1 16172/16180/1 8867/8875/1 +f 3883/3891/1 8836/8844/1 16169/16177/1 8866/8874/1 +f 8836/8844/1 8835/8843/1 16170/16178/1 16169/16177/1 +f 3878/3886/1 16165/16173/1 16168/16176/1 3879/3887/1 +f 8867/8875/1 16172/16180/1 16165/16173/1 3878/3886/1 +f 16172/16180/1 16171/16179/1 16166/16174/1 16165/16173/1 +f 16158/16166/1 16161/16169/1 16164/16172/1 16159/16167/1 +f 8871/8879/1 3876/3884/1 16161/16169/1 16158/16166/1 +f 3876/3884/1 3875/3883/1 16162/16170/1 16161/16169/1 +f 8902/8910/1 16157/16165/1 16160/16168/1 8903/8911/1 +f 3871/3879/1 8872/8880/1 16157/16165/1 8902/8910/1 +f 8872/8880/1 8871/8879/1 16158/16166/1 16157/16165/1 +f 3866/3874/1 16153/16161/1 16156/16164/1 3867/3875/1 +f 8903/8911/1 16160/16168/1 16153/16161/1 3866/3874/1 +f 16160/16168/1 16159/16167/1 16154/16162/1 16153/16161/1 +f 16146/16154/1 16149/16157/1 16152/16160/1 16147/16155/1 +f 8907/8915/1 3864/3872/1 16149/16157/1 16146/16154/1 +f 3864/3872/1 3863/3871/1 16150/16158/1 16149/16157/1 +f 8938/8946/1 16145/16153/1 16148/16156/1 8939/8947/1 +f 3859/3867/1 8908/8916/1 16145/16153/1 8938/8946/1 +f 8908/8916/1 8907/8915/1 16146/16154/1 16145/16153/1 +f 3854/3862/1 16141/16149/1 16144/16152/1 3855/3863/1 +f 8939/8947/1 16148/16156/1 16141/16149/1 3854/3862/1 +f 16148/16156/1 16147/16155/1 16142/16150/1 16141/16149/1 +f 16134/16142/1 16137/16145/1 16140/16148/1 16135/16143/1 +f 8943/8951/1 3852/3860/1 16137/16145/1 16134/16142/1 +f 3852/3860/1 3851/3859/1 16138/16146/1 16137/16145/1 +f 8974/8982/1 16133/16141/1 16136/16144/1 8975/8983/1 +f 3847/3855/1 8944/8952/1 16133/16141/1 8974/8982/1 +f 8944/8952/1 8943/8951/1 16134/16142/1 16133/16141/1 +f 3842/3850/1 16129/16137/1 16132/16140/1 3843/3851/1 +f 8975/8983/1 16136/16144/1 16129/16137/1 3842/3850/1 +f 16136/16144/1 16135/16143/1 16130/16138/1 16129/16137/1 +f 16122/16130/1 16125/16133/1 16128/16136/1 16123/16131/1 +f 8979/8987/1 3840/3848/1 16125/16133/1 16122/16130/1 +f 3840/3848/1 3839/3847/1 16126/16134/1 16125/16133/1 +f 9010/9018/1 16121/16129/1 16124/16132/1 9011/9019/1 +f 3835/3843/1 8980/8988/1 16121/16129/1 9010/9018/1 +f 8980/8988/1 8979/8987/1 16122/16130/1 16121/16129/1 +f 3830/3838/1 16117/16125/1 16120/16128/1 3831/3839/1 +f 9011/9019/1 16124/16132/1 16117/16125/1 3830/3838/1 +f 16124/16132/1 16123/16131/1 16118/16126/1 16117/16125/1 +f 16110/16118/1 16113/16121/1 16116/16124/1 16111/16119/1 +f 9015/9023/1 3828/3836/1 16113/16121/1 16110/16118/1 +f 3828/3836/1 3827/3835/1 16114/16122/1 16113/16121/1 +f 9046/9054/1 16109/16117/1 16112/16120/1 9047/9055/1 +f 3823/3831/1 9016/9024/1 16109/16117/1 9046/9054/1 +f 9016/9024/1 9015/9023/1 16110/16118/1 16109/16117/1 +f 3818/3826/1 16105/16113/1 16108/16116/1 3819/3827/1 +f 9047/9055/1 16112/16120/1 16105/16113/1 3818/3826/1 +f 16112/16120/1 16111/16119/1 16106/16114/1 16105/16113/1 +f 16098/16106/1 16101/16109/1 16104/16112/1 16099/16107/1 +f 9051/9059/1 3816/3824/1 16101/16109/1 16098/16106/1 +f 3816/3824/1 3815/3823/1 16102/16110/1 16101/16109/1 +f 9082/9090/1 16097/16105/1 16100/16108/1 9083/9091/1 +f 3811/3819/1 9052/9060/1 16097/16105/1 9082/9090/1 +f 9052/9060/1 9051/9059/1 16098/16106/1 16097/16105/1 +f 3806/3814/1 16093/16101/1 16096/16104/1 3807/3815/1 +f 9083/9091/1 16100/16108/1 16093/16101/1 3806/3814/1 +f 16100/16108/1 16099/16107/1 16094/16102/1 16093/16101/1 +f 16086/16094/1 16089/16097/1 16092/16100/1 16087/16095/1 +f 9087/9095/1 3804/3812/1 16089/16097/1 16086/16094/1 +f 3804/3812/1 3803/3811/1 16090/16098/1 16089/16097/1 +f 9118/9126/1 16085/16093/1 16088/16096/1 9119/9127/1 +f 3799/3807/1 9088/9096/1 16085/16093/1 9118/9126/1 +f 9088/9096/1 9087/9095/1 16086/16094/1 16085/16093/1 +f 3794/3802/1 16081/16089/1 16084/16092/1 3795/3803/1 +f 9119/9127/1 16088/16096/1 16081/16089/1 3794/3802/1 +f 16088/16096/1 16087/16095/1 16082/16090/1 16081/16089/1 +f 16074/16082/1 16077/16085/1 16080/16088/1 16075/16083/1 +f 9123/9131/1 3792/3800/1 16077/16085/1 16074/16082/1 +f 3792/3800/1 3791/3799/1 16078/16086/1 16077/16085/1 +f 9154/9162/1 16073/16081/1 16076/16084/1 9155/9163/1 +f 3787/3795/1 9124/9132/1 16073/16081/1 9154/9162/1 +f 9124/9132/1 9123/9131/1 16074/16082/1 16073/16081/1 +f 3782/3790/1 16069/16077/1 16072/16080/1 3783/3791/1 +f 9155/9163/1 16076/16084/1 16069/16077/1 3782/3790/1 +f 16076/16084/1 16075/16083/1 16070/16078/1 16069/16077/1 +f 16062/16070/1 16065/16073/1 16068/16076/1 16063/16071/1 +f 9159/9167/1 3780/3788/1 16065/16073/1 16062/16070/1 +f 3780/3788/1 3779/3787/1 16066/16074/1 16065/16073/1 +f 9190/9198/1 16061/16069/1 16064/16072/1 9191/9199/1 +f 3775/3783/1 9160/9168/1 16061/16069/1 9190/9198/1 +f 9160/9168/1 9159/9167/1 16062/16070/1 16061/16069/1 +f 3770/3778/1 16057/16065/1 16060/16068/1 3771/3779/1 +f 9191/9199/1 16064/16072/1 16057/16065/1 3770/3778/1 +f 16064/16072/1 16063/16071/1 16058/16066/1 16057/16065/1 +f 16050/16058/1 16053/16061/1 16056/16064/1 16051/16059/1 +f 9195/9203/1 3768/3776/1 16053/16061/1 16050/16058/1 +f 3768/3776/1 3767/3775/1 16054/16062/1 16053/16061/1 +f 9226/9234/1 16049/16057/1 16052/16060/1 9227/9235/1 +f 3763/3771/1 9196/9204/1 16049/16057/1 9226/9234/1 +f 9196/9204/1 9195/9203/1 16050/16058/1 16049/16057/1 +f 3758/3766/1 16045/16053/1 16048/16056/1 3759/3767/1 +f 9227/9235/1 16052/16060/1 16045/16053/1 3758/3766/1 +f 16052/16060/1 16051/16059/1 16046/16054/1 16045/16053/1 +f 16038/16046/1 16041/16049/1 16044/16052/1 16039/16047/1 +f 9231/9239/1 3756/3764/1 16041/16049/1 16038/16046/1 +f 3756/3764/1 3755/3763/1 16042/16050/1 16041/16049/1 +f 9262/9270/1 16037/16045/1 16040/16048/1 9263/9271/1 +f 3751/3759/1 9232/9240/1 16037/16045/1 9262/9270/1 +f 9232/9240/1 9231/9239/1 16038/16046/1 16037/16045/1 +f 3746/3754/1 16033/16041/1 16036/16044/1 3747/3755/1 +f 9263/9271/1 16040/16048/1 16033/16041/1 3746/3754/1 +f 16040/16048/1 16039/16047/1 16034/16042/1 16033/16041/1 +f 16026/16034/1 16029/16037/1 16032/16040/1 16027/16035/1 +f 9267/9275/1 3744/3752/1 16029/16037/1 16026/16034/1 +f 3744/3752/1 3743/3751/1 16030/16038/1 16029/16037/1 +f 9298/9306/1 16025/16033/1 16028/16036/1 9299/9307/1 +f 3739/3747/1 9268/9276/1 16025/16033/1 9298/9306/1 +f 9268/9276/1 9267/9275/1 16026/16034/1 16025/16033/1 +f 3734/3742/1 16021/16029/1 16024/16032/1 3735/3743/1 +f 9299/9307/1 16028/16036/1 16021/16029/1 3734/3742/1 +f 16028/16036/1 16027/16035/1 16022/16030/1 16021/16029/1 +f 16014/16022/1 16017/16025/1 16020/16028/1 16015/16023/1 +f 9303/9311/1 3732/3740/1 16017/16025/1 16014/16022/1 +f 3732/3740/1 3731/3739/1 16018/16026/1 16017/16025/1 +f 9334/9342/1 16013/16021/1 16016/16024/1 9335/9343/1 +f 3727/3735/1 9304/9312/1 16013/16021/1 9334/9342/1 +f 9304/9312/1 9303/9311/1 16014/16022/1 16013/16021/1 +f 3722/3730/1 16009/16017/1 16012/16020/1 3723/3731/1 +f 9335/9343/1 16016/16024/1 16009/16017/1 3722/3730/1 +f 16016/16024/1 16015/16023/1 16010/16018/1 16009/16017/1 +f 16002/16010/1 16005/16013/1 16008/16016/1 16003/16011/1 +f 9339/9347/1 3720/3728/1 16005/16013/1 16002/16010/1 +f 3720/3728/1 3719/3727/1 16006/16014/1 16005/16013/1 +f 9370/9378/1 16001/16009/1 16004/16012/1 9371/9379/1 +f 3715/3723/1 9340/9348/1 16001/16009/1 9370/9378/1 +f 9340/9348/1 9339/9347/1 16002/16010/1 16001/16009/1 +f 3710/3718/1 15997/16005/1 16000/16008/1 3711/3719/1 +f 9371/9379/1 16004/16012/1 15997/16005/1 3710/3718/1 +f 16004/16012/1 16003/16011/1 15998/16006/1 15997/16005/1 +f 15990/15998/1 15993/16001/1 15996/16004/1 15991/15999/1 +f 9375/9383/1 3708/3716/1 15993/16001/1 15990/15998/1 +f 3708/3716/1 3707/3715/1 15994/16002/1 15993/16001/1 +f 9406/9414/1 15989/15997/1 15992/16000/1 9407/9415/1 +f 3703/3711/1 9376/9384/1 15989/15997/1 9406/9414/1 +f 9376/9384/1 9375/9383/1 15990/15998/1 15989/15997/1 +f 3698/3706/1 15985/15993/1 15988/15996/1 3699/3707/1 +f 9407/9415/1 15992/16000/1 15985/15993/1 3698/3706/1 +f 15992/16000/1 15991/15999/1 15986/15994/1 15985/15993/1 +f 15978/15986/1 15981/15989/1 15984/15992/1 15979/15987/1 +f 9411/9419/1 3696/3704/1 15981/15989/1 15978/15986/1 +f 3696/3704/1 3695/3703/1 15982/15990/1 15981/15989/1 +f 9442/9450/1 15977/15985/1 15980/15988/1 9443/9451/1 +f 3691/3699/1 9412/9420/1 15977/15985/1 9442/9450/1 +f 9412/9420/1 9411/9419/1 15978/15986/1 15977/15985/1 +f 3686/3694/1 15973/15981/1 15976/15984/1 3687/3695/1 +f 9443/9451/1 15980/15988/1 15973/15981/1 3686/3694/1 +f 15980/15988/1 15979/15987/1 15974/15982/1 15973/15981/1 +f 15966/15974/1 15969/15977/1 15972/15980/1 15967/15975/1 +f 9447/9455/1 3684/3692/1 15969/15977/1 15966/15974/1 +f 3684/3692/1 3683/3691/1 15970/15978/1 15969/15977/1 +f 9478/9486/1 15965/15973/1 15968/15976/1 9479/9487/1 +f 3679/3687/1 9448/9456/1 15965/15973/1 9478/9486/1 +f 9448/9456/1 9447/9455/1 15966/15974/1 15965/15973/1 +f 3674/3682/1 15961/15969/1 15964/15972/1 3675/3683/1 +f 9479/9487/1 15968/15976/1 15961/15969/1 3674/3682/1 +f 15968/15976/1 15967/15975/1 15962/15970/1 15961/15969/1 +f 15954/15962/1 15957/15965/1 15960/15968/1 15955/15963/1 +f 9483/9491/1 3672/3680/1 15957/15965/1 15954/15962/1 +f 3672/3680/1 3671/3679/1 15958/15966/1 15957/15965/1 +f 9514/9522/1 15953/15961/1 15956/15964/1 9515/9523/1 +f 3667/3675/1 9484/9492/1 15953/15961/1 9514/9522/1 +f 9484/9492/1 9483/9491/1 15954/15962/1 15953/15961/1 +f 3662/3670/1 15949/15957/1 15952/15960/1 3663/3671/1 +f 9515/9523/1 15956/15964/1 15949/15957/1 3662/3670/1 +f 15956/15964/1 15955/15963/1 15950/15958/1 15949/15957/1 +f 15942/15950/1 15945/15953/1 15948/15956/1 15943/15951/1 +f 9519/9527/1 3660/3668/1 15945/15953/1 15942/15950/1 +f 3660/3668/1 3659/3667/1 15946/15954/1 15945/15953/1 +f 9550/9558/1 15941/15949/1 15944/15952/1 9551/9559/1 +f 3655/3663/1 9520/9528/1 15941/15949/1 9550/9558/1 +f 9520/9528/1 9519/9527/1 15942/15950/1 15941/15949/1 +f 3650/3658/1 15937/15945/1 15940/15948/1 3651/3659/1 +f 9551/9559/1 15944/15952/1 15937/15945/1 3650/3658/1 +f 15944/15952/1 15943/15951/1 15938/15946/1 15937/15945/1 +f 15930/15938/1 15933/15941/1 15936/15944/1 15931/15939/1 +f 9555/9563/1 3648/3656/1 15933/15941/1 15930/15938/1 +f 3648/3656/1 3647/3655/1 15934/15942/1 15933/15941/1 +f 9586/9594/1 15929/15937/1 15932/15940/1 9587/9595/1 +f 3643/3651/1 9556/9564/1 15929/15937/1 9586/9594/1 +f 9556/9564/1 9555/9563/1 15930/15938/1 15929/15937/1 +f 3638/3646/1 15925/15933/1 15928/15936/1 3639/3647/1 +f 9587/9595/1 15932/15940/1 15925/15933/1 3638/3646/1 +f 15932/15940/1 15931/15939/1 15926/15934/1 15925/15933/1 +f 15918/15926/1 15921/15929/1 15924/15932/1 15919/15927/1 +f 9591/9599/1 3636/3644/1 15921/15929/1 15918/15926/1 +f 3636/3644/1 3635/3643/1 15922/15930/1 15921/15929/1 +f 9622/9630/1 15917/15925/1 15920/15928/1 9623/9631/1 +f 3631/3639/1 9592/9600/1 15917/15925/1 9622/9630/1 +f 9592/9600/1 9591/9599/1 15918/15926/1 15917/15925/1 +f 3626/3634/1 15913/15921/1 15916/15924/1 3627/3635/1 +f 9623/9631/1 15920/15928/1 15913/15921/1 3626/3634/1 +f 15920/15928/1 15919/15927/1 15914/15922/1 15913/15921/1 +f 15906/15914/1 15909/15917/1 15912/15920/1 15907/15915/1 +f 9627/9635/1 3624/3632/1 15909/15917/1 15906/15914/1 +f 3624/3632/1 3623/3631/1 15910/15918/1 15909/15917/1 +f 9658/9666/1 15905/15913/1 15908/15916/1 9659/9667/1 +f 3619/3627/1 9628/9636/1 15905/15913/1 9658/9666/1 +f 9628/9636/1 9627/9635/1 15906/15914/1 15905/15913/1 +f 3614/3622/1 15901/15909/1 15904/15912/1 3615/3623/1 +f 9659/9667/1 15908/15916/1 15901/15909/1 3614/3622/1 +f 15908/15916/1 15907/15915/1 15902/15910/1 15901/15909/1 +f 15894/15902/1 15897/15905/1 15900/15908/1 15895/15903/1 +f 9663/9671/1 3612/3620/1 15897/15905/1 15894/15902/1 +f 3612/3620/1 3611/3619/1 15898/15906/1 15897/15905/1 +f 9694/9702/1 15893/15901/1 15896/15904/1 9695/9703/1 +f 3607/3615/1 9664/9672/1 15893/15901/1 9694/9702/1 +f 9664/9672/1 9663/9671/1 15894/15902/1 15893/15901/1 +f 3602/3610/1 15889/15897/1 15892/15900/1 3603/3611/1 +f 9695/9703/1 15896/15904/1 15889/15897/1 3602/3610/1 +f 15896/15904/1 15895/15903/1 15890/15898/1 15889/15897/1 +f 15882/15890/1 15885/15893/1 15888/15896/1 15883/15891/1 +f 9699/9707/1 3600/3608/1 15885/15893/1 15882/15890/1 +f 3600/3608/1 3599/3607/1 15886/15894/1 15885/15893/1 +f 9730/9738/1 15881/15889/1 15884/15892/1 9731/9739/1 +f 3595/3603/1 9700/9708/1 15881/15889/1 9730/9738/1 +f 9700/9708/1 9699/9707/1 15882/15890/1 15881/15889/1 +f 3590/3598/1 15877/15885/1 15880/15888/1 3591/3599/1 +f 9731/9739/1 15884/15892/1 15877/15885/1 3590/3598/1 +f 15884/15892/1 15883/15891/1 15878/15886/1 15877/15885/1 +f 15870/15878/1 15873/15881/1 15876/15884/1 15871/15879/1 +f 9735/9743/1 3588/3596/1 15873/15881/1 15870/15878/1 +f 3588/3596/1 3587/3595/1 15874/15882/1 15873/15881/1 +f 9766/9774/1 15869/15877/1 15872/15880/1 9767/9775/1 +f 3583/3591/1 9736/9744/1 15869/15877/1 9766/9774/1 +f 9736/9744/1 9735/9743/1 15870/15878/1 15869/15877/1 +f 3578/3586/1 15865/15873/1 15868/15876/1 3579/3587/1 +f 9767/9775/1 15872/15880/1 15865/15873/1 3578/3586/1 +f 15872/15880/1 15871/15879/1 15866/15874/1 15865/15873/1 +f 15858/15866/1 15861/15869/1 15864/15872/1 15859/15867/1 +f 9771/9779/1 3576/3584/1 15861/15869/1 15858/15866/1 +f 3576/3584/1 3575/3583/1 15862/15870/1 15861/15869/1 +f 9802/9810/1 15857/15865/1 15860/15868/1 9803/9811/1 +f 3571/3579/1 9772/9780/1 15857/15865/1 9802/9810/1 +f 9772/9780/1 9771/9779/1 15858/15866/1 15857/15865/1 +f 3566/3574/1 15853/15861/1 15856/15864/1 3567/3575/1 +f 9803/9811/1 15860/15868/1 15853/15861/1 3566/3574/1 +f 15860/15868/1 15859/15867/1 15854/15862/1 15853/15861/1 +f 15846/15854/1 15849/15857/1 15852/15860/1 15847/15855/1 +f 9807/9815/1 3564/3572/1 15849/15857/1 15846/15854/1 +f 3564/3572/1 3563/3571/1 15850/15858/1 15849/15857/1 +f 9838/9846/1 15845/15853/1 15848/15856/1 9839/9847/1 +f 3559/3567/1 9808/9816/1 15845/15853/1 9838/9846/1 +f 9808/9816/1 9807/9815/1 15846/15854/1 15845/15853/1 +f 3554/3562/1 15841/15849/1 15844/15852/1 3555/3563/1 +f 9839/9847/1 15848/15856/1 15841/15849/1 3554/3562/1 +f 15848/15856/1 15847/15855/1 15842/15850/1 15841/15849/1 +f 15834/15842/1 15837/15845/1 15840/15848/1 15835/15843/1 +f 9843/9851/1 3552/3560/1 15837/15845/1 15834/15842/1 +f 3552/3560/1 3551/3559/1 15838/15846/1 15837/15845/1 +f 9874/9882/1 15833/15841/1 15836/15844/1 9875/9883/1 +f 3547/3555/1 9844/9852/1 15833/15841/1 9874/9882/1 +f 9844/9852/1 9843/9851/1 15834/15842/1 15833/15841/1 +f 3542/3550/1 15829/15837/1 15832/15840/1 3543/3551/1 +f 9875/9883/1 15836/15844/1 15829/15837/1 3542/3550/1 +f 15836/15844/1 15835/15843/1 15830/15838/1 15829/15837/1 +f 15822/15830/1 15825/15833/1 15828/15836/1 15823/15831/1 +f 9879/9887/1 3540/3548/1 15825/15833/1 15822/15830/1 +f 3540/3548/1 3539/3547/1 15826/15834/1 15825/15833/1 +f 9910/9918/1 15821/15829/1 15824/15832/1 9911/9919/1 +f 3535/3543/1 9880/9888/1 15821/15829/1 9910/9918/1 +f 9880/9888/1 9879/9887/1 15822/15830/1 15821/15829/1 +f 3530/3538/1 15817/15825/1 15820/15828/1 3531/3539/1 +f 9911/9919/1 15824/15832/1 15817/15825/1 3530/3538/1 +f 15824/15832/1 15823/15831/1 15818/15826/1 15817/15825/1 +f 15810/15818/1 15813/15821/1 15816/15824/1 15811/15819/1 +f 9915/9923/1 3528/3536/1 15813/15821/1 15810/15818/1 +f 3528/3536/1 3527/3535/1 15814/15822/1 15813/15821/1 +f 9946/9954/1 15809/15817/1 15812/15820/1 9947/9955/1 +f 3523/3531/1 9916/9924/1 15809/15817/1 9946/9954/1 +f 9916/9924/1 9915/9923/1 15810/15818/1 15809/15817/1 +f 3518/3526/1 15805/15813/1 15808/15816/1 3519/3527/1 +f 9947/9955/1 15812/15820/1 15805/15813/1 3518/3526/1 +f 15812/15820/1 15811/15819/1 15806/15814/1 15805/15813/1 +f 15798/15806/1 15801/15809/1 15804/15812/1 15799/15807/1 +f 9951/9959/1 3516/3524/1 15801/15809/1 15798/15806/1 +f 3516/3524/1 3515/3523/1 15802/15810/1 15801/15809/1 +f 9982/9990/1 15797/15805/1 15800/15808/1 9983/9991/1 +f 3511/3519/1 9952/9960/1 15797/15805/1 9982/9990/1 +f 9952/9960/1 9951/9959/1 15798/15806/1 15797/15805/1 +f 3506/3514/1 15793/15801/1 15796/15804/1 3507/3515/1 +f 9983/9991/1 15800/15808/1 15793/15801/1 3506/3514/1 +f 15800/15808/1 15799/15807/1 15794/15802/1 15793/15801/1 +f 15786/15794/1 15789/15797/1 15792/15800/1 15787/15795/1 +f 9987/9995/1 3504/3512/1 15789/15797/1 15786/15794/1 +f 3504/3512/1 3503/3511/1 15790/15798/1 15789/15797/1 +f 10018/10026/1 15785/15793/1 15788/15796/1 10019/10027/1 +f 3499/3507/1 9988/9996/1 15785/15793/1 10018/10026/1 +f 9988/9996/1 9987/9995/1 15786/15794/1 15785/15793/1 +f 3494/3502/1 15781/15789/1 15784/15792/1 3495/3503/1 +f 10019/10027/1 15788/15796/1 15781/15789/1 3494/3502/1 +f 15788/15796/1 15787/15795/1 15782/15790/1 15781/15789/1 +f 15774/15782/1 15777/15785/1 15780/15788/1 15775/15783/1 +f 10023/10031/1 3492/3500/1 15777/15785/1 15774/15782/1 +f 3492/3500/1 3491/3499/1 15778/15786/1 15777/15785/1 +f 10054/10062/1 15773/15781/1 15776/15784/1 10055/10063/1 +f 3487/3495/1 10024/10032/1 15773/15781/1 10054/10062/1 +f 10024/10032/1 10023/10031/1 15774/15782/1 15773/15781/1 +f 3482/3490/1 15769/15777/1 15772/15780/1 3483/3491/1 +f 10055/10063/1 15776/15784/1 15769/15777/1 3482/3490/1 +f 15776/15784/1 15775/15783/1 15770/15778/1 15769/15777/1 +f 15762/15770/1 15765/15773/1 15768/15776/1 15763/15771/1 +f 10059/10067/1 3480/3488/1 15765/15773/1 15762/15770/1 +f 3480/3488/1 3479/3487/1 15766/15774/1 15765/15773/1 +f 10090/10098/1 15761/15769/1 15764/15772/1 10091/10099/1 +f 3475/3483/1 10060/10068/1 15761/15769/1 10090/10098/1 +f 10060/10068/1 10059/10067/1 15762/15770/1 15761/15769/1 +f 3470/3478/1 15757/15765/1 15760/15768/1 3471/3479/1 +f 10091/10099/1 15764/15772/1 15757/15765/1 3470/3478/1 +f 15764/15772/1 15763/15771/1 15758/15766/1 15757/15765/1 +f 15750/15758/1 15753/15761/1 15756/15764/1 15751/15759/1 +f 10095/10103/1 3468/3476/1 15753/15761/1 15750/15758/1 +f 3468/3476/1 3467/3475/1 15754/15762/1 15753/15761/1 +f 10126/10134/1 15749/15757/1 15752/15760/1 10127/10135/1 +f 3463/3471/1 10096/10104/1 15749/15757/1 10126/10134/1 +f 10096/10104/1 10095/10103/1 15750/15758/1 15749/15757/1 +f 3458/3466/1 15745/15753/1 15748/15756/1 3459/3467/1 +f 10127/10135/1 15752/15760/1 15745/15753/1 3458/3466/1 +f 15752/15760/1 15751/15759/1 15746/15754/1 15745/15753/1 +f 15738/15746/1 15741/15749/1 15744/15752/1 15739/15747/1 +f 10131/10139/1 3456/3464/1 15741/15749/1 15738/15746/1 +f 3456/3464/1 3455/3463/1 15742/15750/1 15741/15749/1 +f 10162/10170/1 15737/15745/1 15740/15748/1 10163/10171/1 +f 3451/3459/1 10132/10140/1 15737/15745/1 10162/10170/1 +f 10132/10140/1 10131/10139/1 15738/15746/1 15737/15745/1 +f 3446/3454/1 15733/15741/1 15736/15744/1 3447/3455/1 +f 10163/10171/1 15740/15748/1 15733/15741/1 3446/3454/1 +f 15740/15748/1 15739/15747/1 15734/15742/1 15733/15741/1 +f 15726/15734/1 15729/15737/1 15732/15740/1 15727/15735/1 +f 10167/10175/1 3444/3452/1 15729/15737/1 15726/15734/1 +f 3444/3452/1 3443/3451/1 15730/15738/1 15729/15737/1 +f 10198/10206/1 15725/15733/1 15728/15736/1 10199/10207/1 +f 3439/3447/1 10168/10176/1 15725/15733/1 10198/10206/1 +f 10168/10176/1 10167/10175/1 15726/15734/1 15725/15733/1 +f 3434/3442/1 15721/15729/1 15724/15732/1 3435/3443/1 +f 10199/10207/1 15728/15736/1 15721/15729/1 3434/3442/1 +f 15728/15736/1 15727/15735/1 15722/15730/1 15721/15729/1 +f 15714/15722/1 15717/15725/1 15720/15728/1 15715/15723/1 +f 10203/10211/1 3432/3440/1 15717/15725/1 15714/15722/1 +f 3432/3440/1 3431/3439/1 15718/15726/1 15717/15725/1 +f 10234/10242/1 15713/15721/1 15716/15724/1 10235/10243/1 +f 3427/3435/1 10204/10212/1 15713/15721/1 10234/10242/1 +f 10204/10212/1 10203/10211/1 15714/15722/1 15713/15721/1 +f 3422/3430/1 15709/15717/1 15712/15720/1 3423/3431/1 +f 10235/10243/1 15716/15724/1 15709/15717/1 3422/3430/1 +f 15716/15724/1 15715/15723/1 15710/15718/1 15709/15717/1 +f 15702/15710/1 15705/15713/1 15708/15716/1 15703/15711/1 +f 10239/10247/1 3420/3428/1 15705/15713/1 15702/15710/1 +f 3420/3428/1 3419/3427/1 15706/15714/1 15705/15713/1 +f 10270/10278/1 15701/15709/1 15704/15712/1 10271/10279/1 +f 3415/3423/1 10240/10248/1 15701/15709/1 10270/10278/1 +f 10240/10248/1 10239/10247/1 15702/15710/1 15701/15709/1 +f 3410/3418/1 15697/15705/1 15700/15708/1 3411/3419/1 +f 10271/10279/1 15704/15712/1 15697/15705/1 3410/3418/1 +f 15704/15712/1 15703/15711/1 15698/15706/1 15697/15705/1 +f 15690/15698/1 15693/15701/1 15696/15704/1 15691/15699/1 +f 10275/10283/1 3408/3416/1 15693/15701/1 15690/15698/1 +f 3408/3416/1 3407/3415/1 15694/15702/1 15693/15701/1 +f 10306/10314/1 15689/15697/1 15692/15700/1 10307/10315/1 +f 3403/3411/1 10276/10284/1 15689/15697/1 10306/10314/1 +f 10276/10284/1 10275/10283/1 15690/15698/1 15689/15697/1 +f 3398/3406/1 15685/15693/1 15688/15696/1 3399/3407/1 +f 10307/10315/1 15692/15700/1 15685/15693/1 3398/3406/1 +f 15692/15700/1 15691/15699/1 15686/15694/1 15685/15693/1 +f 15678/15686/1 15681/15689/1 15684/15692/1 15679/15687/1 +f 10311/10319/1 3396/3404/1 15681/15689/1 15678/15686/1 +f 3396/3404/1 3395/3403/1 15682/15690/1 15681/15689/1 +f 10342/10350/1 15677/15685/1 15680/15688/1 10343/10351/1 +f 3391/3399/1 10312/10320/1 15677/15685/1 10342/10350/1 +f 10312/10320/1 10311/10319/1 15678/15686/1 15677/15685/1 +f 3386/3394/1 15673/15681/1 15676/15684/1 3387/3395/1 +f 10343/10351/1 15680/15688/1 15673/15681/1 3386/3394/1 +f 15680/15688/1 15679/15687/1 15674/15682/1 15673/15681/1 +f 15666/15674/1 15669/15677/1 15672/15680/1 15667/15675/1 +f 10347/10355/1 3384/3392/1 15669/15677/1 15666/15674/1 +f 3384/3392/1 3383/3391/1 15670/15678/1 15669/15677/1 +f 10378/10386/1 15665/15673/1 15668/15676/1 10379/10387/1 +f 3379/3387/1 10348/10356/1 15665/15673/1 10378/10386/1 +f 10348/10356/1 10347/10355/1 15666/15674/1 15665/15673/1 +f 3374/3382/1 15661/15669/1 15664/15672/1 3375/3383/1 +f 10379/10387/1 15668/15676/1 15661/15669/1 3374/3382/1 +f 15668/15676/1 15667/15675/1 15662/15670/1 15661/15669/1 +f 15654/15662/1 15657/15665/1 15660/15668/1 15655/15663/1 +f 10383/10391/1 3372/3380/1 15657/15665/1 15654/15662/1 +f 3372/3380/1 3371/3379/1 15658/15666/1 15657/15665/1 +f 10414/10422/1 15653/15661/1 15656/15664/1 10415/10423/1 +f 3367/3375/1 10384/10392/1 15653/15661/1 10414/10422/1 +f 10384/10392/1 10383/10391/1 15654/15662/1 15653/15661/1 +f 3362/3370/1 15649/15657/1 15652/15660/1 3363/3371/1 +f 10415/10423/1 15656/15664/1 15649/15657/1 3362/3370/1 +f 15656/15664/1 15655/15663/1 15650/15658/1 15649/15657/1 +f 15642/15650/1 15645/15653/1 15648/15656/1 15643/15651/1 +f 10419/10427/1 3360/3368/1 15645/15653/1 15642/15650/1 +f 3360/3368/1 3359/3367/1 15646/15654/1 15645/15653/1 +f 10450/10458/1 15641/15649/1 15644/15652/1 10451/10459/1 +f 3355/3363/1 10420/10428/1 15641/15649/1 10450/10458/1 +f 10420/10428/1 10419/10427/1 15642/15650/1 15641/15649/1 +f 3350/3358/1 15637/15645/1 15640/15648/1 3351/3359/1 +f 10451/10459/1 15644/15652/1 15637/15645/1 3350/3358/1 +f 15644/15652/1 15643/15651/1 15638/15646/1 15637/15645/1 +f 15630/15638/1 15633/15641/1 15636/15644/1 15631/15639/1 +f 10455/10463/1 3348/3356/1 15633/15641/1 15630/15638/1 +f 3348/3356/1 3347/3355/1 15634/15642/1 15633/15641/1 +f 10486/10494/1 15629/15637/1 15632/15640/1 10487/10495/1 +f 3343/3351/1 10456/10464/1 15629/15637/1 10486/10494/1 +f 10456/10464/1 10455/10463/1 15630/15638/1 15629/15637/1 +f 3338/3346/1 15625/15633/1 15628/15636/1 3339/3347/1 +f 10487/10495/1 15632/15640/1 15625/15633/1 3338/3346/1 +f 15632/15640/1 15631/15639/1 15626/15634/1 15625/15633/1 +f 15618/15626/1 15621/15629/1 15624/15632/1 15619/15627/1 +f 10491/10499/1 3336/3344/1 15621/15629/1 15618/15626/1 +f 3336/3344/1 3335/3343/1 15622/15630/1 15621/15629/1 +f 10522/10530/1 15617/15625/1 15620/15628/1 10523/10531/1 +f 3331/3339/1 10492/10500/1 15617/15625/1 10522/10530/1 +f 10492/10500/1 10491/10499/1 15618/15626/1 15617/15625/1 +f 3326/3334/1 15613/15621/1 15616/15624/1 3327/3335/1 +f 10523/10531/1 15620/15628/1 15613/15621/1 3326/3334/1 +f 15620/15628/1 15619/15627/1 15614/15622/1 15613/15621/1 +f 15606/15614/1 15609/15617/1 15612/15620/1 15607/15615/1 +f 10527/10535/1 3324/3332/1 15609/15617/1 15606/15614/1 +f 3324/3332/1 3323/3331/1 15610/15618/1 15609/15617/1 +f 10558/10566/1 15605/15613/1 15608/15616/1 10559/10567/1 +f 3319/3327/1 10528/10536/1 15605/15613/1 10558/10566/1 +f 10528/10536/1 10527/10535/1 15606/15614/1 15605/15613/1 +f 3314/3322/1 15601/15609/1 15604/15612/1 3315/3323/1 +f 10559/10567/1 15608/15616/1 15601/15609/1 3314/3322/1 +f 15608/15616/1 15607/15615/1 15602/15610/1 15601/15609/1 +f 15594/15602/1 15597/15605/1 15600/15608/1 15595/15603/1 +f 10563/10571/1 3312/3320/1 15597/15605/1 15594/15602/1 +f 3312/3320/1 3311/3319/1 15598/15606/1 15597/15605/1 +f 10594/10602/1 15593/15601/1 15596/15604/1 10595/10603/1 +f 3307/3315/1 10564/10572/1 15593/15601/1 10594/10602/1 +f 10564/10572/1 10563/10571/1 15594/15602/1 15593/15601/1 +f 3302/3310/1 15589/15597/1 15592/15600/1 3303/3311/1 +f 10595/10603/1 15596/15604/1 15589/15597/1 3302/3310/1 +f 15596/15604/1 15595/15603/1 15590/15598/1 15589/15597/1 +f 15582/15590/1 15585/15593/1 15588/15596/1 15583/15591/1 +f 10599/10607/1 3300/3308/1 15585/15593/1 15582/15590/1 +f 3300/3308/1 3299/3307/1 15586/15594/1 15585/15593/1 +f 10630/10638/1 15581/15589/1 15584/15592/1 10631/10639/1 +f 3295/3303/1 10600/10608/1 15581/15589/1 10630/10638/1 +f 10600/10608/1 10599/10607/1 15582/15590/1 15581/15589/1 +f 3290/3298/1 15577/15585/1 15580/15588/1 3291/3299/1 +f 10631/10639/1 15584/15592/1 15577/15585/1 3290/3298/1 +f 15584/15592/1 15583/15591/1 15578/15586/1 15577/15585/1 +f 15570/15578/1 15573/15581/1 15576/15584/1 15571/15579/1 +f 10635/10643/1 3288/3296/1 15573/15581/1 15570/15578/1 +f 3288/3296/1 3287/3295/1 15574/15582/1 15573/15581/1 +f 10666/10674/1 15569/15577/1 15572/15580/1 10667/10675/1 +f 3283/3291/1 10636/10644/1 15569/15577/1 10666/10674/1 +f 10636/10644/1 10635/10643/1 15570/15578/1 15569/15577/1 +f 3278/3286/1 15565/15573/1 15568/15576/1 3279/3287/1 +f 10667/10675/1 15572/15580/1 15565/15573/1 3278/3286/1 +f 15572/15580/1 15571/15579/1 15566/15574/1 15565/15573/1 +f 15558/15566/1 15561/15569/1 15564/15572/1 15559/15567/1 +f 10671/10679/1 3276/3284/1 15561/15569/1 15558/15566/1 +f 3276/3284/1 3275/3283/1 15562/15570/1 15561/15569/1 +f 10702/10710/1 15557/15565/1 15560/15568/1 10703/10711/1 +f 3271/3279/1 10672/10680/1 15557/15565/1 10702/10710/1 +f 10672/10680/1 10671/10679/1 15558/15566/1 15557/15565/1 +f 3266/3274/1 15553/15561/1 15556/15564/1 3267/3275/1 +f 10703/10711/1 15560/15568/1 15553/15561/1 3266/3274/1 +f 15560/15568/1 15559/15567/1 15554/15562/1 15553/15561/1 +f 15546/15554/1 15549/15557/1 15552/15560/1 15547/15555/1 +f 10707/10715/1 3264/3272/1 15549/15557/1 15546/15554/1 +f 3264/3272/1 3263/3271/1 15550/15558/1 15549/15557/1 +f 10738/10746/1 15545/15553/1 15548/15556/1 10739/10747/1 +f 3259/3267/1 10708/10716/1 15545/15553/1 10738/10746/1 +f 10708/10716/1 10707/10715/1 15546/15554/1 15545/15553/1 +f 3254/3262/1 15541/15549/1 15544/15552/1 3255/3263/1 +f 10739/10747/1 15548/15556/1 15541/15549/1 3254/3262/1 +f 15548/15556/1 15547/15555/1 15542/15550/1 15541/15549/1 +f 15534/15542/1 15537/15545/1 15540/15548/1 15535/15543/1 +f 10743/10751/1 3252/3260/1 15537/15545/1 15534/15542/1 +f 3252/3260/1 3251/3259/1 15538/15546/1 15537/15545/1 +f 10774/10782/1 15533/15541/1 15536/15544/1 10775/10783/1 +f 3247/3255/1 10744/10752/1 15533/15541/1 10774/10782/1 +f 10744/10752/1 10743/10751/1 15534/15542/1 15533/15541/1 +f 3242/3250/1 15529/15537/1 15532/15540/1 3243/3251/1 +f 10775/10783/1 15536/15544/1 15529/15537/1 3242/3250/1 +f 15536/15544/1 15535/15543/1 15530/15538/1 15529/15537/1 +f 15522/15530/1 15525/15533/1 15528/15536/1 15523/15531/1 +f 10779/10787/1 3240/3248/1 15525/15533/1 15522/15530/1 +f 3240/3248/1 3239/3247/1 15526/15534/1 15525/15533/1 +f 10810/10818/1 15521/15529/1 15524/15532/1 10811/10819/1 +f 3235/3243/1 10780/10788/1 15521/15529/1 10810/10818/1 +f 10780/10788/1 10779/10787/1 15522/15530/1 15521/15529/1 +f 3230/3238/1 15517/15525/1 15520/15528/1 3231/3239/1 +f 10811/10819/1 15524/15532/1 15517/15525/1 3230/3238/1 +f 15524/15532/1 15523/15531/1 15518/15526/1 15517/15525/1 +f 15510/15518/1 15513/15521/1 15516/15524/1 15511/15519/1 +f 10815/10823/1 3228/3236/1 15513/15521/1 15510/15518/1 +f 3228/3236/1 3227/3235/1 15514/15522/1 15513/15521/1 +f 10846/10854/1 15509/15517/1 15512/15520/1 10847/10855/1 +f 3223/3231/1 10816/10824/1 15509/15517/1 10846/10854/1 +f 10816/10824/1 10815/10823/1 15510/15518/1 15509/15517/1 +f 3218/3226/1 15505/15513/1 15508/15516/1 3219/3227/1 +f 10847/10855/1 15512/15520/1 15505/15513/1 3218/3226/1 +f 15512/15520/1 15511/15519/1 15506/15514/1 15505/15513/1 +f 15498/15506/1 15501/15509/1 15504/15512/1 15499/15507/1 +f 10851/10859/1 3216/3224/1 15501/15509/1 15498/15506/1 +f 3216/3224/1 3215/3223/1 15502/15510/1 15501/15509/1 +f 10882/10890/1 15497/15505/1 15500/15508/1 10883/10891/1 +f 3211/3219/1 10852/10860/1 15497/15505/1 10882/10890/1 +f 10852/10860/1 10851/10859/1 15498/15506/1 15497/15505/1 +f 3206/3214/1 15493/15501/1 15496/15504/1 3207/3215/1 +f 10883/10891/1 15500/15508/1 15493/15501/1 3206/3214/1 +f 15500/15508/1 15499/15507/1 15494/15502/1 15493/15501/1 +f 15486/15494/1 15489/15497/1 15492/15500/1 15487/15495/1 +f 10887/10895/1 3204/3212/1 15489/15497/1 15486/15494/1 +f 3204/3212/1 3203/3211/1 15490/15498/1 15489/15497/1 +f 10918/10926/1 15485/15493/1 15488/15496/1 10919/10927/1 +f 3199/3207/1 10888/10896/1 15485/15493/1 10918/10926/1 +f 10888/10896/1 10887/10895/1 15486/15494/1 15485/15493/1 +f 3194/3202/1 15481/15489/1 15484/15492/1 3195/3203/1 +f 10919/10927/1 15488/15496/1 15481/15489/1 3194/3202/1 +f 15488/15496/1 15487/15495/1 15482/15490/1 15481/15489/1 +f 15474/15482/1 15477/15485/1 15480/15488/1 15475/15483/1 +f 10923/10931/1 3192/3200/1 15477/15485/1 15474/15482/1 +f 3192/3200/1 3191/3199/1 15478/15486/1 15477/15485/1 +f 10954/10962/1 15473/15481/1 15476/15484/1 10955/10963/1 +f 3187/3195/1 10924/10932/1 15473/15481/1 10954/10962/1 +f 10924/10932/1 10923/10931/1 15474/15482/1 15473/15481/1 +f 3182/3190/1 15469/15477/1 15472/15480/1 3183/3191/1 +f 10955/10963/1 15476/15484/1 15469/15477/1 3182/3190/1 +f 15476/15484/1 15475/15483/1 15470/15478/1 15469/15477/1 +f 15462/15470/1 15465/15473/1 15468/15476/1 15463/15471/1 +f 10959/10967/1 3180/3188/1 15465/15473/1 15462/15470/1 +f 3180/3188/1 3179/3187/1 15466/15474/1 15465/15473/1 +f 10990/10998/1 15461/15469/1 15464/15472/1 10991/10999/1 +f 3175/3183/1 10960/10968/1 15461/15469/1 10990/10998/1 +f 10960/10968/1 10959/10967/1 15462/15470/1 15461/15469/1 +f 3170/3178/1 15457/15465/1 15460/15468/1 3171/3179/1 +f 10991/10999/1 15464/15472/1 15457/15465/1 3170/3178/1 +f 15464/15472/1 15463/15471/1 15458/15466/1 15457/15465/1 +f 15450/15458/1 15453/15461/1 15456/15464/1 15451/15459/1 +f 10995/11003/1 3168/3176/1 15453/15461/1 15450/15458/1 +f 3168/3176/1 3167/3175/1 15454/15462/1 15453/15461/1 +f 11026/11034/1 15449/15457/1 15452/15460/1 11027/11035/1 +f 3163/3171/1 10996/11004/1 15449/15457/1 11026/11034/1 +f 10996/11004/1 10995/11003/1 15450/15458/1 15449/15457/1 +f 3158/3166/1 15445/15453/1 15448/15456/1 3159/3167/1 +f 11027/11035/1 15452/15460/1 15445/15453/1 3158/3166/1 +f 15452/15460/1 15451/15459/1 15446/15454/1 15445/15453/1 +f 15438/15446/1 15441/15449/1 15444/15452/1 15439/15447/1 +f 11031/11039/1 3156/3164/1 15441/15449/1 15438/15446/1 +f 3156/3164/1 3155/3163/1 15442/15450/1 15441/15449/1 +f 11062/11070/1 15437/15445/1 15440/15448/1 11063/11071/1 +f 3151/3159/1 11032/11040/1 15437/15445/1 11062/11070/1 +f 11032/11040/1 11031/11039/1 15438/15446/1 15437/15445/1 +f 3146/3154/1 15433/15441/1 15436/15444/1 3147/3155/1 +f 11063/11071/1 15440/15448/1 15433/15441/1 3146/3154/1 +f 15440/15448/1 15439/15447/1 15434/15442/1 15433/15441/1 +f 15426/15434/1 15429/15437/1 15432/15440/1 15427/15435/1 +f 11067/11075/1 3144/3152/1 15429/15437/1 15426/15434/1 +f 3144/3152/1 3143/3151/1 15430/15438/1 15429/15437/1 +f 11098/11106/1 15425/15433/1 15428/15436/1 11099/11107/1 +f 3139/3147/1 11068/11076/1 15425/15433/1 11098/11106/1 +f 11068/11076/1 11067/11075/1 15426/15434/1 15425/15433/1 +f 3134/3142/1 15421/15429/1 15424/15432/1 3135/3143/1 +f 11099/11107/1 15428/15436/1 15421/15429/1 3134/3142/1 +f 15428/15436/1 15427/15435/1 15422/15430/1 15421/15429/1 +f 15414/15422/1 15417/15425/1 15420/15428/1 15415/15423/1 +f 11103/11111/1 3132/3140/1 15417/15425/1 15414/15422/1 +f 3132/3140/1 3131/3139/1 15418/15426/1 15417/15425/1 +f 11134/11142/1 15413/15421/1 15416/15424/1 11135/11143/1 +f 3127/3135/1 11104/11112/1 15413/15421/1 11134/11142/1 +f 11104/11112/1 11103/11111/1 15414/15422/1 15413/15421/1 +f 3122/3130/1 15409/15417/1 15412/15420/1 3123/3131/1 +f 11135/11143/1 15416/15424/1 15409/15417/1 3122/3130/1 +f 15416/15424/1 15415/15423/1 15410/15418/1 15409/15417/1 +f 15402/15410/1 15405/15413/1 15408/15416/1 15403/15411/1 +f 11139/11147/1 3120/3128/1 15405/15413/1 15402/15410/1 +f 3120/3128/1 3119/3127/1 15406/15414/1 15405/15413/1 +f 11170/11178/1 15401/15409/1 15404/15412/1 11171/11179/1 +f 3115/3123/1 11140/11148/1 15401/15409/1 11170/11178/1 +f 11140/11148/1 11139/11147/1 15402/15410/1 15401/15409/1 +f 3110/3118/1 15397/15405/1 15400/15408/1 3111/3119/1 +f 11171/11179/1 15404/15412/1 15397/15405/1 3110/3118/1 +f 15404/15412/1 15403/15411/1 15398/15406/1 15397/15405/1 +f 15390/15398/1 15393/15401/1 15396/15404/1 15391/15399/1 +f 11175/11183/1 3108/3116/1 15393/15401/1 15390/15398/1 +f 3108/3116/1 3107/3115/1 15394/15402/1 15393/15401/1 +f 11206/11214/1 15389/15397/1 15392/15400/1 11207/11215/1 +f 3103/3111/1 11176/11184/1 15389/15397/1 11206/11214/1 +f 11176/11184/1 11175/11183/1 15390/15398/1 15389/15397/1 +f 3098/3106/1 15385/15393/1 15388/15396/1 3099/3107/1 +f 11207/11215/1 15392/15400/1 15385/15393/1 3098/3106/1 +f 15392/15400/1 15391/15399/1 15386/15394/1 15385/15393/1 +f 15378/15386/1 15381/15389/1 15384/15392/1 15379/15387/1 +f 11211/11219/1 3096/3104/1 15381/15389/1 15378/15386/1 +f 3096/3104/1 3095/3103/1 15382/15390/1 15381/15389/1 +f 11242/11250/1 15377/15385/1 15380/15388/1 11243/11251/1 +f 3091/3099/1 11212/11220/1 15377/15385/1 11242/11250/1 +f 11212/11220/1 11211/11219/1 15378/15386/1 15377/15385/1 +f 3086/3094/1 15373/15381/1 15376/15384/1 3087/3095/1 +f 11243/11251/1 15380/15388/1 15373/15381/1 3086/3094/1 +f 15380/15388/1 15379/15387/1 15374/15382/1 15373/15381/1 +f 15366/15374/1 15369/15377/1 15372/15380/1 15367/15375/1 +f 11247/11255/1 3084/3092/1 15369/15377/1 15366/15374/1 +f 3084/3092/1 3083/3091/1 15370/15378/1 15369/15377/1 +f 11278/11286/1 15365/15373/1 15368/15376/1 11279/11287/1 +f 3079/3087/1 11248/11256/1 15365/15373/1 11278/11286/1 +f 11248/11256/1 11247/11255/1 15366/15374/1 15365/15373/1 +f 3074/3082/1 15361/15369/1 15364/15372/1 3075/3083/1 +f 11279/11287/1 15368/15376/1 15361/15369/1 3074/3082/1 +f 15368/15376/1 15367/15375/1 15362/15370/1 15361/15369/1 +f 15354/15362/1 15357/15365/1 15360/15368/1 15355/15363/1 +f 11283/11291/1 3072/3080/1 15357/15365/1 15354/15362/1 +f 3072/3080/1 3071/3079/1 15358/15366/1 15357/15365/1 +f 11314/11322/1 15353/15361/1 15356/15364/1 11315/11323/1 +f 3067/3075/1 11284/11292/1 15353/15361/1 11314/11322/1 +f 11284/11292/1 11283/11291/1 15354/15362/1 15353/15361/1 +f 3062/3070/1 15349/15357/1 15352/15360/1 3063/3071/1 +f 11315/11323/1 15356/15364/1 15349/15357/1 3062/3070/1 +f 15356/15364/1 15355/15363/1 15350/15358/1 15349/15357/1 +f 15342/15350/1 15345/15353/1 15348/15356/1 15343/15351/1 +f 11319/11327/1 3060/3068/1 15345/15353/1 15342/15350/1 +f 3060/3068/1 3059/3067/1 15346/15354/1 15345/15353/1 +f 11350/11358/1 15341/15349/1 15344/15352/1 11351/11359/1 +f 3055/3063/1 11320/11328/1 15341/15349/1 11350/11358/1 +f 11320/11328/1 11319/11327/1 15342/15350/1 15341/15349/1 +f 3050/3058/1 15337/15345/1 15340/15348/1 3051/3059/1 +f 11351/11359/1 15344/15352/1 15337/15345/1 3050/3058/1 +f 15344/15352/1 15343/15351/1 15338/15346/1 15337/15345/1 +f 15330/15338/1 15333/15341/1 15336/15344/1 15331/15339/1 +f 11355/11363/1 3048/3056/1 15333/15341/1 15330/15338/1 +f 3048/3056/1 3047/3055/1 15334/15342/1 15333/15341/1 +f 11386/11394/1 15329/15337/1 15332/15340/1 11387/11395/1 +f 3043/3051/1 11356/11364/1 15329/15337/1 11386/11394/1 +f 11356/11364/1 11355/11363/1 15330/15338/1 15329/15337/1 +f 3038/3046/1 15325/15333/1 15328/15336/1 3039/3047/1 +f 11387/11395/1 15332/15340/1 15325/15333/1 3038/3046/1 +f 15332/15340/1 15331/15339/1 15326/15334/1 15325/15333/1 +f 15318/15326/1 15321/15329/1 15324/15332/1 15319/15327/1 +f 11391/11399/1 3036/3044/1 15321/15329/1 15318/15326/1 +f 3036/3044/1 3035/3043/1 15322/15330/1 15321/15329/1 +f 11422/11430/1 15317/15325/1 15320/15328/1 11423/11431/1 +f 3031/3039/1 11392/11400/1 15317/15325/1 11422/11430/1 +f 11392/11400/1 11391/11399/1 15318/15326/1 15317/15325/1 +f 3026/3034/1 15313/15321/1 15316/15324/1 3027/3035/1 +f 11423/11431/1 15320/15328/1 15313/15321/1 3026/3034/1 +f 15320/15328/1 15319/15327/1 15314/15322/1 15313/15321/1 +f 15306/15314/1 15309/15317/1 15312/15320/1 15307/15315/1 +f 11427/11435/1 3024/3032/1 15309/15317/1 15306/15314/1 +f 3024/3032/1 3023/3031/1 15310/15318/1 15309/15317/1 +f 11458/11466/1 15305/15313/1 15308/15316/1 11459/11467/1 +f 3019/3027/1 11428/11436/1 15305/15313/1 11458/11466/1 +f 11428/11436/1 11427/11435/1 15306/15314/1 15305/15313/1 +f 3014/3022/1 15301/15309/1 15304/15312/1 3015/3023/1 +f 11459/11467/1 15308/15316/1 15301/15309/1 3014/3022/1 +f 15308/15316/1 15307/15315/1 15302/15310/1 15301/15309/1 +f 15294/15302/1 15297/15305/1 15300/15308/1 15295/15303/1 +f 11463/11471/1 3012/3020/1 15297/15305/1 15294/15302/1 +f 3012/3020/1 3011/3019/1 15298/15306/1 15297/15305/1 +f 11494/11502/1 15293/15301/1 15296/15304/1 11495/11503/1 +f 3007/3015/1 11464/11472/1 15293/15301/1 11494/11502/1 +f 11464/11472/1 11463/11471/1 15294/15302/1 15293/15301/1 +f 3002/3010/1 15289/15297/1 15292/15300/1 3003/3011/1 +f 11495/11503/1 15296/15304/1 15289/15297/1 3002/3010/1 +f 15296/15304/1 15295/15303/1 15290/15298/1 15289/15297/1 +f 15282/15290/1 15285/15293/1 15288/15296/1 15283/15291/1 +f 11499/11507/1 3000/3008/1 15285/15293/1 15282/15290/1 +f 3000/3008/1 2999/3007/1 15286/15294/1 15285/15293/1 +f 11530/11538/1 15281/15289/1 15284/15292/1 11531/11539/1 +f 2995/3003/1 11500/11508/1 15281/15289/1 11530/11538/1 +f 11500/11508/1 11499/11507/1 15282/15290/1 15281/15289/1 +f 2990/2998/1 15277/15285/1 15280/15288/1 2991/2999/1 +f 11531/11539/1 15284/15292/1 15277/15285/1 2990/2998/1 +f 15284/15292/1 15283/15291/1 15278/15286/1 15277/15285/1 +f 15270/15278/1 15273/15281/1 15276/15284/1 15271/15279/1 +f 11535/11543/1 2988/2996/1 15273/15281/1 15270/15278/1 +f 2988/2996/1 2987/2995/1 15274/15282/1 15273/15281/1 +f 11566/11574/1 15269/15277/1 15272/15280/1 11567/11575/1 +f 2983/2991/1 11536/11544/1 15269/15277/1 11566/11574/1 +f 11536/11544/1 11535/11543/1 15270/15278/1 15269/15277/1 +f 2978/2986/1 15265/15273/1 15268/15276/1 2979/2987/1 +f 11567/11575/1 15272/15280/1 15265/15273/1 2978/2986/1 +f 15272/15280/1 15271/15279/1 15266/15274/1 15265/15273/1 +f 15258/15266/1 15261/15269/1 15264/15272/1 15259/15267/1 +f 11571/11579/1 2976/2984/1 15261/15269/1 15258/15266/1 +f 2976/2984/1 2975/2983/1 15262/15270/1 15261/15269/1 +f 11602/11610/1 15257/15265/1 15260/15268/1 11603/11611/1 +f 2971/2979/1 11572/11580/1 15257/15265/1 11602/11610/1 +f 11572/11580/1 11571/11579/1 15258/15266/1 15257/15265/1 +f 2966/2974/1 15253/15261/1 15256/15264/1 2967/2975/1 +f 11603/11611/1 15260/15268/1 15253/15261/1 2966/2974/1 +f 15260/15268/1 15259/15267/1 15254/15262/1 15253/15261/1 +f 15246/15254/1 15249/15257/1 15252/15260/1 15247/15255/1 +f 11607/11615/1 2964/2972/1 15249/15257/1 15246/15254/1 +f 2964/2972/1 2963/2971/1 15250/15258/1 15249/15257/1 +f 11638/11646/1 15245/15253/1 15248/15256/1 11639/11647/1 +f 2959/2967/1 11608/11616/1 15245/15253/1 11638/11646/1 +f 11608/11616/1 11607/11615/1 15246/15254/1 15245/15253/1 +f 2954/2962/1 15241/15249/1 15244/15252/1 2955/2963/1 +f 11639/11647/1 15248/15256/1 15241/15249/1 2954/2962/1 +f 15248/15256/1 15247/15255/1 15242/15250/1 15241/15249/1 +f 15234/15242/1 15237/15245/1 15240/15248/1 15235/15243/1 +f 11643/11651/1 2952/2960/1 15237/15245/1 15234/15242/1 +f 2952/2960/1 2951/2959/1 15238/15246/1 15237/15245/1 +f 11674/11682/1 15233/15241/1 15236/15244/1 11675/11683/1 +f 2947/2955/1 11644/11652/1 15233/15241/1 11674/11682/1 +f 11644/11652/1 11643/11651/1 15234/15242/1 15233/15241/1 +f 2942/2950/1 15229/15237/1 15232/15240/1 2943/2951/1 +f 11675/11683/1 15236/15244/1 15229/15237/1 2942/2950/1 +f 15236/15244/1 15235/15243/1 15230/15238/1 15229/15237/1 +f 15222/15230/1 15225/15233/1 15228/15236/1 15223/15231/1 +f 11679/11687/1 2940/2948/1 15225/15233/1 15222/15230/1 +f 2940/2948/1 2939/2947/1 15226/15234/1 15225/15233/1 +f 11710/11718/1 15221/15229/1 15224/15232/1 11711/11719/1 +f 2935/2943/1 11680/11688/1 15221/15229/1 11710/11718/1 +f 11680/11688/1 11679/11687/1 15222/15230/1 15221/15229/1 +f 2930/2938/1 15217/15225/1 15220/15228/1 2931/2939/1 +f 11711/11719/1 15224/15232/1 15217/15225/1 2930/2938/1 +f 15224/15232/1 15223/15231/1 15218/15226/1 15217/15225/1 +f 15210/15218/1 15213/15221/1 15216/15224/1 15211/15219/1 +f 11715/11723/1 2928/2936/1 15213/15221/1 15210/15218/1 +f 2928/2936/1 2927/2935/1 15214/15222/1 15213/15221/1 +f 11746/11754/1 15209/15217/1 15212/15220/1 11747/11755/1 +f 2923/2931/1 11716/11724/1 15209/15217/1 11746/11754/1 +f 11716/11724/1 11715/11723/1 15210/15218/1 15209/15217/1 +f 2918/2926/1 15205/15213/1 15208/15216/1 2919/2927/1 +f 11747/11755/1 15212/15220/1 15205/15213/1 2918/2926/1 +f 15212/15220/1 15211/15219/1 15206/15214/1 15205/15213/1 +f 15198/15206/1 15201/15209/1 15204/15212/1 15199/15207/1 +f 11751/11759/1 2916/2924/1 15201/15209/1 15198/15206/1 +f 2916/2924/1 2915/2923/1 15202/15210/1 15201/15209/1 +f 11782/11790/1 15197/15205/1 15200/15208/1 11783/11791/1 +f 2911/2919/1 11752/11760/1 15197/15205/1 11782/11790/1 +f 11752/11760/1 11751/11759/1 15198/15206/1 15197/15205/1 +f 2906/2914/1 15193/15201/1 15196/15204/1 2907/2915/1 +f 11783/11791/1 15200/15208/1 15193/15201/1 2906/2914/1 +f 15200/15208/1 15199/15207/1 15194/15202/1 15193/15201/1 +f 15186/15194/1 15189/15197/1 15192/15200/1 15187/15195/1 +f 11787/11795/1 2904/2912/1 15189/15197/1 15186/15194/1 +f 2904/2912/1 2903/2911/1 15190/15198/1 15189/15197/1 +f 11818/11826/1 15185/15193/1 15188/15196/1 11819/11827/1 +f 2899/2907/1 11788/11796/1 15185/15193/1 11818/11826/1 +f 11788/11796/1 11787/11795/1 15186/15194/1 15185/15193/1 +f 2894/2902/1 15181/15189/1 15184/15192/1 2895/2903/1 +f 11819/11827/1 15188/15196/1 15181/15189/1 2894/2902/1 +f 15188/15196/1 15187/15195/1 15182/15190/1 15181/15189/1 +f 15174/15182/1 15177/15185/1 15180/15188/1 15175/15183/1 +f 11823/11831/1 2892/2900/1 15177/15185/1 15174/15182/1 +f 2892/2900/1 2891/2899/1 15178/15186/1 15177/15185/1 +f 11854/11862/1 15173/15181/1 15176/15184/1 11855/11863/1 +f 2887/2895/1 11824/11832/1 15173/15181/1 11854/11862/1 +f 11824/11832/1 11823/11831/1 15174/15182/1 15173/15181/1 +f 2882/2890/1 15169/15177/1 15172/15180/1 2883/2891/1 +f 11855/11863/1 15176/15184/1 15169/15177/1 2882/2890/1 +f 15176/15184/1 15175/15183/1 15170/15178/1 15169/15177/1 +f 15162/15170/1 15165/15173/1 15168/15176/1 15163/15171/1 +f 11859/11867/1 2880/2888/1 15165/15173/1 15162/15170/1 +f 2880/2888/1 2879/2887/1 15166/15174/1 15165/15173/1 +f 11890/11898/1 15161/15169/1 15164/15172/1 11891/11899/1 +f 2875/2883/1 11860/11868/1 15161/15169/1 11890/11898/1 +f 11860/11868/1 11859/11867/1 15162/15170/1 15161/15169/1 +f 2870/2878/1 15157/15165/1 15160/15168/1 2871/2879/1 +f 11891/11899/1 15164/15172/1 15157/15165/1 2870/2878/1 +f 15164/15172/1 15163/15171/1 15158/15166/1 15157/15165/1 +f 15150/15158/1 15153/15161/1 15156/15164/1 15151/15159/1 +f 11895/11903/1 2868/2876/1 15153/15161/1 15150/15158/1 +f 2868/2876/1 2867/2875/1 15154/15162/1 15153/15161/1 +f 11926/11934/1 15149/15157/1 15152/15160/1 11927/11935/1 +f 2863/2871/1 11896/11904/1 15149/15157/1 11926/11934/1 +f 11896/11904/1 11895/11903/1 15150/15158/1 15149/15157/1 +f 2858/2866/1 15145/15153/1 15148/15156/1 2859/2867/1 +f 11927/11935/1 15152/15160/1 15145/15153/1 2858/2866/1 +f 15152/15160/1 15151/15159/1 15146/15154/1 15145/15153/1 +f 15138/15146/1 15141/15149/1 15144/15152/1 15139/15147/1 +f 11931/11939/1 2856/2864/1 15141/15149/1 15138/15146/1 +f 2856/2864/1 2855/2863/1 15142/15150/1 15141/15149/1 +f 11962/11970/1 15137/15145/1 15140/15148/1 11963/11971/1 +f 2851/2859/1 11932/11940/1 15137/15145/1 11962/11970/1 +f 11932/11940/1 11931/11939/1 15138/15146/1 15137/15145/1 +f 2846/2854/1 15133/15141/1 15136/15144/1 2847/2855/1 +f 11963/11971/1 15140/15148/1 15133/15141/1 2846/2854/1 +f 15140/15148/1 15139/15147/1 15134/15142/1 15133/15141/1 +f 15126/15134/1 15129/15137/1 15132/15140/1 15127/15135/1 +f 11967/11975/1 2844/2852/1 15129/15137/1 15126/15134/1 +f 2844/2852/1 2843/2851/1 15130/15138/1 15129/15137/1 +f 11998/12006/1 15125/15133/1 15128/15136/1 11999/12007/1 +f 2839/2847/1 11968/11976/1 15125/15133/1 11998/12006/1 +f 11968/11976/1 11967/11975/1 15126/15134/1 15125/15133/1 +f 2834/2842/1 15121/15129/1 15124/15132/1 2835/2843/1 +f 11999/12007/1 15128/15136/1 15121/15129/1 2834/2842/1 +f 15128/15136/1 15127/15135/1 15122/15130/1 15121/15129/1 +f 15114/15122/1 15117/15125/1 15120/15128/1 15115/15123/1 +f 12003/12011/1 2832/2840/1 15117/15125/1 15114/15122/1 +f 2832/2840/1 2831/2839/1 15118/15126/1 15117/15125/1 +f 12034/12042/1 15113/15121/1 15116/15124/1 12035/12043/1 +f 2827/2835/1 12004/12012/1 15113/15121/1 12034/12042/1 +f 12004/12012/1 12003/12011/1 15114/15122/1 15113/15121/1 +f 2822/2830/1 15109/15117/1 15112/15120/1 2823/2831/1 +f 12035/12043/1 15116/15124/1 15109/15117/1 2822/2830/1 +f 15116/15124/1 15115/15123/1 15110/15118/1 15109/15117/1 +f 15102/15110/1 15105/15113/1 15108/15116/1 15103/15111/1 +f 12039/12047/1 2820/2828/1 15105/15113/1 15102/15110/1 +f 2820/2828/1 2819/2827/1 15106/15114/1 15105/15113/1 +f 12070/12078/1 15101/15109/1 15104/15112/1 12071/12079/1 +f 2815/2823/1 12040/12048/1 15101/15109/1 12070/12078/1 +f 12040/12048/1 12039/12047/1 15102/15110/1 15101/15109/1 +f 2810/2818/1 15097/15105/1 15100/15108/1 2811/2819/1 +f 12071/12079/1 15104/15112/1 15097/15105/1 2810/2818/1 +f 15104/15112/1 15103/15111/1 15098/15106/1 15097/15105/1 +f 15090/15098/1 15093/15101/1 15096/15104/1 15091/15099/1 +f 12075/12083/1 2808/2816/1 15093/15101/1 15090/15098/1 +f 2808/2816/1 2807/2815/1 15094/15102/1 15093/15101/1 +f 12106/12114/1 15089/15097/1 15092/15100/1 12107/12115/1 +f 2803/2811/1 12076/12084/1 15089/15097/1 12106/12114/1 +f 12076/12084/1 12075/12083/1 15090/15098/1 15089/15097/1 +f 2798/2806/1 15085/15093/1 15088/15096/1 2799/2807/1 +f 12107/12115/1 15092/15100/1 15085/15093/1 2798/2806/1 +f 15092/15100/1 15091/15099/1 15086/15094/1 15085/15093/1 +f 15078/15086/1 15081/15089/1 15084/15092/1 15079/15087/1 +f 12111/12119/1 2796/2804/1 15081/15089/1 15078/15086/1 +f 2796/2804/1 2795/2803/1 15082/15090/1 15081/15089/1 +f 12142/12150/1 15077/15085/1 15080/15088/1 12143/12151/1 +f 2791/2799/1 12112/12120/1 15077/15085/1 12142/12150/1 +f 12112/12120/1 12111/12119/1 15078/15086/1 15077/15085/1 +f 2786/2794/1 15073/15081/1 15076/15084/1 2787/2795/1 +f 12143/12151/1 15080/15088/1 15073/15081/1 2786/2794/1 +f 15080/15088/1 15079/15087/1 15074/15082/1 15073/15081/1 +f 15066/15074/1 15069/15077/1 15072/15080/1 15067/15075/1 +f 12147/12155/1 2784/2792/1 15069/15077/1 15066/15074/1 +f 2784/2792/1 2783/2791/1 15070/15078/1 15069/15077/1 +f 12178/12186/1 15065/15073/1 15068/15076/1 12179/12187/1 +f 2779/2787/1 12148/12156/1 15065/15073/1 12178/12186/1 +f 12148/12156/1 12147/12155/1 15066/15074/1 15065/15073/1 +f 2774/2782/1 15061/15069/1 15064/15072/1 2775/2783/1 +f 12179/12187/1 15068/15076/1 15061/15069/1 2774/2782/1 +f 15068/15076/1 15067/15075/1 15062/15070/1 15061/15069/1 +f 15054/15062/1 15057/15065/1 15060/15068/1 15055/15063/1 +f 12183/12191/1 2772/2780/1 15057/15065/1 15054/15062/1 +f 2772/2780/1 2771/2779/1 15058/15066/1 15057/15065/1 +f 12214/12222/1 15053/15061/1 15056/15064/1 12215/12223/1 +f 2767/2775/1 12184/12192/1 15053/15061/1 12214/12222/1 +f 12184/12192/1 12183/12191/1 15054/15062/1 15053/15061/1 +f 2762/2770/1 15049/15057/1 15052/15060/1 2763/2771/1 +f 12215/12223/1 15056/15064/1 15049/15057/1 2762/2770/1 +f 15056/15064/1 15055/15063/1 15050/15058/1 15049/15057/1 +f 15042/15050/1 15045/15053/1 15048/15056/1 15043/15051/1 +f 12219/12227/1 2760/2768/1 15045/15053/1 15042/15050/1 +f 2760/2768/1 2759/2767/1 15046/15054/1 15045/15053/1 +f 12250/12258/1 15041/15049/1 15044/15052/1 12251/12259/1 +f 2755/2763/1 12220/12228/1 15041/15049/1 12250/12258/1 +f 12220/12228/1 12219/12227/1 15042/15050/1 15041/15049/1 +f 2750/2758/1 15037/15045/1 15040/15048/1 2751/2759/1 +f 12251/12259/1 15044/15052/1 15037/15045/1 2750/2758/1 +f 15044/15052/1 15043/15051/1 15038/15046/1 15037/15045/1 +f 15030/15038/1 15033/15041/1 15036/15044/1 15031/15039/1 +f 12255/12263/1 2748/2756/1 15033/15041/1 15030/15038/1 +f 2748/2756/1 2747/2755/1 15034/15042/1 15033/15041/1 +f 12286/12294/1 15029/15037/1 15032/15040/1 12287/12295/1 +f 2743/2751/1 12256/12264/1 15029/15037/1 12286/12294/1 +f 12256/12264/1 12255/12263/1 15030/15038/1 15029/15037/1 +f 2738/2746/1 15025/15033/1 15028/15036/1 2739/2747/1 +f 12287/12295/1 15032/15040/1 15025/15033/1 2738/2746/1 +f 15032/15040/1 15031/15039/1 15026/15034/1 15025/15033/1 +f 15018/15026/1 15021/15029/1 15024/15032/1 15019/15027/1 +f 12291/12299/1 2736/2744/1 15021/15029/1 15018/15026/1 +f 2736/2744/1 2735/2743/1 15022/15030/1 15021/15029/1 +f 12322/12330/1 15017/15025/1 15020/15028/1 12323/12331/1 +f 2731/2739/1 12292/12300/1 15017/15025/1 12322/12330/1 +f 12292/12300/1 12291/12299/1 15018/15026/1 15017/15025/1 +f 2726/2734/1 15013/15021/1 15016/15024/1 2727/2735/1 +f 12323/12331/1 15020/15028/1 15013/15021/1 2726/2734/1 +f 15020/15028/1 15019/15027/1 15014/15022/1 15013/15021/1 +f 15006/15014/1 15009/15017/1 15012/15020/1 15007/15015/1 +f 12327/12335/1 2724/2732/1 15009/15017/1 15006/15014/1 +f 2724/2732/1 2723/2731/1 15010/15018/1 15009/15017/1 +f 12358/12366/1 15005/15013/1 15008/15016/1 12359/12367/1 +f 2719/2727/1 12328/12336/1 15005/15013/1 12358/12366/1 +f 12328/12336/1 12327/12335/1 15006/15014/1 15005/15013/1 +f 2714/2722/1 15001/15009/1 15004/15012/1 2715/2723/1 +f 12359/12367/1 15008/15016/1 15001/15009/1 2714/2722/1 +f 15008/15016/1 15007/15015/1 15002/15010/1 15001/15009/1 +f 14994/15002/1 14997/15005/1 15000/15008/1 14995/15003/1 +f 12363/12371/1 2712/2720/1 14997/15005/1 14994/15002/1 +f 2712/2720/1 2711/2719/1 14998/15006/1 14997/15005/1 +f 12394/12402/1 14993/15001/1 14996/15004/1 12395/12403/1 +f 2707/2715/1 12364/12372/1 14993/15001/1 12394/12402/1 +f 12364/12372/1 12363/12371/1 14994/15002/1 14993/15001/1 +f 2702/2710/1 14989/14997/1 14992/15000/1 2703/2711/1 +f 12395/12403/1 14996/15004/1 14989/14997/1 2702/2710/1 +f 14996/15004/1 14995/15003/1 14990/14998/1 14989/14997/1 +f 14982/14990/1 14985/14993/1 14988/14996/1 14983/14991/1 +f 12399/12407/1 2700/2708/1 14985/14993/1 14982/14990/1 +f 2700/2708/1 2699/2707/1 14986/14994/1 14985/14993/1 +f 12430/12438/1 14981/14989/1 14984/14992/1 12431/12439/1 +f 2695/2703/1 12400/12408/1 14981/14989/1 12430/12438/1 +f 12400/12408/1 12399/12407/1 14982/14990/1 14981/14989/1 +f 2690/2698/1 14977/14985/1 14980/14988/1 2691/2699/1 +f 12431/12439/1 14984/14992/1 14977/14985/1 2690/2698/1 +f 14984/14992/1 14983/14991/1 14978/14986/1 14977/14985/1 +f 14970/14978/1 14973/14981/1 14976/14984/1 14971/14979/1 +f 12435/12443/1 2688/2696/1 14973/14981/1 14970/14978/1 +f 2688/2696/1 2687/2695/1 14974/14982/1 14973/14981/1 +f 12466/12474/1 14969/14977/1 14972/14980/1 12467/12475/1 +f 2683/2691/1 12436/12444/1 14969/14977/1 12466/12474/1 +f 12436/12444/1 12435/12443/1 14970/14978/1 14969/14977/1 +f 2678/2686/1 14965/14973/1 14968/14976/1 2679/2687/1 +f 12467/12475/1 14972/14980/1 14965/14973/1 2678/2686/1 +f 14972/14980/1 14971/14979/1 14966/14974/1 14965/14973/1 +f 14958/14966/1 14961/14969/1 14964/14972/1 14959/14967/1 +f 12471/12479/1 2676/2684/1 14961/14969/1 14958/14966/1 +f 2676/2684/1 2675/2683/1 14962/14970/1 14961/14969/1 +f 12502/12510/1 14957/14965/1 14960/14968/1 12503/12511/1 +f 2671/2679/1 12472/12480/1 14957/14965/1 12502/12510/1 +f 12472/12480/1 12471/12479/1 14958/14966/1 14957/14965/1 +f 2666/2674/1 14953/14961/1 14956/14964/1 2667/2675/1 +f 12503/12511/1 14960/14968/1 14953/14961/1 2666/2674/1 +f 14960/14968/1 14959/14967/1 14954/14962/1 14953/14961/1 +f 14946/14954/1 14949/14957/1 14952/14960/1 14947/14955/1 +f 12507/12515/1 2664/2672/1 14949/14957/1 14946/14954/1 +f 2664/2672/1 2663/2671/1 14950/14958/1 14949/14957/1 +f 12538/12546/1 14945/14953/1 14948/14956/1 12539/12547/1 +f 2659/2667/1 12508/12516/1 14945/14953/1 12538/12546/1 +f 12508/12516/1 12507/12515/1 14946/14954/1 14945/14953/1 +f 2654/2662/1 14941/14949/1 14944/14952/1 2655/2663/1 +f 12539/12547/1 14948/14956/1 14941/14949/1 2654/2662/1 +f 14948/14956/1 14947/14955/1 14942/14950/1 14941/14949/1 +f 14934/14942/1 14937/14945/1 14940/14948/1 14935/14943/1 +f 12543/12551/1 2652/2660/1 14937/14945/1 14934/14942/1 +f 2652/2660/1 2651/2659/1 14938/14946/1 14937/14945/1 +f 12574/12582/1 14933/14941/1 14936/14944/1 12575/12583/1 +f 2647/2655/1 12544/12552/1 14933/14941/1 12574/12582/1 +f 12544/12552/1 12543/12551/1 14934/14942/1 14933/14941/1 +f 2642/2650/1 14929/14937/1 14932/14940/1 2643/2651/1 +f 12575/12583/1 14936/14944/1 14929/14937/1 2642/2650/1 +f 14936/14944/1 14935/14943/1 14930/14938/1 14929/14937/1 +f 14922/14930/1 14925/14933/1 14928/14936/1 14923/14931/1 +f 12579/12587/1 2640/2648/1 14925/14933/1 14922/14930/1 +f 2640/2648/1 2639/2647/1 14926/14934/1 14925/14933/1 +f 12610/12618/1 14921/14929/1 14924/14932/1 12611/12619/1 +f 2635/2643/1 12580/12588/1 14921/14929/1 12610/12618/1 +f 12580/12588/1 12579/12587/1 14922/14930/1 14921/14929/1 +f 2630/2638/1 14917/14925/1 14920/14928/1 2631/2639/1 +f 12611/12619/1 14924/14932/1 14917/14925/1 2630/2638/1 +f 14924/14932/1 14923/14931/1 14918/14926/1 14917/14925/1 +f 14910/14918/1 14913/14921/1 14916/14924/1 14911/14919/1 +f 12615/12623/1 2628/2636/1 14913/14921/1 14910/14918/1 +f 2628/2636/1 2627/2635/1 14914/14922/1 14913/14921/1 +f 12646/12654/1 14909/14917/1 14912/14920/1 12647/12655/1 +f 2623/2631/1 12616/12624/1 14909/14917/1 12646/12654/1 +f 12616/12624/1 12615/12623/1 14910/14918/1 14909/14917/1 +f 2618/2626/1 14905/14913/1 14908/14916/1 2619/2627/1 +f 12647/12655/1 14912/14920/1 14905/14913/1 2618/2626/1 +f 14912/14920/1 14911/14919/1 14906/14914/1 14905/14913/1 +f 14898/14906/1 14901/14909/1 14904/14912/1 14899/14907/1 +f 12651/12659/1 2616/2624/1 14901/14909/1 14898/14906/1 +f 2616/2624/1 2615/2623/1 14902/14910/1 14901/14909/1 +f 12682/12690/1 14897/14905/1 14900/14908/1 12683/12691/1 +f 2611/2619/1 12652/12660/1 14897/14905/1 12682/12690/1 +f 12652/12660/1 12651/12659/1 14898/14906/1 14897/14905/1 +f 2606/2614/1 14893/14901/1 14896/14904/1 2607/2615/1 +f 12683/12691/1 14900/14908/1 14893/14901/1 2606/2614/1 +f 14900/14908/1 14899/14907/1 14894/14902/1 14893/14901/1 +f 14886/14894/1 14889/14897/1 14892/14900/1 14887/14895/1 +f 12687/12695/1 2604/2612/1 14889/14897/1 14886/14894/1 +f 2604/2612/1 2603/2611/1 14890/14898/1 14889/14897/1 +f 12718/12726/1 14885/14893/1 14888/14896/1 12719/12727/1 +f 2599/2607/1 12688/12696/1 14885/14893/1 12718/12726/1 +f 12688/12696/1 12687/12695/1 14886/14894/1 14885/14893/1 +f 2594/2602/1 14881/14889/1 14884/14892/1 2595/2603/1 +f 12719/12727/1 14888/14896/1 14881/14889/1 2594/2602/1 +f 14888/14896/1 14887/14895/1 14882/14890/1 14881/14889/1 +f 14874/14882/1 14877/14885/1 14880/14888/1 14875/14883/1 +f 12723/12731/1 2592/2600/1 14877/14885/1 14874/14882/1 +f 2592/2600/1 2591/2599/1 14878/14886/1 14877/14885/1 +f 12754/12762/1 14873/14881/1 14876/14884/1 12755/12763/1 +f 2587/2595/1 12724/12732/1 14873/14881/1 12754/12762/1 +f 12724/12732/1 12723/12731/1 14874/14882/1 14873/14881/1 +f 2582/2590/1 14869/14877/1 14872/14880/1 2583/2591/1 +f 12755/12763/1 14876/14884/1 14869/14877/1 2582/2590/1 +f 14876/14884/1 14875/14883/1 14870/14878/1 14869/14877/1 +f 14862/14870/1 14865/14873/1 14868/14876/1 14863/14871/1 +f 12759/12767/1 2580/2588/1 14865/14873/1 14862/14870/1 +f 2580/2588/1 2579/2587/1 14866/14874/1 14865/14873/1 +f 12790/12798/1 14861/14869/1 14864/14872/1 12791/12799/1 +f 2575/2583/1 12760/12768/1 14861/14869/1 12790/12798/1 +f 12760/12768/1 12759/12767/1 14862/14870/1 14861/14869/1 +f 2570/2578/1 14857/14865/1 14860/14868/1 2571/2579/1 +f 12791/12799/1 14864/14872/1 14857/14865/1 2570/2578/1 +f 14864/14872/1 14863/14871/1 14858/14866/1 14857/14865/1 +f 14850/14858/1 14853/14861/1 14856/14864/1 14851/14859/1 +f 12795/12803/1 2568/2576/1 14853/14861/1 14850/14858/1 +f 2568/2576/1 2567/2575/1 14854/14862/1 14853/14861/1 +f 12826/12834/1 14849/14857/1 14852/14860/1 12827/12835/1 +f 2563/2571/1 12796/12804/1 14849/14857/1 12826/12834/1 +f 12796/12804/1 12795/12803/1 14850/14858/1 14849/14857/1 +f 2558/2566/1 14845/14853/1 14848/14856/1 2559/2567/1 +f 12827/12835/1 14852/14860/1 14845/14853/1 2558/2566/1 +f 14852/14860/1 14851/14859/1 14846/14854/1 14845/14853/1 +f 14838/14846/1 14841/14849/1 14844/14852/1 14839/14847/1 +f 12831/12839/1 2556/2564/1 14841/14849/1 14838/14846/1 +f 2556/2564/1 2555/2563/1 14842/14850/1 14841/14849/1 +f 12862/12870/1 14837/14845/1 14840/14848/1 12863/12871/1 +f 2551/2559/1 12832/12840/1 14837/14845/1 12862/12870/1 +f 12832/12840/1 12831/12839/1 14838/14846/1 14837/14845/1 +f 2546/2554/1 14833/14841/1 14836/14844/1 2547/2555/1 +f 12863/12871/1 14840/14848/1 14833/14841/1 2546/2554/1 +f 14840/14848/1 14839/14847/1 14834/14842/1 14833/14841/1 +f 14826/14834/1 14829/14837/1 14832/14840/1 14827/14835/1 +f 12867/12875/1 2544/2552/1 14829/14837/1 14826/14834/1 +f 2544/2552/1 2543/2551/1 14830/14838/1 14829/14837/1 +f 12898/12906/1 14825/14833/1 14828/14836/1 12899/12907/1 +f 2539/2547/1 12868/12876/1 14825/14833/1 12898/12906/1 +f 12868/12876/1 12867/12875/1 14826/14834/1 14825/14833/1 +f 2534/2542/1 14821/14829/1 14824/14832/1 2535/2543/1 +f 12899/12907/1 14828/14836/1 14821/14829/1 2534/2542/1 +f 14828/14836/1 14827/14835/1 14822/14830/1 14821/14829/1 +f 14814/14822/1 14817/14825/1 14820/14828/1 14815/14823/1 +f 12903/12911/1 2532/2540/1 14817/14825/1 14814/14822/1 +f 2532/2540/1 2531/2539/1 14818/14826/1 14817/14825/1 +f 12934/12942/1 14813/14821/1 14816/14824/1 12935/12943/1 +f 2527/2535/1 12904/12912/1 14813/14821/1 12934/12942/1 +f 12904/12912/1 12903/12911/1 14814/14822/1 14813/14821/1 +f 2522/2530/1 14809/14817/1 14812/14820/1 2523/2531/1 +f 12935/12943/1 14816/14824/1 14809/14817/1 2522/2530/1 +f 14816/14824/1 14815/14823/1 14810/14818/1 14809/14817/1 +f 14802/14810/1 14805/14813/1 14808/14816/1 14803/14811/1 +f 12939/12947/1 2520/2528/1 14805/14813/1 14802/14810/1 +f 2520/2528/1 2519/2527/1 14806/14814/1 14805/14813/1 +f 12970/12978/1 14801/14809/1 14804/14812/1 12971/12979/1 +f 2515/2523/1 12940/12948/1 14801/14809/1 12970/12978/1 +f 12940/12948/1 12939/12947/1 14802/14810/1 14801/14809/1 +f 2510/2518/1 14797/14805/1 14800/14808/1 2511/2519/1 +f 12971/12979/1 14804/14812/1 14797/14805/1 2510/2518/1 +f 14804/14812/1 14803/14811/1 14798/14806/1 14797/14805/1 +f 14790/14798/1 14793/14801/1 14796/14804/1 14791/14799/1 +f 12975/12983/1 2508/2516/1 14793/14801/1 14790/14798/1 +f 2508/2516/1 2507/2515/1 14794/14802/1 14793/14801/1 +f 13006/13014/1 14789/14797/1 14792/14800/1 13007/13015/1 +f 2503/2511/1 12976/12984/1 14789/14797/1 13006/13014/1 +f 12976/12984/1 12975/12983/1 14790/14798/1 14789/14797/1 +f 2498/2506/1 14785/14793/1 14788/14796/1 2499/2507/1 +f 13007/13015/1 14792/14800/1 14785/14793/1 2498/2506/1 +f 14792/14800/1 14791/14799/1 14786/14794/1 14785/14793/1 +f 14778/14786/1 14781/14789/1 14784/14792/1 14779/14787/1 +f 13011/13019/1 2496/2504/1 14781/14789/1 14778/14786/1 +f 2496/2504/1 2495/2503/1 14782/14790/1 14781/14789/1 +f 13042/13050/1 14777/14785/1 14780/14788/1 13043/13051/1 +f 2491/2499/1 13012/13020/1 14777/14785/1 13042/13050/1 +f 13012/13020/1 13011/13019/1 14778/14786/1 14777/14785/1 +f 2486/2494/1 14773/14781/1 14776/14784/1 2487/2495/1 +f 13043/13051/1 14780/14788/1 14773/14781/1 2486/2494/1 +f 14780/14788/1 14779/14787/1 14774/14782/1 14773/14781/1 +f 14766/14774/1 14769/14777/1 14772/14780/1 14767/14775/1 +f 13047/13055/1 2484/2492/1 14769/14777/1 14766/14774/1 +f 2484/2492/1 2483/2491/1 14770/14778/1 14769/14777/1 +f 13078/13086/1 14765/14773/1 14768/14776/1 13079/13087/1 +f 2479/2487/1 13048/13056/1 14765/14773/1 13078/13086/1 +f 13048/13056/1 13047/13055/1 14766/14774/1 14765/14773/1 +f 2474/2482/1 14761/14769/1 14764/14772/1 2475/2483/1 +f 13079/13087/1 14768/14776/1 14761/14769/1 2474/2482/1 +f 14768/14776/1 14767/14775/1 14762/14770/1 14761/14769/1 +f 14754/14762/1 14757/14765/1 14760/14768/1 14755/14763/1 +f 13083/13091/1 2472/2480/1 14757/14765/1 14754/14762/1 +f 2472/2480/1 2471/2479/1 14758/14766/1 14757/14765/1 +f 13114/13122/1 14753/14761/1 14756/14764/1 13115/13123/1 +f 2467/2475/1 13084/13092/1 14753/14761/1 13114/13122/1 +f 13084/13092/1 13083/13091/1 14754/14762/1 14753/14761/1 +f 2462/2470/1 14749/14757/1 14752/14760/1 2463/2471/1 +f 13115/13123/1 14756/14764/1 14749/14757/1 2462/2470/1 +f 14756/14764/1 14755/14763/1 14750/14758/1 14749/14757/1 +f 14742/14750/1 14745/14753/1 14748/14756/1 14743/14751/1 +f 13119/13127/1 2460/2468/1 14745/14753/1 14742/14750/1 +f 2460/2468/1 2459/2467/1 14746/14754/1 14745/14753/1 +f 13150/13158/1 14741/14749/1 14744/14752/1 13151/13159/1 +f 2455/2463/1 13120/13128/1 14741/14749/1 13150/13158/1 +f 13120/13128/1 13119/13127/1 14742/14750/1 14741/14749/1 +f 2450/2458/1 14737/14745/1 14740/14748/1 2451/2459/1 +f 13151/13159/1 14744/14752/1 14737/14745/1 2450/2458/1 +f 14744/14752/1 14743/14751/1 14738/14746/1 14737/14745/1 +f 14730/14738/1 14733/14741/1 14736/14744/1 14731/14739/1 +f 13155/13163/1 2448/2456/1 14733/14741/1 14730/14738/1 +f 2448/2456/1 2447/2455/1 14734/14742/1 14733/14741/1 +f 13186/13194/1 14729/14737/1 14732/14740/1 13187/13195/1 +f 2443/2451/1 13156/13164/1 14729/14737/1 13186/13194/1 +f 13156/13164/1 13155/13163/1 14730/14738/1 14729/14737/1 +f 2438/2446/1 14725/14733/1 14728/14736/1 2439/2447/1 +f 13187/13195/1 14732/14740/1 14725/14733/1 2438/2446/1 +f 14732/14740/1 14731/14739/1 14726/14734/1 14725/14733/1 +f 14718/14726/1 14721/14729/1 14724/14732/1 14719/14727/1 +f 13191/13199/1 2436/2444/1 14721/14729/1 14718/14726/1 +f 2436/2444/1 2435/2443/1 14722/14730/1 14721/14729/1 +f 13222/13230/1 14717/14725/1 14720/14728/1 13223/13231/1 +f 2431/2439/1 13192/13200/1 14717/14725/1 13222/13230/1 +f 13192/13200/1 13191/13199/1 14718/14726/1 14717/14725/1 +f 2426/2434/1 14713/14721/1 14716/14724/1 2427/2435/1 +f 13223/13231/1 14720/14728/1 14713/14721/1 2426/2434/1 +f 14720/14728/1 14719/14727/1 14714/14722/1 14713/14721/1 +f 14706/14714/1 14709/14717/1 14712/14720/1 14707/14715/1 +f 13227/13235/1 2424/2432/1 14709/14717/1 14706/14714/1 +f 2424/2432/1 2423/2431/1 14710/14718/1 14709/14717/1 +f 13258/13266/1 14705/14713/1 14708/14716/1 13259/13267/1 +f 2419/2427/1 13228/13236/1 14705/14713/1 13258/13266/1 +f 13228/13236/1 13227/13235/1 14706/14714/1 14705/14713/1 +f 2414/2422/1 14701/14709/1 14704/14712/1 2415/2423/1 +f 13259/13267/1 14708/14716/1 14701/14709/1 2414/2422/1 +f 14708/14716/1 14707/14715/1 14702/14710/1 14701/14709/1 +f 14694/14702/1 14697/14705/1 14700/14708/1 14695/14703/1 +f 13263/13271/1 2412/2420/1 14697/14705/1 14694/14702/1 +f 2412/2420/1 2411/2419/1 14698/14706/1 14697/14705/1 +f 13294/13302/1 14693/14701/1 14696/14704/1 13295/13303/1 +f 2407/2415/1 13264/13272/1 14693/14701/1 13294/13302/1 +f 13264/13272/1 13263/13271/1 14694/14702/1 14693/14701/1 +f 2402/2410/1 14689/14697/1 14692/14700/1 2403/2411/1 +f 13295/13303/1 14696/14704/1 14689/14697/1 2402/2410/1 +f 14696/14704/1 14695/14703/1 14690/14698/1 14689/14697/1 +f 14682/14690/1 14685/14693/1 14688/14696/1 14683/14691/1 +f 13299/13307/1 2400/2408/1 14685/14693/1 14682/14690/1 +f 2400/2408/1 2399/2407/1 14686/14694/1 14685/14693/1 +f 13330/13338/1 14681/14689/1 14684/14692/1 13331/13339/1 +f 2395/2403/1 13300/13308/1 14681/14689/1 13330/13338/1 +f 13300/13308/1 13299/13307/1 14682/14690/1 14681/14689/1 +f 2390/2398/1 14677/14685/1 14680/14688/1 2391/2399/1 +f 13331/13339/1 14684/14692/1 14677/14685/1 2390/2398/1 +f 14684/14692/1 14683/14691/1 14678/14686/1 14677/14685/1 +f 14670/14678/1 14673/14681/1 14676/14684/1 14671/14679/1 +f 13335/13343/1 2388/2396/1 14673/14681/1 14670/14678/1 +f 2388/2396/1 2387/2395/1 14674/14682/1 14673/14681/1 +f 13366/13374/1 14669/14677/1 14672/14680/1 13367/13375/1 +f 2383/2391/1 13336/13344/1 14669/14677/1 13366/13374/1 +f 13336/13344/1 13335/13343/1 14670/14678/1 14669/14677/1 +f 2378/2386/1 14665/14673/1 14668/14676/1 2379/2387/1 +f 13367/13375/1 14672/14680/1 14665/14673/1 2378/2386/1 +f 14672/14680/1 14671/14679/1 14666/14674/1 14665/14673/1 +f 14658/14666/1 14661/14669/1 14664/14672/1 14659/14667/1 +f 13371/13379/1 2376/2384/1 14661/14669/1 14658/14666/1 +f 2376/2384/1 2375/2383/1 14662/14670/1 14661/14669/1 +f 13402/13410/1 14657/14665/1 14660/14668/1 13403/13411/1 +f 2371/2379/1 13372/13380/1 14657/14665/1 13402/13410/1 +f 13372/13380/1 13371/13379/1 14658/14666/1 14657/14665/1 +f 2366/2374/1 14653/14661/1 14656/14664/1 2367/2375/1 +f 13403/13411/1 14660/14668/1 14653/14661/1 2366/2374/1 +f 14660/14668/1 14659/14667/1 14654/14662/1 14653/14661/1 +f 14646/14654/1 14649/14657/1 14652/14660/1 14647/14655/1 +f 13407/13415/1 2364/2372/1 14649/14657/1 14646/14654/1 +f 2364/2372/1 2363/2371/1 14650/14658/1 14649/14657/1 +f 13438/13446/1 14645/14653/1 14648/14656/1 13439/13447/1 +f 2359/2367/1 13408/13416/1 14645/14653/1 13438/13446/1 +f 13408/13416/1 13407/13415/1 14646/14654/1 14645/14653/1 +f 2354/2362/1 14641/14649/1 14644/14652/1 2355/2363/1 +f 13439/13447/1 14648/14656/1 14641/14649/1 2354/2362/1 +f 14648/14656/1 14647/14655/1 14642/14650/1 14641/14649/1 +f 14634/14642/1 14637/14645/1 14640/14648/1 14635/14643/1 +f 13443/13451/1 2352/2360/1 14637/14645/1 14634/14642/1 +f 2352/2360/1 2351/2359/1 14638/14646/1 14637/14645/1 +f 13474/13482/1 14633/14641/1 14636/14644/1 13475/13483/1 +f 2347/2355/1 13444/13452/1 14633/14641/1 13474/13482/1 +f 13444/13452/1 13443/13451/1 14634/14642/1 14633/14641/1 +f 2342/2350/1 14629/14637/1 14632/14640/1 2343/2351/1 +f 13475/13483/1 14636/14644/1 14629/14637/1 2342/2350/1 +f 14636/14644/1 14635/14643/1 14630/14638/1 14629/14637/1 +f 14622/14630/1 14625/14633/1 14628/14636/1 14623/14631/1 +f 13479/13487/1 2340/2348/1 14625/14633/1 14622/14630/1 +f 2340/2348/1 2339/2347/1 14626/14634/1 14625/14633/1 +f 13510/13518/1 14621/14629/1 14624/14632/1 13511/13519/1 +f 2335/2343/1 13480/13488/1 14621/14629/1 13510/13518/1 +f 13480/13488/1 13479/13487/1 14622/14630/1 14621/14629/1 +f 2330/2338/1 14617/14625/1 14620/14628/1 2331/2339/1 +f 13511/13519/1 14624/14632/1 14617/14625/1 2330/2338/1 +f 14624/14632/1 14623/14631/1 14618/14626/1 14617/14625/1 +f 14610/14618/1 14613/14621/1 14616/14624/1 14611/14619/1 +f 13515/13523/1 2328/2336/1 14613/14621/1 14610/14618/1 +f 2328/2336/1 2327/2335/1 14614/14622/1 14613/14621/1 +f 13546/13554/1 14609/14617/1 14612/14620/1 13547/13555/1 +f 2323/2331/1 13516/13524/1 14609/14617/1 13546/13554/1 +f 13516/13524/1 13515/13523/1 14610/14618/1 14609/14617/1 +f 2318/2326/1 14605/14613/1 14608/14616/1 2319/2327/1 +f 13547/13555/1 14612/14620/1 14605/14613/1 2318/2326/1 +f 14612/14620/1 14611/14619/1 14606/14614/1 14605/14613/1 +f 14598/14606/1 14601/14609/1 14604/14612/1 14599/14607/1 +f 13551/13559/1 2316/2324/1 14601/14609/1 14598/14606/1 +f 2316/2324/1 2315/2323/1 14602/14610/1 14601/14609/1 +f 13582/13590/1 14597/14605/1 14600/14608/1 13583/13591/1 +f 2311/2319/1 13552/13560/1 14597/14605/1 13582/13590/1 +f 13552/13560/1 13551/13559/1 14598/14606/1 14597/14605/1 +f 2306/2314/1 14593/14601/1 14596/14604/1 2307/2315/1 +f 13583/13591/1 14600/14608/1 14593/14601/1 2306/2314/1 +f 14600/14608/1 14599/14607/1 14594/14602/1 14593/14601/1 +f 14586/14594/1 14589/14597/1 14592/14600/1 14587/14595/1 +f 13587/13595/1 2304/2312/1 14589/14597/1 14586/14594/1 +f 2304/2312/1 2303/2311/1 14590/14598/1 14589/14597/1 +f 13618/13626/1 14585/14593/1 14588/14596/1 13619/13627/1 +f 2299/2307/1 13588/13596/1 14585/14593/1 13618/13626/1 +f 13588/13596/1 13587/13595/1 14586/14594/1 14585/14593/1 +f 2294/2302/1 14581/14589/1 14584/14592/1 2295/2303/1 +f 13619/13627/1 14588/14596/1 14581/14589/1 2294/2302/1 +f 14588/14596/1 14587/14595/1 14582/14590/1 14581/14589/1 +f 14574/14582/1 14577/14585/1 14580/14588/1 14575/14583/1 +f 13623/13631/1 2292/2300/1 14577/14585/1 14574/14582/1 +f 2292/2300/1 2291/2299/1 14578/14586/1 14577/14585/1 +f 13654/13662/1 14573/14581/1 14576/14584/1 13655/13663/1 +f 2287/2295/1 13624/13632/1 14573/14581/1 13654/13662/1 +f 13624/13632/1 13623/13631/1 14574/14582/1 14573/14581/1 +f 2282/2290/1 14569/14577/1 14572/14580/1 2283/2291/1 +f 13655/13663/1 14576/14584/1 14569/14577/1 2282/2290/1 +f 14576/14584/1 14575/14583/1 14570/14578/1 14569/14577/1 +f 14562/14570/1 14565/14573/1 14568/14576/1 14563/14571/1 +f 13659/13667/1 2280/2288/1 14565/14573/1 14562/14570/1 +f 2280/2288/1 2279/2287/1 14566/14574/1 14565/14573/1 +f 13690/13698/1 14561/14569/1 14564/14572/1 13691/13699/1 +f 2275/2283/1 13660/13668/1 14561/14569/1 13690/13698/1 +f 13660/13668/1 13659/13667/1 14562/14570/1 14561/14569/1 +f 2270/2278/1 14557/14565/1 14560/14568/1 2271/2279/1 +f 13691/13699/1 14564/14572/1 14557/14565/1 2270/2278/1 +f 14564/14572/1 14563/14571/1 14558/14566/1 14557/14565/1 +f 14550/14558/1 14553/14561/1 14556/14564/1 14551/14559/1 +f 13695/13703/1 2268/2276/1 14553/14561/1 14550/14558/1 +f 2268/2276/1 2267/2275/1 14554/14562/1 14553/14561/1 +f 13726/13734/1 14549/14557/1 14552/14560/1 13727/13735/1 +f 2263/2271/1 13696/13704/1 14549/14557/1 13726/13734/1 +f 13696/13704/1 13695/13703/1 14550/14558/1 14549/14557/1 +f 2258/2266/1 14545/14553/1 14548/14556/1 2259/2267/1 +f 13727/13735/1 14552/14560/1 14545/14553/1 2258/2266/1 +f 14552/14560/1 14551/14559/1 14546/14554/1 14545/14553/1 +f 14538/14546/1 14541/14549/1 14544/14552/1 14539/14547/1 +f 13731/13739/1 2256/2264/1 14541/14549/1 14538/14546/1 +f 2256/2264/1 2255/2263/1 14542/14550/1 14541/14549/1 +f 13762/13770/1 14537/14545/1 14540/14548/1 13763/13771/1 +f 2251/2259/1 13732/13740/1 14537/14545/1 13762/13770/1 +f 13732/13740/1 13731/13739/1 14538/14546/1 14537/14545/1 +f 2246/2254/1 14533/14541/1 14536/14544/1 2247/2255/1 +f 13763/13771/1 14540/14548/1 14533/14541/1 2246/2254/1 +f 14540/14548/1 14539/14547/1 14534/14542/1 14533/14541/1 +f 14526/14534/1 14529/14537/1 14532/14540/1 14527/14535/1 +f 13767/13775/1 2244/2252/1 14529/14537/1 14526/14534/1 +f 2244/2252/1 2243/2251/1 14530/14538/1 14529/14537/1 +f 13798/13806/1 14525/14533/1 14528/14536/1 13799/13807/1 +f 2239/2247/1 13768/13776/1 14525/14533/1 13798/13806/1 +f 13768/13776/1 13767/13775/1 14526/14534/1 14525/14533/1 +f 2234/2242/1 14521/14529/1 14524/14532/1 2235/2243/1 +f 13799/13807/1 14528/14536/1 14521/14529/1 2234/2242/1 +f 14528/14536/1 14527/14535/1 14522/14530/1 14521/14529/1 +f 14514/14522/1 14517/14525/1 14520/14528/1 14515/14523/1 +f 13803/13811/1 2232/2240/1 14517/14525/1 14514/14522/1 +f 2232/2240/1 2231/2239/1 14518/14526/1 14517/14525/1 +f 13834/13842/1 14513/14521/1 14516/14524/1 13835/13843/1 +f 2227/2235/1 13804/13812/1 14513/14521/1 13834/13842/1 +f 13804/13812/1 13803/13811/1 14514/14522/1 14513/14521/1 +f 2222/2230/1 14509/14517/1 14512/14520/1 2223/2231/1 +f 13835/13843/1 14516/14524/1 14509/14517/1 2222/2230/1 +f 14516/14524/1 14515/14523/1 14510/14518/1 14509/14517/1 +f 14502/14510/1 14505/14513/1 14508/14516/1 14503/14511/1 +f 13839/13847/1 2220/2228/1 14505/14513/1 14502/14510/1 +f 2220/2228/1 2219/2227/1 14506/14514/1 14505/14513/1 +f 13870/13878/1 14501/14509/1 14504/14512/1 13871/13879/1 +f 2215/2223/1 13840/13848/1 14501/14509/1 13870/13878/1 +f 13840/13848/1 13839/13847/1 14502/14510/1 14501/14509/1 +f 2210/2218/1 14497/14505/1 14500/14508/1 2211/2219/1 +f 13871/13879/1 14504/14512/1 14497/14505/1 2210/2218/1 +f 14504/14512/1 14503/14511/1 14498/14506/1 14497/14505/1 +f 14490/14498/1 14493/14501/1 14496/14504/1 14491/14499/1 +f 13875/13883/1 2208/2216/1 14493/14501/1 14490/14498/1 +f 2208/2216/1 2207/2215/1 14494/14502/1 14493/14501/1 +f 13906/13914/1 14489/14497/1 14492/14500/1 13907/13915/1 +f 2203/2211/1 13876/13884/1 14489/14497/1 13906/13914/1 +f 13876/13884/1 13875/13883/1 14490/14498/1 14489/14497/1 +f 2198/2206/1 14485/14493/1 14488/14496/1 2199/2207/1 +f 13907/13915/1 14492/14500/1 14485/14493/1 2198/2206/1 +f 14492/14500/1 14491/14499/1 14486/14494/1 14485/14493/1 +f 14478/14486/1 14481/14489/1 14484/14492/1 14479/14487/1 +f 13911/13919/1 2196/2204/1 14481/14489/1 14478/14486/1 +f 2196/2204/1 2195/2203/1 14482/14490/1 14481/14489/1 +f 13942/13950/1 14477/14485/1 14480/14488/1 13943/13951/1 +f 2191/2199/1 13912/13920/1 14477/14485/1 13942/13950/1 +f 13912/13920/1 13911/13919/1 14478/14486/1 14477/14485/1 +f 2186/2194/1 14473/14481/1 14476/14484/1 2187/2195/1 +f 13943/13951/1 14480/14488/1 14473/14481/1 2186/2194/1 +f 14480/14488/1 14479/14487/1 14474/14482/1 14473/14481/1 +f 14466/14474/1 14469/14477/1 14472/14480/1 14467/14475/1 +f 13947/13955/1 2184/2192/1 14469/14477/1 14466/14474/1 +f 2184/2192/1 2183/2191/1 14470/14478/1 14469/14477/1 +f 13978/13986/1 14465/14473/1 14468/14476/1 13979/13987/1 +f 2179/2187/1 13948/13956/1 14465/14473/1 13978/13986/1 +f 13948/13956/1 13947/13955/1 14466/14474/1 14465/14473/1 +f 2174/2182/1 14461/14469/1 14464/14472/1 2175/2183/1 +f 13979/13987/1 14468/14476/1 14461/14469/1 2174/2182/1 +f 14468/14476/1 14467/14475/1 14462/14470/1 14461/14469/1 +f 14454/14462/1 14457/14465/1 14460/14468/1 14455/14463/1 +f 13983/13991/1 2172/2180/1 14457/14465/1 14454/14462/1 +f 2172/2180/1 2171/2179/1 14458/14466/1 14457/14465/1 +f 14014/14022/1 14453/14461/1 14456/14464/1 14015/14023/1 +f 2167/2175/1 13984/13992/1 14453/14461/1 14014/14022/1 +f 13984/13992/1 13983/13991/1 14454/14462/1 14453/14461/1 +f 2162/2170/1 14449/14457/1 14452/14460/1 2163/2171/1 +f 14015/14023/1 14456/14464/1 14449/14457/1 2162/2170/1 +f 14456/14464/1 14455/14463/1 14450/14458/1 14449/14457/1 +f 14442/14450/1 14445/14453/1 14448/14456/1 14443/14451/1 +f 14019/14027/1 2160/2168/1 14445/14453/1 14442/14450/1 +f 2160/2168/1 2159/2167/1 14446/14454/1 14445/14453/1 +f 14050/14058/1 14441/14449/1 14444/14452/1 14051/14059/1 +f 2155/2163/1 14020/14028/1 14441/14449/1 14050/14058/1 +f 14020/14028/1 14019/14027/1 14442/14450/1 14441/14449/1 +f 2150/2158/1 14437/14445/1 14440/14448/1 2151/2159/1 +f 14051/14059/1 14444/14452/1 14437/14445/1 2150/2158/1 +f 14444/14452/1 14443/14451/1 14438/14446/1 14437/14445/1 +f 14430/14438/1 14433/14441/1 14436/14444/1 14431/14439/1 +f 14055/14063/1 2148/2156/1 14433/14441/1 14430/14438/1 +f 2148/2156/1 2147/2155/1 14434/14442/1 14433/14441/1 +f 14086/14094/1 14429/14437/1 14432/14440/1 14087/14095/1 +f 2143/2151/1 14056/14064/1 14429/14437/1 14086/14094/1 +f 14056/14064/1 14055/14063/1 14430/14438/1 14429/14437/1 +f 2138/2146/1 14425/14433/1 14428/14436/1 2139/2147/1 +f 14087/14095/1 14432/14440/1 14425/14433/1 2138/2146/1 +f 14432/14440/1 14431/14439/1 14426/14434/1 14425/14433/1 +f 14418/14426/1 14421/14429/1 14424/14432/1 14419/14427/1 +f 14091/14099/1 2136/2144/1 14421/14429/1 14418/14426/1 +f 2136/2144/1 2135/2143/1 14422/14430/1 14421/14429/1 +f 14122/14130/1 14417/14425/1 14420/14428/1 14123/14131/1 +f 2131/2139/1 14092/14100/1 14417/14425/1 14122/14130/1 +f 14092/14100/1 14091/14099/1 14418/14426/1 14417/14425/1 +f 2126/2134/1 14413/14421/1 14416/14424/1 2127/2135/1 +f 14123/14131/1 14420/14428/1 14413/14421/1 2126/2134/1 +f 14420/14428/1 14419/14427/1 14414/14422/1 14413/14421/1 +f 14406/14414/1 14409/14417/1 14412/14420/1 14407/14415/1 +f 14127/14135/1 2124/2132/1 14409/14417/1 14406/14414/1 +f 2124/2132/1 2123/2131/1 14410/14418/1 14409/14417/1 +f 14158/14166/1 14405/14413/1 14408/14416/1 14159/14167/1 +f 2119/2127/1 14128/14136/1 14405/14413/1 14158/14166/1 +f 14128/14136/1 14127/14135/1 14406/14414/1 14405/14413/1 +f 2114/2122/1 14401/14409/1 14404/14412/1 2115/2123/1 +f 14159/14167/1 14408/14416/1 14401/14409/1 2114/2122/1 +f 14408/14416/1 14407/14415/1 14402/14410/1 14401/14409/1 +f 14394/14402/1 14397/14405/1 14400/14408/1 14395/14403/1 +f 14163/14171/1 2112/2120/1 14397/14405/1 14394/14402/1 +f 2112/2120/1 2111/2119/1 14398/14406/1 14397/14405/1 +f 14194/14202/1 14393/14401/1 14396/14404/1 14195/14203/1 +f 2107/2115/1 14164/14172/1 14393/14401/1 14194/14202/1 +f 14164/14172/1 14163/14171/1 14394/14402/1 14393/14401/1 +f 2102/2110/1 14389/14397/1 14392/14400/1 2103/2111/1 +f 14195/14203/1 14396/14404/1 14389/14397/1 2102/2110/1 +f 14396/14404/1 14395/14403/1 14390/14398/1 14389/14397/1 +f 14382/14390/1 14385/14393/1 14388/14396/1 14383/14391/1 +f 14199/14207/1 2100/2108/1 14385/14393/1 14382/14390/1 +f 2100/2108/1 2099/2107/1 14386/14394/1 14385/14393/1 +f 14230/14238/1 14381/14389/1 14384/14392/1 14231/14239/1 +f 2095/2103/1 14200/14208/1 14381/14389/1 14230/14238/1 +f 14200/14208/1 14199/14207/1 14382/14390/1 14381/14389/1 +f 2090/2098/1 14377/14385/1 14380/14388/1 2091/2099/1 +f 14231/14239/1 14384/14392/1 14377/14385/1 2090/2098/1 +f 14384/14392/1 14383/14391/1 14378/14386/1 14377/14385/1 +f 14370/14378/1 14373/14381/1 14376/14384/1 14371/14379/1 +f 14235/14243/1 2088/2096/1 14373/14381/1 14370/14378/1 +f 2088/2096/1 2087/2095/1 14374/14382/1 14373/14381/1 +f 14266/14274/1 14369/14377/1 14372/14380/1 14267/14275/1 +f 2083/2091/1 14236/14244/1 14369/14377/1 14266/14274/1 +f 14236/14244/1 14235/14243/1 14370/14378/1 14369/14377/1 +f 2078/2086/1 14365/14373/1 14368/14376/1 2079/2087/1 +f 14267/14275/1 14372/14380/1 14365/14373/1 2078/2086/1 +f 14372/14380/1 14371/14379/1 14366/14374/1 14365/14373/1 +f 14358/14366/1 14361/14369/1 14364/14372/1 14359/14367/1 +f 14271/14279/1 2076/2084/1 14361/14369/1 14358/14366/1 +f 2076/2084/1 2075/2083/1 14362/14370/1 14361/14369/1 +f 14302/14310/1 14357/14365/1 14360/14368/1 14303/14311/1 +f 2071/2079/1 14272/14280/1 14357/14365/1 14302/14310/1 +f 14272/14280/1 14271/14279/1 14358/14366/1 14357/14365/1 +f 2066/2074/1 14353/14361/1 14356/14364/1 2067/2075/1 +f 14303/14311/1 14360/14368/1 14353/14361/1 2066/2074/1 +f 14360/14368/1 14359/14367/1 14354/14362/1 14353/14361/1 +f 14346/14354/1 14349/14357/1 14352/14360/1 14347/14355/1 +f 14307/14315/1 2064/2072/1 14349/14357/1 14346/14354/1 +f 2064/2072/1 2063/2071/1 14350/14358/1 14349/14357/1 +f 14338/14346/1 14345/14353/1 14348/14356/1 14339/14347/1 +f 2059/2067/1 14308/14316/1 14345/14353/1 14338/14346/1 +f 14308/14316/1 14307/14315/1 14346/14354/1 14345/14353/1 +f 2054/2062/1 14341/14349/1 14344/14352/1 2055/2063/1 +f 14339/14347/1 14348/14356/1 14341/14349/1 2054/2062/1 +f 14348/14356/1 14347/14355/1 14342/14350/1 14341/14349/1 +f 14334/14342/1 14337/14345/1 14340/14348/1 14335/14343/1 +f 14319/14327/1 2060/2068/1 14337/14345/1 14334/14342/1 +f 2060/2068/1 2059/2067/1 14338/14346/1 14337/14345/1 +f 14362/14370/1 14333/14341/1 14336/14344/1 14363/14371/1 +f 2075/2083/1 14320/14328/1 14333/14341/1 14362/14370/1 +f 14320/14328/1 14319/14327/1 14334/14342/1 14333/14341/1 +f 2046/2054/1 14329/14337/1 14332/14340/1 2047/2055/1 +f 14363/14371/1 14336/14344/1 14329/14337/1 2046/2054/1 +f 14336/14344/1 14335/14343/1 14330/14338/1 14329/14337/1 +f 14322/14330/1 14325/14333/1 14328/14336/1 14323/14331/1 +f 7419/7427/1 4360/4368/1 14325/14333/1 14322/14330/1 +f 4360/4368/1 4359/4367/1 14326/14334/1 14325/14333/1 +f 14278/14286/1 14321/14329/1 14324/14332/1 14279/14287/1 +f 1287/1295/1 7420/7428/1 14321/14329/1 14278/14286/1 +f 7420/7428/1 7419/7427/1 14322/14330/1 14321/14329/1 +f 2074/2082/1 14317/14325/1 14320/14328/1 2075/2083/1 +f 14279/14287/1 14324/14332/1 14317/14325/1 2074/2082/1 +f 14324/14332/1 14323/14331/1 14318/14326/1 14317/14325/1 +f 14310/14318/1 14313/14321/1 14316/14324/1 14311/14319/1 +f 16647/16655/1 1284/1292/1 14313/14321/1 14310/14318/1 +f 1284/1292/1 1283/1291/1 14314/14322/1 14313/14321/1 +f 14326/14334/1 14309/14317/1 14312/14320/1 14327/14335/1 +f 4359/4367/1 16648/16656/1 14309/14317/1 14326/14334/1 +f 16648/16656/1 16647/16655/1 14310/14318/1 14309/14317/1 +f 2058/2066/1 14305/14313/1 14308/14316/1 2059/2067/1 +f 14327/14335/1 14312/14320/1 14305/14313/1 2058/2066/1 +f 14312/14320/1 14311/14319/1 14306/14314/1 14305/14313/1 +f 14298/14306/1 14301/14309/1 14304/14312/1 14299/14307/1 +f 14283/14291/1 2072/2080/1 14301/14309/1 14298/14306/1 +f 2072/2080/1 2071/2079/1 14302/14310/1 14301/14309/1 +f 16546/16554/1 14297/14305/1 14300/14308/1 16547/16555/1 +f 4259/4267/1 14284/14292/1 14297/14305/1 16546/16554/1 +f 14284/14292/1 14283/14291/1 14298/14306/1 14297/14305/1 +f 1318/1326/1 14293/14301/1 14296/14304/1 1319/1327/1 +f 16547/16555/1 14300/14308/1 14293/14301/1 1318/1326/1 +f 14300/14308/1 14299/14307/1 14294/14302/1 14293/14301/1 +f 14286/14294/1 14289/14297/1 14292/14300/1 14287/14295/1 +f 7455/7463/1 4348/4356/1 14289/14297/1 14286/14294/1 +f 4348/4356/1 4347/4355/1 14290/14298/1 14289/14297/1 +f 7726/7734/1 14285/14293/1 14288/14296/1 7727/7735/1 +f 1279/1287/1 7456/7464/1 14285/14293/1 7726/7734/1 +f 7456/7464/1 7455/7463/1 14286/14294/1 14285/14293/1 +f 4258/4266/1 14281/14289/1 14284/14292/1 4259/4267/1 +f 7727/7735/1 14288/14296/1 14281/14289/1 4258/4266/1 +f 14288/14296/1 14287/14295/1 14282/14290/1 14281/14289/1 +f 14274/14282/1 14277/14285/1 14280/14288/1 14275/14283/1 +f 16635/16643/1 1288/1296/1 14277/14285/1 14274/14282/1 +f 1288/1296/1 1287/1295/1 14278/14286/1 14277/14285/1 +f 14290/14298/1 14273/14281/1 14276/14284/1 14291/14299/1 +f 4347/4355/1 16636/16644/1 14273/14281/1 14290/14298/1 +f 16636/16644/1 16635/16643/1 14274/14282/1 14273/14281/1 +f 2070/2078/1 14269/14277/1 14272/14280/1 2071/2079/1 +f 14291/14299/1 14276/14284/1 14269/14277/1 2070/2078/1 +f 14276/14284/1 14275/14283/1 14270/14278/1 14269/14277/1 +f 14262/14270/1 14265/14273/1 14268/14276/1 14263/14271/1 +f 14247/14255/1 2084/2092/1 14265/14273/1 14262/14270/1 +f 2084/2092/1 2083/2091/1 14266/14274/1 14265/14273/1 +f 16678/16686/1 14261/14269/1 14264/14272/1 16679/16687/1 +f 4391/4399/1 14248/14256/1 14261/14269/1 16678/16686/1 +f 14248/14256/1 14247/14255/1 14262/14270/1 14261/14269/1 +f 1274/1282/1 14257/14265/1 14260/14268/1 1275/1283/1 +f 16679/16687/1 14264/14272/1 14257/14265/1 1274/1282/1 +f 14264/14272/1 14263/14271/1 14258/14266/1 14257/14265/1 +f 14250/14258/1 14253/14261/1 14256/14264/1 14251/14259/1 +f 14295/14303/1 2068/2076/1 14253/14261/1 14250/14258/1 +f 2068/2076/1 2067/2075/1 14254/14262/1 14253/14261/1 +f 7330/7338/1 14249/14257/1 14252/14260/1 7331/7339/1 +f 1319/1327/1 14296/14304/1 14249/14257/1 7330/7338/1 +f 14296/14304/1 14295/14303/1 14250/14258/1 14249/14257/1 +f 4390/4398/1 14245/14253/1 14248/14256/1 4391/4399/1 +f 7331/7339/1 14252/14260/1 14245/14253/1 4390/4398/1 +f 14252/14260/1 14251/14259/1 14246/14254/1 14245/14253/1 +f 14238/14246/1 14241/14249/1 14244/14252/1 14239/14247/1 +f 14355/14363/1 2048/2056/1 14241/14249/1 14238/14246/1 +f 2048/2056/1 2047/2055/1 14242/14250/1 14241/14249/1 +f 14254/14262/1 14237/14245/1 14240/14248/1 14255/14263/1 +f 2067/2075/1 14356/14364/1 14237/14245/1 14254/14262/1 +f 14356/14364/1 14355/14363/1 14238/14246/1 14237/14245/1 +f 2082/2090/1 14233/14241/1 14236/14244/1 2083/2091/1 +f 14255/14263/1 14240/14248/1 14233/14241/1 2082/2090/1 +f 14240/14248/1 14239/14247/1 14234/14242/1 14233/14241/1 +f 14226/14234/1 14229/14237/1 14232/14240/1 14227/14235/1 +f 14211/14219/1 2096/2104/1 14229/14237/1 14226/14234/1 +f 2096/2104/1 2095/2103/1 14230/14238/1 14229/14237/1 +f 14398/14406/1 14225/14233/1 14228/14236/1 14399/14407/1 +f 2111/2119/1 14212/14220/1 14225/14233/1 14398/14406/1 +f 14212/14220/1 14211/14219/1 14226/14234/1 14225/14233/1 +f 2034/2042/1 14221/14229/1 14224/14232/1 2035/2043/1 +f 14399/14407/1 14228/14236/1 14221/14229/1 2034/2042/1 +f 14228/14236/1 14227/14235/1 14222/14230/1 14221/14229/1 +f 14214/14222/1 14217/14225/1 14220/14228/1 14215/14223/1 +f 7311/7319/1 4396/4404/1 14217/14225/1 14214/14222/1 +f 4396/4404/1 4395/4403/1 14218/14226/1 14217/14225/1 +f 14170/14178/1 14213/14221/1 14216/14224/1 14171/14179/1 +f 1323/1331/1 7312/7320/1 14213/14221/1 14170/14178/1 +f 7312/7320/1 7311/7319/1 14214/14222/1 14213/14221/1 +f 2110/2118/1 14209/14217/1 14212/14220/1 2111/2119/1 +f 14171/14179/1 14216/14224/1 14209/14217/1 2110/2118/1 +f 14216/14224/1 14215/14223/1 14210/14218/1 14209/14217/1 +f 14202/14210/1 14205/14213/1 14208/14216/1 14203/14211/1 +f 16683/16691/1 1272/1280/1 14205/14213/1 14202/14210/1 +f 1272/1280/1 1271/1279/1 14206/14214/1 14205/14213/1 +f 14218/14226/1 14201/14209/1 14204/14212/1 14219/14227/1 +f 4395/4403/1 16684/16692/1 14201/14209/1 14218/14226/1 +f 16684/16692/1 16683/16691/1 14202/14210/1 14201/14209/1 +f 2094/2102/1 14197/14205/1 14200/14208/1 2095/2103/1 +f 14219/14227/1 14204/14212/1 14197/14205/1 2094/2102/1 +f 14204/14212/1 14203/14211/1 14198/14206/1 14197/14205/1 +f 14190/14198/1 14193/14201/1 14196/14204/1 14191/14199/1 +f 14175/14183/1 2108/2116/1 14193/14201/1 14190/14198/1 +f 2108/2116/1 2107/2115/1 14194/14202/1 14193/14201/1 +f 16438/16446/1 14189/14197/1 14192/14200/1 16439/16447/1 +f 4151/4159/1 14176/14184/1 14189/14197/1 16438/16446/1 +f 14176/14184/1 14175/14183/1 14190/14198/1 14189/14197/1 +f 1354/1362/1 14185/14193/1 14188/14196/1 1355/1363/1 +f 16439/16447/1 14192/14200/1 14185/14193/1 1354/1362/1 +f 14192/14200/1 14191/14199/1 14186/14194/1 14185/14193/1 +f 14178/14186/1 14181/14189/1 14184/14192/1 14179/14187/1 +f 7779/7787/1 4240/4248/1 14181/14189/1 14178/14186/1 +f 4240/4248/1 4239/4247/1 14182/14190/1 14181/14189/1 +f 8050/8058/1 14177/14185/1 14180/14188/1 8051/8059/1 +f 1267/1275/1 7780/7788/1 14177/14185/1 8050/8058/1 +f 7780/7788/1 7779/7787/1 14178/14186/1 14177/14185/1 +f 4150/4158/1 14173/14181/1 14176/14184/1 4151/4159/1 +f 8051/8059/1 14180/14188/1 14173/14181/1 4150/4158/1 +f 14180/14188/1 14179/14187/1 14174/14182/1 14173/14181/1 +f 14166/14174/1 14169/14177/1 14172/14180/1 14167/14175/1 +f 16527/16535/1 1324/1332/1 14169/14177/1 14166/14174/1 +f 1324/1332/1 1323/1331/1 14170/14178/1 14169/14177/1 +f 14182/14190/1 14165/14173/1 14168/14176/1 14183/14191/1 +f 4239/4247/1 16528/16536/1 14165/14173/1 14182/14190/1 +f 16528/16536/1 16527/16535/1 14166/14174/1 14165/14173/1 +f 2106/2114/1 14161/14169/1 14164/14172/1 2107/2115/1 +f 14183/14191/1 14168/14176/1 14161/14169/1 2106/2114/1 +f 14168/14176/1 14167/14175/1 14162/14170/1 14161/14169/1 +f 14154/14162/1 14157/14165/1 14160/14168/1 14155/14163/1 +f 14139/14147/1 2120/2128/1 14157/14165/1 14154/14162/1 +f 2120/2128/1 2119/2127/1 14158/14166/1 14157/14165/1 +f 16714/16722/1 14153/14161/1 14156/14164/1 16715/16723/1 +f 4427/4435/1 14140/14148/1 14153/14161/1 16714/16722/1 +f 14140/14148/1 14139/14147/1 14154/14162/1 14153/14161/1 +f 1262/1270/1 14149/14157/1 14152/14160/1 1263/1271/1 +f 16715/16723/1 14156/14164/1 14149/14157/1 1262/1270/1 +f 14156/14164/1 14155/14163/1 14150/14158/1 14149/14157/1 +f 14142/14150/1 14145/14153/1 14148/14156/1 14143/14151/1 +f 14187/14195/1 2104/2112/1 14145/14153/1 14142/14150/1 +f 2104/2112/1 2103/2111/1 14146/14154/1 14145/14153/1 +f 7222/7230/1 14141/14149/1 14144/14152/1 7223/7231/1 +f 1355/1363/1 14188/14196/1 14141/14149/1 7222/7230/1 +f 14188/14196/1 14187/14195/1 14142/14150/1 14141/14149/1 +f 4426/4434/1 14137/14145/1 14140/14148/1 4427/4435/1 +f 7223/7231/1 14144/14152/1 14137/14145/1 4426/4434/1 +f 14144/14152/1 14143/14151/1 14138/14146/1 14137/14145/1 +f 14130/14138/1 14133/14141/1 14136/14144/1 14131/14139/1 +f 14391/14399/1 2036/2044/1 14133/14141/1 14130/14138/1 +f 2036/2044/1 2035/2043/1 14134/14142/1 14133/14141/1 +f 14146/14154/1 14129/14137/1 14132/14140/1 14147/14155/1 +f 2103/2111/1 14392/14400/1 14129/14137/1 14146/14154/1 +f 14392/14400/1 14391/14399/1 14130/14138/1 14129/14137/1 +f 2118/2126/1 14125/14133/1 14128/14136/1 2119/2127/1 +f 14147/14155/1 14132/14140/1 14125/14133/1 2118/2126/1 +f 14132/14140/1 14131/14139/1 14126/14134/1 14125/14133/1 +f 14118/14126/1 14121/14129/1 14124/14132/1 14119/14127/1 +f 14103/14111/1 2132/2140/1 14121/14129/1 14118/14126/1 +f 2132/2140/1 2131/2139/1 14122/14130/1 14121/14129/1 +f 14434/14442/1 14117/14125/1 14120/14128/1 14435/14443/1 +f 2147/2155/1 14104/14112/1 14117/14125/1 14434/14442/1 +f 14104/14112/1 14103/14111/1 14118/14126/1 14117/14125/1 +f 2022/2030/1 14113/14121/1 14116/14124/1 2023/2031/1 +f 14435/14443/1 14120/14128/1 14113/14121/1 2022/2030/1 +f 14120/14128/1 14119/14127/1 14114/14122/1 14113/14121/1 +f 14106/14114/1 14109/14117/1 14112/14120/1 14107/14115/1 +f 7203/7211/1 4432/4440/1 14109/14117/1 14106/14114/1 +f 4432/4440/1 4431/4439/1 14110/14118/1 14109/14117/1 +f 14062/14070/1 14105/14113/1 14108/14116/1 14063/14071/1 +f 1359/1367/1 7204/7212/1 14105/14113/1 14062/14070/1 +f 7204/7212/1 7203/7211/1 14106/14114/1 14105/14113/1 +f 2146/2154/1 14101/14109/1 14104/14112/1 2147/2155/1 +f 14063/14071/1 14108/14116/1 14101/14109/1 2146/2154/1 +f 14108/14116/1 14107/14115/1 14102/14110/1 14101/14109/1 +f 14094/14102/1 14097/14105/1 14100/14108/1 14095/14103/1 +f 16719/16727/1 1260/1268/1 14097/14105/1 14094/14102/1 +f 1260/1268/1 1259/1267/1 14098/14106/1 14097/14105/1 +f 14110/14118/1 14093/14101/1 14096/14104/1 14111/14119/1 +f 4431/4439/1 16720/16728/1 14093/14101/1 14110/14118/1 +f 16720/16728/1 16719/16727/1 14094/14102/1 14093/14101/1 +f 2130/2138/1 14089/14097/1 14092/14100/1 2131/2139/1 +f 14111/14119/1 14096/14104/1 14089/14097/1 2130/2138/1 +f 14096/14104/1 14095/14103/1 14090/14098/1 14089/14097/1 +f 14082/14090/1 14085/14093/1 14088/14096/1 14083/14091/1 +f 14067/14075/1 2144/2152/1 14085/14093/1 14082/14090/1 +f 2144/2152/1 2143/2151/1 14086/14094/1 14085/14093/1 +f 16330/16338/1 14081/14089/1 14084/14092/1 16331/16339/1 +f 4043/4051/1 14068/14076/1 14081/14089/1 16330/16338/1 +f 14068/14076/1 14067/14075/1 14082/14090/1 14081/14089/1 +f 1390/1398/1 14077/14085/1 14080/14088/1 1391/1399/1 +f 16331/16339/1 14084/14092/1 14077/14085/1 1390/1398/1 +f 14084/14092/1 14083/14091/1 14078/14086/1 14077/14085/1 +f 14070/14078/1 14073/14081/1 14076/14084/1 14071/14079/1 +f 8103/8111/1 4132/4140/1 14073/14081/1 14070/14078/1 +f 4132/4140/1 4131/4139/1 14074/14082/1 14073/14081/1 +f 8374/8382/1 14069/14077/1 14072/14080/1 8375/8383/1 +f 1255/1263/1 8104/8112/1 14069/14077/1 8374/8382/1 +f 8104/8112/1 8103/8111/1 14070/14078/1 14069/14077/1 +f 4042/4050/1 14065/14073/1 14068/14076/1 4043/4051/1 +f 8375/8383/1 14072/14080/1 14065/14073/1 4042/4050/1 +f 14072/14080/1 14071/14079/1 14066/14074/1 14065/14073/1 +f 14058/14066/1 14061/14069/1 14064/14072/1 14059/14067/1 +f 16419/16427/1 1360/1368/1 14061/14069/1 14058/14066/1 +f 1360/1368/1 1359/1367/1 14062/14070/1 14061/14069/1 +f 14074/14082/1 14057/14065/1 14060/14068/1 14075/14083/1 +f 4131/4139/1 16420/16428/1 14057/14065/1 14074/14082/1 +f 16420/16428/1 16419/16427/1 14058/14066/1 14057/14065/1 +f 2142/2150/1 14053/14061/1 14056/14064/1 2143/2151/1 +f 14075/14083/1 14060/14068/1 14053/14061/1 2142/2150/1 +f 14060/14068/1 14059/14067/1 14054/14062/1 14053/14061/1 +f 14046/14054/1 14049/14057/1 14052/14060/1 14047/14055/1 +f 14031/14039/1 2156/2164/1 14049/14057/1 14046/14054/1 +f 2156/2164/1 2155/2163/1 14050/14058/1 14049/14057/1 +f 16750/16758/1 14045/14053/1 14048/14056/1 16751/16759/1 +f 4463/4471/1 14032/14040/1 14045/14053/1 16750/16758/1 +f 14032/14040/1 14031/14039/1 14046/14054/1 14045/14053/1 +f 1250/1258/1 14041/14049/1 14044/14052/1 1251/1259/1 +f 16751/16759/1 14048/14056/1 14041/14049/1 1250/1258/1 +f 14048/14056/1 14047/14055/1 14042/14050/1 14041/14049/1 +f 14034/14042/1 14037/14045/1 14040/14048/1 14035/14043/1 +f 14079/14087/1 2140/2148/1 14037/14045/1 14034/14042/1 +f 2140/2148/1 2139/2147/1 14038/14046/1 14037/14045/1 +f 7114/7122/1 14033/14041/1 14036/14044/1 7115/7123/1 +f 1391/1399/1 14080/14088/1 14033/14041/1 7114/7122/1 +f 14080/14088/1 14079/14087/1 14034/14042/1 14033/14041/1 +f 4462/4470/1 14029/14037/1 14032/14040/1 4463/4471/1 +f 7115/7123/1 14036/14044/1 14029/14037/1 4462/4470/1 +f 14036/14044/1 14035/14043/1 14030/14038/1 14029/14037/1 +f 14022/14030/1 14025/14033/1 14028/14036/1 14023/14031/1 +f 14427/14435/1 2024/2032/1 14025/14033/1 14022/14030/1 +f 2024/2032/1 2023/2031/1 14026/14034/1 14025/14033/1 +f 14038/14046/1 14021/14029/1 14024/14032/1 14039/14047/1 +f 2139/2147/1 14428/14436/1 14021/14029/1 14038/14046/1 +f 14428/14436/1 14427/14435/1 14022/14030/1 14021/14029/1 +f 2154/2162/1 14017/14025/1 14020/14028/1 2155/2163/1 +f 14039/14047/1 14024/14032/1 14017/14025/1 2154/2162/1 +f 14024/14032/1 14023/14031/1 14018/14026/1 14017/14025/1 +f 14010/14018/1 14013/14021/1 14016/14024/1 14011/14019/1 +f 13995/14003/1 2168/2176/1 14013/14021/1 14010/14018/1 +f 2168/2176/1 2167/2175/1 14014/14022/1 14013/14021/1 +f 14470/14478/1 14009/14017/1 14012/14020/1 14471/14479/1 +f 2183/2191/1 13996/14004/1 14009/14017/1 14470/14478/1 +f 13996/14004/1 13995/14003/1 14010/14018/1 14009/14017/1 +f 2010/2018/1 14005/14013/1 14008/14016/1 2011/2019/1 +f 14471/14479/1 14012/14020/1 14005/14013/1 2010/2018/1 +f 14012/14020/1 14011/14019/1 14006/14014/1 14005/14013/1 +f 13998/14006/1 14001/14009/1 14004/14012/1 13999/14007/1 +f 7095/7103/1 4468/4476/1 14001/14009/1 13998/14006/1 +f 4468/4476/1 4467/4475/1 14002/14010/1 14001/14009/1 +f 13954/13962/1 13997/14005/1 14000/14008/1 13955/13963/1 +f 1395/1403/1 7096/7104/1 13997/14005/1 13954/13962/1 +f 7096/7104/1 7095/7103/1 13998/14006/1 13997/14005/1 +f 2182/2190/1 13993/14001/1 13996/14004/1 2183/2191/1 +f 13955/13963/1 14000/14008/1 13993/14001/1 2182/2190/1 +f 14000/14008/1 13999/14007/1 13994/14002/1 13993/14001/1 +f 13986/13994/1 13989/13997/1 13992/14000/1 13987/13995/1 +f 16755/16763/1 1248/1256/1 13989/13997/1 13986/13994/1 +f 1248/1256/1 1247/1255/1 13990/13998/1 13989/13997/1 +f 14002/14010/1 13985/13993/1 13988/13996/1 14003/14011/1 +f 4467/4475/1 16756/16764/1 13985/13993/1 14002/14010/1 +f 16756/16764/1 16755/16763/1 13986/13994/1 13985/13993/1 +f 2166/2174/1 13981/13989/1 13984/13992/1 2167/2175/1 +f 14003/14011/1 13988/13996/1 13981/13989/1 2166/2174/1 +f 13988/13996/1 13987/13995/1 13982/13990/1 13981/13989/1 +f 13974/13982/1 13977/13985/1 13980/13988/1 13975/13983/1 +f 13959/13967/1 2180/2188/1 13977/13985/1 13974/13982/1 +f 2180/2188/1 2179/2187/1 13978/13986/1 13977/13985/1 +f 16222/16230/1 13973/13981/1 13976/13984/1 16223/16231/1 +f 3935/3943/1 13960/13968/1 13973/13981/1 16222/16230/1 +f 13960/13968/1 13959/13967/1 13974/13982/1 13973/13981/1 +f 1426/1434/1 13969/13977/1 13972/13980/1 1427/1435/1 +f 16223/16231/1 13976/13984/1 13969/13977/1 1426/1434/1 +f 13976/13984/1 13975/13983/1 13970/13978/1 13969/13977/1 +f 13962/13970/1 13965/13973/1 13968/13976/1 13963/13971/1 +f 8427/8435/1 4024/4032/1 13965/13973/1 13962/13970/1 +f 4024/4032/1 4023/4031/1 13966/13974/1 13965/13973/1 +f 8698/8706/1 13961/13969/1 13964/13972/1 8699/8707/1 +f 1243/1251/1 8428/8436/1 13961/13969/1 8698/8706/1 +f 8428/8436/1 8427/8435/1 13962/13970/1 13961/13969/1 +f 3934/3942/1 13957/13965/1 13960/13968/1 3935/3943/1 +f 8699/8707/1 13964/13972/1 13957/13965/1 3934/3942/1 +f 13964/13972/1 13963/13971/1 13958/13966/1 13957/13965/1 +f 13950/13958/1 13953/13961/1 13956/13964/1 13951/13959/1 +f 16311/16319/1 1396/1404/1 13953/13961/1 13950/13958/1 +f 1396/1404/1 1395/1403/1 13954/13962/1 13953/13961/1 +f 13966/13974/1 13949/13957/1 13952/13960/1 13967/13975/1 +f 4023/4031/1 16312/16320/1 13949/13957/1 13966/13974/1 +f 16312/16320/1 16311/16319/1 13950/13958/1 13949/13957/1 +f 2178/2186/1 13945/13953/1 13948/13956/1 2179/2187/1 +f 13967/13975/1 13952/13960/1 13945/13953/1 2178/2186/1 +f 13952/13960/1 13951/13959/1 13946/13954/1 13945/13953/1 +f 13938/13946/1 13941/13949/1 13944/13952/1 13939/13947/1 +f 13923/13931/1 2192/2200/1 13941/13949/1 13938/13946/1 +f 2192/2200/1 2191/2199/1 13942/13950/1 13941/13949/1 +f 16786/16794/1 13937/13945/1 13940/13948/1 16787/16795/1 +f 4499/4507/1 13924/13932/1 13937/13945/1 16786/16794/1 +f 13924/13932/1 13923/13931/1 13938/13946/1 13937/13945/1 +f 1238/1246/1 13933/13941/1 13936/13944/1 1239/1247/1 +f 16787/16795/1 13940/13948/1 13933/13941/1 1238/1246/1 +f 13940/13948/1 13939/13947/1 13934/13942/1 13933/13941/1 +f 13926/13934/1 13929/13937/1 13932/13940/1 13927/13935/1 +f 13971/13979/1 2176/2184/1 13929/13937/1 13926/13934/1 +f 2176/2184/1 2175/2183/1 13930/13938/1 13929/13937/1 +f 7006/7014/1 13925/13933/1 13928/13936/1 7007/7015/1 +f 1427/1435/1 13972/13980/1 13925/13933/1 7006/7014/1 +f 13972/13980/1 13971/13979/1 13926/13934/1 13925/13933/1 +f 4498/4506/1 13921/13929/1 13924/13932/1 4499/4507/1 +f 7007/7015/1 13928/13936/1 13921/13929/1 4498/4506/1 +f 13928/13936/1 13927/13935/1 13922/13930/1 13921/13929/1 +f 13914/13922/1 13917/13925/1 13920/13928/1 13915/13923/1 +f 14463/14471/1 2012/2020/1 13917/13925/1 13914/13922/1 +f 2012/2020/1 2011/2019/1 13918/13926/1 13917/13925/1 +f 13930/13938/1 13913/13921/1 13916/13924/1 13931/13939/1 +f 2175/2183/1 14464/14472/1 13913/13921/1 13930/13938/1 +f 14464/14472/1 14463/14471/1 13914/13922/1 13913/13921/1 +f 2190/2198/1 13909/13917/1 13912/13920/1 2191/2199/1 +f 13931/13939/1 13916/13924/1 13909/13917/1 2190/2198/1 +f 13916/13924/1 13915/13923/1 13910/13918/1 13909/13917/1 +f 13902/13910/1 13905/13913/1 13908/13916/1 13903/13911/1 +f 13887/13895/1 2204/2212/1 13905/13913/1 13902/13910/1 +f 2204/2212/1 2203/2211/1 13906/13914/1 13905/13913/1 +f 14506/14514/1 13901/13909/1 13904/13912/1 14507/14515/1 +f 2219/2227/1 13888/13896/1 13901/13909/1 14506/14514/1 +f 13888/13896/1 13887/13895/1 13902/13910/1 13901/13909/1 +f 1998/2006/1 13897/13905/1 13900/13908/1 1999/2007/1 +f 14507/14515/1 13904/13912/1 13897/13905/1 1998/2006/1 +f 13904/13912/1 13903/13911/1 13898/13906/1 13897/13905/1 +f 13890/13898/1 13893/13901/1 13896/13904/1 13891/13899/1 +f 6987/6995/1 4504/4512/1 13893/13901/1 13890/13898/1 +f 4504/4512/1 4503/4511/1 13894/13902/1 13893/13901/1 +f 13846/13854/1 13889/13897/1 13892/13900/1 13847/13855/1 +f 1431/1439/1 6988/6996/1 13889/13897/1 13846/13854/1 +f 6988/6996/1 6987/6995/1 13890/13898/1 13889/13897/1 +f 2218/2226/1 13885/13893/1 13888/13896/1 2219/2227/1 +f 13847/13855/1 13892/13900/1 13885/13893/1 2218/2226/1 +f 13892/13900/1 13891/13899/1 13886/13894/1 13885/13893/1 +f 13878/13886/1 13881/13889/1 13884/13892/1 13879/13887/1 +f 16791/16799/1 1236/1244/1 13881/13889/1 13878/13886/1 +f 1236/1244/1 1235/1243/1 13882/13890/1 13881/13889/1 +f 13894/13902/1 13877/13885/1 13880/13888/1 13895/13903/1 +f 4503/4511/1 16792/16800/1 13877/13885/1 13894/13902/1 +f 16792/16800/1 16791/16799/1 13878/13886/1 13877/13885/1 +f 2202/2210/1 13873/13881/1 13876/13884/1 2203/2211/1 +f 13895/13903/1 13880/13888/1 13873/13881/1 2202/2210/1 +f 13880/13888/1 13879/13887/1 13874/13882/1 13873/13881/1 +f 13866/13874/1 13869/13877/1 13872/13880/1 13867/13875/1 +f 13851/13859/1 2216/2224/1 13869/13877/1 13866/13874/1 +f 2216/2224/1 2215/2223/1 13870/13878/1 13869/13877/1 +f 16114/16122/1 13865/13873/1 13868/13876/1 16115/16123/1 +f 3827/3835/1 13852/13860/1 13865/13873/1 16114/16122/1 +f 13852/13860/1 13851/13859/1 13866/13874/1 13865/13873/1 +f 1462/1470/1 13861/13869/1 13864/13872/1 1463/1471/1 +f 16115/16123/1 13868/13876/1 13861/13869/1 1462/1470/1 +f 13868/13876/1 13867/13875/1 13862/13870/1 13861/13869/1 +f 13854/13862/1 13857/13865/1 13860/13868/1 13855/13863/1 +f 8751/8759/1 3916/3924/1 13857/13865/1 13854/13862/1 +f 3916/3924/1 3915/3923/1 13858/13866/1 13857/13865/1 +f 9022/9030/1 13853/13861/1 13856/13864/1 9023/9031/1 +f 1231/1239/1 8752/8760/1 13853/13861/1 9022/9030/1 +f 8752/8760/1 8751/8759/1 13854/13862/1 13853/13861/1 +f 3826/3834/1 13849/13857/1 13852/13860/1 3827/3835/1 +f 9023/9031/1 13856/13864/1 13849/13857/1 3826/3834/1 +f 13856/13864/1 13855/13863/1 13850/13858/1 13849/13857/1 +f 13842/13850/1 13845/13853/1 13848/13856/1 13843/13851/1 +f 16203/16211/1 1432/1440/1 13845/13853/1 13842/13850/1 +f 1432/1440/1 1431/1439/1 13846/13854/1 13845/13853/1 +f 13858/13866/1 13841/13849/1 13844/13852/1 13859/13867/1 +f 3915/3923/1 16204/16212/1 13841/13849/1 13858/13866/1 +f 16204/16212/1 16203/16211/1 13842/13850/1 13841/13849/1 +f 2214/2222/1 13837/13845/1 13840/13848/1 2215/2223/1 +f 13859/13867/1 13844/13852/1 13837/13845/1 2214/2222/1 +f 13844/13852/1 13843/13851/1 13838/13846/1 13837/13845/1 +f 13830/13838/1 13833/13841/1 13836/13844/1 13831/13839/1 +f 13815/13823/1 2228/2236/1 13833/13841/1 13830/13838/1 +f 2228/2236/1 2227/2235/1 13834/13842/1 13833/13841/1 +f 16822/16830/1 13829/13837/1 13832/13840/1 16823/16831/1 +f 4535/4543/1 13816/13824/1 13829/13837/1 16822/16830/1 +f 13816/13824/1 13815/13823/1 13830/13838/1 13829/13837/1 +f 1226/1234/1 13825/13833/1 13828/13836/1 1227/1235/1 +f 16823/16831/1 13832/13840/1 13825/13833/1 1226/1234/1 +f 13832/13840/1 13831/13839/1 13826/13834/1 13825/13833/1 +f 13818/13826/1 13821/13829/1 13824/13832/1 13819/13827/1 +f 13863/13871/1 2212/2220/1 13821/13829/1 13818/13826/1 +f 2212/2220/1 2211/2219/1 13822/13830/1 13821/13829/1 +f 6898/6906/1 13817/13825/1 13820/13828/1 6899/6907/1 +f 1463/1471/1 13864/13872/1 13817/13825/1 6898/6906/1 +f 13864/13872/1 13863/13871/1 13818/13826/1 13817/13825/1 +f 4534/4542/1 13813/13821/1 13816/13824/1 4535/4543/1 +f 6899/6907/1 13820/13828/1 13813/13821/1 4534/4542/1 +f 13820/13828/1 13819/13827/1 13814/13822/1 13813/13821/1 +f 13806/13814/1 13809/13817/1 13812/13820/1 13807/13815/1 +f 14499/14507/1 2000/2008/1 13809/13817/1 13806/13814/1 +f 2000/2008/1 1999/2007/1 13810/13818/1 13809/13817/1 +f 13822/13830/1 13805/13813/1 13808/13816/1 13823/13831/1 +f 2211/2219/1 14500/14508/1 13805/13813/1 13822/13830/1 +f 14500/14508/1 14499/14507/1 13806/13814/1 13805/13813/1 +f 2226/2234/1 13801/13809/1 13804/13812/1 2227/2235/1 +f 13823/13831/1 13808/13816/1 13801/13809/1 2226/2234/1 +f 13808/13816/1 13807/13815/1 13802/13810/1 13801/13809/1 +f 13794/13802/1 13797/13805/1 13800/13808/1 13795/13803/1 +f 13779/13787/1 2240/2248/1 13797/13805/1 13794/13802/1 +f 2240/2248/1 2239/2247/1 13798/13806/1 13797/13805/1 +f 14542/14550/1 13793/13801/1 13796/13804/1 14543/14551/1 +f 2255/2263/1 13780/13788/1 13793/13801/1 14542/14550/1 +f 13780/13788/1 13779/13787/1 13794/13802/1 13793/13801/1 +f 1986/1994/1 13789/13797/1 13792/13800/1 1987/1995/1 +f 14543/14551/1 13796/13804/1 13789/13797/1 1986/1994/1 +f 13796/13804/1 13795/13803/1 13790/13798/1 13789/13797/1 +f 13782/13790/1 13785/13793/1 13788/13796/1 13783/13791/1 +f 6879/6887/1 4540/4548/1 13785/13793/1 13782/13790/1 +f 4540/4548/1 4539/4547/1 13786/13794/1 13785/13793/1 +f 13738/13746/1 13781/13789/1 13784/13792/1 13739/13747/1 +f 1467/1475/1 6880/6888/1 13781/13789/1 13738/13746/1 +f 6880/6888/1 6879/6887/1 13782/13790/1 13781/13789/1 +f 2254/2262/1 13777/13785/1 13780/13788/1 2255/2263/1 +f 13739/13747/1 13784/13792/1 13777/13785/1 2254/2262/1 +f 13784/13792/1 13783/13791/1 13778/13786/1 13777/13785/1 +f 13770/13778/1 13773/13781/1 13776/13784/1 13771/13779/1 +f 16827/16835/1 1224/1232/1 13773/13781/1 13770/13778/1 +f 1224/1232/1 1223/1231/1 13774/13782/1 13773/13781/1 +f 13786/13794/1 13769/13777/1 13772/13780/1 13787/13795/1 +f 4539/4547/1 16828/16836/1 13769/13777/1 13786/13794/1 +f 16828/16836/1 16827/16835/1 13770/13778/1 13769/13777/1 +f 2238/2246/1 13765/13773/1 13768/13776/1 2239/2247/1 +f 13787/13795/1 13772/13780/1 13765/13773/1 2238/2246/1 +f 13772/13780/1 13771/13779/1 13766/13774/1 13765/13773/1 +f 13758/13766/1 13761/13769/1 13764/13772/1 13759/13767/1 +f 13743/13751/1 2252/2260/1 13761/13769/1 13758/13766/1 +f 2252/2260/1 2251/2259/1 13762/13770/1 13761/13769/1 +f 16006/16014/1 13757/13765/1 13760/13768/1 16007/16015/1 +f 3719/3727/1 13744/13752/1 13757/13765/1 16006/16014/1 +f 13744/13752/1 13743/13751/1 13758/13766/1 13757/13765/1 +f 1498/1506/1 13753/13761/1 13756/13764/1 1499/1507/1 +f 16007/16015/1 13760/13768/1 13753/13761/1 1498/1506/1 +f 13760/13768/1 13759/13767/1 13754/13762/1 13753/13761/1 +f 13746/13754/1 13749/13757/1 13752/13760/1 13747/13755/1 +f 9075/9083/1 3808/3816/1 13749/13757/1 13746/13754/1 +f 3808/3816/1 3807/3815/1 13750/13758/1 13749/13757/1 +f 9346/9354/1 13745/13753/1 13748/13756/1 9347/9355/1 +f 1219/1227/1 9076/9084/1 13745/13753/1 9346/9354/1 +f 9076/9084/1 9075/9083/1 13746/13754/1 13745/13753/1 +f 3718/3726/1 13741/13749/1 13744/13752/1 3719/3727/1 +f 9347/9355/1 13748/13756/1 13741/13749/1 3718/3726/1 +f 13748/13756/1 13747/13755/1 13742/13750/1 13741/13749/1 +f 13734/13742/1 13737/13745/1 13740/13748/1 13735/13743/1 +f 16095/16103/1 1468/1476/1 13737/13745/1 13734/13742/1 +f 1468/1476/1 1467/1475/1 13738/13746/1 13737/13745/1 +f 13750/13758/1 13733/13741/1 13736/13744/1 13751/13759/1 +f 3807/3815/1 16096/16104/1 13733/13741/1 13750/13758/1 +f 16096/16104/1 16095/16103/1 13734/13742/1 13733/13741/1 +f 2250/2258/1 13729/13737/1 13732/13740/1 2251/2259/1 +f 13751/13759/1 13736/13744/1 13729/13737/1 2250/2258/1 +f 13736/13744/1 13735/13743/1 13730/13738/1 13729/13737/1 +f 13722/13730/1 13725/13733/1 13728/13736/1 13723/13731/1 +f 13707/13715/1 2264/2272/1 13725/13733/1 13722/13730/1 +f 2264/2272/1 2263/2271/1 13726/13734/1 13725/13733/1 +f 16858/16866/1 13721/13729/1 13724/13732/1 16859/16867/1 +f 4571/4579/1 13708/13716/1 13721/13729/1 16858/16866/1 +f 13708/13716/1 13707/13715/1 13722/13730/1 13721/13729/1 +f 1214/1222/1 13717/13725/1 13720/13728/1 1215/1223/1 +f 16859/16867/1 13724/13732/1 13717/13725/1 1214/1222/1 +f 13724/13732/1 13723/13731/1 13718/13726/1 13717/13725/1 +f 13710/13718/1 13713/13721/1 13716/13724/1 13711/13719/1 +f 13755/13763/1 2248/2256/1 13713/13721/1 13710/13718/1 +f 2248/2256/1 2247/2255/1 13714/13722/1 13713/13721/1 +f 6790/6798/1 13709/13717/1 13712/13720/1 6791/6799/1 +f 1499/1507/1 13756/13764/1 13709/13717/1 6790/6798/1 +f 13756/13764/1 13755/13763/1 13710/13718/1 13709/13717/1 +f 4570/4578/1 13705/13713/1 13708/13716/1 4571/4579/1 +f 6791/6799/1 13712/13720/1 13705/13713/1 4570/4578/1 +f 13712/13720/1 13711/13719/1 13706/13714/1 13705/13713/1 +f 13698/13706/1 13701/13709/1 13704/13712/1 13699/13707/1 +f 14535/14543/1 1988/1996/1 13701/13709/1 13698/13706/1 +f 1988/1996/1 1987/1995/1 13702/13710/1 13701/13709/1 +f 13714/13722/1 13697/13705/1 13700/13708/1 13715/13723/1 +f 2247/2255/1 14536/14544/1 13697/13705/1 13714/13722/1 +f 14536/14544/1 14535/14543/1 13698/13706/1 13697/13705/1 +f 2262/2270/1 13693/13701/1 13696/13704/1 2263/2271/1 +f 13715/13723/1 13700/13708/1 13693/13701/1 2262/2270/1 +f 13700/13708/1 13699/13707/1 13694/13702/1 13693/13701/1 +f 13686/13694/1 13689/13697/1 13692/13700/1 13687/13695/1 +f 13671/13679/1 2276/2284/1 13689/13697/1 13686/13694/1 +f 2276/2284/1 2275/2283/1 13690/13698/1 13689/13697/1 +f 14578/14586/1 13685/13693/1 13688/13696/1 14579/14587/1 +f 2291/2299/1 13672/13680/1 13685/13693/1 14578/14586/1 +f 13672/13680/1 13671/13679/1 13686/13694/1 13685/13693/1 +f 1974/1982/1 13681/13689/1 13684/13692/1 1975/1983/1 +f 14579/14587/1 13688/13696/1 13681/13689/1 1974/1982/1 +f 13688/13696/1 13687/13695/1 13682/13690/1 13681/13689/1 +f 13674/13682/1 13677/13685/1 13680/13688/1 13675/13683/1 +f 6771/6779/1 4576/4584/1 13677/13685/1 13674/13682/1 +f 4576/4584/1 4575/4583/1 13678/13686/1 13677/13685/1 +f 13630/13638/1 13673/13681/1 13676/13684/1 13631/13639/1 +f 1503/1511/1 6772/6780/1 13673/13681/1 13630/13638/1 +f 6772/6780/1 6771/6779/1 13674/13682/1 13673/13681/1 +f 2290/2298/1 13669/13677/1 13672/13680/1 2291/2299/1 +f 13631/13639/1 13676/13684/1 13669/13677/1 2290/2298/1 +f 13676/13684/1 13675/13683/1 13670/13678/1 13669/13677/1 +f 13662/13670/1 13665/13673/1 13668/13676/1 13663/13671/1 +f 16863/16871/1 1212/1220/1 13665/13673/1 13662/13670/1 +f 1212/1220/1 1211/1219/1 13666/13674/1 13665/13673/1 +f 13678/13686/1 13661/13669/1 13664/13672/1 13679/13687/1 +f 4575/4583/1 16864/16872/1 13661/13669/1 13678/13686/1 +f 16864/16872/1 16863/16871/1 13662/13670/1 13661/13669/1 +f 2274/2282/1 13657/13665/1 13660/13668/1 2275/2283/1 +f 13679/13687/1 13664/13672/1 13657/13665/1 2274/2282/1 +f 13664/13672/1 13663/13671/1 13658/13666/1 13657/13665/1 +f 13650/13658/1 13653/13661/1 13656/13664/1 13651/13659/1 +f 13635/13643/1 2288/2296/1 13653/13661/1 13650/13658/1 +f 2288/2296/1 2287/2295/1 13654/13662/1 13653/13661/1 +f 15898/15906/1 13649/13657/1 13652/13660/1 15899/15907/1 +f 3611/3619/1 13636/13644/1 13649/13657/1 15898/15906/1 +f 13636/13644/1 13635/13643/1 13650/13658/1 13649/13657/1 +f 1534/1542/1 13645/13653/1 13648/13656/1 1535/1543/1 +f 15899/15907/1 13652/13660/1 13645/13653/1 1534/1542/1 +f 13652/13660/1 13651/13659/1 13646/13654/1 13645/13653/1 +f 13638/13646/1 13641/13649/1 13644/13652/1 13639/13647/1 +f 9399/9407/1 3700/3708/1 13641/13649/1 13638/13646/1 +f 3700/3708/1 3699/3707/1 13642/13650/1 13641/13649/1 +f 9670/9678/1 13637/13645/1 13640/13648/1 9671/9679/1 +f 1207/1215/1 9400/9408/1 13637/13645/1 9670/9678/1 +f 9400/9408/1 9399/9407/1 13638/13646/1 13637/13645/1 +f 3610/3618/1 13633/13641/1 13636/13644/1 3611/3619/1 +f 9671/9679/1 13640/13648/1 13633/13641/1 3610/3618/1 +f 13640/13648/1 13639/13647/1 13634/13642/1 13633/13641/1 +f 13626/13634/1 13629/13637/1 13632/13640/1 13627/13635/1 +f 15987/15995/1 1504/1512/1 13629/13637/1 13626/13634/1 +f 1504/1512/1 1503/1511/1 13630/13638/1 13629/13637/1 +f 13642/13650/1 13625/13633/1 13628/13636/1 13643/13651/1 +f 3699/3707/1 15988/15996/1 13625/13633/1 13642/13650/1 +f 15988/15996/1 15987/15995/1 13626/13634/1 13625/13633/1 +f 2286/2294/1 13621/13629/1 13624/13632/1 2287/2295/1 +f 13643/13651/1 13628/13636/1 13621/13629/1 2286/2294/1 +f 13628/13636/1 13627/13635/1 13622/13630/1 13621/13629/1 +f 13614/13622/1 13617/13625/1 13620/13628/1 13615/13623/1 +f 13599/13607/1 2300/2308/1 13617/13625/1 13614/13622/1 +f 2300/2308/1 2299/2307/1 13618/13626/1 13617/13625/1 +f 16894/16902/1 13613/13621/1 13616/13624/1 16895/16903/1 +f 4607/4615/1 13600/13608/1 13613/13621/1 16894/16902/1 +f 13600/13608/1 13599/13607/1 13614/13622/1 13613/13621/1 +f 1202/1210/1 13609/13617/1 13612/13620/1 1203/1211/1 +f 16895/16903/1 13616/13624/1 13609/13617/1 1202/1210/1 +f 13616/13624/1 13615/13623/1 13610/13618/1 13609/13617/1 +f 13602/13610/1 13605/13613/1 13608/13616/1 13603/13611/1 +f 13647/13655/1 2284/2292/1 13605/13613/1 13602/13610/1 +f 2284/2292/1 2283/2291/1 13606/13614/1 13605/13613/1 +f 6682/6690/1 13601/13609/1 13604/13612/1 6683/6691/1 +f 1535/1543/1 13648/13656/1 13601/13609/1 6682/6690/1 +f 13648/13656/1 13647/13655/1 13602/13610/1 13601/13609/1 +f 4606/4614/1 13597/13605/1 13600/13608/1 4607/4615/1 +f 6683/6691/1 13604/13612/1 13597/13605/1 4606/4614/1 +f 13604/13612/1 13603/13611/1 13598/13606/1 13597/13605/1 +f 13590/13598/1 13593/13601/1 13596/13604/1 13591/13599/1 +f 14571/14579/1 1976/1984/1 13593/13601/1 13590/13598/1 +f 1976/1984/1 1975/1983/1 13594/13602/1 13593/13601/1 +f 13606/13614/1 13589/13597/1 13592/13600/1 13607/13615/1 +f 2283/2291/1 14572/14580/1 13589/13597/1 13606/13614/1 +f 14572/14580/1 14571/14579/1 13590/13598/1 13589/13597/1 +f 2298/2306/1 13585/13593/1 13588/13596/1 2299/2307/1 +f 13607/13615/1 13592/13600/1 13585/13593/1 2298/2306/1 +f 13592/13600/1 13591/13599/1 13586/13594/1 13585/13593/1 +f 13578/13586/1 13581/13589/1 13584/13592/1 13579/13587/1 +f 13563/13571/1 2312/2320/1 13581/13589/1 13578/13586/1 +f 2312/2320/1 2311/2319/1 13582/13590/1 13581/13589/1 +f 14614/14622/1 13577/13585/1 13580/13588/1 14615/14623/1 +f 2327/2335/1 13564/13572/1 13577/13585/1 14614/14622/1 +f 13564/13572/1 13563/13571/1 13578/13586/1 13577/13585/1 +f 1962/1970/1 13573/13581/1 13576/13584/1 1963/1971/1 +f 14615/14623/1 13580/13588/1 13573/13581/1 1962/1970/1 +f 13580/13588/1 13579/13587/1 13574/13582/1 13573/13581/1 +f 13566/13574/1 13569/13577/1 13572/13580/1 13567/13575/1 +f 6663/6671/1 4612/4620/1 13569/13577/1 13566/13574/1 +f 4612/4620/1 4611/4619/1 13570/13578/1 13569/13577/1 +f 13522/13530/1 13565/13573/1 13568/13576/1 13523/13531/1 +f 1539/1547/1 6664/6672/1 13565/13573/1 13522/13530/1 +f 6664/6672/1 6663/6671/1 13566/13574/1 13565/13573/1 +f 2326/2334/1 13561/13569/1 13564/13572/1 2327/2335/1 +f 13523/13531/1 13568/13576/1 13561/13569/1 2326/2334/1 +f 13568/13576/1 13567/13575/1 13562/13570/1 13561/13569/1 +f 13554/13562/1 13557/13565/1 13560/13568/1 13555/13563/1 +f 16899/16907/1 1200/1208/1 13557/13565/1 13554/13562/1 +f 1200/1208/1 1199/1207/1 13558/13566/1 13557/13565/1 +f 13570/13578/1 13553/13561/1 13556/13564/1 13571/13579/1 +f 4611/4619/1 16900/16908/1 13553/13561/1 13570/13578/1 +f 16900/16908/1 16899/16907/1 13554/13562/1 13553/13561/1 +f 2310/2318/1 13549/13557/1 13552/13560/1 2311/2319/1 +f 13571/13579/1 13556/13564/1 13549/13557/1 2310/2318/1 +f 13556/13564/1 13555/13563/1 13550/13558/1 13549/13557/1 +f 13542/13550/1 13545/13553/1 13548/13556/1 13543/13551/1 +f 13527/13535/1 2324/2332/1 13545/13553/1 13542/13550/1 +f 2324/2332/1 2323/2331/1 13546/13554/1 13545/13553/1 +f 15790/15798/1 13541/13549/1 13544/13552/1 15791/15799/1 +f 3503/3511/1 13528/13536/1 13541/13549/1 15790/15798/1 +f 13528/13536/1 13527/13535/1 13542/13550/1 13541/13549/1 +f 1570/1578/1 13537/13545/1 13540/13548/1 1571/1579/1 +f 15791/15799/1 13544/13552/1 13537/13545/1 1570/1578/1 +f 13544/13552/1 13543/13551/1 13538/13546/1 13537/13545/1 +f 13530/13538/1 13533/13541/1 13536/13544/1 13531/13539/1 +f 9723/9731/1 3592/3600/1 13533/13541/1 13530/13538/1 +f 3592/3600/1 3591/3599/1 13534/13542/1 13533/13541/1 +f 9994/10002/1 13529/13537/1 13532/13540/1 9995/10003/1 +f 1195/1203/1 9724/9732/1 13529/13537/1 9994/10002/1 +f 9724/9732/1 9723/9731/1 13530/13538/1 13529/13537/1 +f 3502/3510/1 13525/13533/1 13528/13536/1 3503/3511/1 +f 9995/10003/1 13532/13540/1 13525/13533/1 3502/3510/1 +f 13532/13540/1 13531/13539/1 13526/13534/1 13525/13533/1 +f 13518/13526/1 13521/13529/1 13524/13532/1 13519/13527/1 +f 15879/15887/1 1540/1548/1 13521/13529/1 13518/13526/1 +f 1540/1548/1 1539/1547/1 13522/13530/1 13521/13529/1 +f 13534/13542/1 13517/13525/1 13520/13528/1 13535/13543/1 +f 3591/3599/1 15880/15888/1 13517/13525/1 13534/13542/1 +f 15880/15888/1 15879/15887/1 13518/13526/1 13517/13525/1 +f 2322/2330/1 13513/13521/1 13516/13524/1 2323/2331/1 +f 13535/13543/1 13520/13528/1 13513/13521/1 2322/2330/1 +f 13520/13528/1 13519/13527/1 13514/13522/1 13513/13521/1 +f 13506/13514/1 13509/13517/1 13512/13520/1 13507/13515/1 +f 13491/13499/1 2336/2344/1 13509/13517/1 13506/13514/1 +f 2336/2344/1 2335/2343/1 13510/13518/1 13509/13517/1 +f 16930/16938/1 13505/13513/1 13508/13516/1 16931/16939/1 +f 4643/4651/1 13492/13500/1 13505/13513/1 16930/16938/1 +f 13492/13500/1 13491/13499/1 13506/13514/1 13505/13513/1 +f 1190/1198/1 13501/13509/1 13504/13512/1 1191/1199/1 +f 16931/16939/1 13508/13516/1 13501/13509/1 1190/1198/1 +f 13508/13516/1 13507/13515/1 13502/13510/1 13501/13509/1 +f 13494/13502/1 13497/13505/1 13500/13508/1 13495/13503/1 +f 13539/13547/1 2320/2328/1 13497/13505/1 13494/13502/1 +f 2320/2328/1 2319/2327/1 13498/13506/1 13497/13505/1 +f 6574/6582/1 13493/13501/1 13496/13504/1 6575/6583/1 +f 1571/1579/1 13540/13548/1 13493/13501/1 6574/6582/1 +f 13540/13548/1 13539/13547/1 13494/13502/1 13493/13501/1 +f 4642/4650/1 13489/13497/1 13492/13500/1 4643/4651/1 +f 6575/6583/1 13496/13504/1 13489/13497/1 4642/4650/1 +f 13496/13504/1 13495/13503/1 13490/13498/1 13489/13497/1 +f 13482/13490/1 13485/13493/1 13488/13496/1 13483/13491/1 +f 14607/14615/1 1964/1972/1 13485/13493/1 13482/13490/1 +f 1964/1972/1 1963/1971/1 13486/13494/1 13485/13493/1 +f 13498/13506/1 13481/13489/1 13484/13492/1 13499/13507/1 +f 2319/2327/1 14608/14616/1 13481/13489/1 13498/13506/1 +f 14608/14616/1 14607/14615/1 13482/13490/1 13481/13489/1 +f 2334/2342/1 13477/13485/1 13480/13488/1 2335/2343/1 +f 13499/13507/1 13484/13492/1 13477/13485/1 2334/2342/1 +f 13484/13492/1 13483/13491/1 13478/13486/1 13477/13485/1 +f 13470/13478/1 13473/13481/1 13476/13484/1 13471/13479/1 +f 13455/13463/1 2348/2356/1 13473/13481/1 13470/13478/1 +f 2348/2356/1 2347/2355/1 13474/13482/1 13473/13481/1 +f 14650/14658/1 13469/13477/1 13472/13480/1 14651/14659/1 +f 2363/2371/1 13456/13464/1 13469/13477/1 14650/14658/1 +f 13456/13464/1 13455/13463/1 13470/13478/1 13469/13477/1 +f 1950/1958/1 13465/13473/1 13468/13476/1 1951/1959/1 +f 14651/14659/1 13472/13480/1 13465/13473/1 1950/1958/1 +f 13472/13480/1 13471/13479/1 13466/13474/1 13465/13473/1 +f 13458/13466/1 13461/13469/1 13464/13472/1 13459/13467/1 +f 6555/6563/1 4648/4656/1 13461/13469/1 13458/13466/1 +f 4648/4656/1 4647/4655/1 13462/13470/1 13461/13469/1 +f 13414/13422/1 13457/13465/1 13460/13468/1 13415/13423/1 +f 1575/1583/1 6556/6564/1 13457/13465/1 13414/13422/1 +f 6556/6564/1 6555/6563/1 13458/13466/1 13457/13465/1 +f 2362/2370/1 13453/13461/1 13456/13464/1 2363/2371/1 +f 13415/13423/1 13460/13468/1 13453/13461/1 2362/2370/1 +f 13460/13468/1 13459/13467/1 13454/13462/1 13453/13461/1 +f 13446/13454/1 13449/13457/1 13452/13460/1 13447/13455/1 +f 16935/16943/1 1188/1196/1 13449/13457/1 13446/13454/1 +f 1188/1196/1 1187/1195/1 13450/13458/1 13449/13457/1 +f 13462/13470/1 13445/13453/1 13448/13456/1 13463/13471/1 +f 4647/4655/1 16936/16944/1 13445/13453/1 13462/13470/1 +f 16936/16944/1 16935/16943/1 13446/13454/1 13445/13453/1 +f 2346/2354/1 13441/13449/1 13444/13452/1 2347/2355/1 +f 13463/13471/1 13448/13456/1 13441/13449/1 2346/2354/1 +f 13448/13456/1 13447/13455/1 13442/13450/1 13441/13449/1 +f 13434/13442/1 13437/13445/1 13440/13448/1 13435/13443/1 +f 13419/13427/1 2360/2368/1 13437/13445/1 13434/13442/1 +f 2360/2368/1 2359/2367/1 13438/13446/1 13437/13445/1 +f 15682/15690/1 13433/13441/1 13436/13444/1 15683/15691/1 +f 3395/3403/1 13420/13428/1 13433/13441/1 15682/15690/1 +f 13420/13428/1 13419/13427/1 13434/13442/1 13433/13441/1 +f 1606/1614/1 13429/13437/1 13432/13440/1 1607/1615/1 +f 15683/15691/1 13436/13444/1 13429/13437/1 1606/1614/1 +f 13436/13444/1 13435/13443/1 13430/13438/1 13429/13437/1 +f 13422/13430/1 13425/13433/1 13428/13436/1 13423/13431/1 +f 10047/10055/1 3484/3492/1 13425/13433/1 13422/13430/1 +f 3484/3492/1 3483/3491/1 13426/13434/1 13425/13433/1 +f 10318/10326/1 13421/13429/1 13424/13432/1 10319/10327/1 +f 1183/1191/1 10048/10056/1 13421/13429/1 10318/10326/1 +f 10048/10056/1 10047/10055/1 13422/13430/1 13421/13429/1 +f 3394/3402/1 13417/13425/1 13420/13428/1 3395/3403/1 +f 10319/10327/1 13424/13432/1 13417/13425/1 3394/3402/1 +f 13424/13432/1 13423/13431/1 13418/13426/1 13417/13425/1 +f 13410/13418/1 13413/13421/1 13416/13424/1 13411/13419/1 +f 15771/15779/1 1576/1584/1 13413/13421/1 13410/13418/1 +f 1576/1584/1 1575/1583/1 13414/13422/1 13413/13421/1 +f 13426/13434/1 13409/13417/1 13412/13420/1 13427/13435/1 +f 3483/3491/1 15772/15780/1 13409/13417/1 13426/13434/1 +f 15772/15780/1 15771/15779/1 13410/13418/1 13409/13417/1 +f 2358/2366/1 13405/13413/1 13408/13416/1 2359/2367/1 +f 13427/13435/1 13412/13420/1 13405/13413/1 2358/2366/1 +f 13412/13420/1 13411/13419/1 13406/13414/1 13405/13413/1 +f 13398/13406/1 13401/13409/1 13404/13412/1 13399/13407/1 +f 13383/13391/1 2372/2380/1 13401/13409/1 13398/13406/1 +f 2372/2380/1 2371/2379/1 13402/13410/1 13401/13409/1 +f 16966/16974/1 13397/13405/1 13400/13408/1 16967/16975/1 +f 4679/4687/1 13384/13392/1 13397/13405/1 16966/16974/1 +f 13384/13392/1 13383/13391/1 13398/13406/1 13397/13405/1 +f 1178/1186/1 13393/13401/1 13396/13404/1 1179/1187/1 +f 16967/16975/1 13400/13408/1 13393/13401/1 1178/1186/1 +f 13400/13408/1 13399/13407/1 13394/13402/1 13393/13401/1 +f 13386/13394/1 13389/13397/1 13392/13400/1 13387/13395/1 +f 13431/13439/1 2356/2364/1 13389/13397/1 13386/13394/1 +f 2356/2364/1 2355/2363/1 13390/13398/1 13389/13397/1 +f 6466/6474/1 13385/13393/1 13388/13396/1 6467/6475/1 +f 1607/1615/1 13432/13440/1 13385/13393/1 6466/6474/1 +f 13432/13440/1 13431/13439/1 13386/13394/1 13385/13393/1 +f 4678/4686/1 13381/13389/1 13384/13392/1 4679/4687/1 +f 6467/6475/1 13388/13396/1 13381/13389/1 4678/4686/1 +f 13388/13396/1 13387/13395/1 13382/13390/1 13381/13389/1 +f 13374/13382/1 13377/13385/1 13380/13388/1 13375/13383/1 +f 14643/14651/1 1952/1960/1 13377/13385/1 13374/13382/1 +f 1952/1960/1 1951/1959/1 13378/13386/1 13377/13385/1 +f 13390/13398/1 13373/13381/1 13376/13384/1 13391/13399/1 +f 2355/2363/1 14644/14652/1 13373/13381/1 13390/13398/1 +f 14644/14652/1 14643/14651/1 13374/13382/1 13373/13381/1 +f 2370/2378/1 13369/13377/1 13372/13380/1 2371/2379/1 +f 13391/13399/1 13376/13384/1 13369/13377/1 2370/2378/1 +f 13376/13384/1 13375/13383/1 13370/13378/1 13369/13377/1 +f 13362/13370/1 13365/13373/1 13368/13376/1 13363/13371/1 +f 13347/13355/1 2384/2392/1 13365/13373/1 13362/13370/1 +f 2384/2392/1 2383/2391/1 13366/13374/1 13365/13373/1 +f 14686/14694/1 13361/13369/1 13364/13372/1 14687/14695/1 +f 2399/2407/1 13348/13356/1 13361/13369/1 14686/14694/1 +f 13348/13356/1 13347/13355/1 13362/13370/1 13361/13369/1 +f 1938/1946/1 13357/13365/1 13360/13368/1 1939/1947/1 +f 14687/14695/1 13364/13372/1 13357/13365/1 1938/1946/1 +f 13364/13372/1 13363/13371/1 13358/13366/1 13357/13365/1 +f 13350/13358/1 13353/13361/1 13356/13364/1 13351/13359/1 +f 6447/6455/1 4684/4692/1 13353/13361/1 13350/13358/1 +f 4684/4692/1 4683/4691/1 13354/13362/1 13353/13361/1 +f 13306/13314/1 13349/13357/1 13352/13360/1 13307/13315/1 +f 1611/1619/1 6448/6456/1 13349/13357/1 13306/13314/1 +f 6448/6456/1 6447/6455/1 13350/13358/1 13349/13357/1 +f 2398/2406/1 13345/13353/1 13348/13356/1 2399/2407/1 +f 13307/13315/1 13352/13360/1 13345/13353/1 2398/2406/1 +f 13352/13360/1 13351/13359/1 13346/13354/1 13345/13353/1 +f 13338/13346/1 13341/13349/1 13344/13352/1 13339/13347/1 +f 16971/16979/1 1176/1184/1 13341/13349/1 13338/13346/1 +f 1176/1184/1 1175/1183/1 13342/13350/1 13341/13349/1 +f 13354/13362/1 13337/13345/1 13340/13348/1 13355/13363/1 +f 4683/4691/1 16972/16980/1 13337/13345/1 13354/13362/1 +f 16972/16980/1 16971/16979/1 13338/13346/1 13337/13345/1 +f 2382/2390/1 13333/13341/1 13336/13344/1 2383/2391/1 +f 13355/13363/1 13340/13348/1 13333/13341/1 2382/2390/1 +f 13340/13348/1 13339/13347/1 13334/13342/1 13333/13341/1 +f 13326/13334/1 13329/13337/1 13332/13340/1 13327/13335/1 +f 13311/13319/1 2396/2404/1 13329/13337/1 13326/13334/1 +f 2396/2404/1 2395/2403/1 13330/13338/1 13329/13337/1 +f 15574/15582/1 13325/13333/1 13328/13336/1 15575/15583/1 +f 3287/3295/1 13312/13320/1 13325/13333/1 15574/15582/1 +f 13312/13320/1 13311/13319/1 13326/13334/1 13325/13333/1 +f 1642/1650/1 13321/13329/1 13324/13332/1 1643/1651/1 +f 15575/15583/1 13328/13336/1 13321/13329/1 1642/1650/1 +f 13328/13336/1 13327/13335/1 13322/13330/1 13321/13329/1 +f 13314/13322/1 13317/13325/1 13320/13328/1 13315/13323/1 +f 10371/10379/1 3376/3384/1 13317/13325/1 13314/13322/1 +f 3376/3384/1 3375/3383/1 13318/13326/1 13317/13325/1 +f 10642/10650/1 13313/13321/1 13316/13324/1 10643/10651/1 +f 1171/1179/1 10372/10380/1 13313/13321/1 10642/10650/1 +f 10372/10380/1 10371/10379/1 13314/13322/1 13313/13321/1 +f 3286/3294/1 13309/13317/1 13312/13320/1 3287/3295/1 +f 10643/10651/1 13316/13324/1 13309/13317/1 3286/3294/1 +f 13316/13324/1 13315/13323/1 13310/13318/1 13309/13317/1 +f 13302/13310/1 13305/13313/1 13308/13316/1 13303/13311/1 +f 15663/15671/1 1612/1620/1 13305/13313/1 13302/13310/1 +f 1612/1620/1 1611/1619/1 13306/13314/1 13305/13313/1 +f 13318/13326/1 13301/13309/1 13304/13312/1 13319/13327/1 +f 3375/3383/1 15664/15672/1 13301/13309/1 13318/13326/1 +f 15664/15672/1 15663/15671/1 13302/13310/1 13301/13309/1 +f 2394/2402/1 13297/13305/1 13300/13308/1 2395/2403/1 +f 13319/13327/1 13304/13312/1 13297/13305/1 2394/2402/1 +f 13304/13312/1 13303/13311/1 13298/13306/1 13297/13305/1 +f 13290/13298/1 13293/13301/1 13296/13304/1 13291/13299/1 +f 13275/13283/1 2408/2416/1 13293/13301/1 13290/13298/1 +f 2408/2416/1 2407/2415/1 13294/13302/1 13293/13301/1 +f 17002/17010/1 13289/13297/1 13292/13300/1 17003/17011/1 +f 4715/4723/1 13276/13284/1 13289/13297/1 17002/17010/1 +f 13276/13284/1 13275/13283/1 13290/13298/1 13289/13297/1 +f 1166/1174/1 13285/13293/1 13288/13296/1 1167/1175/1 +f 17003/17011/1 13292/13300/1 13285/13293/1 1166/1174/1 +f 13292/13300/1 13291/13299/1 13286/13294/1 13285/13293/1 +f 13278/13286/1 13281/13289/1 13284/13292/1 13279/13287/1 +f 13323/13331/1 2392/2400/1 13281/13289/1 13278/13286/1 +f 2392/2400/1 2391/2399/1 13282/13290/1 13281/13289/1 +f 6358/6366/1 13277/13285/1 13280/13288/1 6359/6367/1 +f 1643/1651/1 13324/13332/1 13277/13285/1 6358/6366/1 +f 13324/13332/1 13323/13331/1 13278/13286/1 13277/13285/1 +f 4714/4722/1 13273/13281/1 13276/13284/1 4715/4723/1 +f 6359/6367/1 13280/13288/1 13273/13281/1 4714/4722/1 +f 13280/13288/1 13279/13287/1 13274/13282/1 13273/13281/1 +f 13266/13274/1 13269/13277/1 13272/13280/1 13267/13275/1 +f 14679/14687/1 1940/1948/1 13269/13277/1 13266/13274/1 +f 1940/1948/1 1939/1947/1 13270/13278/1 13269/13277/1 +f 13282/13290/1 13265/13273/1 13268/13276/1 13283/13291/1 +f 2391/2399/1 14680/14688/1 13265/13273/1 13282/13290/1 +f 14680/14688/1 14679/14687/1 13266/13274/1 13265/13273/1 +f 2406/2414/1 13261/13269/1 13264/13272/1 2407/2415/1 +f 13283/13291/1 13268/13276/1 13261/13269/1 2406/2414/1 +f 13268/13276/1 13267/13275/1 13262/13270/1 13261/13269/1 +f 13254/13262/1 13257/13265/1 13260/13268/1 13255/13263/1 +f 13239/13247/1 2420/2428/1 13257/13265/1 13254/13262/1 +f 2420/2428/1 2419/2427/1 13258/13266/1 13257/13265/1 +f 14722/14730/1 13253/13261/1 13256/13264/1 14723/14731/1 +f 2435/2443/1 13240/13248/1 13253/13261/1 14722/14730/1 +f 13240/13248/1 13239/13247/1 13254/13262/1 13253/13261/1 +f 1926/1934/1 13249/13257/1 13252/13260/1 1927/1935/1 +f 14723/14731/1 13256/13264/1 13249/13257/1 1926/1934/1 +f 13256/13264/1 13255/13263/1 13250/13258/1 13249/13257/1 +f 13242/13250/1 13245/13253/1 13248/13256/1 13243/13251/1 +f 6339/6347/1 4720/4728/1 13245/13253/1 13242/13250/1 +f 4720/4728/1 4719/4727/1 13246/13254/1 13245/13253/1 +f 13198/13206/1 13241/13249/1 13244/13252/1 13199/13207/1 +f 1647/1655/1 6340/6348/1 13241/13249/1 13198/13206/1 +f 6340/6348/1 6339/6347/1 13242/13250/1 13241/13249/1 +f 2434/2442/1 13237/13245/1 13240/13248/1 2435/2443/1 +f 13199/13207/1 13244/13252/1 13237/13245/1 2434/2442/1 +f 13244/13252/1 13243/13251/1 13238/13246/1 13237/13245/1 +f 13230/13238/1 13233/13241/1 13236/13244/1 13231/13239/1 +f 17007/17015/1 1164/1172/1 13233/13241/1 13230/13238/1 +f 1164/1172/1 1163/1171/1 13234/13242/1 13233/13241/1 +f 13246/13254/1 13229/13237/1 13232/13240/1 13247/13255/1 +f 4719/4727/1 17008/17016/1 13229/13237/1 13246/13254/1 +f 17008/17016/1 17007/17015/1 13230/13238/1 13229/13237/1 +f 2418/2426/1 13225/13233/1 13228/13236/1 2419/2427/1 +f 13247/13255/1 13232/13240/1 13225/13233/1 2418/2426/1 +f 13232/13240/1 13231/13239/1 13226/13234/1 13225/13233/1 +f 13218/13226/1 13221/13229/1 13224/13232/1 13219/13227/1 +f 13203/13211/1 2432/2440/1 13221/13229/1 13218/13226/1 +f 2432/2440/1 2431/2439/1 13222/13230/1 13221/13229/1 +f 15466/15474/1 13217/13225/1 13220/13228/1 15467/15475/1 +f 3179/3187/1 13204/13212/1 13217/13225/1 15466/15474/1 +f 13204/13212/1 13203/13211/1 13218/13226/1 13217/13225/1 +f 1678/1686/1 13213/13221/1 13216/13224/1 1679/1687/1 +f 15467/15475/1 13220/13228/1 13213/13221/1 1678/1686/1 +f 13220/13228/1 13219/13227/1 13214/13222/1 13213/13221/1 +f 13206/13214/1 13209/13217/1 13212/13220/1 13207/13215/1 +f 10695/10703/1 3268/3276/1 13209/13217/1 13206/13214/1 +f 3268/3276/1 3267/3275/1 13210/13218/1 13209/13217/1 +f 10966/10974/1 13205/13213/1 13208/13216/1 10967/10975/1 +f 1159/1167/1 10696/10704/1 13205/13213/1 10966/10974/1 +f 10696/10704/1 10695/10703/1 13206/13214/1 13205/13213/1 +f 3178/3186/1 13201/13209/1 13204/13212/1 3179/3187/1 +f 10967/10975/1 13208/13216/1 13201/13209/1 3178/3186/1 +f 13208/13216/1 13207/13215/1 13202/13210/1 13201/13209/1 +f 13194/13202/1 13197/13205/1 13200/13208/1 13195/13203/1 +f 15555/15563/1 1648/1656/1 13197/13205/1 13194/13202/1 +f 1648/1656/1 1647/1655/1 13198/13206/1 13197/13205/1 +f 13210/13218/1 13193/13201/1 13196/13204/1 13211/13219/1 +f 3267/3275/1 15556/15564/1 13193/13201/1 13210/13218/1 +f 15556/15564/1 15555/15563/1 13194/13202/1 13193/13201/1 +f 2430/2438/1 13189/13197/1 13192/13200/1 2431/2439/1 +f 13211/13219/1 13196/13204/1 13189/13197/1 2430/2438/1 +f 13196/13204/1 13195/13203/1 13190/13198/1 13189/13197/1 +f 13182/13190/1 13185/13193/1 13188/13196/1 13183/13191/1 +f 13167/13175/1 2444/2452/1 13185/13193/1 13182/13190/1 +f 2444/2452/1 2443/2451/1 13186/13194/1 13185/13193/1 +f 17038/17046/1 13181/13189/1 13184/13192/1 17039/17047/1 +f 4751/4759/1 13168/13176/1 13181/13189/1 17038/17046/1 +f 13168/13176/1 13167/13175/1 13182/13190/1 13181/13189/1 +f 1154/1162/1 13177/13185/1 13180/13188/1 1155/1163/1 +f 17039/17047/1 13184/13192/1 13177/13185/1 1154/1162/1 +f 13184/13192/1 13183/13191/1 13178/13186/1 13177/13185/1 +f 13170/13178/1 13173/13181/1 13176/13184/1 13171/13179/1 +f 13215/13223/1 2428/2436/1 13173/13181/1 13170/13178/1 +f 2428/2436/1 2427/2435/1 13174/13182/1 13173/13181/1 +f 6250/6258/1 13169/13177/1 13172/13180/1 6251/6259/1 +f 1679/1687/1 13216/13224/1 13169/13177/1 6250/6258/1 +f 13216/13224/1 13215/13223/1 13170/13178/1 13169/13177/1 +f 4750/4758/1 13165/13173/1 13168/13176/1 4751/4759/1 +f 6251/6259/1 13172/13180/1 13165/13173/1 4750/4758/1 +f 13172/13180/1 13171/13179/1 13166/13174/1 13165/13173/1 +f 13158/13166/1 13161/13169/1 13164/13172/1 13159/13167/1 +f 14715/14723/1 1928/1936/1 13161/13169/1 13158/13166/1 +f 1928/1936/1 1927/1935/1 13162/13170/1 13161/13169/1 +f 13174/13182/1 13157/13165/1 13160/13168/1 13175/13183/1 +f 2427/2435/1 14716/14724/1 13157/13165/1 13174/13182/1 +f 14716/14724/1 14715/14723/1 13158/13166/1 13157/13165/1 +f 2442/2450/1 13153/13161/1 13156/13164/1 2443/2451/1 +f 13175/13183/1 13160/13168/1 13153/13161/1 2442/2450/1 +f 13160/13168/1 13159/13167/1 13154/13162/1 13153/13161/1 +f 13146/13154/1 13149/13157/1 13152/13160/1 13147/13155/1 +f 13131/13139/1 2456/2464/1 13149/13157/1 13146/13154/1 +f 2456/2464/1 2455/2463/1 13150/13158/1 13149/13157/1 +f 14758/14766/1 13145/13153/1 13148/13156/1 14759/14767/1 +f 2471/2479/1 13132/13140/1 13145/13153/1 14758/14766/1 +f 13132/13140/1 13131/13139/1 13146/13154/1 13145/13153/1 +f 1914/1922/1 13141/13149/1 13144/13152/1 1915/1923/1 +f 14759/14767/1 13148/13156/1 13141/13149/1 1914/1922/1 +f 13148/13156/1 13147/13155/1 13142/13150/1 13141/13149/1 +f 13134/13142/1 13137/13145/1 13140/13148/1 13135/13143/1 +f 6231/6239/1 4756/4764/1 13137/13145/1 13134/13142/1 +f 4756/4764/1 4755/4763/1 13138/13146/1 13137/13145/1 +f 13090/13098/1 13133/13141/1 13136/13144/1 13091/13099/1 +f 1683/1691/1 6232/6240/1 13133/13141/1 13090/13098/1 +f 6232/6240/1 6231/6239/1 13134/13142/1 13133/13141/1 +f 2470/2478/1 13129/13137/1 13132/13140/1 2471/2479/1 +f 13091/13099/1 13136/13144/1 13129/13137/1 2470/2478/1 +f 13136/13144/1 13135/13143/1 13130/13138/1 13129/13137/1 +f 13122/13130/1 13125/13133/1 13128/13136/1 13123/13131/1 +f 17043/17051/1 1152/1160/1 13125/13133/1 13122/13130/1 +f 1152/1160/1 1151/1159/1 13126/13134/1 13125/13133/1 +f 13138/13146/1 13121/13129/1 13124/13132/1 13139/13147/1 +f 4755/4763/1 17044/17052/1 13121/13129/1 13138/13146/1 +f 17044/17052/1 17043/17051/1 13122/13130/1 13121/13129/1 +f 2454/2462/1 13117/13125/1 13120/13128/1 2455/2463/1 +f 13139/13147/1 13124/13132/1 13117/13125/1 2454/2462/1 +f 13124/13132/1 13123/13131/1 13118/13126/1 13117/13125/1 +f 13110/13118/1 13113/13121/1 13116/13124/1 13111/13119/1 +f 13095/13103/1 2468/2476/1 13113/13121/1 13110/13118/1 +f 2468/2476/1 2467/2475/1 13114/13122/1 13113/13121/1 +f 15358/15366/1 13109/13117/1 13112/13120/1 15359/15367/1 +f 3071/3079/1 13096/13104/1 13109/13117/1 15358/15366/1 +f 13096/13104/1 13095/13103/1 13110/13118/1 13109/13117/1 +f 1714/1722/1 13105/13113/1 13108/13116/1 1715/1723/1 +f 15359/15367/1 13112/13120/1 13105/13113/1 1714/1722/1 +f 13112/13120/1 13111/13119/1 13106/13114/1 13105/13113/1 +f 13098/13106/1 13101/13109/1 13104/13112/1 13099/13107/1 +f 11019/11027/1 3160/3168/1 13101/13109/1 13098/13106/1 +f 3160/3168/1 3159/3167/1 13102/13110/1 13101/13109/1 +f 11290/11298/1 13097/13105/1 13100/13108/1 11291/11299/1 +f 1147/1155/1 11020/11028/1 13097/13105/1 11290/11298/1 +f 11020/11028/1 11019/11027/1 13098/13106/1 13097/13105/1 +f 3070/3078/1 13093/13101/1 13096/13104/1 3071/3079/1 +f 11291/11299/1 13100/13108/1 13093/13101/1 3070/3078/1 +f 13100/13108/1 13099/13107/1 13094/13102/1 13093/13101/1 +f 13086/13094/1 13089/13097/1 13092/13100/1 13087/13095/1 +f 15447/15455/1 1684/1692/1 13089/13097/1 13086/13094/1 +f 1684/1692/1 1683/1691/1 13090/13098/1 13089/13097/1 +f 13102/13110/1 13085/13093/1 13088/13096/1 13103/13111/1 +f 3159/3167/1 15448/15456/1 13085/13093/1 13102/13110/1 +f 15448/15456/1 15447/15455/1 13086/13094/1 13085/13093/1 +f 2466/2474/1 13081/13089/1 13084/13092/1 2467/2475/1 +f 13103/13111/1 13088/13096/1 13081/13089/1 2466/2474/1 +f 13088/13096/1 13087/13095/1 13082/13090/1 13081/13089/1 +f 13074/13082/1 13077/13085/1 13080/13088/1 13075/13083/1 +f 13059/13067/1 2480/2488/1 13077/13085/1 13074/13082/1 +f 2480/2488/1 2479/2487/1 13078/13086/1 13077/13085/1 +f 17074/17082/1 13073/13081/1 13076/13084/1 17075/17083/1 +f 4787/4795/1 13060/13068/1 13073/13081/1 17074/17082/1 +f 13060/13068/1 13059/13067/1 13074/13082/1 13073/13081/1 +f 1142/1150/1 13069/13077/1 13072/13080/1 1143/1151/1 +f 17075/17083/1 13076/13084/1 13069/13077/1 1142/1150/1 +f 13076/13084/1 13075/13083/1 13070/13078/1 13069/13077/1 +f 13062/13070/1 13065/13073/1 13068/13076/1 13063/13071/1 +f 13107/13115/1 2464/2472/1 13065/13073/1 13062/13070/1 +f 2464/2472/1 2463/2471/1 13066/13074/1 13065/13073/1 +f 6142/6150/1 13061/13069/1 13064/13072/1 6143/6151/1 +f 1715/1723/1 13108/13116/1 13061/13069/1 6142/6150/1 +f 13108/13116/1 13107/13115/1 13062/13070/1 13061/13069/1 +f 4786/4794/1 13057/13065/1 13060/13068/1 4787/4795/1 +f 6143/6151/1 13064/13072/1 13057/13065/1 4786/4794/1 +f 13064/13072/1 13063/13071/1 13058/13066/1 13057/13065/1 +f 13050/13058/1 13053/13061/1 13056/13064/1 13051/13059/1 +f 14751/14759/1 1916/1924/1 13053/13061/1 13050/13058/1 +f 1916/1924/1 1915/1923/1 13054/13062/1 13053/13061/1 +f 13066/13074/1 13049/13057/1 13052/13060/1 13067/13075/1 +f 2463/2471/1 14752/14760/1 13049/13057/1 13066/13074/1 +f 14752/14760/1 14751/14759/1 13050/13058/1 13049/13057/1 +f 2478/2486/1 13045/13053/1 13048/13056/1 2479/2487/1 +f 13067/13075/1 13052/13060/1 13045/13053/1 2478/2486/1 +f 13052/13060/1 13051/13059/1 13046/13054/1 13045/13053/1 +f 13038/13046/1 13041/13049/1 13044/13052/1 13039/13047/1 +f 13023/13031/1 2492/2500/1 13041/13049/1 13038/13046/1 +f 2492/2500/1 2491/2499/1 13042/13050/1 13041/13049/1 +f 14794/14802/1 13037/13045/1 13040/13048/1 14795/14803/1 +f 2507/2515/1 13024/13032/1 13037/13045/1 14794/14802/1 +f 13024/13032/1 13023/13031/1 13038/13046/1 13037/13045/1 +f 1902/1910/1 13033/13041/1 13036/13044/1 1903/1911/1 +f 14795/14803/1 13040/13048/1 13033/13041/1 1902/1910/1 +f 13040/13048/1 13039/13047/1 13034/13042/1 13033/13041/1 +f 13026/13034/1 13029/13037/1 13032/13040/1 13027/13035/1 +f 6123/6131/1 4792/4800/1 13029/13037/1 13026/13034/1 +f 4792/4800/1 4791/4799/1 13030/13038/1 13029/13037/1 +f 12982/12990/1 13025/13033/1 13028/13036/1 12983/12991/1 +f 1719/1727/1 6124/6132/1 13025/13033/1 12982/12990/1 +f 6124/6132/1 6123/6131/1 13026/13034/1 13025/13033/1 +f 2506/2514/1 13021/13029/1 13024/13032/1 2507/2515/1 +f 12983/12991/1 13028/13036/1 13021/13029/1 2506/2514/1 +f 13028/13036/1 13027/13035/1 13022/13030/1 13021/13029/1 +f 13014/13022/1 13017/13025/1 13020/13028/1 13015/13023/1 +f 17079/17087/1 1140/1148/1 13017/13025/1 13014/13022/1 +f 1140/1148/1 1139/1147/1 13018/13026/1 13017/13025/1 +f 13030/13038/1 13013/13021/1 13016/13024/1 13031/13039/1 +f 4791/4799/1 17080/17088/1 13013/13021/1 13030/13038/1 +f 17080/17088/1 17079/17087/1 13014/13022/1 13013/13021/1 +f 2490/2498/1 13009/13017/1 13012/13020/1 2491/2499/1 +f 13031/13039/1 13016/13024/1 13009/13017/1 2490/2498/1 +f 13016/13024/1 13015/13023/1 13010/13018/1 13009/13017/1 +f 13002/13010/1 13005/13013/1 13008/13016/1 13003/13011/1 +f 12987/12995/1 2504/2512/1 13005/13013/1 13002/13010/1 +f 2504/2512/1 2503/2511/1 13006/13014/1 13005/13013/1 +f 15250/15258/1 13001/13009/1 13004/13012/1 15251/15259/1 +f 2963/2971/1 12988/12996/1 13001/13009/1 15250/15258/1 +f 12988/12996/1 12987/12995/1 13002/13010/1 13001/13009/1 +f 1750/1758/1 12997/13005/1 13000/13008/1 1751/1759/1 +f 15251/15259/1 13004/13012/1 12997/13005/1 1750/1758/1 +f 13004/13012/1 13003/13011/1 12998/13006/1 12997/13005/1 +f 12990/12998/1 12993/13001/1 12996/13004/1 12991/12999/1 +f 11343/11351/1 3052/3060/1 12993/13001/1 12990/12998/1 +f 3052/3060/1 3051/3059/1 12994/13002/1 12993/13001/1 +f 11614/11622/1 12989/12997/1 12992/13000/1 11615/11623/1 +f 1135/1143/1 11344/11352/1 12989/12997/1 11614/11622/1 +f 11344/11352/1 11343/11351/1 12990/12998/1 12989/12997/1 +f 2962/2970/1 12985/12993/1 12988/12996/1 2963/2971/1 +f 11615/11623/1 12992/13000/1 12985/12993/1 2962/2970/1 +f 12992/13000/1 12991/12999/1 12986/12994/1 12985/12993/1 +f 12978/12986/1 12981/12989/1 12984/12992/1 12979/12987/1 +f 15339/15347/1 1720/1728/1 12981/12989/1 12978/12986/1 +f 1720/1728/1 1719/1727/1 12982/12990/1 12981/12989/1 +f 12994/13002/1 12977/12985/1 12980/12988/1 12995/13003/1 +f 3051/3059/1 15340/15348/1 12977/12985/1 12994/13002/1 +f 15340/15348/1 15339/15347/1 12978/12986/1 12977/12985/1 +f 2502/2510/1 12973/12981/1 12976/12984/1 2503/2511/1 +f 12995/13003/1 12980/12988/1 12973/12981/1 2502/2510/1 +f 12980/12988/1 12979/12987/1 12974/12982/1 12973/12981/1 +f 12966/12974/1 12969/12977/1 12972/12980/1 12967/12975/1 +f 12951/12959/1 2516/2524/1 12969/12977/1 12966/12974/1 +f 2516/2524/1 2515/2523/1 12970/12978/1 12969/12977/1 +f 17110/17118/1 12965/12973/1 12968/12976/1 17111/17119/1 +f 4823/4831/1 12952/12960/1 12965/12973/1 17110/17118/1 +f 12952/12960/1 12951/12959/1 12966/12974/1 12965/12973/1 +f 1130/1138/1 12961/12969/1 12964/12972/1 1131/1139/1 +f 17111/17119/1 12968/12976/1 12961/12969/1 1130/1138/1 +f 12968/12976/1 12967/12975/1 12962/12970/1 12961/12969/1 +f 12954/12962/1 12957/12965/1 12960/12968/1 12955/12963/1 +f 12999/13007/1 2500/2508/1 12957/12965/1 12954/12962/1 +f 2500/2508/1 2499/2507/1 12958/12966/1 12957/12965/1 +f 6034/6042/1 12953/12961/1 12956/12964/1 6035/6043/1 +f 1751/1759/1 13000/13008/1 12953/12961/1 6034/6042/1 +f 13000/13008/1 12999/13007/1 12954/12962/1 12953/12961/1 +f 4822/4830/1 12949/12957/1 12952/12960/1 4823/4831/1 +f 6035/6043/1 12956/12964/1 12949/12957/1 4822/4830/1 +f 12956/12964/1 12955/12963/1 12950/12958/1 12949/12957/1 +f 12942/12950/1 12945/12953/1 12948/12956/1 12943/12951/1 +f 14787/14795/1 1904/1912/1 12945/12953/1 12942/12950/1 +f 1904/1912/1 1903/1911/1 12946/12954/1 12945/12953/1 +f 12958/12966/1 12941/12949/1 12944/12952/1 12959/12967/1 +f 2499/2507/1 14788/14796/1 12941/12949/1 12958/12966/1 +f 14788/14796/1 14787/14795/1 12942/12950/1 12941/12949/1 +f 2514/2522/1 12937/12945/1 12940/12948/1 2515/2523/1 +f 12959/12967/1 12944/12952/1 12937/12945/1 2514/2522/1 +f 12944/12952/1 12943/12951/1 12938/12946/1 12937/12945/1 +f 12930/12938/1 12933/12941/1 12936/12944/1 12931/12939/1 +f 12915/12923/1 2528/2536/1 12933/12941/1 12930/12938/1 +f 2528/2536/1 2527/2535/1 12934/12942/1 12933/12941/1 +f 14830/14838/1 12929/12937/1 12932/12940/1 14831/14839/1 +f 2543/2551/1 12916/12924/1 12929/12937/1 14830/14838/1 +f 12916/12924/1 12915/12923/1 12930/12938/1 12929/12937/1 +f 1890/1898/1 12925/12933/1 12928/12936/1 1891/1899/1 +f 14831/14839/1 12932/12940/1 12925/12933/1 1890/1898/1 +f 12932/12940/1 12931/12939/1 12926/12934/1 12925/12933/1 +f 12918/12926/1 12921/12929/1 12924/12932/1 12919/12927/1 +f 6015/6023/1 4828/4836/1 12921/12929/1 12918/12926/1 +f 4828/4836/1 4827/4835/1 12922/12930/1 12921/12929/1 +f 12874/12882/1 12917/12925/1 12920/12928/1 12875/12883/1 +f 1755/1763/1 6016/6024/1 12917/12925/1 12874/12882/1 +f 6016/6024/1 6015/6023/1 12918/12926/1 12917/12925/1 +f 2542/2550/1 12913/12921/1 12916/12924/1 2543/2551/1 +f 12875/12883/1 12920/12928/1 12913/12921/1 2542/2550/1 +f 12920/12928/1 12919/12927/1 12914/12922/1 12913/12921/1 +f 12906/12914/1 12909/12917/1 12912/12920/1 12907/12915/1 +f 17115/17123/1 1128/1136/1 12909/12917/1 12906/12914/1 +f 1128/1136/1 1127/1135/1 12910/12918/1 12909/12917/1 +f 12922/12930/1 12905/12913/1 12908/12916/1 12923/12931/1 +f 4827/4835/1 17116/17124/1 12905/12913/1 12922/12930/1 +f 17116/17124/1 17115/17123/1 12906/12914/1 12905/12913/1 +f 2526/2534/1 12901/12909/1 12904/12912/1 2527/2535/1 +f 12923/12931/1 12908/12916/1 12901/12909/1 2526/2534/1 +f 12908/12916/1 12907/12915/1 12902/12910/1 12901/12909/1 +f 12894/12902/1 12897/12905/1 12900/12908/1 12895/12903/1 +f 12879/12887/1 2540/2548/1 12897/12905/1 12894/12902/1 +f 2540/2548/1 2539/2547/1 12898/12906/1 12897/12905/1 +f 15142/15150/1 12893/12901/1 12896/12904/1 15143/15151/1 +f 2855/2863/1 12880/12888/1 12893/12901/1 15142/15150/1 +f 12880/12888/1 12879/12887/1 12894/12902/1 12893/12901/1 +f 1786/1794/1 12889/12897/1 12892/12900/1 1787/1795/1 +f 15143/15151/1 12896/12904/1 12889/12897/1 1786/1794/1 +f 12896/12904/1 12895/12903/1 12890/12898/1 12889/12897/1 +f 12882/12890/1 12885/12893/1 12888/12896/1 12883/12891/1 +f 11667/11675/1 2944/2952/1 12885/12893/1 12882/12890/1 +f 2944/2952/1 2943/2951/1 12886/12894/1 12885/12893/1 +f 11938/11946/1 12881/12889/1 12884/12892/1 11939/11947/1 +f 1123/1131/1 11668/11676/1 12881/12889/1 11938/11946/1 +f 11668/11676/1 11667/11675/1 12882/12890/1 12881/12889/1 +f 2854/2862/1 12877/12885/1 12880/12888/1 2855/2863/1 +f 11939/11947/1 12884/12892/1 12877/12885/1 2854/2862/1 +f 12884/12892/1 12883/12891/1 12878/12886/1 12877/12885/1 +f 12870/12878/1 12873/12881/1 12876/12884/1 12871/12879/1 +f 15231/15239/1 1756/1764/1 12873/12881/1 12870/12878/1 +f 1756/1764/1 1755/1763/1 12874/12882/1 12873/12881/1 +f 12886/12894/1 12869/12877/1 12872/12880/1 12887/12895/1 +f 2943/2951/1 15232/15240/1 12869/12877/1 12886/12894/1 +f 15232/15240/1 15231/15239/1 12870/12878/1 12869/12877/1 +f 2538/2546/1 12865/12873/1 12868/12876/1 2539/2547/1 +f 12887/12895/1 12872/12880/1 12865/12873/1 2538/2546/1 +f 12872/12880/1 12871/12879/1 12866/12874/1 12865/12873/1 +f 12858/12866/1 12861/12869/1 12864/12872/1 12859/12867/1 +f 12843/12851/1 2552/2560/1 12861/12869/1 12858/12866/1 +f 2552/2560/1 2551/2559/1 12862/12870/1 12861/12869/1 +f 17146/17154/1 12857/12865/1 12860/12868/1 17147/17155/1 +f 4859/4867/1 12844/12852/1 12857/12865/1 17146/17154/1 +f 12844/12852/1 12843/12851/1 12858/12866/1 12857/12865/1 +f 1118/1126/1 12853/12861/1 12856/12864/1 1119/1127/1 +f 17147/17155/1 12860/12868/1 12853/12861/1 1118/1126/1 +f 12860/12868/1 12859/12867/1 12854/12862/1 12853/12861/1 +f 12846/12854/1 12849/12857/1 12852/12860/1 12847/12855/1 +f 12891/12899/1 2536/2544/1 12849/12857/1 12846/12854/1 +f 2536/2544/1 2535/2543/1 12850/12858/1 12849/12857/1 +f 5926/5934/1 12845/12853/1 12848/12856/1 5927/5935/1 +f 1787/1795/1 12892/12900/1 12845/12853/1 5926/5934/1 +f 12892/12900/1 12891/12899/1 12846/12854/1 12845/12853/1 +f 4858/4866/1 12841/12849/1 12844/12852/1 4859/4867/1 +f 5927/5935/1 12848/12856/1 12841/12849/1 4858/4866/1 +f 12848/12856/1 12847/12855/1 12842/12850/1 12841/12849/1 +f 12834/12842/1 12837/12845/1 12840/12848/1 12835/12843/1 +f 14823/14831/1 1892/1900/1 12837/12845/1 12834/12842/1 +f 1892/1900/1 1891/1899/1 12838/12846/1 12837/12845/1 +f 12850/12858/1 12833/12841/1 12836/12844/1 12851/12859/1 +f 2535/2543/1 14824/14832/1 12833/12841/1 12850/12858/1 +f 14824/14832/1 14823/14831/1 12834/12842/1 12833/12841/1 +f 2550/2558/1 12829/12837/1 12832/12840/1 2551/2559/1 +f 12851/12859/1 12836/12844/1 12829/12837/1 2550/2558/1 +f 12836/12844/1 12835/12843/1 12830/12838/1 12829/12837/1 +f 12822/12830/1 12825/12833/1 12828/12836/1 12823/12831/1 +f 12807/12815/1 2564/2572/1 12825/12833/1 12822/12830/1 +f 2564/2572/1 2563/2571/1 12826/12834/1 12825/12833/1 +f 14866/14874/1 12821/12829/1 12824/12832/1 14867/14875/1 +f 2579/2587/1 12808/12816/1 12821/12829/1 14866/14874/1 +f 12808/12816/1 12807/12815/1 12822/12830/1 12821/12829/1 +f 1878/1886/1 12817/12825/1 12820/12828/1 1879/1887/1 +f 14867/14875/1 12824/12832/1 12817/12825/1 1878/1886/1 +f 12824/12832/1 12823/12831/1 12818/12826/1 12817/12825/1 +f 12810/12818/1 12813/12821/1 12816/12824/1 12811/12819/1 +f 5907/5915/1 4864/4872/1 12813/12821/1 12810/12818/1 +f 4864/4872/1 4863/4871/1 12814/12822/1 12813/12821/1 +f 12766/12774/1 12809/12817/1 12812/12820/1 12767/12775/1 +f 1791/1799/1 5908/5916/1 12809/12817/1 12766/12774/1 +f 5908/5916/1 5907/5915/1 12810/12818/1 12809/12817/1 +f 2578/2586/1 12805/12813/1 12808/12816/1 2579/2587/1 +f 12767/12775/1 12812/12820/1 12805/12813/1 2578/2586/1 +f 12812/12820/1 12811/12819/1 12806/12814/1 12805/12813/1 +f 12798/12806/1 12801/12809/1 12804/12812/1 12799/12807/1 +f 17151/17159/1 1116/1124/1 12801/12809/1 12798/12806/1 +f 1116/1124/1 1115/1123/1 12802/12810/1 12801/12809/1 +f 12814/12822/1 12797/12805/1 12800/12808/1 12815/12823/1 +f 4863/4871/1 17152/17160/1 12797/12805/1 12814/12822/1 +f 17152/17160/1 17151/17159/1 12798/12806/1 12797/12805/1 +f 2562/2570/1 12793/12801/1 12796/12804/1 2563/2571/1 +f 12815/12823/1 12800/12808/1 12793/12801/1 2562/2570/1 +f 12800/12808/1 12799/12807/1 12794/12802/1 12793/12801/1 +f 12786/12794/1 12789/12797/1 12792/12800/1 12787/12795/1 +f 12771/12779/1 2576/2584/1 12789/12797/1 12786/12794/1 +f 2576/2584/1 2575/2583/1 12790/12798/1 12789/12797/1 +f 15034/15042/1 12785/12793/1 12788/12796/1 15035/15043/1 +f 2747/2755/1 12772/12780/1 12785/12793/1 15034/15042/1 +f 12772/12780/1 12771/12779/1 12786/12794/1 12785/12793/1 +f 1822/1830/1 12781/12789/1 12784/12792/1 1823/1831/1 +f 15035/15043/1 12788/12796/1 12781/12789/1 1822/1830/1 +f 12788/12796/1 12787/12795/1 12782/12790/1 12781/12789/1 +f 12774/12782/1 12777/12785/1 12780/12788/1 12775/12783/1 +f 11991/11999/1 2836/2844/1 12777/12785/1 12774/12782/1 +f 2836/2844/1 2835/2843/1 12778/12786/1 12777/12785/1 +f 12262/12270/1 12773/12781/1 12776/12784/1 12263/12271/1 +f 1111/1119/1 11992/12000/1 12773/12781/1 12262/12270/1 +f 11992/12000/1 11991/11999/1 12774/12782/1 12773/12781/1 +f 2746/2754/1 12769/12777/1 12772/12780/1 2747/2755/1 +f 12263/12271/1 12776/12784/1 12769/12777/1 2746/2754/1 +f 12776/12784/1 12775/12783/1 12770/12778/1 12769/12777/1 +f 12762/12770/1 12765/12773/1 12768/12776/1 12763/12771/1 +f 15123/15131/1 1792/1800/1 12765/12773/1 12762/12770/1 +f 1792/1800/1 1791/1799/1 12766/12774/1 12765/12773/1 +f 12778/12786/1 12761/12769/1 12764/12772/1 12779/12787/1 +f 2835/2843/1 15124/15132/1 12761/12769/1 12778/12786/1 +f 15124/15132/1 15123/15131/1 12762/12770/1 12761/12769/1 +f 2574/2582/1 12757/12765/1 12760/12768/1 2575/2583/1 +f 12779/12787/1 12764/12772/1 12757/12765/1 2574/2582/1 +f 12764/12772/1 12763/12771/1 12758/12766/1 12757/12765/1 +f 12750/12758/1 12753/12761/1 12756/12764/1 12751/12759/1 +f 12735/12743/1 2588/2596/1 12753/12761/1 12750/12758/1 +f 2588/2596/1 2587/2595/1 12754/12762/1 12753/12761/1 +f 17182/17190/1 12749/12757/1 12752/12760/1 17183/17191/1 +f 4895/4903/1 12736/12744/1 12749/12757/1 17182/17190/1 +f 12736/12744/1 12735/12743/1 12750/12758/1 12749/12757/1 +f 1106/1114/1 12745/12753/1 12748/12756/1 1107/1115/1 +f 17183/17191/1 12752/12760/1 12745/12753/1 1106/1114/1 +f 12752/12760/1 12751/12759/1 12746/12754/1 12745/12753/1 +f 12738/12746/1 12741/12749/1 12744/12752/1 12739/12747/1 +f 12783/12791/1 2572/2580/1 12741/12749/1 12738/12746/1 +f 2572/2580/1 2571/2579/1 12742/12750/1 12741/12749/1 +f 5818/5826/1 12737/12745/1 12740/12748/1 5819/5827/1 +f 1823/1831/1 12784/12792/1 12737/12745/1 5818/5826/1 +f 12784/12792/1 12783/12791/1 12738/12746/1 12737/12745/1 +f 4894/4902/1 12733/12741/1 12736/12744/1 4895/4903/1 +f 5819/5827/1 12740/12748/1 12733/12741/1 4894/4902/1 +f 12740/12748/1 12739/12747/1 12734/12742/1 12733/12741/1 +f 12726/12734/1 12729/12737/1 12732/12740/1 12727/12735/1 +f 14859/14867/1 1880/1888/1 12729/12737/1 12726/12734/1 +f 1880/1888/1 1879/1887/1 12730/12738/1 12729/12737/1 +f 12742/12750/1 12725/12733/1 12728/12736/1 12743/12751/1 +f 2571/2579/1 14860/14868/1 12725/12733/1 12742/12750/1 +f 14860/14868/1 14859/14867/1 12726/12734/1 12725/12733/1 +f 2586/2594/1 12721/12729/1 12724/12732/1 2587/2595/1 +f 12743/12751/1 12728/12736/1 12721/12729/1 2586/2594/1 +f 12728/12736/1 12727/12735/1 12722/12730/1 12721/12729/1 +f 12714/12722/1 12717/12725/1 12720/12728/1 12715/12723/1 +f 12699/12707/1 2600/2608/1 12717/12725/1 12714/12722/1 +f 2600/2608/1 2599/2607/1 12718/12726/1 12717/12725/1 +f 14902/14910/1 12713/12721/1 12716/12724/1 14903/14911/1 +f 2615/2623/1 12700/12708/1 12713/12721/1 14902/14910/1 +f 12700/12708/1 12699/12707/1 12714/12722/1 12713/12721/1 +f 1866/1874/1 12709/12717/1 12712/12720/1 1867/1875/1 +f 14903/14911/1 12716/12724/1 12709/12717/1 1866/1874/1 +f 12716/12724/1 12715/12723/1 12710/12718/1 12709/12717/1 +f 12702/12710/1 12705/12713/1 12708/12716/1 12703/12711/1 +f 5799/5807/1 4900/4908/1 12705/12713/1 12702/12710/1 +f 4900/4908/1 4899/4907/1 12706/12714/1 12705/12713/1 +f 12658/12666/1 12701/12709/1 12704/12712/1 12659/12667/1 +f 1827/1835/1 5800/5808/1 12701/12709/1 12658/12666/1 +f 5800/5808/1 5799/5807/1 12702/12710/1 12701/12709/1 +f 2614/2622/1 12697/12705/1 12700/12708/1 2615/2623/1 +f 12659/12667/1 12704/12712/1 12697/12705/1 2614/2622/1 +f 12704/12712/1 12703/12711/1 12698/12706/1 12697/12705/1 +f 12690/12698/1 12693/12701/1 12696/12704/1 12691/12699/1 +f 17187/17195/1 1104/1112/1 12693/12701/1 12690/12698/1 +f 1104/1112/1 1103/1111/1 12694/12702/1 12693/12701/1 +f 12706/12714/1 12689/12697/1 12692/12700/1 12707/12715/1 +f 4899/4907/1 17188/17196/1 12689/12697/1 12706/12714/1 +f 17188/17196/1 17187/17195/1 12690/12698/1 12689/12697/1 +f 2598/2606/1 12685/12693/1 12688/12696/1 2599/2607/1 +f 12707/12715/1 12692/12700/1 12685/12693/1 2598/2606/1 +f 12692/12700/1 12691/12699/1 12686/12694/1 12685/12693/1 +f 12678/12686/1 12681/12689/1 12684/12692/1 12679/12687/1 +f 12663/12671/1 2612/2620/1 12681/12689/1 12678/12686/1 +f 2612/2620/1 2611/2619/1 12682/12690/1 12681/12689/1 +f 14926/14934/1 12677/12685/1 12680/12688/1 14927/14935/1 +f 2639/2647/1 12664/12672/1 12677/12685/1 14926/14934/1 +f 12664/12672/1 12663/12671/1 12678/12686/1 12677/12685/1 +f 1858/1866/1 12673/12681/1 12676/12684/1 1859/1867/1 +f 14927/14935/1 12680/12688/1 12673/12681/1 1858/1866/1 +f 12680/12688/1 12679/12687/1 12674/12682/1 12673/12681/1 +f 12666/12674/1 12669/12677/1 12672/12680/1 12667/12675/1 +f 12315/12323/1 2728/2736/1 12669/12677/1 12666/12674/1 +f 2728/2736/1 2727/2735/1 12670/12678/1 12669/12677/1 +f 12586/12594/1 12665/12673/1 12668/12676/1 12587/12595/1 +f 1099/1107/1 12316/12324/1 12665/12673/1 12586/12594/1 +f 12316/12324/1 12315/12323/1 12666/12674/1 12665/12673/1 +f 2638/2646/1 12661/12669/1 12664/12672/1 2639/2647/1 +f 12587/12595/1 12668/12676/1 12661/12669/1 2638/2646/1 +f 12668/12676/1 12667/12675/1 12662/12670/1 12661/12669/1 +f 12654/12662/1 12657/12665/1 12660/12668/1 12655/12663/1 +f 15015/15023/1 1828/1836/1 12657/12665/1 12654/12662/1 +f 1828/1836/1 1827/1835/1 12658/12666/1 12657/12665/1 +f 12670/12678/1 12653/12661/1 12656/12664/1 12671/12679/1 +f 2727/2735/1 15016/15024/1 12653/12661/1 12670/12678/1 +f 15016/15024/1 15015/15023/1 12654/12662/1 12653/12661/1 +f 2610/2618/1 12649/12657/1 12652/12660/1 2611/2619/1 +f 12671/12679/1 12656/12664/1 12649/12657/1 2610/2618/1 +f 12656/12664/1 12655/12663/1 12650/12658/1 12649/12657/1 +f 12642/12650/1 12645/12653/1 12648/12656/1 12643/12651/1 +f 12627/12635/1 2624/2632/1 12645/12653/1 12642/12650/1 +f 2624/2632/1 2623/2631/1 12646/12654/1 12645/12653/1 +f 17218/17226/1 12641/12649/1 12644/12652/1 17219/17227/1 +f 4931/4939/1 12628/12636/1 12641/12649/1 17218/17226/1 +f 12628/12636/1 12627/12635/1 12642/12650/1 12641/12649/1 +f 1094/1102/1 12637/12645/1 12640/12648/1 1095/1103/1 +f 17219/17227/1 12644/12652/1 12637/12645/1 1094/1102/1 +f 12644/12652/1 12643/12651/1 12638/12646/1 12637/12645/1 +f 12630/12638/1 12633/12641/1 12636/12644/1 12631/12639/1 +f 12675/12683/1 2608/2616/1 12633/12641/1 12630/12638/1 +f 2608/2616/1 2607/2615/1 12634/12642/1 12633/12641/1 +f 5710/5718/1 12629/12637/1 12632/12640/1 5711/5719/1 +f 1859/1867/1 12676/12684/1 12629/12637/1 5710/5718/1 +f 12676/12684/1 12675/12683/1 12630/12638/1 12629/12637/1 +f 4930/4938/1 12625/12633/1 12628/12636/1 4931/4939/1 +f 5711/5719/1 12632/12640/1 12625/12633/1 4930/4938/1 +f 12632/12640/1 12631/12639/1 12626/12634/1 12625/12633/1 +f 12618/12626/1 12621/12629/1 12624/12632/1 12619/12627/1 +f 14895/14903/1 1868/1876/1 12621/12629/1 12618/12626/1 +f 1868/1876/1 1867/1875/1 12622/12630/1 12621/12629/1 +f 12634/12642/1 12617/12625/1 12620/12628/1 12635/12643/1 +f 2607/2615/1 14896/14904/1 12617/12625/1 12634/12642/1 +f 14896/14904/1 14895/14903/1 12618/12626/1 12617/12625/1 +f 2622/2630/1 12613/12621/1 12616/12624/1 2623/2631/1 +f 12635/12643/1 12620/12628/1 12613/12621/1 2622/2630/1 +f 12620/12628/1 12619/12627/1 12614/12622/1 12613/12621/1 +f 12606/12614/1 12609/12617/1 12612/12620/1 12607/12615/1 +f 12591/12599/1 2636/2644/1 12609/12617/1 12606/12614/1 +f 2636/2644/1 2635/2643/1 12610/12618/1 12609/12617/1 +f 14938/14946/1 12605/12613/1 12608/12616/1 14939/14947/1 +f 2651/2659/1 12592/12600/1 12605/12613/1 14938/14946/1 +f 12592/12600/1 12591/12599/1 12606/12614/1 12605/12613/1 +f 1854/1862/1 12601/12609/1 12604/12612/1 1855/1863/1 +f 14939/14947/1 12608/12616/1 12601/12609/1 1854/1862/1 +f 12608/12616/1 12607/12615/1 12602/12610/1 12601/12609/1 +f 12594/12602/1 12597/12605/1 12600/12608/1 12595/12603/1 +f 5763/5771/1 4912/4920/1 12597/12605/1 12594/12602/1 +f 4912/4920/1 4911/4919/1 12598/12606/1 12597/12605/1 +f 12550/12558/1 12593/12601/1 12596/12604/1 12551/12559/1 +f 1839/1847/1 5764/5772/1 12593/12601/1 12550/12558/1 +f 5764/5772/1 5763/5771/1 12594/12602/1 12593/12601/1 +f 2650/2658/1 12589/12597/1 12592/12600/1 2651/2659/1 +f 12551/12559/1 12596/12604/1 12589/12597/1 2650/2658/1 +f 12596/12604/1 12595/12603/1 12590/12598/1 12589/12597/1 +f 12582/12590/1 12585/12593/1 12588/12596/1 12583/12591/1 +f 17199/17207/1 1100/1108/1 12585/12593/1 12582/12590/1 +f 1100/1108/1 1099/1107/1 12586/12594/1 12585/12593/1 +f 12598/12606/1 12581/12589/1 12584/12592/1 12599/12607/1 +f 4911/4919/1 17200/17208/1 12581/12589/1 12598/12606/1 +f 17200/17208/1 17199/17207/1 12582/12590/1 12581/12589/1 +f 2634/2642/1 12577/12585/1 12580/12588/1 2635/2643/1 +f 12599/12607/1 12584/12592/1 12577/12585/1 2634/2642/1 +f 12584/12592/1 12583/12591/1 12578/12586/1 12577/12585/1 +f 12570/12578/1 12573/12581/1 12576/12584/1 12571/12579/1 +f 12555/12563/1 2648/2656/1 12573/12581/1 12570/12578/1 +f 2648/2656/1 2647/2655/1 12574/12582/1 12573/12581/1 +f 14854/14862/1 12569/12577/1 12572/12580/1 14855/14863/1 +f 2567/2575/1 12556/12564/1 12569/12577/1 14854/14862/1 +f 12556/12564/1 12555/12563/1 12570/12578/1 12569/12577/1 +f 1882/1890/1 12565/12573/1 12568/12576/1 1883/1891/1 +f 14855/14863/1 12572/12580/1 12565/12573/1 1882/1890/1 +f 12572/12580/1 12571/12579/1 12566/12574/1 12565/12573/1 +f 12558/12566/1 12561/12569/1 12564/12572/1 12559/12567/1 +f 12423/12431/1 2692/2700/1 12561/12569/1 12558/12566/1 +f 2692/2700/1 2691/2699/1 12562/12570/1 12561/12569/1 +f 12802/12810/1 12557/12565/1 12560/12568/1 12803/12811/1 +f 1115/1123/1 12424/12432/1 12557/12565/1 12802/12810/1 +f 12424/12432/1 12423/12431/1 12558/12566/1 12557/12565/1 +f 2566/2574/1 12553/12561/1 12556/12564/1 2567/2575/1 +f 12803/12811/1 12560/12568/1 12553/12561/1 2566/2574/1 +f 12560/12568/1 12559/12567/1 12554/12562/1 12553/12561/1 +f 12546/12554/1 12549/12557/1 12552/12560/1 12547/12555/1 +f 14979/14987/1 1840/1848/1 12549/12557/1 12546/12554/1 +f 1840/1848/1 1839/1847/1 12550/12558/1 12549/12557/1 +f 12562/12570/1 12545/12553/1 12548/12556/1 12563/12571/1 +f 2691/2699/1 14980/14988/1 12545/12553/1 12562/12570/1 +f 14980/14988/1 14979/14987/1 12546/12554/1 12545/12553/1 +f 2646/2654/1 12541/12549/1 12544/12552/1 2647/2655/1 +f 12563/12571/1 12548/12556/1 12541/12549/1 2646/2654/1 +f 12548/12556/1 12547/12555/1 12542/12550/1 12541/12549/1 +f 12534/12542/1 12537/12545/1 12540/12548/1 12535/12543/1 +f 12519/12527/1 2660/2668/1 12537/12545/1 12534/12542/1 +f 2660/2668/1 2659/2667/1 12538/12546/1 12537/12545/1 +f 17242/17250/1 12533/12541/1 12536/12544/1 17243/17251/1 +f 4955/4963/1 12520/12528/1 12533/12541/1 17242/17250/1 +f 12520/12528/1 12519/12527/1 12534/12542/1 12533/12541/1 +f 1086/1094/1 12529/12537/1 12532/12540/1 1087/1095/1 +f 17243/17251/1 12536/12544/1 12529/12537/1 1086/1094/1 +f 12536/12544/1 12535/12543/1 12530/12538/1 12529/12537/1 +f 12522/12530/1 12525/12533/1 12528/12536/1 12523/12531/1 +f 12567/12575/1 2644/2652/1 12525/12533/1 12522/12530/1 +f 2644/2652/1 2643/2651/1 12526/12534/1 12525/12533/1 +f 5638/5646/1 12521/12529/1 12524/12532/1 5639/5647/1 +f 1883/1891/1 12568/12576/1 12521/12529/1 5638/5646/1 +f 12568/12576/1 12567/12575/1 12522/12530/1 12521/12529/1 +f 4954/4962/1 12517/12525/1 12520/12528/1 4955/4963/1 +f 5639/5647/1 12524/12532/1 12517/12525/1 4954/4962/1 +f 12524/12532/1 12523/12531/1 12518/12526/1 12517/12525/1 +f 12510/12518/1 12513/12521/1 12516/12524/1 12511/12519/1 +f 14931/14939/1 1856/1864/1 12513/12521/1 12510/12518/1 +f 1856/1864/1 1855/1863/1 12514/12522/1 12513/12521/1 +f 12526/12534/1 12509/12517/1 12512/12520/1 12527/12535/1 +f 2643/2651/1 14932/14940/1 12509/12517/1 12526/12534/1 +f 14932/14940/1 14931/14939/1 12510/12518/1 12509/12517/1 +f 2658/2666/1 12505/12513/1 12508/12516/1 2659/2667/1 +f 12527/12535/1 12512/12520/1 12505/12513/1 2658/2666/1 +f 12512/12520/1 12511/12519/1 12506/12514/1 12505/12513/1 +f 12498/12506/1 12501/12509/1 12504/12512/1 12499/12507/1 +f 12483/12491/1 2672/2680/1 12501/12509/1 12498/12506/1 +f 2672/2680/1 2671/2679/1 12502/12510/1 12501/12509/1 +f 14974/14982/1 12497/12505/1 12500/12508/1 14975/14983/1 +f 2687/2695/1 12484/12492/1 12497/12505/1 14974/14982/1 +f 12484/12492/1 12483/12491/1 12498/12506/1 12497/12505/1 +f 1842/1850/1 12493/12501/1 12496/12504/1 1843/1851/1 +f 14975/14983/1 12500/12508/1 12493/12501/1 1842/1850/1 +f 12500/12508/1 12499/12507/1 12494/12502/1 12493/12501/1 +f 12486/12494/1 12489/12497/1 12492/12500/1 12487/12495/1 +f 7023/7031/1 4492/4500/1 12489/12497/1 12486/12494/1 +f 4492/4500/1 4491/4499/1 12490/12498/1 12489/12497/1 +f 12442/12450/1 12485/12493/1 12488/12496/1 12443/12451/1 +f 1419/1427/1 7024/7032/1 12485/12493/1 12442/12450/1 +f 7024/7032/1 7023/7031/1 12486/12494/1 12485/12493/1 +f 2686/2694/1 12481/12489/1 12484/12492/1 2687/2695/1 +f 12443/12451/1 12488/12496/1 12481/12489/1 2686/2694/1 +f 12488/12496/1 12487/12495/1 12482/12490/1 12481/12489/1 +f 12474/12482/1 12477/12485/1 12480/12488/1 12475/12483/1 +f 16779/16787/1 1240/1248/1 12477/12485/1 12474/12482/1 +f 1240/1248/1 1239/1247/1 12478/12486/1 12477/12485/1 +f 12490/12498/1 12473/12481/1 12476/12484/1 12491/12499/1 +f 4491/4499/1 16780/16788/1 12473/12481/1 12490/12498/1 +f 16780/16788/1 16779/16787/1 12474/12482/1 12473/12481/1 +f 2670/2678/1 12469/12477/1 12472/12480/1 2671/2679/1 +f 12491/12499/1 12476/12484/1 12469/12477/1 2670/2678/1 +f 12476/12484/1 12475/12483/1 12470/12478/1 12469/12477/1 +f 12462/12470/1 12465/12473/1 12468/12476/1 12463/12471/1 +f 12447/12455/1 2684/2692/1 12465/12473/1 12462/12470/1 +f 2684/2692/1 2683/2691/1 12466/12474/1 12465/12473/1 +f 15106/15114/1 12461/12469/1 12464/12472/1 15107/15115/1 +f 2819/2827/1 12448/12456/1 12461/12469/1 15106/15114/1 +f 12448/12456/1 12447/12455/1 12462/12470/1 12461/12469/1 +f 1798/1806/1 12457/12465/1 12460/12468/1 1799/1807/1 +f 15107/15115/1 12464/12472/1 12457/12465/1 1798/1806/1 +f 12464/12472/1 12463/12471/1 12458/12466/1 12457/12465/1 +f 12450/12458/1 12453/12461/1 12456/12464/1 12451/12459/1 +f 8643/8651/1 3952/3960/1 12453/12461/1 12450/12458/1 +f 3952/3960/1 3951/3959/1 12454/12462/1 12453/12461/1 +f 12046/12054/1 12449/12457/1 12452/12460/1 12047/12055/1 +f 1047/1055/1 8644/8652/1 12449/12457/1 12046/12054/1 +f 8644/8652/1 8643/8651/1 12450/12458/1 12449/12457/1 +f 2818/2826/1 12445/12453/1 12448/12456/1 2819/2827/1 +f 12047/12055/1 12452/12460/1 12445/12453/1 2818/2826/1 +f 12452/12460/1 12451/12459/1 12446/12454/1 12445/12453/1 +f 12438/12446/1 12441/12449/1 12444/12452/1 12439/12447/1 +f 16239/16247/1 1420/1428/1 12441/12449/1 12438/12446/1 +f 1420/1428/1 1419/1427/1 12442/12450/1 12441/12449/1 +f 12454/12462/1 12437/12445/1 12440/12448/1 12455/12463/1 +f 3951/3959/1 16240/16248/1 12437/12445/1 12454/12462/1 +f 16240/16248/1 16239/16247/1 12438/12446/1 12437/12445/1 +f 2682/2690/1 12433/12441/1 12436/12444/1 2683/2691/1 +f 12455/12463/1 12440/12448/1 12433/12441/1 2682/2690/1 +f 12440/12448/1 12439/12447/1 12434/12442/1 12433/12441/1 +f 12426/12434/1 12429/12437/1 12432/12440/1 12427/12435/1 +f 12411/12419/1 2696/2704/1 12429/12437/1 12426/12434/1 +f 2696/2704/1 2695/2703/1 12430/12438/1 12429/12437/1 +f 17158/17166/1 12425/12433/1 12428/12436/1 17159/17167/1 +f 4871/4879/1 12412/12420/1 12425/12433/1 17158/17166/1 +f 12412/12420/1 12411/12419/1 12426/12434/1 12425/12433/1 +f 1114/1122/1 12421/12429/1 12424/12432/1 1115/1123/1 +f 17159/17167/1 12428/12436/1 12421/12429/1 1114/1122/1 +f 12428/12436/1 12427/12435/1 12422/12430/1 12421/12429/1 +f 12414/12422/1 12417/12425/1 12420/12428/1 12415/12423/1 +f 12459/12467/1 2680/2688/1 12417/12425/1 12414/12422/1 +f 2680/2688/1 2679/2687/1 12418/12426/1 12417/12425/1 +f 5890/5898/1 12413/12421/1 12416/12424/1 5891/5899/1 +f 1799/1807/1 12460/12468/1 12413/12421/1 5890/5898/1 +f 12460/12468/1 12459/12467/1 12414/12422/1 12413/12421/1 +f 4870/4878/1 12409/12417/1 12412/12420/1 4871/4879/1 +f 5891/5899/1 12416/12424/1 12409/12417/1 4870/4878/1 +f 12416/12424/1 12415/12423/1 12410/12418/1 12409/12417/1 +f 12402/12410/1 12405/12413/1 12408/12416/1 12403/12411/1 +f 14967/14975/1 1844/1852/1 12405/12413/1 12402/12410/1 +f 1844/1852/1 1843/1851/1 12406/12414/1 12405/12413/1 +f 12418/12426/1 12401/12409/1 12404/12412/1 12419/12427/1 +f 2679/2687/1 14968/14976/1 12401/12409/1 12418/12426/1 +f 14968/14976/1 14967/14975/1 12402/12410/1 12401/12409/1 +f 2694/2702/1 12397/12405/1 12400/12408/1 2695/2703/1 +f 12419/12427/1 12404/12412/1 12397/12405/1 2694/2702/1 +f 12404/12412/1 12403/12411/1 12398/12406/1 12397/12405/1 +f 12390/12398/1 12393/12401/1 12396/12404/1 12391/12399/1 +f 12375/12383/1 2708/2716/1 12393/12401/1 12390/12398/1 +f 2708/2716/1 2707/2715/1 12394/12402/1 12393/12401/1 +f 15010/15018/1 12389/12397/1 12392/12400/1 15011/15019/1 +f 2723/2731/1 12376/12384/1 12389/12397/1 15010/15018/1 +f 12376/12384/1 12375/12383/1 12390/12398/1 12389/12397/1 +f 1830/1838/1 12385/12393/1 12388/12396/1 1831/1839/1 +f 15011/15019/1 12392/12400/1 12385/12393/1 1830/1838/1 +f 12392/12400/1 12391/12399/1 12386/12394/1 12385/12393/1 +f 12378/12386/1 12381/12389/1 12384/12392/1 12379/12387/1 +f 5259/5267/1 5080/5088/1 12381/12389/1 12378/12386/1 +f 5080/5088/1 5079/5087/1 12382/12390/1 12381/12389/1 +f 12334/12342/1 12377/12385/1 12380/12388/1 12335/12343/1 +f 2007/2015/1 5260/5268/1 12377/12385/1 12334/12342/1 +f 5260/5268/1 5259/5267/1 12378/12386/1 12377/12385/1 +f 2722/2730/1 12373/12381/1 12376/12384/1 2723/2731/1 +f 12335/12343/1 12380/12388/1 12373/12381/1 2722/2730/1 +f 12380/12388/1 12379/12387/1 12374/12382/1 12373/12381/1 +f 12366/12374/1 12369/12377/1 12372/12380/1 12367/12375/1 +f 17367/17375/1 1044/1052/1 12369/12377/1 12366/12374/1 +f 1044/1052/1 1043/1051/1 12370/12378/1 12369/12377/1 +f 12382/12390/1 12365/12373/1 12368/12376/1 12383/12391/1 +f 5079/5087/1 17368/17376/1 12365/12373/1 12382/12390/1 +f 17368/17376/1 17367/17375/1 12366/12374/1 12365/12373/1 +f 2706/2714/1 12361/12369/1 12364/12372/1 2707/2715/1 +f 12383/12391/1 12368/12376/1 12361/12369/1 2706/2714/1 +f 12368/12376/1 12367/12375/1 12362/12370/1 12361/12369/1 +f 12354/12362/1 12357/12365/1 12360/12368/1 12355/12363/1 +f 12339/12347/1 2720/2728/1 12357/12365/1 12354/12362/1 +f 2720/2728/1 2719/2727/1 12358/12366/1 12357/12365/1 +f 14962/14970/1 12353/12361/1 12356/12364/1 14963/14971/1 +f 2675/2683/1 12340/12348/1 12353/12361/1 14962/14970/1 +f 12340/12348/1 12339/12347/1 12354/12362/1 12353/12361/1 +f 1846/1854/1 12349/12357/1 12352/12360/1 1847/1855/1 +f 14963/14971/1 12356/12364/1 12349/12357/1 1846/1854/1 +f 12356/12364/1 12355/12363/1 12350/12358/1 12349/12357/1 +f 12342/12350/1 12345/12353/1 12348/12356/1 12343/12351/1 +f 13935/13943/1 2188/2196/1 12345/12353/1 12342/12350/1 +f 2188/2196/1 2187/2195/1 12346/12354/1 12345/12353/1 +f 12478/12486/1 12341/12349/1 12344/12352/1 12479/12487/1 +f 1239/1247/1 13936/13944/1 12341/12349/1 12478/12486/1 +f 13936/13944/1 13935/13943/1 12342/12350/1 12341/12349/1 +f 2674/2682/1 12337/12345/1 12340/12348/1 2675/2683/1 +f 12479/12487/1 12344/12352/1 12337/12345/1 2674/2682/1 +f 12344/12352/1 12343/12351/1 12338/12346/1 12337/12345/1 +f 12330/12338/1 12333/12341/1 12336/12344/1 12331/12339/1 +f 14475/14483/1 2008/2016/1 12333/12341/1 12330/12338/1 +f 2008/2016/1 2007/2015/1 12334/12342/1 12333/12341/1 +f 12346/12354/1 12329/12337/1 12332/12340/1 12347/12355/1 +f 2187/2195/1 14476/14484/1 12329/12337/1 12346/12354/1 +f 14476/14484/1 14475/14483/1 12330/12338/1 12329/12337/1 +f 2718/2726/1 12325/12333/1 12328/12336/1 2719/2727/1 +f 12347/12355/1 12332/12340/1 12325/12333/1 2718/2726/1 +f 12332/12340/1 12331/12339/1 12326/12334/1 12325/12333/1 +f 12318/12326/1 12321/12329/1 12324/12332/1 12319/12327/1 +f 12303/12311/1 2732/2740/1 12321/12329/1 12318/12326/1 +f 2732/2740/1 2731/2739/1 12322/12330/1 12321/12329/1 +f 17206/17214/1 12317/12325/1 12320/12328/1 17207/17215/1 +f 4919/4927/1 12304/12312/1 12317/12325/1 17206/17214/1 +f 12304/12312/1 12303/12311/1 12318/12326/1 12317/12325/1 +f 1098/1106/1 12313/12321/1 12316/12324/1 1099/1107/1 +f 17207/17215/1 12320/12328/1 12313/12321/1 1098/1106/1 +f 12320/12328/1 12319/12327/1 12314/12322/1 12313/12321/1 +f 12306/12314/1 12309/12317/1 12312/12320/1 12307/12315/1 +f 12351/12359/1 2716/2724/1 12309/12317/1 12306/12314/1 +f 2716/2724/1 2715/2723/1 12310/12318/1 12309/12317/1 +f 5746/5754/1 12305/12313/1 12308/12316/1 5747/5755/1 +f 1847/1855/1 12352/12360/1 12305/12313/1 5746/5754/1 +f 12352/12360/1 12351/12359/1 12306/12314/1 12305/12313/1 +f 4918/4926/1 12301/12309/1 12304/12312/1 4919/4927/1 +f 5747/5755/1 12308/12316/1 12301/12309/1 4918/4926/1 +f 12308/12316/1 12307/12315/1 12302/12310/1 12301/12309/1 +f 12294/12302/1 12297/12305/1 12300/12308/1 12295/12303/1 +f 15003/15011/1 1832/1840/1 12297/12305/1 12294/12302/1 +f 1832/1840/1 1831/1839/1 12298/12306/1 12297/12305/1 +f 12310/12318/1 12293/12301/1 12296/12304/1 12311/12319/1 +f 2715/2723/1 15004/15012/1 12293/12301/1 12310/12318/1 +f 15004/15012/1 15003/15011/1 12294/12302/1 12293/12301/1 +f 2730/2738/1 12289/12297/1 12292/12300/1 2731/2739/1 +f 12311/12319/1 12296/12304/1 12289/12297/1 2730/2738/1 +f 12296/12304/1 12295/12303/1 12290/12298/1 12289/12297/1 +f 12282/12290/1 12285/12293/1 12288/12296/1 12283/12291/1 +f 12267/12275/1 2744/2752/1 12285/12293/1 12282/12290/1 +f 2744/2752/1 2743/2751/1 12286/12294/1 12285/12293/1 +f 15046/15054/1 12281/12289/1 12284/12292/1 15047/15055/1 +f 2759/2767/1 12268/12276/1 12281/12289/1 15046/15054/1 +f 12268/12276/1 12267/12275/1 12282/12290/1 12281/12289/1 +f 1818/1826/1 12277/12285/1 12280/12288/1 1819/1827/1 +f 15047/15055/1 12284/12292/1 12277/12285/1 1818/1826/1 +f 12284/12292/1 12283/12291/1 12278/12286/1 12277/12285/1 +f 12270/12278/1 12273/12281/1 12276/12284/1 12271/12279/1 +f 5871/5879/1 4876/4884/1 12273/12281/1 12270/12278/1 +f 4876/4884/1 4875/4883/1 12274/12282/1 12273/12281/1 +f 12226/12234/1 12269/12277/1 12272/12280/1 12227/12235/1 +f 1803/1811/1 5872/5880/1 12269/12277/1 12226/12234/1 +f 5872/5880/1 5871/5879/1 12270/12278/1 12269/12277/1 +f 2758/2766/1 12265/12273/1 12268/12276/1 2759/2767/1 +f 12227/12235/1 12272/12280/1 12265/12273/1 2758/2766/1 +f 12272/12280/1 12271/12279/1 12266/12274/1 12265/12273/1 +f 12258/12266/1 12261/12269/1 12264/12272/1 12259/12267/1 +f 17163/17171/1 1112/1120/1 12261/12269/1 12258/12266/1 +f 1112/1120/1 1111/1119/1 12262/12270/1 12261/12269/1 +f 12274/12282/1 12257/12265/1 12260/12268/1 12275/12283/1 +f 4875/4883/1 17164/17172/1 12257/12265/1 12274/12282/1 +f 17164/17172/1 17163/17171/1 12258/12266/1 12257/12265/1 +f 2742/2750/1 12253/12261/1 12256/12264/1 2743/2751/1 +f 12275/12283/1 12260/12268/1 12253/12261/1 2742/2750/1 +f 12260/12268/1 12259/12267/1 12254/12262/1 12253/12261/1 +f 12246/12254/1 12249/12257/1 12252/12260/1 12247/12255/1 +f 12231/12239/1 2756/2764/1 12249/12257/1 12246/12254/1 +f 2756/2764/1 2755/2763/1 12250/12258/1 12249/12257/1 +f 14782/14790/1 12245/12253/1 12248/12256/1 14783/14791/1 +f 2495/2503/1 12232/12240/1 12245/12253/1 14782/14790/1 +f 12232/12240/1 12231/12239/1 12246/12254/1 12245/12253/1 +f 1906/1914/1 12241/12249/1 12244/12252/1 1907/1915/1 +f 14783/14791/1 12248/12256/1 12241/12249/1 1906/1914/1 +f 12248/12256/1 12247/12255/1 12242/12250/1 12241/12249/1 +f 12234/12242/1 12237/12245/1 12240/12248/1 12235/12243/1 +f 12099/12107/1 2800/2808/1 12237/12245/1 12234/12242/1 +f 2800/2808/1 2799/2807/1 12238/12246/1 12237/12245/1 +f 13018/13026/1 12233/12241/1 12236/12244/1 13019/13027/1 +f 1139/1147/1 12100/12108/1 12233/12241/1 13018/13026/1 +f 12100/12108/1 12099/12107/1 12234/12242/1 12233/12241/1 +f 2494/2502/1 12229/12237/1 12232/12240/1 2495/2503/1 +f 13019/13027/1 12236/12244/1 12229/12237/1 2494/2502/1 +f 12236/12244/1 12235/12243/1 12230/12238/1 12229/12237/1 +f 12222/12230/1 12225/12233/1 12228/12236/1 12223/12231/1 +f 15087/15095/1 1804/1812/1 12225/12233/1 12222/12230/1 +f 1804/1812/1 1803/1811/1 12226/12234/1 12225/12233/1 +f 12238/12246/1 12221/12229/1 12224/12232/1 12239/12247/1 +f 2799/2807/1 15088/15096/1 12221/12229/1 12238/12246/1 +f 15088/15096/1 15087/15095/1 12222/12230/1 12221/12229/1 +f 2754/2762/1 12217/12225/1 12220/12228/1 2755/2763/1 +f 12239/12247/1 12224/12232/1 12217/12225/1 2754/2762/1 +f 12224/12232/1 12223/12231/1 12218/12226/1 12217/12225/1 +f 12210/12218/1 12213/12221/1 12216/12224/1 12211/12219/1 +f 12195/12203/1 2768/2776/1 12213/12221/1 12210/12218/1 +f 2768/2776/1 2767/2775/1 12214/12222/1 12213/12221/1 +f 17266/17274/1 12209/12217/1 12212/12220/1 17267/17275/1 +f 4979/4987/1 12196/12204/1 12209/12217/1 17266/17274/1 +f 12196/12204/1 12195/12203/1 12210/12218/1 12209/12217/1 +f 1078/1086/1 12205/12213/1 12208/12216/1 1079/1087/1 +f 17267/17275/1 12212/12220/1 12205/12213/1 1078/1086/1 +f 12212/12220/1 12211/12219/1 12206/12214/1 12205/12213/1 +f 12198/12206/1 12201/12209/1 12204/12212/1 12199/12207/1 +f 12243/12251/1 2752/2760/1 12201/12209/1 12198/12206/1 +f 2752/2760/1 2751/2759/1 12202/12210/1 12201/12209/1 +f 5566/5574/1 12197/12205/1 12200/12208/1 5567/5575/1 +f 1907/1915/1 12244/12252/1 12197/12205/1 5566/5574/1 +f 12244/12252/1 12243/12251/1 12198/12206/1 12197/12205/1 +f 4978/4986/1 12193/12201/1 12196/12204/1 4979/4987/1 +f 5567/5575/1 12200/12208/1 12193/12201/1 4978/4986/1 +f 12200/12208/1 12199/12207/1 12194/12202/1 12193/12201/1 +f 12186/12194/1 12189/12197/1 12192/12200/1 12187/12195/1 +f 15039/15047/1 1820/1828/1 12189/12197/1 12186/12194/1 +f 1820/1828/1 1819/1827/1 12190/12198/1 12189/12197/1 +f 12202/12210/1 12185/12193/1 12188/12196/1 12203/12211/1 +f 2751/2759/1 15040/15048/1 12185/12193/1 12202/12210/1 +f 15040/15048/1 15039/15047/1 12186/12194/1 12185/12193/1 +f 2766/2774/1 12181/12189/1 12184/12192/1 2767/2775/1 +f 12203/12211/1 12188/12196/1 12181/12189/1 2766/2774/1 +f 12188/12196/1 12187/12195/1 12182/12190/1 12181/12189/1 +f 12174/12182/1 12177/12185/1 12180/12188/1 12175/12183/1 +f 12159/12167/1 2780/2788/1 12177/12185/1 12174/12182/1 +f 2780/2788/1 2779/2787/1 12178/12186/1 12177/12185/1 +f 15082/15090/1 12173/12181/1 12176/12184/1 15083/15091/1 +f 2795/2803/1 12160/12168/1 12173/12181/1 15082/15090/1 +f 12160/12168/1 12159/12167/1 12174/12182/1 12173/12181/1 +f 1806/1814/1 12169/12177/1 12172/12180/1 1807/1815/1 +f 15083/15091/1 12176/12184/1 12169/12177/1 1806/1814/1 +f 12176/12184/1 12175/12183/1 12170/12178/1 12169/12177/1 +f 12162/12170/1 12165/12173/1 12168/12176/1 12163/12171/1 +f 6915/6923/1 4528/4536/1 12165/12173/1 12162/12170/1 +f 4528/4536/1 4527/4535/1 12166/12174/1 12165/12173/1 +f 12118/12126/1 12161/12169/1 12164/12172/1 12119/12127/1 +f 1455/1463/1 6916/6924/1 12161/12169/1 12118/12126/1 +f 6916/6924/1 6915/6923/1 12162/12170/1 12161/12169/1 +f 2794/2802/1 12157/12165/1 12160/12168/1 2795/2803/1 +f 12119/12127/1 12164/12172/1 12157/12165/1 2794/2802/1 +f 12164/12172/1 12163/12171/1 12158/12166/1 12157/12165/1 +f 12150/12158/1 12153/12161/1 12156/12164/1 12151/12159/1 +f 16815/16823/1 1228/1236/1 12153/12161/1 12150/12158/1 +f 1228/1236/1 1227/1235/1 12154/12162/1 12153/12161/1 +f 12166/12174/1 12149/12157/1 12152/12160/1 12167/12175/1 +f 4527/4535/1 16816/16824/1 12149/12157/1 12166/12174/1 +f 16816/16824/1 16815/16823/1 12150/12158/1 12149/12157/1 +f 2778/2786/1 12145/12153/1 12148/12156/1 2779/2787/1 +f 12167/12175/1 12152/12160/1 12145/12153/1 2778/2786/1 +f 12152/12160/1 12151/12159/1 12146/12154/1 12145/12153/1 +f 12138/12146/1 12141/12149/1 12144/12152/1 12139/12147/1 +f 12123/12131/1 2792/2800/1 12141/12149/1 12138/12146/1 +f 2792/2800/1 2791/2799/1 12142/12150/1 12141/12149/1 +f 15322/15330/1 12137/12145/1 12140/12148/1 15323/15331/1 +f 3035/3043/1 12124/12132/1 12137/12145/1 15322/15330/1 +f 12124/12132/1 12123/12131/1 12138/12146/1 12137/12145/1 +f 1726/1734/1 12133/12141/1 12136/12144/1 1727/1735/1 +f 15323/15331/1 12140/12148/1 12133/12141/1 1726/1734/1 +f 12140/12148/1 12139/12147/1 12134/12142/1 12133/12141/1 +f 12126/12134/1 12129/12137/1 12132/12140/1 12127/12135/1 +f 8967/8975/1 3844/3852/1 12129/12137/1 12126/12134/1 +f 3844/3852/1 3843/3851/1 12130/12138/1 12129/12137/1 +f 11398/11406/1 12125/12133/1 12128/12136/1 11399/11407/1 +f 1039/1047/1 8968/8976/1 12125/12133/1 11398/11406/1 +f 8968/8976/1 8967/8975/1 12126/12134/1 12125/12133/1 +f 3034/3042/1 12121/12129/1 12124/12132/1 3035/3043/1 +f 11399/11407/1 12128/12136/1 12121/12129/1 3034/3042/1 +f 12128/12136/1 12127/12135/1 12122/12130/1 12121/12129/1 +f 12114/12122/1 12117/12125/1 12120/12128/1 12115/12123/1 +f 16131/16139/1 1456/1464/1 12117/12125/1 12114/12122/1 +f 1456/1464/1 1455/1463/1 12118/12126/1 12117/12125/1 +f 12130/12138/1 12113/12121/1 12116/12124/1 12131/12139/1 +f 3843/3851/1 16132/16140/1 12113/12121/1 12130/12138/1 +f 16132/16140/1 16131/16139/1 12114/12122/1 12113/12121/1 +f 2790/2798/1 12109/12117/1 12112/12120/1 2791/2799/1 +f 12131/12139/1 12116/12124/1 12109/12117/1 2790/2798/1 +f 12116/12124/1 12115/12123/1 12110/12118/1 12109/12117/1 +f 12102/12110/1 12105/12113/1 12108/12116/1 12103/12111/1 +f 12087/12095/1 2804/2812/1 12105/12113/1 12102/12110/1 +f 2804/2812/1 2803/2811/1 12106/12114/1 12105/12113/1 +f 17086/17094/1 12101/12109/1 12104/12112/1 17087/17095/1 +f 4799/4807/1 12088/12096/1 12101/12109/1 17086/17094/1 +f 12088/12096/1 12087/12095/1 12102/12110/1 12101/12109/1 +f 1138/1146/1 12097/12105/1 12100/12108/1 1139/1147/1 +f 17087/17095/1 12104/12112/1 12097/12105/1 1138/1146/1 +f 12104/12112/1 12103/12111/1 12098/12106/1 12097/12105/1 +f 12090/12098/1 12093/12101/1 12096/12104/1 12091/12099/1 +f 12135/12143/1 2788/2796/1 12093/12101/1 12090/12098/1 +f 2788/2796/1 2787/2795/1 12094/12102/1 12093/12101/1 +f 6106/6114/1 12089/12097/1 12092/12100/1 6107/6115/1 +f 1727/1735/1 12136/12144/1 12089/12097/1 6106/6114/1 +f 12136/12144/1 12135/12143/1 12090/12098/1 12089/12097/1 +f 4798/4806/1 12085/12093/1 12088/12096/1 4799/4807/1 +f 6107/6115/1 12092/12100/1 12085/12093/1 4798/4806/1 +f 12092/12100/1 12091/12099/1 12086/12094/1 12085/12093/1 +f 12078/12086/1 12081/12089/1 12084/12092/1 12079/12087/1 +f 15075/15083/1 1808/1816/1 12081/12089/1 12078/12086/1 +f 1808/1816/1 1807/1815/1 12082/12090/1 12081/12089/1 +f 12094/12102/1 12077/12085/1 12080/12088/1 12095/12103/1 +f 2787/2795/1 15076/15084/1 12077/12085/1 12094/12102/1 +f 15076/15084/1 15075/15083/1 12078/12086/1 12077/12085/1 +f 2802/2810/1 12073/12081/1 12076/12084/1 2803/2811/1 +f 12095/12103/1 12080/12088/1 12073/12081/1 2802/2810/1 +f 12080/12088/1 12079/12087/1 12074/12082/1 12073/12081/1 +f 12066/12074/1 12069/12077/1 12072/12080/1 12067/12075/1 +f 12051/12059/1 2816/2824/1 12069/12077/1 12066/12074/1 +f 2816/2824/1 2815/2823/1 12070/12078/1 12069/12077/1 +f 15118/15126/1 12065/12073/1 12068/12076/1 15119/15127/1 +f 2831/2839/1 12052/12060/1 12065/12073/1 15118/15126/1 +f 12052/12060/1 12051/12059/1 12066/12074/1 12065/12073/1 +f 1794/1802/1 12061/12069/1 12064/12072/1 1795/1803/1 +f 15119/15127/1 12068/12076/1 12061/12069/1 1794/1802/1 +f 12068/12076/1 12067/12075/1 12062/12070/1 12061/12069/1 +f 12054/12062/1 12057/12065/1 12060/12068/1 12055/12063/1 +f 5295/5303/1 5068/5076/1 12057/12065/1 12054/12062/1 +f 5068/5076/1 5067/5075/1 12058/12066/1 12057/12065/1 +f 12010/12018/1 12053/12061/1 12056/12064/1 12011/12019/1 +f 1995/2003/1 5296/5304/1 12053/12061/1 12010/12018/1 +f 5296/5304/1 5295/5303/1 12054/12062/1 12053/12061/1 +f 2830/2838/1 12049/12057/1 12052/12060/1 2831/2839/1 +f 12011/12019/1 12056/12064/1 12049/12057/1 2830/2838/1 +f 12056/12064/1 12055/12063/1 12050/12058/1 12049/12057/1 +f 12042/12050/1 12045/12053/1 12048/12056/1 12043/12051/1 +f 17355/17363/1 1048/1056/1 12045/12053/1 12042/12050/1 +f 1048/1056/1 1047/1055/1 12046/12054/1 12045/12053/1 +f 12058/12066/1 12041/12049/1 12044/12052/1 12059/12067/1 +f 5067/5075/1 17356/17364/1 12041/12049/1 12058/12066/1 +f 17356/17364/1 17355/17363/1 12042/12050/1 12041/12049/1 +f 2814/2822/1 12037/12045/1 12040/12048/1 2815/2823/1 +f 12059/12067/1 12044/12052/1 12037/12045/1 2814/2822/1 +f 12044/12052/1 12043/12051/1 12038/12046/1 12037/12045/1 +f 12030/12038/1 12033/12041/1 12036/12044/1 12031/12039/1 +f 12015/12023/1 2828/2836/1 12033/12041/1 12030/12038/1 +f 2828/2836/1 2827/2835/1 12034/12042/1 12033/12041/1 +f 15070/15078/1 12029/12037/1 12032/12040/1 15071/15079/1 +f 2783/2791/1 12016/12024/1 12029/12037/1 15070/15078/1 +f 12016/12024/1 12015/12023/1 12030/12038/1 12029/12037/1 +f 1810/1818/1 12025/12033/1 12028/12036/1 1811/1819/1 +f 15071/15079/1 12032/12040/1 12025/12033/1 1810/1818/1 +f 12032/12040/1 12031/12039/1 12026/12034/1 12025/12033/1 +f 12018/12026/1 12021/12029/1 12024/12032/1 12019/12027/1 +f 13827/13835/1 2224/2232/1 12021/12029/1 12018/12026/1 +f 2224/2232/1 2223/2231/1 12022/12030/1 12021/12029/1 +f 12154/12162/1 12017/12025/1 12020/12028/1 12155/12163/1 +f 1227/1235/1 13828/13836/1 12017/12025/1 12154/12162/1 +f 13828/13836/1 13827/13835/1 12018/12026/1 12017/12025/1 +f 2782/2790/1 12013/12021/1 12016/12024/1 2783/2791/1 +f 12155/12163/1 12020/12028/1 12013/12021/1 2782/2790/1 +f 12020/12028/1 12019/12027/1 12014/12022/1 12013/12021/1 +f 12006/12014/1 12009/12017/1 12012/12020/1 12007/12015/1 +f 14511/14519/1 1996/2004/1 12009/12017/1 12006/12014/1 +f 1996/2004/1 1995/2003/1 12010/12018/1 12009/12017/1 +f 12022/12030/1 12005/12013/1 12008/12016/1 12023/12031/1 +f 2223/2231/1 14512/14520/1 12005/12013/1 12022/12030/1 +f 14512/14520/1 14511/14519/1 12006/12014/1 12005/12013/1 +f 2826/2834/1 12001/12009/1 12004/12012/1 2827/2835/1 +f 12023/12031/1 12008/12016/1 12001/12009/1 2826/2834/1 +f 12008/12016/1 12007/12015/1 12002/12010/1 12001/12009/1 +f 11994/12002/1 11997/12005/1 12000/12008/1 11995/12003/1 +f 11979/11987/1 2840/2848/1 11997/12005/1 11994/12002/1 +f 2840/2848/1 2839/2847/1 11998/12006/1 11997/12005/1 +f 17170/17178/1 11993/12001/1 11996/12004/1 17171/17179/1 +f 4883/4891/1 11980/11988/1 11993/12001/1 17170/17178/1 +f 11980/11988/1 11979/11987/1 11994/12002/1 11993/12001/1 +f 1110/1118/1 11989/11997/1 11992/12000/1 1111/1119/1 +f 17171/17179/1 11996/12004/1 11989/11997/1 1110/1118/1 +f 11996/12004/1 11995/12003/1 11990/11998/1 11989/11997/1 +f 11982/11990/1 11985/11993/1 11988/11996/1 11983/11991/1 +f 12027/12035/1 2824/2832/1 11985/11993/1 11982/11990/1 +f 2824/2832/1 2823/2831/1 11986/11994/1 11985/11993/1 +f 5854/5862/1 11981/11989/1 11984/11992/1 5855/5863/1 +f 1811/1819/1 12028/12036/1 11981/11989/1 5854/5862/1 +f 12028/12036/1 12027/12035/1 11982/11990/1 11981/11989/1 +f 4882/4890/1 11977/11985/1 11980/11988/1 4883/4891/1 +f 5855/5863/1 11984/11992/1 11977/11985/1 4882/4890/1 +f 11984/11992/1 11983/11991/1 11978/11986/1 11977/11985/1 +f 11970/11978/1 11973/11981/1 11976/11984/1 11971/11979/1 +f 15111/15119/1 1796/1804/1 11973/11981/1 11970/11978/1 +f 1796/1804/1 1795/1803/1 11974/11982/1 11973/11981/1 +f 11986/11994/1 11969/11977/1 11972/11980/1 11987/11995/1 +f 2823/2831/1 15112/15120/1 11969/11977/1 11986/11994/1 +f 15112/15120/1 15111/15119/1 11970/11978/1 11969/11977/1 +f 2838/2846/1 11965/11973/1 11968/11976/1 2839/2847/1 +f 11987/11995/1 11972/11980/1 11965/11973/1 2838/2846/1 +f 11972/11980/1 11971/11979/1 11966/11974/1 11965/11973/1 +f 11958/11966/1 11961/11969/1 11964/11972/1 11959/11967/1 +f 11943/11951/1 2852/2860/1 11961/11969/1 11958/11966/1 +f 2852/2860/1 2851/2859/1 11962/11970/1 11961/11969/1 +f 15154/15162/1 11957/11965/1 11960/11968/1 15155/15163/1 +f 2867/2875/1 11944/11952/1 11957/11965/1 15154/15162/1 +f 11944/11952/1 11943/11951/1 11958/11966/1 11957/11965/1 +f 1782/1790/1 11953/11961/1 11956/11964/1 1783/1791/1 +f 15155/15163/1 11960/11968/1 11953/11961/1 1782/1790/1 +f 11960/11968/1 11959/11967/1 11954/11962/1 11953/11961/1 +f 11946/11954/1 11949/11957/1 11952/11960/1 11947/11955/1 +f 5979/5987/1 4840/4848/1 11949/11957/1 11946/11954/1 +f 4840/4848/1 4839/4847/1 11950/11958/1 11949/11957/1 +f 11902/11910/1 11945/11953/1 11948/11956/1 11903/11911/1 +f 1767/1775/1 5980/5988/1 11945/11953/1 11902/11910/1 +f 5980/5988/1 5979/5987/1 11946/11954/1 11945/11953/1 +f 2866/2874/1 11941/11949/1 11944/11952/1 2867/2875/1 +f 11903/11911/1 11948/11956/1 11941/11949/1 2866/2874/1 +f 11948/11956/1 11947/11955/1 11942/11950/1 11941/11949/1 +f 11934/11942/1 11937/11945/1 11940/11948/1 11935/11943/1 +f 17127/17135/1 1124/1132/1 11937/11945/1 11934/11942/1 +f 1124/1132/1 1123/1131/1 11938/11946/1 11937/11945/1 +f 11950/11958/1 11933/11941/1 11936/11944/1 11951/11959/1 +f 4839/4847/1 17128/17136/1 11933/11941/1 11950/11958/1 +f 17128/17136/1 17127/17135/1 11934/11942/1 11933/11941/1 +f 2850/2858/1 11929/11937/1 11932/11940/1 2851/2859/1 +f 11951/11959/1 11936/11944/1 11929/11937/1 2850/2858/1 +f 11936/11944/1 11935/11943/1 11930/11938/1 11929/11937/1 +f 11922/11930/1 11925/11933/1 11928/11936/1 11923/11931/1 +f 11907/11915/1 2864/2872/1 11925/11933/1 11922/11930/1 +f 2864/2872/1 2863/2871/1 11926/11934/1 11925/11933/1 +f 14386/14394/1 11921/11929/1 11924/11932/1 14387/14395/1 +f 2099/2107/1 11908/11916/1 11921/11929/1 14386/14394/1 +f 11908/11916/1 11907/11915/1 11922/11930/1 11921/11929/1 +f 2038/2046/1 11917/11925/1 11920/11928/1 2039/2047/1 +f 14387/14395/1 11924/11932/1 11917/11925/1 2038/2046/1 +f 11924/11932/1 11923/11931/1 11918/11926/1 11917/11925/1 +f 11910/11918/1 11913/11921/1 11916/11924/1 11911/11919/1 +f 11775/11783/1 2908/2916/1 11913/11921/1 11910/11918/1 +f 2908/2916/1 2907/2915/1 11914/11922/1 11913/11921/1 +f 14206/14214/1 11909/11917/1 11912/11920/1 14207/14215/1 +f 1271/1279/1 11776/11784/1 11909/11917/1 14206/14214/1 +f 11776/11784/1 11775/11783/1 11910/11918/1 11909/11917/1 +f 2098/2106/1 11905/11913/1 11908/11916/1 2099/2107/1 +f 14207/14215/1 11912/11920/1 11905/11913/1 2098/2106/1 +f 11912/11920/1 11911/11919/1 11906/11914/1 11905/11913/1 +f 11898/11906/1 11901/11909/1 11904/11912/1 11899/11907/1 +f 15195/15203/1 1768/1776/1 11901/11909/1 11898/11906/1 +f 1768/1776/1 1767/1775/1 11902/11910/1 11901/11909/1 +f 11914/11922/1 11897/11905/1 11900/11908/1 11915/11923/1 +f 2907/2915/1 15196/15204/1 11897/11905/1 11914/11922/1 +f 15196/15204/1 15195/15203/1 11898/11906/1 11897/11905/1 +f 2862/2870/1 11893/11901/1 11896/11904/1 2863/2871/1 +f 11915/11923/1 11900/11908/1 11893/11901/1 2862/2870/1 +f 11900/11908/1 11899/11907/1 11894/11902/1 11893/11901/1 +f 11886/11894/1 11889/11897/1 11892/11900/1 11887/11895/1 +f 11871/11879/1 2876/2884/1 11889/11897/1 11886/11894/1 +f 2876/2884/1 2875/2883/1 11890/11898/1 11889/11897/1 +f 17398/17406/1 11885/11893/1 11888/11896/1 17399/17407/1 +f 5111/5119/1 11872/11880/1 11885/11893/1 17398/17406/1 +f 11872/11880/1 11871/11879/1 11886/11894/1 11885/11893/1 +f 1034/1042/1 11881/11889/1 11884/11892/1 1035/1043/1 +f 17399/17407/1 11888/11896/1 11881/11889/1 1034/1042/1 +f 11888/11896/1 11887/11895/1 11882/11890/1 11881/11889/1 +f 11874/11882/1 11877/11885/1 11880/11888/1 11875/11883/1 +f 11919/11927/1 2860/2868/1 11877/11885/1 11874/11882/1 +f 2860/2868/1 2859/2867/1 11878/11886/1 11877/11885/1 +f 5170/5178/1 11873/11881/1 11876/11884/1 5171/5179/1 +f 2039/2047/1 11920/11928/1 11873/11881/1 5170/5178/1 +f 11920/11928/1 11919/11927/1 11874/11882/1 11873/11881/1 +f 5110/5118/1 11869/11877/1 11872/11880/1 5111/5119/1 +f 5171/5179/1 11876/11884/1 11869/11877/1 5110/5118/1 +f 11876/11884/1 11875/11883/1 11870/11878/1 11869/11877/1 +f 11862/11870/1 11865/11873/1 11868/11876/1 11863/11871/1 +f 15147/15155/1 1784/1792/1 11865/11873/1 11862/11870/1 +f 1784/1792/1 1783/1791/1 11866/11874/1 11865/11873/1 +f 11878/11886/1 11861/11869/1 11864/11872/1 11879/11887/1 +f 2859/2867/1 15148/15156/1 11861/11869/1 11878/11886/1 +f 15148/15156/1 15147/15155/1 11862/11870/1 11861/11869/1 +f 2874/2882/1 11857/11865/1 11860/11868/1 2875/2883/1 +f 11879/11887/1 11864/11872/1 11857/11865/1 2874/2882/1 +f 11864/11872/1 11863/11871/1 11858/11866/1 11857/11865/1 +f 11850/11858/1 11853/11861/1 11856/11864/1 11851/11859/1 +f 11835/11843/1 2888/2896/1 11853/11861/1 11850/11858/1 +f 2888/2896/1 2887/2895/1 11854/11862/1 11853/11861/1 +f 15190/15198/1 11849/11857/1 11852/11860/1 15191/15199/1 +f 2903/2911/1 11836/11844/1 11849/11857/1 15190/15198/1 +f 11836/11844/1 11835/11843/1 11850/11858/1 11849/11857/1 +f 1770/1778/1 11845/11853/1 11848/11856/1 1771/1779/1 +f 15191/15199/1 11852/11860/1 11845/11853/1 1770/1778/1 +f 11852/11860/1 11851/11859/1 11846/11854/1 11845/11853/1 +f 11838/11846/1 11841/11849/1 11844/11852/1 11839/11847/1 +f 5835/5843/1 4888/4896/1 11841/11849/1 11838/11846/1 +f 4888/4896/1 4887/4895/1 11842/11850/1 11841/11849/1 +f 11794/11802/1 11837/11845/1 11840/11848/1 11795/11803/1 +f 1815/1823/1 5836/5844/1 11837/11845/1 11794/11802/1 +f 5836/5844/1 5835/5843/1 11838/11846/1 11837/11845/1 +f 2902/2910/1 11833/11841/1 11836/11844/1 2903/2911/1 +f 11795/11803/1 11840/11848/1 11833/11841/1 2902/2910/1 +f 11840/11848/1 11839/11847/1 11834/11842/1 11833/11841/1 +f 11826/11834/1 11829/11837/1 11832/11840/1 11827/11835/1 +f 17175/17183/1 1108/1116/1 11829/11837/1 11826/11834/1 +f 1108/1116/1 1107/1115/1 11830/11838/1 11829/11837/1 +f 11842/11850/1 11825/11833/1 11828/11836/1 11843/11851/1 +f 4887/4895/1 17176/17184/1 11825/11833/1 11842/11850/1 +f 17176/17184/1 17175/17183/1 11826/11834/1 11825/11833/1 +f 2886/2894/1 11821/11829/1 11824/11832/1 2887/2895/1 +f 11843/11851/1 11828/11836/1 11821/11829/1 2886/2894/1 +f 11828/11836/1 11827/11835/1 11822/11830/1 11821/11829/1 +f 11814/11822/1 11817/11825/1 11820/11828/1 11815/11823/1 +f 11799/11807/1 2900/2908/1 11817/11825/1 11814/11822/1 +f 2900/2908/1 2899/2907/1 11818/11826/1 11817/11825/1 +f 16510/16518/1 11813/11821/1 11816/11824/1 16511/16519/1 +f 4223/4231/1 11800/11808/1 11813/11821/1 16510/16518/1 +f 11800/11808/1 11799/11807/1 11814/11822/1 11813/11821/1 +f 1330/1338/1 11809/11817/1 11812/11820/1 1331/1339/1 +f 16511/16519/1 11816/11824/1 11809/11817/1 1330/1338/1 +f 11816/11824/1 11815/11823/1 11810/11818/1 11809/11817/1 +f 11802/11810/1 11805/11813/1 11808/11816/1 11803/11811/1 +f 12207/12215/1 2764/2772/1 11805/11813/1 11802/11810/1 +f 2764/2772/1 2763/2771/1 11806/11814/1 11805/11813/1 +f 7834/7842/1 11801/11809/1 11804/11812/1 7835/7843/1 +f 1079/1087/1 12208/12216/1 11801/11809/1 7834/7842/1 +f 12208/12216/1 12207/12215/1 11802/11810/1 11801/11809/1 +f 4222/4230/1 11797/11805/1 11800/11808/1 4223/4231/1 +f 7835/7843/1 11804/11812/1 11797/11805/1 4222/4230/1 +f 11804/11812/1 11803/11811/1 11798/11806/1 11797/11805/1 +f 11790/11798/1 11793/11801/1 11796/11804/1 11791/11799/1 +f 15051/15059/1 1816/1824/1 11793/11801/1 11790/11798/1 +f 1816/1824/1 1815/1823/1 11794/11802/1 11793/11801/1 +f 11806/11814/1 11789/11797/1 11792/11800/1 11807/11815/1 +f 2763/2771/1 15052/15060/1 11789/11797/1 11806/11814/1 +f 15052/15060/1 15051/15059/1 11790/11798/1 11789/11797/1 +f 2898/2906/1 11785/11793/1 11788/11796/1 2899/2907/1 +f 11807/11815/1 11792/11800/1 11785/11793/1 2898/2906/1 +f 11792/11800/1 11791/11799/1 11786/11794/1 11785/11793/1 +f 11778/11786/1 11781/11789/1 11784/11792/1 11779/11787/1 +f 11763/11771/1 2912/2920/1 11781/11789/1 11778/11786/1 +f 2912/2920/1 2911/2919/1 11782/11790/1 11781/11789/1 +f 16690/16698/1 11777/11785/1 11780/11788/1 16691/16699/1 +f 4403/4411/1 11764/11772/1 11777/11785/1 16690/16698/1 +f 11764/11772/1 11763/11771/1 11778/11786/1 11777/11785/1 +f 1270/1278/1 11773/11781/1 11776/11784/1 1271/1279/1 +f 16691/16699/1 11780/11788/1 11773/11781/1 1270/1278/1 +f 11780/11788/1 11779/11787/1 11774/11782/1 11773/11781/1 +f 11766/11774/1 11769/11777/1 11772/11780/1 11767/11775/1 +f 11811/11819/1 2896/2904/1 11769/11777/1 11766/11774/1 +f 2896/2904/1 2895/2903/1 11770/11778/1 11769/11777/1 +f 7294/7302/1 11765/11773/1 11768/11776/1 7295/7303/1 +f 1331/1339/1 11812/11820/1 11765/11773/1 7294/7302/1 +f 11812/11820/1 11811/11819/1 11766/11774/1 11765/11773/1 +f 4402/4410/1 11761/11769/1 11764/11772/1 4403/4411/1 +f 7295/7303/1 11768/11776/1 11761/11769/1 4402/4410/1 +f 11768/11776/1 11767/11775/1 11762/11770/1 11761/11769/1 +f 11754/11762/1 11757/11765/1 11760/11768/1 11755/11763/1 +f 15183/15191/1 1772/1780/1 11757/11765/1 11754/11762/1 +f 1772/1780/1 1771/1779/1 11758/11766/1 11757/11765/1 +f 11770/11778/1 11753/11761/1 11756/11764/1 11771/11779/1 +f 2895/2903/1 15184/15192/1 11753/11761/1 11770/11778/1 +f 15184/15192/1 15183/15191/1 11754/11762/1 11753/11761/1 +f 2910/2918/1 11749/11757/1 11752/11760/1 2911/2919/1 +f 11771/11779/1 11756/11764/1 11749/11757/1 2910/2918/1 +f 11756/11764/1 11755/11763/1 11750/11758/1 11749/11757/1 +f 11742/11750/1 11745/11753/1 11748/11756/1 11743/11751/1 +f 11727/11735/1 2924/2932/1 11745/11753/1 11742/11750/1 +f 2924/2932/1 2923/2931/1 11746/11754/1 11745/11753/1 +f 15226/15234/1 11741/11749/1 11744/11752/1 15227/15235/1 +f 2939/2947/1 11728/11736/1 11741/11749/1 15226/15234/1 +f 11728/11736/1 11727/11735/1 11742/11750/1 11741/11749/1 +f 1758/1766/1 11737/11745/1 11740/11748/1 1759/1767/1 +f 15227/15235/1 11744/11752/1 11737/11745/1 1758/1766/1 +f 11744/11752/1 11743/11751/1 11738/11746/1 11737/11745/1 +f 11730/11738/1 11733/11741/1 11736/11744/1 11731/11739/1 +f 5655/5663/1 4948/4956/1 11733/11741/1 11730/11738/1 +f 4948/4956/1 4947/4955/1 11734/11742/1 11733/11741/1 +f 11686/11694/1 11729/11737/1 11732/11740/1 11687/11695/1 +f 1875/1883/1 5656/5664/1 11729/11737/1 11686/11694/1 +f 5656/5664/1 5655/5663/1 11730/11738/1 11729/11737/1 +f 2938/2946/1 11725/11733/1 11728/11736/1 2939/2947/1 +f 11687/11695/1 11732/11740/1 11725/11733/1 2938/2946/1 +f 11732/11740/1 11731/11739/1 11726/11734/1 11725/11733/1 +f 11718/11726/1 11721/11729/1 11724/11732/1 11719/11727/1 +f 17235/17243/1 1088/1096/1 11721/11729/1 11718/11726/1 +f 1088/1096/1 1087/1095/1 11722/11730/1 11721/11729/1 +f 11734/11742/1 11717/11725/1 11720/11728/1 11735/11743/1 +f 4947/4955/1 17236/17244/1 11717/11725/1 11734/11742/1 +f 17236/17244/1 17235/17243/1 11718/11726/1 11717/11725/1 +f 2922/2930/1 11713/11721/1 11716/11724/1 2923/2931/1 +f 11735/11743/1 11720/11728/1 11713/11721/1 2922/2930/1 +f 11720/11728/1 11719/11727/1 11714/11722/1 11713/11721/1 +f 11706/11714/1 11709/11717/1 11712/11720/1 11707/11715/1 +f 11691/11699/1 2936/2944/1 11709/11717/1 11706/11714/1 +f 2936/2944/1 2935/2943/1 11710/11718/1 11709/11717/1 +f 15178/15186/1 11705/11713/1 11708/11716/1 15179/15187/1 +f 2891/2899/1 11692/11700/1 11705/11713/1 15178/15186/1 +f 11692/11700/1 11691/11699/1 11706/11714/1 11705/11713/1 +f 1774/1782/1 11701/11709/1 11704/11712/1 1775/1783/1 +f 15179/15187/1 11708/11716/1 11701/11709/1 1774/1782/1 +f 11708/11716/1 11707/11715/1 11702/11710/1 11701/11709/1 +f 11694/11702/1 11697/11705/1 11700/11708/1 11695/11703/1 +f 12747/12755/1 2584/2592/1 11697/11705/1 11694/11702/1 +f 2584/2592/1 2583/2591/1 11698/11706/1 11697/11705/1 +f 11830/11838/1 11693/11701/1 11696/11704/1 11831/11839/1 +f 1107/1115/1 12748/12756/1 11693/11701/1 11830/11838/1 +f 12748/12756/1 12747/12755/1 11694/11702/1 11693/11701/1 +f 2890/2898/1 11689/11697/1 11692/11700/1 2891/2899/1 +f 11831/11839/1 11696/11704/1 11689/11697/1 2890/2898/1 +f 11696/11704/1 11695/11703/1 11690/11698/1 11689/11697/1 +f 11682/11690/1 11685/11693/1 11688/11696/1 11683/11691/1 +f 14871/14879/1 1876/1884/1 11685/11693/1 11682/11690/1 +f 1876/1884/1 1875/1883/1 11686/11694/1 11685/11693/1 +f 11698/11706/1 11681/11689/1 11684/11692/1 11699/11707/1 +f 2583/2591/1 14872/14880/1 11681/11689/1 11698/11706/1 +f 14872/14880/1 14871/14879/1 11682/11690/1 11681/11689/1 +f 2934/2942/1 11677/11685/1 11680/11688/1 2935/2943/1 +f 11699/11707/1 11684/11692/1 11677/11685/1 2934/2942/1 +f 11684/11692/1 11683/11691/1 11678/11686/1 11677/11685/1 +f 11670/11678/1 11673/11681/1 11676/11684/1 11671/11679/1 +f 11655/11663/1 2948/2956/1 11673/11681/1 11670/11678/1 +f 2948/2956/1 2947/2955/1 11674/11682/1 11673/11681/1 +f 17134/17142/1 11669/11677/1 11672/11680/1 17135/17143/1 +f 4847/4855/1 11656/11664/1 11669/11677/1 17134/17142/1 +f 11656/11664/1 11655/11663/1 11670/11678/1 11669/11677/1 +f 1122/1130/1 11665/11673/1 11668/11676/1 1123/1131/1 +f 17135/17143/1 11672/11680/1 11665/11673/1 1122/1130/1 +f 11672/11680/1 11671/11679/1 11666/11674/1 11665/11673/1 +f 11658/11666/1 11661/11669/1 11664/11672/1 11659/11667/1 +f 11703/11711/1 2932/2940/1 11661/11669/1 11658/11666/1 +f 2932/2940/1 2931/2939/1 11662/11670/1 11661/11669/1 +f 5962/5970/1 11657/11665/1 11660/11668/1 5963/5971/1 +f 1775/1783/1 11704/11712/1 11657/11665/1 5962/5970/1 +f 11704/11712/1 11703/11711/1 11658/11666/1 11657/11665/1 +f 4846/4854/1 11653/11661/1 11656/11664/1 4847/4855/1 +f 5963/5971/1 11660/11668/1 11653/11661/1 4846/4854/1 +f 11660/11668/1 11659/11667/1 11654/11662/1 11653/11661/1 +f 11646/11654/1 11649/11657/1 11652/11660/1 11647/11655/1 +f 15219/15227/1 1760/1768/1 11649/11657/1 11646/11654/1 +f 1760/1768/1 1759/1767/1 11650/11658/1 11649/11657/1 +f 11662/11670/1 11645/11653/1 11648/11656/1 11663/11671/1 +f 2931/2939/1 15220/15228/1 11645/11653/1 11662/11670/1 +f 15220/15228/1 15219/15227/1 11646/11654/1 11645/11653/1 +f 2946/2954/1 11641/11649/1 11644/11652/1 2947/2955/1 +f 11663/11671/1 11648/11656/1 11641/11649/1 2946/2954/1 +f 11648/11656/1 11647/11655/1 11642/11650/1 11641/11649/1 +f 11634/11642/1 11637/11645/1 11640/11648/1 11635/11643/1 +f 11619/11627/1 2960/2968/1 11637/11645/1 11634/11642/1 +f 2960/2968/1 2959/2967/1 11638/11646/1 11637/11645/1 +f 15262/15270/1 11633/11641/1 11636/11644/1 15263/15271/1 +f 2975/2983/1 11620/11628/1 11633/11641/1 15262/15270/1 +f 11620/11628/1 11619/11627/1 11634/11642/1 11633/11641/1 +f 1746/1754/1 11629/11637/1 11632/11640/1 1747/1755/1 +f 15263/15271/1 11636/11644/1 11629/11637/1 1746/1754/1 +f 11636/11644/1 11635/11643/1 11630/11638/1 11629/11637/1 +f 11622/11630/1 11625/11633/1 11628/11636/1 11623/11631/1 +f 6087/6095/1 4804/4812/1 11625/11633/1 11622/11630/1 +f 4804/4812/1 4803/4811/1 11626/11634/1 11625/11633/1 +f 11578/11586/1 11621/11629/1 11624/11632/1 11579/11587/1 +f 1731/1739/1 6088/6096/1 11621/11629/1 11578/11586/1 +f 6088/6096/1 6087/6095/1 11622/11630/1 11621/11629/1 +f 2974/2982/1 11617/11625/1 11620/11628/1 2975/2983/1 +f 11579/11587/1 11624/11632/1 11617/11625/1 2974/2982/1 +f 11624/11632/1 11623/11631/1 11618/11626/1 11617/11625/1 +f 11610/11618/1 11613/11621/1 11616/11624/1 11611/11619/1 +f 17091/17099/1 1136/1144/1 11613/11621/1 11610/11618/1 +f 1136/1144/1 1135/1143/1 11614/11622/1 11613/11621/1 +f 11626/11634/1 11609/11617/1 11612/11620/1 11627/11635/1 +f 4803/4811/1 17092/17100/1 11609/11617/1 11626/11634/1 +f 17092/17100/1 17091/17099/1 11610/11618/1 11609/11617/1 +f 2958/2966/1 11605/11613/1 11608/11616/1 2959/2967/1 +f 11627/11635/1 11612/11620/1 11605/11613/1 2958/2966/1 +f 11612/11620/1 11611/11619/1 11606/11614/1 11605/11613/1 +f 11598/11606/1 11601/11609/1 11604/11612/1 11599/11607/1 +f 11583/11591/1 2972/2980/1 11601/11609/1 11598/11606/1 +f 2972/2980/1 2971/2979/1 11602/11610/1 11601/11609/1 +f 14746/14754/1 11597/11605/1 11600/11608/1 14747/14755/1 +f 2459/2467/1 11584/11592/1 11597/11605/1 14746/14754/1 +f 11584/11592/1 11583/11591/1 11598/11606/1 11597/11605/1 +f 1918/1926/1 11593/11601/1 11596/11604/1 1919/1927/1 +f 14747/14755/1 11600/11608/1 11593/11601/1 1918/1926/1 +f 11600/11608/1 11599/11607/1 11594/11602/1 11593/11601/1 +f 11586/11594/1 11589/11597/1 11592/11600/1 11587/11595/1 +f 11451/11459/1 3016/3024/1 11589/11597/1 11586/11594/1 +f 3016/3024/1 3015/3023/1 11590/11598/1 11589/11597/1 +f 13126/13134/1 11585/11593/1 11588/11596/1 13127/13135/1 +f 1151/1159/1 11452/11460/1 11585/11593/1 13126/13134/1 +f 11452/11460/1 11451/11459/1 11586/11594/1 11585/11593/1 +f 2458/2466/1 11581/11589/1 11584/11592/1 2459/2467/1 +f 13127/13135/1 11588/11596/1 11581/11589/1 2458/2466/1 +f 11588/11596/1 11587/11595/1 11582/11590/1 11581/11589/1 +f 11574/11582/1 11577/11585/1 11580/11588/1 11575/11583/1 +f 15303/15311/1 1732/1740/1 11577/11585/1 11574/11582/1 +f 1732/1740/1 1731/1739/1 11578/11586/1 11577/11585/1 +f 11590/11598/1 11573/11581/1 11576/11584/1 11591/11599/1 +f 3015/3023/1 15304/15312/1 11573/11581/1 11590/11598/1 +f 15304/15312/1 15303/15311/1 11574/11582/1 11573/11581/1 +f 2970/2978/1 11569/11577/1 11572/11580/1 2971/2979/1 +f 11591/11599/1 11576/11584/1 11569/11577/1 2970/2978/1 +f 11576/11584/1 11575/11583/1 11570/11578/1 11569/11577/1 +f 11562/11570/1 11565/11573/1 11568/11576/1 11563/11571/1 +f 11547/11555/1 2984/2992/1 11565/11573/1 11562/11570/1 +f 2984/2992/1 2983/2991/1 11566/11574/1 11565/11573/1 +f 17278/17286/1 11561/11569/1 11564/11572/1 17279/17287/1 +f 4991/4999/1 11548/11556/1 11561/11569/1 17278/17286/1 +f 11548/11556/1 11547/11555/1 11562/11570/1 11561/11569/1 +f 1074/1082/1 11557/11565/1 11560/11568/1 1075/1083/1 +f 17279/17287/1 11564/11572/1 11557/11565/1 1074/1082/1 +f 11564/11572/1 11563/11571/1 11558/11566/1 11557/11565/1 +f 11550/11558/1 11553/11561/1 11556/11564/1 11551/11559/1 +f 11595/11603/1 2968/2976/1 11553/11561/1 11550/11558/1 +f 2968/2976/1 2967/2975/1 11554/11562/1 11553/11561/1 +f 5530/5538/1 11549/11557/1 11552/11560/1 5531/5539/1 +f 1919/1927/1 11596/11604/1 11549/11557/1 5530/5538/1 +f 11596/11604/1 11595/11603/1 11550/11558/1 11549/11557/1 +f 4990/4998/1 11545/11553/1 11548/11556/1 4991/4999/1 +f 5531/5539/1 11552/11560/1 11545/11553/1 4990/4998/1 +f 11552/11560/1 11551/11559/1 11546/11554/1 11545/11553/1 +f 11538/11546/1 11541/11549/1 11544/11552/1 11539/11547/1 +f 15255/15263/1 1748/1756/1 11541/11549/1 11538/11546/1 +f 1748/1756/1 1747/1755/1 11542/11550/1 11541/11549/1 +f 11554/11562/1 11537/11545/1 11540/11548/1 11555/11563/1 +f 2967/2975/1 15256/15264/1 11537/11545/1 11554/11562/1 +f 15256/15264/1 15255/15263/1 11538/11546/1 11537/11545/1 +f 2982/2990/1 11533/11541/1 11536/11544/1 2983/2991/1 +f 11555/11563/1 11540/11548/1 11533/11541/1 2982/2990/1 +f 11540/11548/1 11539/11547/1 11534/11542/1 11533/11541/1 +f 11526/11534/1 11529/11537/1 11532/11540/1 11527/11535/1 +f 11511/11519/1 2996/3004/1 11529/11537/1 11526/11534/1 +f 2996/3004/1 2995/3003/1 11530/11538/1 11529/11537/1 +f 15298/15306/1 11525/11533/1 11528/11536/1 15299/15307/1 +f 3011/3019/1 11512/11520/1 11525/11533/1 15298/15306/1 +f 11512/11520/1 11511/11519/1 11526/11534/1 11525/11533/1 +f 1734/1742/1 11521/11529/1 11524/11532/1 1735/1743/1 +f 15299/15307/1 11528/11536/1 11521/11529/1 1734/1742/1 +f 11528/11536/1 11527/11535/1 11522/11530/1 11521/11529/1 +f 11514/11522/1 11517/11525/1 11520/11528/1 11515/11523/1 +f 7131/7139/1 4456/4464/1 11517/11525/1 11514/11522/1 +f 4456/4464/1 4455/4463/1 11518/11526/1 11517/11525/1 +f 11470/11478/1 11513/11521/1 11516/11524/1 11471/11479/1 +f 1383/1391/1 7132/7140/1 11513/11521/1 11470/11478/1 +f 7132/7140/1 7131/7139/1 11514/11522/1 11513/11521/1 +f 3010/3018/1 11509/11517/1 11512/11520/1 3011/3019/1 +f 11471/11479/1 11516/11524/1 11509/11517/1 3010/3018/1 +f 11516/11524/1 11515/11523/1 11510/11518/1 11509/11517/1 +f 11502/11510/1 11505/11513/1 11508/11516/1 11503/11511/1 +f 16743/16751/1 1252/1260/1 11505/11513/1 11502/11510/1 +f 1252/1260/1 1251/1259/1 11506/11514/1 11505/11513/1 +f 11518/11526/1 11501/11509/1 11504/11512/1 11519/11527/1 +f 4455/4463/1 16744/16752/1 11501/11509/1 11518/11526/1 +f 16744/16752/1 16743/16751/1 11502/11510/1 11501/11509/1 +f 2994/3002/1 11497/11505/1 11500/11508/1 2995/3003/1 +f 11519/11527/1 11504/11512/1 11497/11505/1 2994/3002/1 +f 11504/11512/1 11503/11511/1 11498/11506/1 11497/11505/1 +f 11490/11498/1 11493/11501/1 11496/11504/1 11491/11499/1 +f 11475/11483/1 3008/3016/1 11493/11501/1 11490/11498/1 +f 3008/3016/1 3007/3015/1 11494/11502/1 11493/11501/1 +f 15430/15438/1 11489/11497/1 11492/11500/1 15431/15439/1 +f 3143/3151/1 11476/11484/1 11489/11497/1 15430/15438/1 +f 11476/11484/1 11475/11483/1 11490/11498/1 11489/11497/1 +f 1690/1698/1 11485/11493/1 11488/11496/1 1691/1699/1 +f 15431/15439/1 11492/11500/1 11485/11493/1 1690/1698/1 +f 11492/11500/1 11491/11499/1 11486/11494/1 11485/11493/1 +f 11478/11486/1 11481/11489/1 11484/11492/1 11479/11487/1 +f 8319/8327/1 4060/4068/1 11481/11489/1 11478/11486/1 +f 4060/4068/1 4059/4067/1 11482/11490/1 11481/11489/1 +f 11074/11082/1 11477/11485/1 11480/11488/1 11075/11083/1 +f 1059/1067/1 8320/8328/1 11477/11485/1 11074/11082/1 +f 8320/8328/1 8319/8327/1 11478/11486/1 11477/11485/1 +f 3142/3150/1 11473/11481/1 11476/11484/1 3143/3151/1 +f 11075/11083/1 11480/11488/1 11473/11481/1 3142/3150/1 +f 11480/11488/1 11479/11487/1 11474/11482/1 11473/11481/1 +f 11466/11474/1 11469/11477/1 11472/11480/1 11467/11475/1 +f 16347/16355/1 1384/1392/1 11469/11477/1 11466/11474/1 +f 1384/1392/1 1383/1391/1 11470/11478/1 11469/11477/1 +f 11482/11490/1 11465/11473/1 11468/11476/1 11483/11491/1 +f 4059/4067/1 16348/16356/1 11465/11473/1 11482/11490/1 +f 16348/16356/1 16347/16355/1 11466/11474/1 11465/11473/1 +f 3006/3014/1 11461/11469/1 11464/11472/1 3007/3015/1 +f 11483/11491/1 11468/11476/1 11461/11469/1 3006/3014/1 +f 11468/11476/1 11467/11475/1 11462/11470/1 11461/11469/1 +f 11454/11462/1 11457/11465/1 11460/11468/1 11455/11463/1 +f 11439/11447/1 3020/3028/1 11457/11465/1 11454/11462/1 +f 3020/3028/1 3019/3027/1 11458/11466/1 11457/11465/1 +f 17050/17058/1 11453/11461/1 11456/11464/1 17051/17059/1 +f 4763/4771/1 11440/11448/1 11453/11461/1 17050/17058/1 +f 11440/11448/1 11439/11447/1 11454/11462/1 11453/11461/1 +f 1150/1158/1 11449/11457/1 11452/11460/1 1151/1159/1 +f 17051/17059/1 11456/11464/1 11449/11457/1 1150/1158/1 +f 11456/11464/1 11455/11463/1 11450/11458/1 11449/11457/1 +f 11442/11450/1 11445/11453/1 11448/11456/1 11443/11451/1 +f 11487/11495/1 3004/3012/1 11445/11453/1 11442/11450/1 +f 3004/3012/1 3003/3011/1 11446/11454/1 11445/11453/1 +f 6214/6222/1 11441/11449/1 11444/11452/1 6215/6223/1 +f 1691/1699/1 11488/11496/1 11441/11449/1 6214/6222/1 +f 11488/11496/1 11487/11495/1 11442/11450/1 11441/11449/1 +f 4762/4770/1 11437/11445/1 11440/11448/1 4763/4771/1 +f 6215/6223/1 11444/11452/1 11437/11445/1 4762/4770/1 +f 11444/11452/1 11443/11451/1 11438/11446/1 11437/11445/1 +f 11430/11438/1 11433/11441/1 11436/11444/1 11431/11439/1 +f 15291/15299/1 1736/1744/1 11433/11441/1 11430/11438/1 +f 1736/1744/1 1735/1743/1 11434/11442/1 11433/11441/1 +f 11446/11454/1 11429/11437/1 11432/11440/1 11447/11455/1 +f 3003/3011/1 15292/15300/1 11429/11437/1 11446/11454/1 +f 15292/15300/1 15291/15299/1 11430/11438/1 11429/11437/1 +f 3018/3026/1 11425/11433/1 11428/11436/1 3019/3027/1 +f 11447/11455/1 11432/11440/1 11425/11433/1 3018/3026/1 +f 11432/11440/1 11431/11439/1 11426/11434/1 11425/11433/1 +f 11418/11426/1 11421/11429/1 11424/11432/1 11419/11427/1 +f 11403/11411/1 3032/3040/1 11421/11429/1 11418/11426/1 +f 3032/3040/1 3031/3039/1 11422/11430/1 11421/11429/1 +f 15334/15342/1 11417/11425/1 11420/11428/1 15335/15343/1 +f 3047/3055/1 11404/11412/1 11417/11425/1 15334/15342/1 +f 11404/11412/1 11403/11411/1 11418/11426/1 11417/11425/1 +f 1722/1730/1 11413/11421/1 11416/11424/1 1723/1731/1 +f 15335/15343/1 11420/11428/1 11413/11421/1 1722/1730/1 +f 11420/11428/1 11419/11427/1 11414/11422/1 11413/11421/1 +f 11406/11414/1 11409/11417/1 11412/11420/1 11407/11415/1 +f 5223/5231/1 5092/5100/1 11409/11417/1 11406/11414/1 +f 5092/5100/1 5091/5099/1 11410/11418/1 11409/11417/1 +f 11362/11370/1 11405/11413/1 11408/11416/1 11363/11371/1 +f 2019/2027/1 5224/5232/1 11405/11413/1 11362/11370/1 +f 5224/5232/1 5223/5231/1 11406/11414/1 11405/11413/1 +f 3046/3054/1 11401/11409/1 11404/11412/1 3047/3055/1 +f 11363/11371/1 11408/11416/1 11401/11409/1 3046/3054/1 +f 11408/11416/1 11407/11415/1 11402/11410/1 11401/11409/1 +f 11394/11402/1 11397/11405/1 11400/11408/1 11395/11403/1 +f 17379/17387/1 1040/1048/1 11397/11405/1 11394/11402/1 +f 1040/1048/1 1039/1047/1 11398/11406/1 11397/11405/1 +f 11410/11418/1 11393/11401/1 11396/11404/1 11411/11419/1 +f 5091/5099/1 17380/17388/1 11393/11401/1 11410/11418/1 +f 17380/17388/1 17379/17387/1 11394/11402/1 11393/11401/1 +f 3030/3038/1 11389/11397/1 11392/11400/1 3031/3039/1 +f 11411/11419/1 11396/11404/1 11389/11397/1 3030/3038/1 +f 11396/11404/1 11395/11403/1 11390/11398/1 11389/11397/1 +f 11382/11390/1 11385/11393/1 11388/11396/1 11383/11391/1 +f 11367/11375/1 3044/3052/1 11385/11393/1 11382/11390/1 +f 3044/3052/1 3043/3051/1 11386/11394/1 11385/11393/1 +f 15286/15294/1 11381/11389/1 11384/11392/1 15287/15295/1 +f 2999/3007/1 11368/11376/1 11381/11389/1 15286/15294/1 +f 11368/11376/1 11367/11375/1 11382/11390/1 11381/11389/1 +f 1738/1746/1 11377/11385/1 11380/11388/1 1739/1747/1 +f 15287/15295/1 11384/11392/1 11377/11385/1 1738/1746/1 +f 11384/11392/1 11383/11391/1 11378/11386/1 11377/11385/1 +f 11370/11378/1 11373/11381/1 11376/11384/1 11371/11379/1 +f 14043/14051/1 2152/2160/1 11373/11381/1 11370/11378/1 +f 2152/2160/1 2151/2159/1 11374/11382/1 11373/11381/1 +f 11506/11514/1 11369/11377/1 11372/11380/1 11507/11515/1 +f 1251/1259/1 14044/14052/1 11369/11377/1 11506/11514/1 +f 14044/14052/1 14043/14051/1 11370/11378/1 11369/11377/1 +f 2998/3006/1 11365/11373/1 11368/11376/1 2999/3007/1 +f 11507/11515/1 11372/11380/1 11365/11373/1 2998/3006/1 +f 11372/11380/1 11371/11379/1 11366/11374/1 11365/11373/1 +f 11358/11366/1 11361/11369/1 11364/11372/1 11359/11367/1 +f 14439/14447/1 2020/2028/1 11361/11369/1 11358/11366/1 +f 2020/2028/1 2019/2027/1 11362/11370/1 11361/11369/1 +f 11374/11382/1 11357/11365/1 11360/11368/1 11375/11383/1 +f 2151/2159/1 14440/14448/1 11357/11365/1 11374/11382/1 +f 14440/14448/1 14439/14447/1 11358/11366/1 11357/11365/1 +f 3042/3050/1 11353/11361/1 11356/11364/1 3043/3051/1 +f 11375/11383/1 11360/11368/1 11353/11361/1 3042/3050/1 +f 11360/11368/1 11359/11367/1 11354/11362/1 11353/11361/1 +f 11346/11354/1 11349/11357/1 11352/11360/1 11347/11355/1 +f 11331/11339/1 3056/3064/1 11349/11357/1 11346/11354/1 +f 3056/3064/1 3055/3063/1 11350/11358/1 11349/11357/1 +f 17098/17106/1 11345/11353/1 11348/11356/1 17099/17107/1 +f 4811/4819/1 11332/11340/1 11345/11353/1 17098/17106/1 +f 11332/11340/1 11331/11339/1 11346/11354/1 11345/11353/1 +f 1134/1142/1 11341/11349/1 11344/11352/1 1135/1143/1 +f 17099/17107/1 11348/11356/1 11341/11349/1 1134/1142/1 +f 11348/11356/1 11347/11355/1 11342/11350/1 11341/11349/1 +f 11334/11342/1 11337/11345/1 11340/11348/1 11335/11343/1 +f 11379/11387/1 3040/3048/1 11337/11345/1 11334/11342/1 +f 3040/3048/1 3039/3047/1 11338/11346/1 11337/11345/1 +f 6070/6078/1 11333/11341/1 11336/11344/1 6071/6079/1 +f 1739/1747/1 11380/11388/1 11333/11341/1 6070/6078/1 +f 11380/11388/1 11379/11387/1 11334/11342/1 11333/11341/1 +f 4810/4818/1 11329/11337/1 11332/11340/1 4811/4819/1 +f 6071/6079/1 11336/11344/1 11329/11337/1 4810/4818/1 +f 11336/11344/1 11335/11343/1 11330/11338/1 11329/11337/1 +f 11322/11330/1 11325/11333/1 11328/11336/1 11323/11331/1 +f 15327/15335/1 1724/1732/1 11325/11333/1 11322/11330/1 +f 1724/1732/1 1723/1731/1 11326/11334/1 11325/11333/1 +f 11338/11346/1 11321/11329/1 11324/11332/1 11339/11347/1 +f 3039/3047/1 15328/15336/1 11321/11329/1 11338/11346/1 +f 15328/15336/1 15327/15335/1 11322/11330/1 11321/11329/1 +f 3054/3062/1 11317/11325/1 11320/11328/1 3055/3063/1 +f 11339/11347/1 11324/11332/1 11317/11325/1 3054/3062/1 +f 11324/11332/1 11323/11331/1 11318/11326/1 11317/11325/1 +f 11310/11318/1 11313/11321/1 11316/11324/1 11311/11319/1 +f 11295/11303/1 3068/3076/1 11313/11321/1 11310/11318/1 +f 3068/3076/1 3067/3075/1 11314/11322/1 11313/11321/1 +f 15370/15378/1 11309/11317/1 11312/11320/1 15371/15379/1 +f 3083/3091/1 11296/11304/1 11309/11317/1 15370/15378/1 +f 11296/11304/1 11295/11303/1 11310/11318/1 11309/11317/1 +f 1710/1718/1 11305/11313/1 11308/11316/1 1711/1719/1 +f 15371/15379/1 11312/11320/1 11305/11313/1 1710/1718/1 +f 11312/11320/1 11311/11319/1 11306/11314/1 11305/11313/1 +f 11298/11306/1 11301/11309/1 11304/11312/1 11299/11307/1 +f 6195/6203/1 4768/4776/1 11301/11309/1 11298/11306/1 +f 4768/4776/1 4767/4775/1 11302/11310/1 11301/11309/1 +f 11254/11262/1 11297/11305/1 11300/11308/1 11255/11263/1 +f 1695/1703/1 6196/6204/1 11297/11305/1 11254/11262/1 +f 6196/6204/1 6195/6203/1 11298/11306/1 11297/11305/1 +f 3082/3090/1 11293/11301/1 11296/11304/1 3083/3091/1 +f 11255/11263/1 11300/11308/1 11293/11301/1 3082/3090/1 +f 11300/11308/1 11299/11307/1 11294/11302/1 11293/11301/1 +f 11286/11294/1 11289/11297/1 11292/11300/1 11287/11295/1 +f 17055/17063/1 1148/1156/1 11289/11297/1 11286/11294/1 +f 1148/1156/1 1147/1155/1 11290/11298/1 11289/11297/1 +f 11302/11310/1 11285/11293/1 11288/11296/1 11303/11311/1 +f 4767/4775/1 17056/17064/1 11285/11293/1 11302/11310/1 +f 17056/17064/1 17055/17063/1 11286/11294/1 11285/11293/1 +f 3066/3074/1 11281/11289/1 11284/11292/1 3067/3075/1 +f 11303/11311/1 11288/11296/1 11281/11289/1 3066/3074/1 +f 11288/11296/1 11287/11295/1 11282/11290/1 11281/11289/1 +f 11274/11282/1 11277/11285/1 11280/11288/1 11275/11283/1 +f 11259/11267/1 3080/3088/1 11277/11285/1 11274/11282/1 +f 3080/3088/1 3079/3087/1 11278/11286/1 11277/11285/1 +f 17413/17421/1 11273/11281/1 11276/11284/1 17414/17422/1 +f 17415/17423/1 11260/11268/1 11273/11281/1 17413/17421/1 +f 11260/11268/1 11259/11267/1 11274/11282/1 11273/11281/1 +f 17416/17424/1 11269/11277/1 11272/11280/1 17417/17425/1 +f 17414/17422/1 11276/11284/1 11269/11277/1 17416/17424/1 +f 11276/11284/1 11275/11283/1 11270/11278/1 11269/11277/1 +f 11262/11270/1 11265/11273/1 11268/11276/1 11263/11271/1 +f 11127/11135/1 3124/3132/1 11265/11273/1 11262/11270/1 +f 3124/3132/1 3123/3131/1 11266/11274/1 11265/11273/1 +f 17418/17426/1 11261/11269/1 11264/11272/1 17419/17427/1 +f 17420/17428/1 11128/11136/1 11261/11269/1 17418/17426/1 +f 11128/11136/1 11127/11135/1 11262/11270/1 11261/11269/1 +f 17421/17429/1 11257/11265/1 11260/11268/1 17415/17423/1 +f 17419/17427/1 11264/11272/1 11257/11265/1 17421/17429/1 +f 11264/11272/1 11263/11271/1 11258/11266/1 11257/11265/1 +f 11250/11258/1 11253/11261/1 11256/11264/1 11251/11259/1 +f 15411/15419/1 1696/1704/1 11253/11261/1 11250/11258/1 +f 1696/1704/1 1695/1703/1 11254/11262/1 11253/11261/1 +f 11266/11274/1 11249/11257/1 11252/11260/1 11267/11275/1 +f 3123/3131/1 15412/15420/1 11249/11257/1 11266/11274/1 +f 15412/15420/1 15411/15419/1 11250/11258/1 11249/11257/1 +f 3078/3086/1 11245/11253/1 11248/11256/1 3079/3087/1 +f 11267/11275/1 11252/11260/1 11245/11253/1 3078/3086/1 +f 11252/11260/1 11251/11259/1 11246/11254/1 11245/11253/1 +f 11238/11246/1 11241/11249/1 11244/11252/1 11239/11247/1 +f 11223/11231/1 3092/3100/1 11241/11249/1 11238/11246/1 +f 3092/3100/1 3091/3099/1 11242/11250/1 11241/11249/1 +f 17422/17430/1 11237/11245/1 11240/11248/1 17423/17431/1 +f 17424/17432/1 11224/11232/1 11237/11245/1 17422/17430/1 +f 11224/11232/1 11223/11231/1 11238/11246/1 11237/11245/1 +f 17425/17433/1 11233/11241/1 11236/11244/1 17426/17434/1 +f 17423/17431/1 11240/11248/1 11233/11241/1 17425/17433/1 +f 11240/11248/1 11239/11247/1 11234/11242/1 11233/11241/1 +f 11226/11234/1 11229/11237/1 11232/11240/1 11227/11235/1 +f 11271/11279/1 3076/3084/1 11229/11237/1 11226/11234/1 +f 3076/3084/1 3075/3083/1 11230/11238/1 11229/11237/1 +f 17427/17435/1 11225/11233/1 11228/11236/1 17428/17436/1 +f 17417/17425/1 11272/11280/1 11225/11233/1 17427/17435/1 +f 11272/11280/1 11271/11279/1 11226/11234/1 11225/11233/1 +f 17429/17437/1 11221/11229/1 11224/11232/1 17424/17432/1 +f 17428/17436/1 11228/11236/1 11221/11229/1 17429/17437/1 +f 11228/11236/1 11227/11235/1 11222/11230/1 11221/11229/1 +f 11214/11222/1 11217/11225/1 11220/11228/1 11215/11223/1 +f 15363/15371/1 1712/1720/1 11217/11225/1 11214/11222/1 +f 1712/1720/1 1711/1719/1 11218/11226/1 11217/11225/1 +f 11230/11238/1 11213/11221/1 11216/11224/1 11231/11239/1 +f 3075/3083/1 15364/15372/1 11213/11221/1 11230/11238/1 +f 15364/15372/1 15363/15371/1 11214/11222/1 11213/11221/1 +f 3090/3098/1 11209/11217/1 11212/11220/1 3091/3099/1 +f 11231/11239/1 11216/11224/1 11209/11217/1 3090/3098/1 +f 11216/11224/1 11215/11223/1 11210/11218/1 11209/11217/1 +f 11202/11210/1 11205/11213/1 11208/11216/1 11203/11211/1 +f 11187/11195/1 3104/3112/1 11205/11213/1 11202/11210/1 +f 3104/3112/1 3103/3111/1 11206/11214/1 11205/11213/1 +f 15406/15414/1 11201/11209/1 11204/11212/1 15407/15415/1 +f 3119/3127/1 11188/11196/1 11201/11209/1 15406/15414/1 +f 11188/11196/1 11187/11195/1 11202/11210/1 11201/11209/1 +f 1698/1706/1 11197/11205/1 11200/11208/1 1699/1707/1 +f 15407/15415/1 11204/11212/1 11197/11205/1 1698/1706/1 +f 11204/11212/1 11203/11211/1 11198/11206/1 11197/11205/1 +f 11190/11198/1 11193/11201/1 11196/11204/1 11191/11199/1 +f 6591/6599/1 4636/4644/1 11193/11201/1 11190/11198/1 +f 4636/4644/1 4635/4643/1 11194/11202/1 11193/11201/1 +f 11146/11154/1 11189/11197/1 11192/11200/1 11147/11155/1 +f 1563/1571/1 6592/6600/1 11189/11197/1 11146/11154/1 +f 6592/6600/1 6591/6599/1 11190/11198/1 11189/11197/1 +f 3118/3126/1 11185/11193/1 11188/11196/1 3119/3127/1 +f 11147/11155/1 11192/11200/1 11185/11193/1 3118/3126/1 +f 11192/11200/1 11191/11199/1 11186/11194/1 11185/11193/1 +f 11178/11186/1 11181/11189/1 11184/11192/1 11179/11187/1 +f 16923/16931/1 1192/1200/1 11181/11189/1 11178/11186/1 +f 1192/1200/1 1191/1199/1 11182/11190/1 11181/11189/1 +f 11194/11202/1 11177/11185/1 11180/11188/1 11195/11203/1 +f 4635/4643/1 16924/16932/1 11177/11185/1 11194/11202/1 +f 16924/16932/1 16923/16931/1 11178/11186/1 11177/11185/1 +f 3102/3110/1 11173/11181/1 11176/11184/1 3103/3111/1 +f 11195/11203/1 11180/11188/1 11173/11181/1 3102/3110/1 +f 11180/11188/1 11179/11187/1 11174/11182/1 11173/11181/1 +f 11166/11174/1 11169/11177/1 11172/11180/1 11167/11175/1 +f 11151/11159/1 3116/3124/1 11169/11177/1 11166/11174/1 +f 3116/3124/1 3115/3123/1 11170/11178/1 11169/11177/1 +f 17430/17438/1 11165/11173/1 11168/11176/1 17431/17439/1 +f 17432/17440/1 11152/11160/1 11165/11173/1 17430/17438/1 +f 11152/11160/1 11151/11159/1 11166/11174/1 11165/11173/1 +f 17433/17441/1 11161/11169/1 11164/11172/1 17434/17442/1 +f 17431/17439/1 11168/11176/1 11161/11169/1 17433/17441/1 +f 11168/11176/1 11167/11175/1 11162/11170/1 11161/11169/1 +f 11154/11162/1 11157/11165/1 11160/11168/1 11155/11163/1 +f 9939/9947/1 3520/3528/1 11157/11165/1 11154/11162/1 +f 3520/3528/1 3519/3527/1 11158/11166/1 11157/11165/1 +f 17435/17443/1 11153/11161/1 11156/11164/1 17436/17444/1 +f 17437/17445/1 9940/9948/1 11153/11161/1 17435/17443/1 +f 9940/9948/1 9939/9947/1 11154/11162/1 11153/11161/1 +f 17438/17446/1 11149/11157/1 11152/11160/1 17432/17440/1 +f 17436/17444/1 11156/11164/1 11149/11157/1 17438/17446/1 +f 11156/11164/1 11155/11163/1 11150/11158/1 11149/11157/1 +f 11142/11150/1 11145/11153/1 11148/11156/1 11143/11151/1 +f 15807/15815/1 1564/1572/1 11145/11153/1 11142/11150/1 +f 1564/1572/1 1563/1571/1 11146/11154/1 11145/11153/1 +f 11158/11166/1 11141/11149/1 11144/11152/1 11159/11167/1 +f 3519/3527/1 15808/15816/1 11141/11149/1 11158/11166/1 +f 15808/15816/1 15807/15815/1 11142/11150/1 11141/11149/1 +f 3114/3122/1 11137/11145/1 11140/11148/1 3115/3123/1 +f 11159/11167/1 11144/11152/1 11137/11145/1 3114/3122/1 +f 11144/11152/1 11143/11151/1 11138/11146/1 11137/11145/1 +f 11130/11138/1 11133/11141/1 11136/11144/1 11131/11139/1 +f 11115/11123/1 3128/3136/1 11133/11141/1 11130/11138/1 +f 3128/3136/1 3127/3135/1 11134/11142/1 11133/11141/1 +f 17439/17447/1 11129/11137/1 11132/11140/1 17440/17448/1 +f 17441/17449/1 11116/11124/1 11129/11137/1 17439/17447/1 +f 11116/11124/1 11115/11123/1 11130/11138/1 11129/11137/1 +f 17442/17450/1 11125/11133/1 11128/11136/1 17420/17428/1 +f 17440/17448/1 11132/11140/1 11125/11133/1 17442/17450/1 +f 11132/11140/1 11131/11139/1 11126/11134/1 11125/11133/1 +f 11118/11126/1 11121/11129/1 11124/11132/1 11119/11127/1 +f 11163/11171/1 3112/3120/1 11121/11129/1 11118/11126/1 +f 3112/3120/1 3111/3119/1 11122/11130/1 11121/11129/1 +f 17443/17451/1 11117/11125/1 11120/11128/1 17444/17452/1 +f 17434/17442/1 11164/11172/1 11117/11125/1 17443/17451/1 +f 11164/11172/1 11163/11171/1 11118/11126/1 11117/11125/1 +f 17445/17453/1 11113/11121/1 11116/11124/1 17441/17449/1 +f 17444/17452/1 11120/11128/1 11113/11121/1 17445/17453/1 +f 11120/11128/1 11119/11127/1 11114/11122/1 11113/11121/1 +f 11106/11114/1 11109/11117/1 11112/11120/1 11107/11115/1 +f 15399/15407/1 1700/1708/1 11109/11117/1 11106/11114/1 +f 1700/1708/1 1699/1707/1 11110/11118/1 11109/11117/1 +f 11122/11130/1 11105/11113/1 11108/11116/1 11123/11131/1 +f 3111/3119/1 15400/15408/1 11105/11113/1 11122/11130/1 +f 15400/15408/1 15399/15407/1 11106/11114/1 11105/11113/1 +f 3126/3134/1 11101/11109/1 11104/11112/1 3127/3135/1 +f 11123/11131/1 11108/11116/1 11101/11109/1 3126/3134/1 +f 11108/11116/1 11107/11115/1 11102/11110/1 11101/11109/1 +f 11094/11102/1 11097/11105/1 11100/11108/1 11095/11103/1 +f 11079/11087/1 3140/3148/1 11097/11105/1 11094/11102/1 +f 3140/3148/1 3139/3147/1 11098/11106/1 11097/11105/1 +f 15442/15450/1 11093/11101/1 11096/11104/1 15443/15451/1 +f 3155/3163/1 11080/11088/1 11093/11101/1 15442/15450/1 +f 11080/11088/1 11079/11087/1 11094/11102/1 11093/11101/1 +f 1686/1694/1 11089/11097/1 11092/11100/1 1687/1695/1 +f 15443/15451/1 11096/11104/1 11089/11097/1 1686/1694/1 +f 11096/11104/1 11095/11103/1 11090/11098/1 11089/11097/1 +f 11082/11090/1 11085/11093/1 11088/11096/1 11083/11091/1 +f 5403/5411/1 5032/5040/1 11085/11093/1 11082/11090/1 +f 5032/5040/1 5031/5039/1 11086/11094/1 11085/11093/1 +f 11038/11046/1 11081/11089/1 11084/11092/1 11039/11047/1 +f 1959/1967/1 5404/5412/1 11081/11089/1 11038/11046/1 +f 5404/5412/1 5403/5411/1 11082/11090/1 11081/11089/1 +f 3154/3162/1 11077/11085/1 11080/11088/1 3155/3163/1 +f 11039/11047/1 11084/11092/1 11077/11085/1 3154/3162/1 +f 11084/11092/1 11083/11091/1 11078/11086/1 11077/11085/1 +f 11070/11078/1 11073/11081/1 11076/11084/1 11071/11079/1 +f 17319/17327/1 1060/1068/1 11073/11081/1 11070/11078/1 +f 1060/1068/1 1059/1067/1 11074/11082/1 11073/11081/1 +f 11086/11094/1 11069/11077/1 11072/11080/1 11087/11095/1 +f 5031/5039/1 17320/17328/1 11069/11077/1 11086/11094/1 +f 17320/17328/1 17319/17327/1 11070/11078/1 11069/11077/1 +f 3138/3146/1 11065/11073/1 11068/11076/1 3139/3147/1 +f 11087/11095/1 11072/11080/1 11065/11073/1 3138/3146/1 +f 11072/11080/1 11071/11079/1 11066/11074/1 11065/11073/1 +f 11058/11066/1 11061/11069/1 11064/11072/1 11059/11067/1 +f 11043/11051/1 3152/3160/1 11061/11069/1 11058/11066/1 +f 3152/3160/1 3151/3159/1 11062/11070/1 11061/11069/1 +f 15394/15402/1 11057/11065/1 11060/11068/1 15395/15403/1 +f 3107/3115/1 11044/11052/1 11057/11065/1 15394/15402/1 +f 11044/11052/1 11043/11051/1 11058/11066/1 11057/11065/1 +f 1702/1710/1 11053/11061/1 11056/11064/1 1703/1711/1 +f 15395/15403/1 11060/11068/1 11053/11061/1 1702/1710/1 +f 11060/11068/1 11059/11067/1 11054/11062/1 11053/11061/1 +f 11046/11054/1 11049/11057/1 11052/11060/1 11047/11055/1 +f 13503/13511/1 2332/2340/1 11049/11057/1 11046/11054/1 +f 2332/2340/1 2331/2339/1 11050/11058/1 11049/11057/1 +f 11182/11190/1 11045/11053/1 11048/11056/1 11183/11191/1 +f 1191/1199/1 13504/13512/1 11045/11053/1 11182/11190/1 +f 13504/13512/1 13503/13511/1 11046/11054/1 11045/11053/1 +f 3106/3114/1 11041/11049/1 11044/11052/1 3107/3115/1 +f 11183/11191/1 11048/11056/1 11041/11049/1 3106/3114/1 +f 11048/11056/1 11047/11055/1 11042/11050/1 11041/11049/1 +f 11034/11042/1 11037/11045/1 11040/11048/1 11035/11043/1 +f 14619/14627/1 1960/1968/1 11037/11045/1 11034/11042/1 +f 1960/1968/1 1959/1967/1 11038/11046/1 11037/11045/1 +f 11050/11058/1 11033/11041/1 11036/11044/1 11051/11059/1 +f 2331/2339/1 14620/14628/1 11033/11041/1 11050/11058/1 +f 14620/14628/1 14619/14627/1 11034/11042/1 11033/11041/1 +f 3150/3158/1 11029/11037/1 11032/11040/1 3151/3159/1 +f 11051/11059/1 11036/11044/1 11029/11037/1 3150/3158/1 +f 11036/11044/1 11035/11043/1 11030/11038/1 11029/11037/1 +f 11022/11030/1 11025/11033/1 11028/11036/1 11023/11031/1 +f 11007/11015/1 3164/3172/1 11025/11033/1 11022/11030/1 +f 3164/3172/1 3163/3171/1 11026/11034/1 11025/11033/1 +f 17062/17070/1 11021/11029/1 11024/11032/1 17063/17071/1 +f 4775/4783/1 11008/11016/1 11021/11029/1 17062/17070/1 +f 11008/11016/1 11007/11015/1 11022/11030/1 11021/11029/1 +f 1146/1154/1 11017/11025/1 11020/11028/1 1147/1155/1 +f 17063/17071/1 11024/11032/1 11017/11025/1 1146/1154/1 +f 11024/11032/1 11023/11031/1 11018/11026/1 11017/11025/1 +f 11010/11018/1 11013/11021/1 11016/11024/1 11011/11019/1 +f 11055/11063/1 3148/3156/1 11013/11021/1 11010/11018/1 +f 3148/3156/1 3147/3155/1 11014/11022/1 11013/11021/1 +f 6178/6186/1 11009/11017/1 11012/11020/1 6179/6187/1 +f 1703/1711/1 11056/11064/1 11009/11017/1 6178/6186/1 +f 11056/11064/1 11055/11063/1 11010/11018/1 11009/11017/1 +f 4774/4782/1 11005/11013/1 11008/11016/1 4775/4783/1 +f 6179/6187/1 11012/11020/1 11005/11013/1 4774/4782/1 +f 11012/11020/1 11011/11019/1 11006/11014/1 11005/11013/1 +f 10998/11006/1 11001/11009/1 11004/11012/1 10999/11007/1 +f 15435/15443/1 1688/1696/1 11001/11009/1 10998/11006/1 +f 1688/1696/1 1687/1695/1 11002/11010/1 11001/11009/1 +f 11014/11022/1 10997/11005/1 11000/11008/1 11015/11023/1 +f 3147/3155/1 15436/15444/1 10997/11005/1 11014/11022/1 +f 15436/15444/1 15435/15443/1 10998/11006/1 10997/11005/1 +f 3162/3170/1 10993/11001/1 10996/11004/1 3163/3171/1 +f 11015/11023/1 11000/11008/1 10993/11001/1 3162/3170/1 +f 11000/11008/1 10999/11007/1 10994/11002/1 10993/11001/1 +f 10986/10994/1 10989/10997/1 10992/11000/1 10987/10995/1 +f 10971/10979/1 3176/3184/1 10989/10997/1 10986/10994/1 +f 3176/3184/1 3175/3183/1 10990/10998/1 10989/10997/1 +f 15478/15486/1 10985/10993/1 10988/10996/1 15479/15487/1 +f 3191/3199/1 10972/10980/1 10985/10993/1 15478/15486/1 +f 10972/10980/1 10971/10979/1 10986/10994/1 10985/10993/1 +f 1674/1682/1 10981/10989/1 10984/10992/1 1675/1683/1 +f 15479/15487/1 10988/10996/1 10981/10989/1 1674/1682/1 +f 10988/10996/1 10987/10995/1 10982/10990/1 10981/10989/1 +f 10974/10982/1 10977/10985/1 10980/10988/1 10975/10983/1 +f 6303/6311/1 4732/4740/1 10977/10985/1 10974/10982/1 +f 4732/4740/1 4731/4739/1 10978/10986/1 10977/10985/1 +f 10930/10938/1 10973/10981/1 10976/10984/1 10931/10939/1 +f 1659/1667/1 6304/6312/1 10973/10981/1 10930/10938/1 +f 6304/6312/1 6303/6311/1 10974/10982/1 10973/10981/1 +f 3190/3198/1 10969/10977/1 10972/10980/1 3191/3199/1 +f 10931/10939/1 10976/10984/1 10969/10977/1 3190/3198/1 +f 10976/10984/1 10975/10983/1 10970/10978/1 10969/10977/1 +f 10962/10970/1 10965/10973/1 10968/10976/1 10963/10971/1 +f 17019/17027/1 1160/1168/1 10965/10973/1 10962/10970/1 +f 1160/1168/1 1159/1167/1 10966/10974/1 10965/10973/1 +f 10978/10986/1 10961/10969/1 10964/10972/1 10979/10987/1 +f 4731/4739/1 17020/17028/1 10961/10969/1 10978/10986/1 +f 17020/17028/1 17019/17027/1 10962/10970/1 10961/10969/1 +f 3174/3182/1 10957/10965/1 10960/10968/1 3175/3183/1 +f 10979/10987/1 10964/10972/1 10957/10965/1 3174/3182/1 +f 10964/10972/1 10963/10971/1 10958/10966/1 10957/10965/1 +f 10950/10958/1 10953/10961/1 10956/10964/1 10951/10959/1 +f 10935/10943/1 3188/3196/1 10953/10961/1 10950/10958/1 +f 3188/3196/1 3187/3195/1 10954/10962/1 10953/10961/1 +f 17446/17454/1 10949/10957/1 10952/10960/1 17447/17455/1 +f 17448/17456/1 10936/10944/1 10949/10957/1 17446/17454/1 +f 10936/10944/1 10935/10943/1 10950/10958/1 10949/10957/1 +f 17449/17457/1 10945/10953/1 10948/10956/1 17450/17458/1 +f 17447/17455/1 10952/10960/1 10945/10953/1 17449/17457/1 +f 10952/10960/1 10951/10959/1 10946/10954/1 10945/10953/1 +f 10938/10946/1 10941/10949/1 10944/10952/1 10939/10947/1 +f 10803/10811/1 3232/3240/1 10941/10949/1 10938/10946/1 +f 3232/3240/1 3231/3239/1 10942/10950/1 10941/10949/1 +f 17451/17459/1 10937/10945/1 10940/10948/1 17452/17460/1 +f 17453/17461/1 10804/10812/1 10937/10945/1 17451/17459/1 +f 10804/10812/1 10803/10811/1 10938/10946/1 10937/10945/1 +f 17454/17462/1 10933/10941/1 10936/10944/1 17448/17456/1 +f 17452/17460/1 10940/10948/1 10933/10941/1 17454/17462/1 +f 10940/10948/1 10939/10947/1 10934/10942/1 10933/10941/1 +f 10926/10934/1 10929/10937/1 10932/10940/1 10927/10935/1 +f 15519/15527/1 1660/1668/1 10929/10937/1 10926/10934/1 +f 1660/1668/1 1659/1667/1 10930/10938/1 10929/10937/1 +f 10942/10950/1 10925/10933/1 10928/10936/1 10943/10951/1 +f 3231/3239/1 15520/15528/1 10925/10933/1 10942/10950/1 +f 15520/15528/1 15519/15527/1 10926/10934/1 10925/10933/1 +f 3186/3194/1 10921/10929/1 10924/10932/1 3187/3195/1 +f 10943/10951/1 10928/10936/1 10921/10929/1 3186/3194/1 +f 10928/10936/1 10927/10935/1 10922/10930/1 10921/10929/1 +f 10914/10922/1 10917/10925/1 10920/10928/1 10915/10923/1 +f 10899/10907/1 3200/3208/1 10917/10925/1 10914/10922/1 +f 3200/3208/1 3199/3207/1 10918/10926/1 10917/10925/1 +f 17455/17463/1 10913/10921/1 10916/10924/1 17456/17464/1 +f 17457/17465/1 10900/10908/1 10913/10921/1 17455/17463/1 +f 10900/10908/1 10899/10907/1 10914/10922/1 10913/10921/1 +f 17458/17466/1 10909/10917/1 10912/10920/1 17459/17467/1 +f 17456/17464/1 10916/10924/1 10909/10917/1 17458/17466/1 +f 10916/10924/1 10915/10923/1 10910/10918/1 10909/10917/1 +f 10902/10910/1 10905/10913/1 10908/10916/1 10903/10911/1 +f 10947/10955/1 3184/3192/1 10905/10913/1 10902/10910/1 +f 3184/3192/1 3183/3191/1 10906/10914/1 10905/10913/1 +f 17460/17468/1 10901/10909/1 10904/10912/1 17461/17469/1 +f 17450/17458/1 10948/10956/1 10901/10909/1 17460/17468/1 +f 10948/10956/1 10947/10955/1 10902/10910/1 10901/10909/1 +f 17462/17470/1 10897/10905/1 10900/10908/1 17457/17465/1 +f 17461/17469/1 10904/10912/1 10897/10905/1 17462/17470/1 +f 10904/10912/1 10903/10911/1 10898/10906/1 10897/10905/1 +f 10890/10898/1 10893/10901/1 10896/10904/1 10891/10899/1 +f 15471/15479/1 1676/1684/1 10893/10901/1 10890/10898/1 +f 1676/1684/1 1675/1683/1 10894/10902/1 10893/10901/1 +f 10906/10914/1 10889/10897/1 10892/10900/1 10907/10915/1 +f 3183/3191/1 15472/15480/1 10889/10897/1 10906/10914/1 +f 15472/15480/1 15471/15479/1 10890/10898/1 10889/10897/1 +f 3198/3206/1 10885/10893/1 10888/10896/1 3199/3207/1 +f 10907/10915/1 10892/10900/1 10885/10893/1 3198/3206/1 +f 10892/10900/1 10891/10899/1 10886/10894/1 10885/10893/1 +f 10878/10886/1 10881/10889/1 10884/10892/1 10879/10887/1 +f 10863/10871/1 3212/3220/1 10881/10889/1 10878/10886/1 +f 3212/3220/1 3211/3219/1 10882/10890/1 10881/10889/1 +f 15514/15522/1 10877/10885/1 10880/10888/1 15515/15523/1 +f 3227/3235/1 10864/10872/1 10877/10885/1 15514/15522/1 +f 10864/10872/1 10863/10871/1 10878/10886/1 10877/10885/1 +f 1662/1670/1 10873/10881/1 10876/10884/1 1663/1671/1 +f 15515/15523/1 10880/10888/1 10873/10881/1 1662/1670/1 +f 10880/10888/1 10879/10887/1 10874/10882/1 10873/10881/1 +f 10866/10874/1 10869/10877/1 10872/10880/1 10867/10875/1 +f 6159/6167/1 4780/4788/1 10869/10877/1 10866/10874/1 +f 4780/4788/1 4779/4787/1 10870/10878/1 10869/10877/1 +f 10822/10830/1 10865/10873/1 10868/10876/1 10823/10831/1 +f 1707/1715/1 6160/6168/1 10865/10873/1 10822/10830/1 +f 6160/6168/1 6159/6167/1 10866/10874/1 10865/10873/1 +f 3226/3234/1 10861/10869/1 10864/10872/1 3227/3235/1 +f 10823/10831/1 10868/10876/1 10861/10869/1 3226/3234/1 +f 10868/10876/1 10867/10875/1 10862/10870/1 10861/10869/1 +f 10854/10862/1 10857/10865/1 10860/10868/1 10855/10863/1 +f 17067/17075/1 1144/1152/1 10857/10865/1 10854/10862/1 +f 1144/1152/1 1143/1151/1 10858/10866/1 10857/10865/1 +f 10870/10878/1 10853/10861/1 10856/10864/1 10871/10879/1 +f 4779/4787/1 17068/17076/1 10853/10861/1 10870/10878/1 +f 17068/17076/1 17067/17075/1 10854/10862/1 10853/10861/1 +f 3210/3218/1 10849/10857/1 10852/10860/1 3211/3219/1 +f 10871/10879/1 10856/10864/1 10849/10857/1 3210/3218/1 +f 10856/10864/1 10855/10863/1 10850/10858/1 10849/10857/1 +f 10842/10850/1 10845/10853/1 10848/10856/1 10843/10851/1 +f 10827/10835/1 3224/3232/1 10845/10853/1 10842/10850/1 +f 3224/3232/1 3223/3231/1 10846/10854/1 10845/10853/1 +f 17463/17471/1 10841/10849/1 10844/10852/1 17464/17472/1 +f 17465/17473/1 10828/10836/1 10841/10849/1 17463/17471/1 +f 10828/10836/1 10827/10835/1 10842/10850/1 10841/10849/1 +f 17466/17474/1 10837/10845/1 10840/10848/1 17467/17475/1 +f 17464/17472/1 10844/10852/1 10837/10845/1 17466/17474/1 +f 10844/10852/1 10843/10851/1 10838/10846/1 10837/10845/1 +f 10830/10838/1 10833/10841/1 10836/10844/1 10831/10839/1 +f 11235/11243/1 3088/3096/1 10833/10841/1 10830/10838/1 +f 3088/3096/1 3087/3095/1 10834/10842/1 10833/10841/1 +f 17468/17476/1 10829/10837/1 10832/10840/1 17469/17477/1 +f 17426/17434/1 11236/11244/1 10829/10837/1 17468/17476/1 +f 11236/11244/1 11235/11243/1 10830/10838/1 10829/10837/1 +f 17470/17478/1 10825/10833/1 10828/10836/1 17465/17473/1 +f 17469/17477/1 10832/10840/1 10825/10833/1 17470/17478/1 +f 10832/10840/1 10831/10839/1 10826/10834/1 10825/10833/1 +f 10818/10826/1 10821/10829/1 10824/10832/1 10819/10827/1 +f 15375/15383/1 1708/1716/1 10821/10829/1 10818/10826/1 +f 1708/1716/1 1707/1715/1 10822/10830/1 10821/10829/1 +f 10834/10842/1 10817/10825/1 10820/10828/1 10835/10843/1 +f 3087/3095/1 15376/15384/1 10817/10825/1 10834/10842/1 +f 15376/15384/1 15375/15383/1 10818/10826/1 10817/10825/1 +f 3222/3230/1 10813/10821/1 10816/10824/1 3223/3231/1 +f 10835/10843/1 10820/10828/1 10813/10821/1 3222/3230/1 +f 10820/10828/1 10819/10827/1 10814/10822/1 10813/10821/1 +f 10806/10814/1 10809/10817/1 10812/10820/1 10807/10815/1 +f 10791/10799/1 3236/3244/1 10809/10817/1 10806/10814/1 +f 3236/3244/1 3235/3243/1 10810/10818/1 10809/10817/1 +f 17471/17479/1 10805/10813/1 10808/10816/1 17472/17480/1 +f 17473/17481/1 10792/10800/1 10805/10813/1 17471/17479/1 +f 10792/10800/1 10791/10799/1 10806/10814/1 10805/10813/1 +f 17474/17482/1 10801/10809/1 10804/10812/1 17453/17461/1 +f 17472/17480/1 10808/10816/1 10801/10809/1 17474/17482/1 +f 10808/10816/1 10807/10815/1 10802/10810/1 10801/10809/1 +f 10794/10802/1 10797/10805/1 10800/10808/1 10795/10803/1 +f 10839/10847/1 3220/3228/1 10797/10805/1 10794/10802/1 +f 3220/3228/1 3219/3227/1 10798/10806/1 10797/10805/1 +f 17475/17483/1 10793/10801/1 10796/10804/1 17476/17484/1 +f 17467/17475/1 10840/10848/1 10793/10801/1 17475/17483/1 +f 10840/10848/1 10839/10847/1 10794/10802/1 10793/10801/1 +f 17477/17485/1 10789/10797/1 10792/10800/1 17473/17481/1 +f 17476/17484/1 10796/10804/1 10789/10797/1 17477/17485/1 +f 10796/10804/1 10795/10803/1 10790/10798/1 10789/10797/1 +f 10782/10790/1 10785/10793/1 10788/10796/1 10783/10791/1 +f 15507/15515/1 1664/1672/1 10785/10793/1 10782/10790/1 +f 1664/1672/1 1663/1671/1 10786/10794/1 10785/10793/1 +f 10798/10806/1 10781/10789/1 10784/10792/1 10799/10807/1 +f 3219/3227/1 15508/15516/1 10781/10789/1 10798/10806/1 +f 15508/15516/1 15507/15515/1 10782/10790/1 10781/10789/1 +f 3234/3242/1 10777/10785/1 10780/10788/1 3235/3243/1 +f 10799/10807/1 10784/10792/1 10777/10785/1 3234/3242/1 +f 10784/10792/1 10783/10791/1 10778/10786/1 10777/10785/1 +f 10770/10778/1 10773/10781/1 10776/10784/1 10771/10779/1 +f 10755/10763/1 3248/3256/1 10773/10781/1 10770/10778/1 +f 3248/3256/1 3247/3255/1 10774/10782/1 10773/10781/1 +f 15550/15558/1 10769/10777/1 10772/10780/1 15551/15559/1 +f 3263/3271/1 10756/10764/1 10769/10777/1 15550/15558/1 +f 10756/10764/1 10755/10763/1 10770/10778/1 10769/10777/1 +f 1650/1658/1 10765/10773/1 10768/10776/1 1651/1659/1 +f 15551/15559/1 10772/10780/1 10765/10773/1 1650/1658/1 +f 10772/10780/1 10771/10779/1 10766/10774/1 10765/10773/1 +f 10758/10766/1 10761/10769/1 10764/10772/1 10759/10767/1 +f 5547/5555/1 4984/4992/1 10761/10769/1 10758/10766/1 +f 4984/4992/1 4983/4991/1 10762/10770/1 10761/10769/1 +f 10714/10722/1 10757/10765/1 10760/10768/1 10715/10723/1 +f 1911/1919/1 5548/5556/1 10757/10765/1 10714/10722/1 +f 5548/5556/1 5547/5555/1 10758/10766/1 10757/10765/1 +f 3262/3270/1 10753/10761/1 10756/10764/1 3263/3271/1 +f 10715/10723/1 10760/10768/1 10753/10761/1 3262/3270/1 +f 10760/10768/1 10759/10767/1 10754/10762/1 10753/10761/1 +f 10746/10754/1 10749/10757/1 10752/10760/1 10747/10755/1 +f 17271/17279/1 1076/1084/1 10749/10757/1 10746/10754/1 +f 1076/1084/1 1075/1083/1 10750/10758/1 10749/10757/1 +f 10762/10770/1 10745/10753/1 10748/10756/1 10763/10771/1 +f 4983/4991/1 17272/17280/1 10745/10753/1 10762/10770/1 +f 17272/17280/1 17271/17279/1 10746/10754/1 10745/10753/1 +f 3246/3254/1 10741/10749/1 10744/10752/1 3247/3255/1 +f 10763/10771/1 10748/10756/1 10741/10749/1 3246/3254/1 +f 10748/10756/1 10747/10755/1 10742/10750/1 10741/10749/1 +f 10734/10742/1 10737/10745/1 10740/10748/1 10735/10743/1 +f 10719/10727/1 3260/3268/1 10737/10745/1 10734/10742/1 +f 3260/3268/1 3259/3267/1 10738/10746/1 10737/10745/1 +f 15502/15510/1 10733/10741/1 10736/10744/1 15503/15511/1 +f 3215/3223/1 10720/10728/1 10733/10741/1 15502/15510/1 +f 10720/10728/1 10719/10727/1 10734/10742/1 10733/10741/1 +f 1666/1674/1 10729/10737/1 10732/10740/1 1667/1675/1 +f 15503/15511/1 10736/10744/1 10729/10737/1 1666/1674/1 +f 10736/10744/1 10735/10743/1 10730/10738/1 10729/10737/1 +f 10722/10730/1 10725/10733/1 10728/10736/1 10723/10731/1 +f 13071/13079/1 2476/2484/1 10725/10733/1 10722/10730/1 +f 2476/2484/1 2475/2483/1 10726/10734/1 10725/10733/1 +f 10858/10866/1 10721/10729/1 10724/10732/1 10859/10867/1 +f 1143/1151/1 13072/13080/1 10721/10729/1 10858/10866/1 +f 13072/13080/1 13071/13079/1 10722/10730/1 10721/10729/1 +f 3214/3222/1 10717/10725/1 10720/10728/1 3215/3223/1 +f 10859/10867/1 10724/10732/1 10717/10725/1 3214/3222/1 +f 10724/10732/1 10723/10731/1 10718/10726/1 10717/10725/1 +f 10710/10718/1 10713/10721/1 10716/10724/1 10711/10719/1 +f 14763/14771/1 1912/1920/1 10713/10721/1 10710/10718/1 +f 1912/1920/1 1911/1919/1 10714/10722/1 10713/10721/1 +f 10726/10734/1 10709/10717/1 10712/10720/1 10727/10735/1 +f 2475/2483/1 14764/14772/1 10709/10717/1 10726/10734/1 +f 14764/14772/1 14763/14771/1 10710/10718/1 10709/10717/1 +f 3258/3266/1 10705/10713/1 10708/10716/1 3259/3267/1 +f 10727/10735/1 10712/10720/1 10705/10713/1 3258/3266/1 +f 10712/10720/1 10711/10719/1 10706/10714/1 10705/10713/1 +f 10698/10706/1 10701/10709/1 10704/10712/1 10699/10707/1 +f 10683/10691/1 3272/3280/1 10701/10709/1 10698/10706/1 +f 3272/3280/1 3271/3279/1 10702/10710/1 10701/10709/1 +f 17026/17034/1 10697/10705/1 10700/10708/1 17027/17035/1 +f 4739/4747/1 10684/10692/1 10697/10705/1 17026/17034/1 +f 10684/10692/1 10683/10691/1 10698/10706/1 10697/10705/1 +f 1158/1166/1 10693/10701/1 10696/10704/1 1159/1167/1 +f 17027/17035/1 10700/10708/1 10693/10701/1 1158/1166/1 +f 10700/10708/1 10699/10707/1 10694/10702/1 10693/10701/1 +f 10686/10694/1 10689/10697/1 10692/10700/1 10687/10695/1 +f 10731/10739/1 3256/3264/1 10689/10697/1 10686/10694/1 +f 3256/3264/1 3255/3263/1 10690/10698/1 10689/10697/1 +f 6286/6294/1 10685/10693/1 10688/10696/1 6287/6295/1 +f 1667/1675/1 10732/10740/1 10685/10693/1 6286/6294/1 +f 10732/10740/1 10731/10739/1 10686/10694/1 10685/10693/1 +f 4738/4746/1 10681/10689/1 10684/10692/1 4739/4747/1 +f 6287/6295/1 10688/10696/1 10681/10689/1 4738/4746/1 +f 10688/10696/1 10687/10695/1 10682/10690/1 10681/10689/1 +f 10674/10682/1 10677/10685/1 10680/10688/1 10675/10683/1 +f 15543/15551/1 1652/1660/1 10677/10685/1 10674/10682/1 +f 1652/1660/1 1651/1659/1 10678/10686/1 10677/10685/1 +f 10690/10698/1 10673/10681/1 10676/10684/1 10691/10699/1 +f 3255/3263/1 15544/15552/1 10673/10681/1 10690/10698/1 +f 15544/15552/1 15543/15551/1 10674/10682/1 10673/10681/1 +f 3270/3278/1 10669/10677/1 10672/10680/1 3271/3279/1 +f 10691/10699/1 10676/10684/1 10669/10677/1 3270/3278/1 +f 10676/10684/1 10675/10683/1 10670/10678/1 10669/10677/1 +f 10662/10670/1 10665/10673/1 10668/10676/1 10663/10671/1 +f 10647/10655/1 3284/3292/1 10665/10673/1 10662/10670/1 +f 3284/3292/1 3283/3291/1 10666/10674/1 10665/10673/1 +f 15586/15594/1 10661/10669/1 10664/10672/1 15587/15595/1 +f 3299/3307/1 10648/10656/1 10661/10669/1 15586/15594/1 +f 10648/10656/1 10647/10655/1 10662/10670/1 10661/10669/1 +f 1638/1646/1 10657/10665/1 10660/10668/1 1639/1647/1 +f 15587/15595/1 10664/10672/1 10657/10665/1 1638/1646/1 +f 10664/10672/1 10663/10671/1 10658/10666/1 10657/10665/1 +f 10650/10658/1 10653/10661/1 10656/10664/1 10651/10659/1 +f 6411/6419/1 4696/4704/1 10653/10661/1 10650/10658/1 +f 4696/4704/1 4695/4703/1 10654/10662/1 10653/10661/1 +f 10606/10614/1 10649/10657/1 10652/10660/1 10607/10615/1 +f 1623/1631/1 6412/6420/1 10649/10657/1 10606/10614/1 +f 6412/6420/1 6411/6419/1 10650/10658/1 10649/10657/1 +f 3298/3306/1 10645/10653/1 10648/10656/1 3299/3307/1 +f 10607/10615/1 10652/10660/1 10645/10653/1 3298/3306/1 +f 10652/10660/1 10651/10659/1 10646/10654/1 10645/10653/1 +f 10638/10646/1 10641/10649/1 10644/10652/1 10639/10647/1 +f 16983/16991/1 1172/1180/1 10641/10649/1 10638/10646/1 +f 1172/1180/1 1171/1179/1 10642/10650/1 10641/10649/1 +f 10654/10662/1 10637/10645/1 10640/10648/1 10655/10663/1 +f 4695/4703/1 16984/16992/1 10637/10645/1 10654/10662/1 +f 16984/16992/1 16983/16991/1 10638/10646/1 10637/10645/1 +f 3282/3290/1 10633/10641/1 10636/10644/1 3283/3291/1 +f 10655/10663/1 10640/10648/1 10633/10641/1 3282/3290/1 +f 10640/10648/1 10639/10647/1 10634/10642/1 10633/10641/1 +f 10626/10634/1 10629/10637/1 10632/10640/1 10627/10635/1 +f 10611/10619/1 3296/3304/1 10629/10637/1 10626/10634/1 +f 3296/3304/1 3295/3303/1 10630/10638/1 10629/10637/1 +f 14638/14646/1 10625/10633/1 10628/10636/1 14639/14647/1 +f 2351/2359/1 10612/10620/1 10625/10633/1 14638/14646/1 +f 10612/10620/1 10611/10619/1 10626/10634/1 10625/10633/1 +f 1954/1962/1 10621/10629/1 10624/10632/1 1955/1963/1 +f 14639/14647/1 10628/10636/1 10621/10629/1 1954/1962/1 +f 10628/10636/1 10627/10635/1 10622/10630/1 10621/10629/1 +f 10614/10622/1 10617/10625/1 10620/10628/1 10615/10623/1 +f 10479/10487/1 3340/3348/1 10617/10625/1 10614/10622/1 +f 3340/3348/1 3339/3347/1 10618/10626/1 10617/10625/1 +f 13450/13458/1 10613/10621/1 10616/10624/1 13451/13459/1 +f 1187/1195/1 10480/10488/1 10613/10621/1 13450/13458/1 +f 10480/10488/1 10479/10487/1 10614/10622/1 10613/10621/1 +f 2350/2358/1 10609/10617/1 10612/10620/1 2351/2359/1 +f 13451/13459/1 10616/10624/1 10609/10617/1 2350/2358/1 +f 10616/10624/1 10615/10623/1 10610/10618/1 10609/10617/1 +f 10602/10610/1 10605/10613/1 10608/10616/1 10603/10611/1 +f 15627/15635/1 1624/1632/1 10605/10613/1 10602/10610/1 +f 1624/1632/1 1623/1631/1 10606/10614/1 10605/10613/1 +f 10618/10626/1 10601/10609/1 10604/10612/1 10619/10627/1 +f 3339/3347/1 15628/15636/1 10601/10609/1 10618/10626/1 +f 15628/15636/1 15627/15635/1 10602/10610/1 10601/10609/1 +f 3294/3302/1 10597/10605/1 10600/10608/1 3295/3303/1 +f 10619/10627/1 10604/10612/1 10597/10605/1 3294/3302/1 +f 10604/10612/1 10603/10611/1 10598/10606/1 10597/10605/1 +f 10590/10598/1 10593/10601/1 10596/10604/1 10591/10599/1 +f 10575/10583/1 3308/3316/1 10593/10601/1 10590/10598/1 +f 3308/3316/1 3307/3315/1 10594/10602/1 10593/10601/1 +f 17314/17322/1 10589/10597/1 10592/10600/1 17315/17323/1 +f 5027/5035/1 10576/10584/1 10589/10597/1 17314/17322/1 +f 10576/10584/1 10575/10583/1 10590/10598/1 10589/10597/1 +f 1062/1070/1 10585/10593/1 10588/10596/1 1063/1071/1 +f 17315/17323/1 10592/10600/1 10585/10593/1 1062/1070/1 +f 10592/10600/1 10591/10599/1 10586/10594/1 10585/10593/1 +f 10578/10586/1 10581/10589/1 10584/10592/1 10579/10587/1 +f 10623/10631/1 3292/3300/1 10581/10589/1 10578/10586/1 +f 3292/3300/1 3291/3299/1 10582/10590/1 10581/10589/1 +f 5422/5430/1 10577/10585/1 10580/10588/1 5423/5431/1 +f 1955/1963/1 10624/10632/1 10577/10585/1 5422/5430/1 +f 10624/10632/1 10623/10631/1 10578/10586/1 10577/10585/1 +f 5026/5034/1 10573/10581/1 10576/10584/1 5027/5035/1 +f 5423/5431/1 10580/10588/1 10573/10581/1 5026/5034/1 +f 10580/10588/1 10579/10587/1 10574/10582/1 10573/10581/1 +f 10566/10574/1 10569/10577/1 10572/10580/1 10567/10575/1 +f 15579/15587/1 1640/1648/1 10569/10577/1 10566/10574/1 +f 1640/1648/1 1639/1647/1 10570/10578/1 10569/10577/1 +f 10582/10590/1 10565/10573/1 10568/10576/1 10583/10591/1 +f 3291/3299/1 15580/15588/1 10565/10573/1 10582/10590/1 +f 15580/15588/1 15579/15587/1 10566/10574/1 10565/10573/1 +f 3306/3314/1 10561/10569/1 10564/10572/1 3307/3315/1 +f 10583/10591/1 10568/10576/1 10561/10569/1 3306/3314/1 +f 10568/10576/1 10567/10575/1 10562/10570/1 10561/10569/1 +f 10554/10562/1 10557/10565/1 10560/10568/1 10555/10563/1 +f 10539/10547/1 3320/3328/1 10557/10565/1 10554/10562/1 +f 3320/3328/1 3319/3327/1 10558/10566/1 10557/10565/1 +f 15622/15630/1 10553/10561/1 10556/10564/1 15623/15631/1 +f 3335/3343/1 10540/10548/1 10553/10561/1 15622/15630/1 +f 10540/10548/1 10539/10547/1 10554/10562/1 10553/10561/1 +f 1626/1634/1 10549/10557/1 10552/10560/1 1627/1635/1 +f 15623/15631/1 10556/10564/1 10549/10557/1 1626/1634/1 +f 10556/10564/1 10555/10563/1 10550/10558/1 10549/10557/1 +f 10542/10550/1 10545/10553/1 10548/10556/1 10543/10551/1 +f 17478/17486/1 17479/17487/1 10545/10553/1 10542/10550/1 +f 17479/17487/1 17480/17488/1 10546/10554/1 10545/10553/1 +f 10498/10506/1 10541/10549/1 10544/10552/1 10499/10507/1 +f 17481/17489/1 17482/17490/1 10541/10549/1 10498/10506/1 +f 17482/17490/1 17478/17486/1 10542/10550/1 10541/10549/1 +f 3334/3342/1 10537/10545/1 10540/10548/1 3335/3343/1 +f 10499/10507/1 10544/10552/1 10537/10545/1 3334/3342/1 +f 10544/10552/1 10543/10551/1 10538/10546/1 10537/10545/1 +f 10530/10538/1 10533/10541/1 10536/10544/1 10531/10539/1 +f 17483/17491/1 17484/17492/1 10533/10541/1 10530/10538/1 +f 17484/17492/1 17485/17493/1 10534/10542/1 10533/10541/1 +f 10546/10554/1 10529/10537/1 10532/10540/1 10547/10555/1 +f 17480/17488/1 17486/17494/1 10529/10537/1 10546/10554/1 +f 17486/17494/1 17483/17491/1 10530/10538/1 10529/10537/1 +f 3318/3326/1 10525/10533/1 10528/10536/1 3319/3327/1 +f 10547/10555/1 10532/10540/1 10525/10533/1 3318/3326/1 +f 10532/10540/1 10531/10539/1 10526/10534/1 10525/10533/1 +f 10518/10526/1 10521/10529/1 10524/10532/1 10519/10527/1 +f 10503/10511/1 3332/3340/1 10521/10529/1 10518/10526/1 +f 3332/3340/1 3331/3339/1 10522/10530/1 10521/10529/1 +f 15754/15762/1 10517/10525/1 10520/10528/1 15755/15763/1 +f 3467/3475/1 10504/10512/1 10517/10525/1 15754/15762/1 +f 10504/10512/1 10503/10511/1 10518/10526/1 10517/10525/1 +f 1582/1590/1 10513/10521/1 10516/10524/1 1583/1591/1 +f 15755/15763/1 10520/10528/1 10513/10521/1 1582/1590/1 +f 10520/10528/1 10519/10527/1 10514/10522/1 10513/10521/1 +f 10506/10514/1 10509/10517/1 10512/10520/1 10507/10515/1 +f 17487/17495/1 17488/17496/1 10509/10517/1 10506/10514/1 +f 17488/17496/1 17489/17497/1 10510/10518/1 10509/10517/1 +f 10102/10110/1 10505/10513/1 10508/10516/1 10103/10111/1 +f 17490/17498/1 17491/17499/1 10505/10513/1 10102/10110/1 +f 17491/17499/1 17487/17495/1 10506/10514/1 10505/10513/1 +f 3466/3474/1 10501/10509/1 10504/10512/1 3467/3475/1 +f 10103/10111/1 10508/10516/1 10501/10509/1 3466/3474/1 +f 10508/10516/1 10507/10515/1 10502/10510/1 10501/10509/1 +f 10494/10502/1 10497/10505/1 10500/10508/1 10495/10503/1 +f 17492/17500/1 17493/17501/1 10497/10505/1 10494/10502/1 +f 17493/17501/1 17481/17489/1 10498/10506/1 10497/10505/1 +f 10510/10518/1 10493/10501/1 10496/10504/1 10511/10519/1 +f 17489/17497/1 17494/17502/1 10493/10501/1 10510/10518/1 +f 17494/17502/1 17492/17500/1 10494/10502/1 10493/10501/1 +f 3330/3338/1 10489/10497/1 10492/10500/1 3331/3339/1 +f 10511/10519/1 10496/10504/1 10489/10497/1 3330/3338/1 +f 10496/10504/1 10495/10503/1 10490/10498/1 10489/10497/1 +f 10482/10490/1 10485/10493/1 10488/10496/1 10483/10491/1 +f 10467/10475/1 3344/3352/1 10485/10493/1 10482/10490/1 +f 3344/3352/1 3343/3351/1 10486/10494/1 10485/10493/1 +f 16942/16950/1 10481/10489/1 10484/10492/1 16943/16951/1 +f 4655/4663/1 10468/10476/1 10481/10489/1 16942/16950/1 +f 10468/10476/1 10467/10475/1 10482/10490/1 10481/10489/1 +f 1186/1194/1 10477/10485/1 10480/10488/1 1187/1195/1 +f 16943/16951/1 10484/10492/1 10477/10485/1 1186/1194/1 +f 10484/10492/1 10483/10491/1 10478/10486/1 10477/10485/1 +f 10470/10478/1 10473/10481/1 10476/10484/1 10471/10479/1 +f 10515/10523/1 3328/3336/1 10473/10481/1 10470/10478/1 +f 3328/3336/1 3327/3335/1 10474/10482/1 10473/10481/1 +f 6538/6546/1 10469/10477/1 10472/10480/1 6539/6547/1 +f 1583/1591/1 10516/10524/1 10469/10477/1 6538/6546/1 +f 10516/10524/1 10515/10523/1 10470/10478/1 10469/10477/1 +f 4654/4662/1 10465/10473/1 10468/10476/1 4655/4663/1 +f 6539/6547/1 10472/10480/1 10465/10473/1 4654/4662/1 +f 10472/10480/1 10471/10479/1 10466/10474/1 10465/10473/1 +f 10458/10466/1 10461/10469/1 10464/10472/1 10459/10467/1 +f 15615/15623/1 1628/1636/1 10461/10469/1 10458/10466/1 +f 1628/1636/1 1627/1635/1 10462/10470/1 10461/10469/1 +f 10474/10482/1 10457/10465/1 10460/10468/1 10475/10483/1 +f 3327/3335/1 15616/15624/1 10457/10465/1 10474/10482/1 +f 15616/15624/1 15615/15623/1 10458/10466/1 10457/10465/1 +f 3342/3350/1 10453/10461/1 10456/10464/1 3343/3351/1 +f 10475/10483/1 10460/10468/1 10453/10461/1 3342/3350/1 +f 10460/10468/1 10459/10467/1 10454/10462/1 10453/10461/1 +f 10446/10454/1 10449/10457/1 10452/10460/1 10447/10455/1 +f 10431/10439/1 3356/3364/1 10449/10457/1 10446/10454/1 +f 3356/3364/1 3355/3363/1 10450/10458/1 10449/10457/1 +f 15658/15666/1 10445/10453/1 10448/10456/1 15659/15667/1 +f 3371/3379/1 10432/10440/1 10445/10453/1 15658/15666/1 +f 10432/10440/1 10431/10439/1 10446/10454/1 10445/10453/1 +f 1614/1622/1 10441/10449/1 10444/10452/1 1615/1623/1 +f 15659/15667/1 10448/10456/1 10441/10449/1 1614/1622/1 +f 10448/10456/1 10447/10455/1 10442/10450/1 10441/10449/1 +f 10434/10442/1 10437/10445/1 10440/10448/1 10435/10443/1 +f 17495/17503/1 17496/17504/1 10437/10445/1 10434/10442/1 +f 17496/17504/1 17497/17505/1 10438/10446/1 10437/10445/1 +f 10390/10398/1 10433/10441/1 10436/10444/1 10391/10399/1 +f 17498/17506/1 17499/17507/1 10433/10441/1 10390/10398/1 +f 17499/17507/1 17495/17503/1 10434/10442/1 10433/10441/1 +f 3370/3378/1 10429/10437/1 10432/10440/1 3371/3379/1 +f 10391/10399/1 10436/10444/1 10429/10437/1 3370/3378/1 +f 10436/10444/1 10435/10443/1 10430/10438/1 10429/10437/1 +f 10422/10430/1 10425/10433/1 10428/10436/1 10423/10431/1 +f 17500/17508/1 17501/17509/1 10425/10433/1 10422/10430/1 +f 17501/17509/1 17502/17510/1 10426/10434/1 10425/10433/1 +f 10438/10446/1 10421/10429/1 10424/10432/1 10439/10447/1 +f 17497/17505/1 17503/17511/1 10421/10429/1 10438/10446/1 +f 17503/17511/1 17500/17508/1 10422/10430/1 10421/10429/1 +f 3354/3362/1 10417/10425/1 10420/10428/1 3355/3363/1 +f 10439/10447/1 10424/10432/1 10417/10425/1 3354/3362/1 +f 10424/10432/1 10423/10431/1 10418/10426/1 10417/10425/1 +f 10410/10418/1 10413/10421/1 10416/10424/1 10411/10419/1 +f 10395/10403/1 3368/3376/1 10413/10421/1 10410/10418/1 +f 3368/3376/1 3367/3375/1 10414/10422/1 10413/10421/1 +f 15610/15618/1 10409/10417/1 10412/10420/1 15611/15619/1 +f 3323/3331/1 10396/10404/1 10409/10417/1 15610/15618/1 +f 10396/10404/1 10395/10403/1 10410/10418/1 10409/10417/1 +f 1630/1638/1 10405/10413/1 10408/10416/1 1631/1639/1 +f 15611/15619/1 10412/10420/1 10405/10413/1 1630/1638/1 +f 10412/10420/1 10411/10419/1 10406/10414/1 10405/10413/1 +f 10398/10406/1 10401/10409/1 10404/10412/1 10399/10407/1 +f 17504/17512/1 17505/17513/1 10401/10409/1 10398/10406/1 +f 17505/17513/1 17506/17514/1 10402/10410/1 10401/10409/1 +f 10534/10542/1 10397/10405/1 10400/10408/1 10535/10543/1 +f 17485/17493/1 17507/17515/1 10397/10405/1 10534/10542/1 +f 17507/17515/1 17504/17512/1 10398/10406/1 10397/10405/1 +f 3322/3330/1 10393/10401/1 10396/10404/1 3323/3331/1 +f 10535/10543/1 10400/10408/1 10393/10401/1 3322/3330/1 +f 10400/10408/1 10399/10407/1 10394/10402/1 10393/10401/1 +f 10386/10394/1 10389/10397/1 10392/10400/1 10387/10395/1 +f 17508/17516/1 17509/17517/1 10389/10397/1 10386/10394/1 +f 17509/17517/1 17498/17506/1 10390/10398/1 10389/10397/1 +f 10402/10410/1 10385/10393/1 10388/10396/1 10403/10411/1 +f 17506/17514/1 17510/17518/1 10385/10393/1 10402/10410/1 +f 17510/17518/1 17508/17516/1 10386/10394/1 10385/10393/1 +f 3366/3374/1 10381/10389/1 10384/10392/1 3367/3375/1 +f 10403/10411/1 10388/10396/1 10381/10389/1 3366/3374/1 +f 10388/10396/1 10387/10395/1 10382/10390/1 10381/10389/1 +f 10374/10382/1 10377/10385/1 10380/10388/1 10375/10383/1 +f 10359/10367/1 3380/3388/1 10377/10385/1 10374/10382/1 +f 3380/3388/1 3379/3387/1 10378/10386/1 10377/10385/1 +f 16990/16998/1 10373/10381/1 10376/10384/1 16991/16999/1 +f 4703/4711/1 10360/10368/1 10373/10381/1 16990/16998/1 +f 10360/10368/1 10359/10367/1 10374/10382/1 10373/10381/1 +f 1170/1178/1 10369/10377/1 10372/10380/1 1171/1179/1 +f 16991/16999/1 10376/10384/1 10369/10377/1 1170/1178/1 +f 10376/10384/1 10375/10383/1 10370/10378/1 10369/10377/1 +f 10362/10370/1 10365/10373/1 10368/10376/1 10363/10371/1 +f 10407/10415/1 3364/3372/1 10365/10373/1 10362/10370/1 +f 3364/3372/1 3363/3371/1 10366/10374/1 10365/10373/1 +f 6394/6402/1 10361/10369/1 10364/10372/1 6395/6403/1 +f 1631/1639/1 10408/10416/1 10361/10369/1 6394/6402/1 +f 10408/10416/1 10407/10415/1 10362/10370/1 10361/10369/1 +f 4702/4710/1 10357/10365/1 10360/10368/1 4703/4711/1 +f 6395/6403/1 10364/10372/1 10357/10365/1 4702/4710/1 +f 10364/10372/1 10363/10371/1 10358/10366/1 10357/10365/1 +f 10350/10358/1 10353/10361/1 10356/10364/1 10351/10359/1 +f 15651/15659/1 1616/1624/1 10353/10361/1 10350/10358/1 +f 1616/1624/1 1615/1623/1 10354/10362/1 10353/10361/1 +f 10366/10374/1 10349/10357/1 10352/10360/1 10367/10375/1 +f 3363/3371/1 15652/15660/1 10349/10357/1 10366/10374/1 +f 15652/15660/1 15651/15659/1 10350/10358/1 10349/10357/1 +f 3378/3386/1 10345/10353/1 10348/10356/1 3379/3387/1 +f 10367/10375/1 10352/10360/1 10345/10353/1 3378/3386/1 +f 10352/10360/1 10351/10359/1 10346/10354/1 10345/10353/1 +f 10338/10346/1 10341/10349/1 10344/10352/1 10339/10347/1 +f 10323/10331/1 3392/3400/1 10341/10349/1 10338/10346/1 +f 3392/3400/1 3391/3399/1 10342/10350/1 10341/10349/1 +f 15694/15702/1 10337/10345/1 10340/10348/1 15695/15703/1 +f 3407/3415/1 10324/10332/1 10337/10345/1 15694/15702/1 +f 10324/10332/1 10323/10331/1 10338/10346/1 10337/10345/1 +f 1602/1610/1 10333/10341/1 10336/10344/1 1603/1611/1 +f 15695/15703/1 10340/10348/1 10333/10341/1 1602/1610/1 +f 10340/10348/1 10339/10347/1 10334/10342/1 10333/10341/1 +f 10326/10334/1 10329/10337/1 10332/10340/1 10327/10335/1 +f 6519/6527/1 4660/4668/1 10329/10337/1 10326/10334/1 +f 4660/4668/1 4659/4667/1 10330/10338/1 10329/10337/1 +f 10282/10290/1 10325/10333/1 10328/10336/1 10283/10291/1 +f 1587/1595/1 6520/6528/1 10325/10333/1 10282/10290/1 +f 6520/6528/1 6519/6527/1 10326/10334/1 10325/10333/1 +f 3406/3414/1 10321/10329/1 10324/10332/1 3407/3415/1 +f 10283/10291/1 10328/10336/1 10321/10329/1 3406/3414/1 +f 10328/10336/1 10327/10335/1 10322/10330/1 10321/10329/1 +f 10314/10322/1 10317/10325/1 10320/10328/1 10315/10323/1 +f 16947/16955/1 1184/1192/1 10317/10325/1 10314/10322/1 +f 1184/1192/1 1183/1191/1 10318/10326/1 10317/10325/1 +f 10330/10338/1 10313/10321/1 10316/10324/1 10331/10339/1 +f 4659/4667/1 16948/16956/1 10313/10321/1 10330/10338/1 +f 16948/16956/1 16947/16955/1 10314/10322/1 10313/10321/1 +f 3390/3398/1 10309/10317/1 10312/10320/1 3391/3399/1 +f 10331/10339/1 10316/10324/1 10309/10317/1 3390/3398/1 +f 10316/10324/1 10315/10323/1 10310/10318/1 10309/10317/1 +f 10302/10310/1 10305/10313/1 10308/10316/1 10303/10311/1 +f 10287/10295/1 3404/3412/1 10305/10313/1 10302/10310/1 +f 3404/3412/1 3403/3411/1 10306/10314/1 10305/10313/1 +f 17511/17519/1 10301/10309/1 10304/10312/1 17512/17520/1 +f 17513/17521/1 10288/10296/1 10301/10309/1 17511/17519/1 +f 10288/10296/1 10287/10295/1 10302/10310/1 10301/10309/1 +f 17514/17522/1 10297/10305/1 10300/10308/1 17515/17523/1 +f 17512/17520/1 10304/10312/1 10297/10305/1 17514/17522/1 +f 10304/10312/1 10303/10311/1 10298/10306/1 10297/10305/1 +f 10290/10298/1 10293/10301/1 10296/10304/1 10291/10299/1 +f 10155/10163/1 3448/3456/1 10293/10301/1 10290/10298/1 +f 3448/3456/1 3447/3455/1 10294/10302/1 10293/10301/1 +f 17516/17524/1 10289/10297/1 10292/10300/1 17517/17525/1 +f 17518/17526/1 10156/10164/1 10289/10297/1 17516/17524/1 +f 10156/10164/1 10155/10163/1 10290/10298/1 10289/10297/1 +f 17519/17527/1 10285/10293/1 10288/10296/1 17513/17521/1 +f 17517/17525/1 10292/10300/1 10285/10293/1 17519/17527/1 +f 10292/10300/1 10291/10299/1 10286/10294/1 10285/10293/1 +f 10278/10286/1 10281/10289/1 10284/10292/1 10279/10287/1 +f 15735/15743/1 1588/1596/1 10281/10289/1 10278/10286/1 +f 1588/1596/1 1587/1595/1 10282/10290/1 10281/10289/1 +f 10294/10302/1 10277/10285/1 10280/10288/1 10295/10303/1 +f 3447/3455/1 15736/15744/1 10277/10285/1 10294/10302/1 +f 15736/15744/1 15735/15743/1 10278/10286/1 10277/10285/1 +f 3402/3410/1 10273/10281/1 10276/10284/1 3403/3411/1 +f 10295/10303/1 10280/10288/1 10273/10281/1 3402/3410/1 +f 10280/10288/1 10279/10287/1 10274/10282/1 10273/10281/1 +f 10266/10274/1 10269/10277/1 10272/10280/1 10267/10275/1 +f 10251/10259/1 3416/3424/1 10269/10277/1 10266/10274/1 +f 3416/3424/1 3415/3423/1 10270/10278/1 10269/10277/1 +f 17520/17528/1 10265/10273/1 10268/10276/1 17521/17529/1 +f 17522/17530/1 10252/10260/1 10265/10273/1 17520/17528/1 +f 10252/10260/1 10251/10259/1 10266/10274/1 10265/10273/1 +f 17523/17531/1 10261/10269/1 10264/10272/1 17524/17532/1 +f 17521/17529/1 10268/10276/1 10261/10269/1 17523/17531/1 +f 10268/10276/1 10267/10275/1 10262/10270/1 10261/10269/1 +f 10254/10262/1 10257/10265/1 10260/10268/1 10255/10263/1 +f 10299/10307/1 3400/3408/1 10257/10265/1 10254/10262/1 +f 3400/3408/1 3399/3407/1 10258/10266/1 10257/10265/1 +f 17525/17533/1 10253/10261/1 10256/10264/1 17526/17534/1 +f 17515/17523/1 10300/10308/1 10253/10261/1 17525/17533/1 +f 10300/10308/1 10299/10307/1 10254/10262/1 10253/10261/1 +f 17527/17535/1 10249/10257/1 10252/10260/1 17522/17530/1 +f 17526/17534/1 10256/10264/1 10249/10257/1 17527/17535/1 +f 10256/10264/1 10255/10263/1 10250/10258/1 10249/10257/1 +f 10242/10250/1 10245/10253/1 10248/10256/1 10243/10251/1 +f 15687/15695/1 1604/1612/1 10245/10253/1 10242/10250/1 +f 1604/1612/1 1603/1611/1 10246/10254/1 10245/10253/1 +f 10258/10266/1 10241/10249/1 10244/10252/1 10259/10267/1 +f 3399/3407/1 15688/15696/1 10241/10249/1 10258/10266/1 +f 15688/15696/1 15687/15695/1 10242/10250/1 10241/10249/1 +f 3414/3422/1 10237/10245/1 10240/10248/1 3415/3423/1 +f 10259/10267/1 10244/10252/1 10237/10245/1 3414/3422/1 +f 10244/10252/1 10243/10251/1 10238/10246/1 10237/10245/1 +f 10230/10238/1 10233/10241/1 10236/10244/1 10231/10239/1 +f 10215/10223/1 3428/3436/1 10233/10241/1 10230/10238/1 +f 3428/3436/1 3427/3435/1 10234/10242/1 10233/10241/1 +f 15730/15738/1 10229/10237/1 10232/10240/1 15731/15739/1 +f 3443/3451/1 10216/10224/1 10229/10237/1 15730/15738/1 +f 10216/10224/1 10215/10223/1 10230/10238/1 10229/10237/1 +f 1590/1598/1 10225/10233/1 10228/10236/1 1591/1599/1 +f 15731/15739/1 10232/10240/1 10225/10233/1 1590/1598/1 +f 10232/10240/1 10231/10239/1 10226/10234/1 10225/10233/1 +f 10218/10226/1 10221/10229/1 10224/10232/1 10219/10227/1 +f 17528/17536/1 17529/17537/1 10221/10229/1 10218/10226/1 +f 17529/17537/1 17530/17538/1 10222/10230/1 10221/10229/1 +f 10174/10182/1 10217/10225/1 10220/10228/1 10175/10183/1 +f 17531/17539/1 17532/17540/1 10217/10225/1 10174/10182/1 +f 17532/17540/1 17528/17536/1 10218/10226/1 10217/10225/1 +f 3442/3450/1 10213/10221/1 10216/10224/1 3443/3451/1 +f 10175/10183/1 10220/10228/1 10213/10221/1 3442/3450/1 +f 10220/10228/1 10219/10227/1 10214/10222/1 10213/10221/1 +f 10206/10214/1 10209/10217/1 10212/10220/1 10207/10215/1 +f 17533/17541/1 17534/17542/1 10209/10217/1 10206/10214/1 +f 17534/17542/1 17535/17543/1 10210/10218/1 10209/10217/1 +f 10222/10230/1 10205/10213/1 10208/10216/1 10223/10231/1 +f 17530/17538/1 17536/17544/1 10205/10213/1 10222/10230/1 +f 17536/17544/1 17533/17541/1 10206/10214/1 10205/10213/1 +f 3426/3434/1 10201/10209/1 10204/10212/1 3427/3435/1 +f 10223/10231/1 10208/10216/1 10201/10209/1 3426/3434/1 +f 10208/10216/1 10207/10215/1 10202/10210/1 10201/10209/1 +f 10194/10202/1 10197/10205/1 10200/10208/1 10195/10203/1 +f 10179/10187/1 3440/3448/1 10197/10205/1 10194/10202/1 +f 3440/3448/1 3439/3447/1 10198/10206/1 10197/10205/1 +f 17537/17545/1 10193/10201/1 10196/10204/1 17538/17546/1 +f 17539/17547/1 10180/10188/1 10193/10201/1 17537/17545/1 +f 10180/10188/1 10179/10187/1 10194/10202/1 10193/10201/1 +f 17540/17548/1 10189/10197/1 10192/10200/1 17541/17549/1 +f 17538/17546/1 10196/10204/1 10189/10197/1 17540/17548/1 +f 10196/10204/1 10195/10203/1 10190/10198/1 10189/10197/1 +f 10182/10190/1 10185/10193/1 10188/10196/1 10183/10191/1 +f 17542/17550/1 17543/17551/1 10185/10193/1 10182/10190/1 +f 17543/17551/1 17544/17552/1 10186/10194/1 10185/10193/1 +f 17545/17553/1 10181/10189/1 10184/10192/1 17546/17554/1 +f 17547/17555/1 17548/17556/1 10181/10189/1 17545/17553/1 +f 17548/17556/1 17542/17550/1 10182/10190/1 10181/10189/1 +f 17549/17557/1 10177/10185/1 10180/10188/1 17539/17547/1 +f 17546/17554/1 10184/10192/1 10177/10185/1 17549/17557/1 +f 10184/10192/1 10183/10191/1 10178/10186/1 10177/10185/1 +f 10170/10178/1 10173/10181/1 10176/10184/1 10171/10179/1 +f 17550/17558/1 17551/17559/1 10173/10181/1 10170/10178/1 +f 17551/17559/1 17531/17539/1 10174/10182/1 10173/10181/1 +f 10186/10194/1 10169/10177/1 10172/10180/1 10187/10195/1 +f 17544/17552/1 17552/17560/1 10169/10177/1 10186/10194/1 +f 17552/17560/1 17550/17558/1 10170/10178/1 10169/10177/1 +f 3438/3446/1 10165/10173/1 10168/10176/1 3439/3447/1 +f 10187/10195/1 10172/10180/1 10165/10173/1 3438/3446/1 +f 10172/10180/1 10171/10179/1 10166/10174/1 10165/10173/1 +f 10158/10166/1 10161/10169/1 10164/10172/1 10159/10167/1 +f 10143/10151/1 3452/3460/1 10161/10169/1 10158/10166/1 +f 3452/3460/1 3451/3459/1 10162/10170/1 10161/10169/1 +f 17553/17561/1 10157/10165/1 10160/10168/1 17554/17562/1 +f 17555/17563/1 10144/10152/1 10157/10165/1 17553/17561/1 +f 10144/10152/1 10143/10151/1 10158/10166/1 10157/10165/1 +f 17556/17564/1 10153/10161/1 10156/10164/1 17518/17526/1 +f 17554/17562/1 10160/10168/1 10153/10161/1 17556/17564/1 +f 10160/10168/1 10159/10167/1 10154/10162/1 10153/10161/1 +f 10146/10154/1 10149/10157/1 10152/10160/1 10147/10155/1 +f 10191/10199/1 3436/3444/1 10149/10157/1 10146/10154/1 +f 3436/3444/1 3435/3443/1 10150/10158/1 10149/10157/1 +f 17557/17565/1 10145/10153/1 10148/10156/1 17558/17566/1 +f 17541/17549/1 10192/10200/1 10145/10153/1 17557/17565/1 +f 10192/10200/1 10191/10199/1 10146/10154/1 10145/10153/1 +f 17559/17567/1 10141/10149/1 10144/10152/1 17555/17563/1 +f 17558/17566/1 10148/10156/1 10141/10149/1 17559/17567/1 +f 10148/10156/1 10147/10155/1 10142/10150/1 10141/10149/1 +f 10134/10142/1 10137/10145/1 10140/10148/1 10135/10143/1 +f 15723/15731/1 1592/1600/1 10137/10145/1 10134/10142/1 +f 1592/1600/1 1591/1599/1 10138/10146/1 10137/10145/1 +f 10150/10158/1 10133/10141/1 10136/10144/1 10151/10159/1 +f 3435/3443/1 15724/15732/1 10133/10141/1 10150/10158/1 +f 15724/15732/1 15723/15731/1 10134/10142/1 10133/10141/1 +f 3450/3458/1 10129/10137/1 10132/10140/1 3451/3459/1 +f 10151/10159/1 10136/10144/1 10129/10137/1 3450/3458/1 +f 10136/10144/1 10135/10143/1 10130/10138/1 10129/10137/1 +f 10122/10130/1 10125/10133/1 10128/10136/1 10123/10131/1 +f 10107/10115/1 3464/3472/1 10125/10133/1 10122/10130/1 +f 3464/3472/1 3463/3471/1 10126/10134/1 10125/10133/1 +f 15766/15774/1 10121/10129/1 10124/10132/1 15767/15775/1 +f 3479/3487/1 10108/10116/1 10121/10129/1 15766/15774/1 +f 10108/10116/1 10107/10115/1 10122/10130/1 10121/10129/1 +f 1578/1586/1 10117/10125/1 10120/10128/1 1579/1587/1 +f 15767/15775/1 10124/10132/1 10117/10125/1 1578/1586/1 +f 10124/10132/1 10123/10131/1 10118/10126/1 10117/10125/1 +f 10110/10118/1 10113/10121/1 10116/10124/1 10111/10119/1 +f 17560/17568/1 17561/17569/1 10113/10121/1 10110/10118/1 +f 17561/17569/1 17562/17570/1 10114/10122/1 10113/10121/1 +f 10066/10074/1 10109/10117/1 10112/10120/1 10067/10075/1 +f 17563/17571/1 17564/17572/1 10109/10117/1 10066/10074/1 +f 17564/17572/1 17560/17568/1 10110/10118/1 10109/10117/1 +f 3478/3486/1 10105/10113/1 10108/10116/1 3479/3487/1 +f 10067/10075/1 10112/10120/1 10105/10113/1 3478/3486/1 +f 10112/10120/1 10111/10119/1 10106/10114/1 10105/10113/1 +f 10098/10106/1 10101/10109/1 10104/10112/1 10099/10107/1 +f 17565/17573/1 17566/17574/1 10101/10109/1 10098/10106/1 +f 17566/17574/1 17490/17498/1 10102/10110/1 10101/10109/1 +f 10114/10122/1 10097/10105/1 10100/10108/1 10115/10123/1 +f 17562/17570/1 17567/17575/1 10097/10105/1 10114/10122/1 +f 17567/17575/1 17565/17573/1 10098/10106/1 10097/10105/1 +f 3462/3470/1 10093/10101/1 10096/10104/1 3463/3471/1 +f 10115/10123/1 10100/10108/1 10093/10101/1 3462/3470/1 +f 10100/10108/1 10099/10107/1 10094/10102/1 10093/10101/1 +f 10086/10094/1 10089/10097/1 10092/10100/1 10087/10095/1 +f 10071/10079/1 3476/3484/1 10089/10097/1 10086/10094/1 +f 3476/3484/1 3475/3483/1 10090/10098/1 10089/10097/1 +f 15718/15726/1 10085/10093/1 10088/10096/1 15719/15727/1 +f 3431/3439/1 10072/10080/1 10085/10093/1 15718/15726/1 +f 10072/10080/1 10071/10079/1 10086/10094/1 10085/10093/1 +f 1594/1602/1 10081/10089/1 10084/10092/1 1595/1603/1 +f 15719/15727/1 10088/10096/1 10081/10089/1 1594/1602/1 +f 10088/10096/1 10087/10095/1 10082/10090/1 10081/10089/1 +f 10074/10082/1 10077/10085/1 10080/10088/1 10075/10083/1 +f 17568/17576/1 17569/17577/1 10077/10085/1 10074/10082/1 +f 17569/17577/1 17570/17578/1 10078/10086/1 10077/10085/1 +f 10210/10218/1 10073/10081/1 10076/10084/1 10211/10219/1 +f 17535/17543/1 17571/17579/1 10073/10081/1 10210/10218/1 +f 17571/17579/1 17568/17576/1 10074/10082/1 10073/10081/1 +f 3430/3438/1 10069/10077/1 10072/10080/1 3431/3439/1 +f 10211/10219/1 10076/10084/1 10069/10077/1 3430/3438/1 +f 10076/10084/1 10075/10083/1 10070/10078/1 10069/10077/1 +f 10062/10070/1 10065/10073/1 10068/10076/1 10063/10071/1 +f 17572/17580/1 17573/17581/1 10065/10073/1 10062/10070/1 +f 17573/17581/1 17563/17571/1 10066/10074/1 10065/10073/1 +f 10078/10086/1 10061/10069/1 10064/10072/1 10079/10087/1 +f 17570/17578/1 17574/17582/1 10061/10069/1 10078/10086/1 +f 17574/17582/1 17572/17580/1 10062/10070/1 10061/10069/1 +f 3474/3482/1 10057/10065/1 10060/10068/1 3475/3483/1 +f 10079/10087/1 10064/10072/1 10057/10065/1 3474/3482/1 +f 10064/10072/1 10063/10071/1 10058/10066/1 10057/10065/1 +f 10050/10058/1 10053/10061/1 10056/10064/1 10051/10059/1 +f 10035/10043/1 3488/3496/1 10053/10061/1 10050/10058/1 +f 3488/3496/1 3487/3495/1 10054/10062/1 10053/10061/1 +f 16954/16962/1 10049/10057/1 10052/10060/1 16955/16963/1 +f 4667/4675/1 10036/10044/1 10049/10057/1 16954/16962/1 +f 10036/10044/1 10035/10043/1 10050/10058/1 10049/10057/1 +f 1182/1190/1 10045/10053/1 10048/10056/1 1183/1191/1 +f 16955/16963/1 10052/10060/1 10045/10053/1 1182/1190/1 +f 10052/10060/1 10051/10059/1 10046/10054/1 10045/10053/1 +f 10038/10046/1 10041/10049/1 10044/10052/1 10039/10047/1 +f 10083/10091/1 3472/3480/1 10041/10049/1 10038/10046/1 +f 3472/3480/1 3471/3479/1 10042/10050/1 10041/10049/1 +f 6502/6510/1 10037/10045/1 10040/10048/1 6503/6511/1 +f 1595/1603/1 10084/10092/1 10037/10045/1 6502/6510/1 +f 10084/10092/1 10083/10091/1 10038/10046/1 10037/10045/1 +f 4666/4674/1 10033/10041/1 10036/10044/1 4667/4675/1 +f 6503/6511/1 10040/10048/1 10033/10041/1 4666/4674/1 +f 10040/10048/1 10039/10047/1 10034/10042/1 10033/10041/1 +f 10026/10034/1 10029/10037/1 10032/10040/1 10027/10035/1 +f 15759/15767/1 1580/1588/1 10029/10037/1 10026/10034/1 +f 1580/1588/1 1579/1587/1 10030/10038/1 10029/10037/1 +f 10042/10050/1 10025/10033/1 10028/10036/1 10043/10051/1 +f 3471/3479/1 15760/15768/1 10025/10033/1 10042/10050/1 +f 15760/15768/1 15759/15767/1 10026/10034/1 10025/10033/1 +f 3486/3494/1 10021/10029/1 10024/10032/1 3487/3495/1 +f 10043/10051/1 10028/10036/1 10021/10029/1 3486/3494/1 +f 10028/10036/1 10027/10035/1 10022/10030/1 10021/10029/1 +f 10014/10022/1 10017/10025/1 10020/10028/1 10015/10023/1 +f 9999/10007/1 3500/3508/1 10017/10025/1 10014/10022/1 +f 3500/3508/1 3499/3507/1 10018/10026/1 10017/10025/1 +f 15802/15810/1 10013/10021/1 10016/10024/1 15803/15811/1 +f 3515/3523/1 10000/10008/1 10013/10021/1 15802/15810/1 +f 10000/10008/1 9999/10007/1 10014/10022/1 10013/10021/1 +f 1566/1574/1 10009/10017/1 10012/10020/1 1567/1575/1 +f 15803/15811/1 10016/10024/1 10009/10017/1 1566/1574/1 +f 10016/10024/1 10015/10023/1 10010/10018/1 10009/10017/1 +f 10002/10010/1 10005/10013/1 10008/10016/1 10003/10011/1 +f 6627/6635/1 4624/4632/1 10005/10013/1 10002/10010/1 +f 4624/4632/1 4623/4631/1 10006/10014/1 10005/10013/1 +f 9958/9966/1 10001/10009/1 10004/10012/1 9959/9967/1 +f 1551/1559/1 6628/6636/1 10001/10009/1 9958/9966/1 +f 6628/6636/1 6627/6635/1 10002/10010/1 10001/10009/1 +f 3514/3522/1 9997/10005/1 10000/10008/1 3515/3523/1 +f 9959/9967/1 10004/10012/1 9997/10005/1 3514/3522/1 +f 10004/10012/1 10003/10011/1 9998/10006/1 9997/10005/1 +f 9990/9998/1 9993/10001/1 9996/10004/1 9991/9999/1 +f 16911/16919/1 1196/1204/1 9993/10001/1 9990/9998/1 +f 1196/1204/1 1195/1203/1 9994/10002/1 9993/10001/1 +f 10006/10014/1 9989/9997/1 9992/10000/1 10007/10015/1 +f 4623/4631/1 16912/16920/1 9989/9997/1 10006/10014/1 +f 16912/16920/1 16911/16919/1 9990/9998/1 9989/9997/1 +f 3498/3506/1 9985/9993/1 9988/9996/1 3499/3507/1 +f 10007/10015/1 9992/10000/1 9985/9993/1 3498/3506/1 +f 9992/10000/1 9991/9999/1 9986/9994/1 9985/9993/1 +f 9978/9986/1 9981/9989/1 9984/9992/1 9979/9987/1 +f 9963/9971/1 3512/3520/1 9981/9989/1 9978/9986/1 +f 3512/3520/1 3511/3519/1 9982/9990/1 9981/9989/1 +f 17575/17583/1 9977/9985/1 9980/9988/1 17576/17584/1 +f 17577/17585/1 9964/9972/1 9977/9985/1 17575/17583/1 +f 9964/9972/1 9963/9971/1 9978/9986/1 9977/9985/1 +f 17578/17586/1 9973/9981/1 9976/9984/1 17579/17587/1 +f 17576/17584/1 9980/9988/1 9973/9981/1 17578/17586/1 +f 9980/9988/1 9979/9987/1 9974/9982/1 9973/9981/1 +f 9966/9974/1 9969/9977/1 9972/9980/1 9967/9975/1 +f 9831/9839/1 3556/3564/1 9969/9977/1 9966/9974/1 +f 3556/3564/1 3555/3563/1 9970/9978/1 9969/9977/1 +f 17580/17588/1 9965/9973/1 9968/9976/1 17581/17589/1 +f 17582/17590/1 9832/9840/1 9965/9973/1 17580/17588/1 +f 9832/9840/1 9831/9839/1 9966/9974/1 9965/9973/1 +f 17583/17591/1 9961/9969/1 9964/9972/1 17577/17585/1 +f 17581/17589/1 9968/9976/1 9961/9969/1 17583/17591/1 +f 9968/9976/1 9967/9975/1 9962/9970/1 9961/9969/1 +f 9954/9962/1 9957/9965/1 9960/9968/1 9955/9963/1 +f 15843/15851/1 1552/1560/1 9957/9965/1 9954/9962/1 +f 1552/1560/1 1551/1559/1 9958/9966/1 9957/9965/1 +f 9970/9978/1 9953/9961/1 9956/9964/1 9971/9979/1 +f 3555/3563/1 15844/15852/1 9953/9961/1 9970/9978/1 +f 15844/15852/1 15843/15851/1 9954/9962/1 9953/9961/1 +f 3510/3518/1 9949/9957/1 9952/9960/1 3511/3519/1 +f 9971/9979/1 9956/9964/1 9949/9957/1 3510/3518/1 +f 9956/9964/1 9955/9963/1 9950/9958/1 9949/9957/1 +f 9942/9950/1 9945/9953/1 9948/9956/1 9943/9951/1 +f 9927/9935/1 3524/3532/1 9945/9953/1 9942/9950/1 +f 3524/3532/1 3523/3531/1 9946/9954/1 9945/9953/1 +f 17584/17592/1 9941/9949/1 9944/9952/1 17585/17593/1 +f 17586/17594/1 9928/9936/1 9941/9949/1 17584/17592/1 +f 9928/9936/1 9927/9935/1 9942/9950/1 9941/9949/1 +f 17587/17595/1 9937/9945/1 9940/9948/1 17437/17445/1 +f 17585/17593/1 9944/9952/1 9937/9945/1 17587/17595/1 +f 9944/9952/1 9943/9951/1 9938/9946/1 9937/9945/1 +f 9930/9938/1 9933/9941/1 9936/9944/1 9931/9939/1 +f 9975/9983/1 3508/3516/1 9933/9941/1 9930/9938/1 +f 3508/3516/1 3507/3515/1 9934/9942/1 9933/9941/1 +f 17588/17596/1 9929/9937/1 9932/9940/1 17589/17597/1 +f 17579/17587/1 9976/9984/1 9929/9937/1 17588/17596/1 +f 9976/9984/1 9975/9983/1 9930/9938/1 9929/9937/1 +f 17590/17598/1 9925/9933/1 9928/9936/1 17586/17594/1 +f 17589/17597/1 9932/9940/1 9925/9933/1 17590/17598/1 +f 9932/9940/1 9931/9939/1 9926/9934/1 9925/9933/1 +f 9918/9926/1 9921/9929/1 9924/9932/1 9919/9927/1 +f 15795/15803/1 1568/1576/1 9921/9929/1 9918/9926/1 +f 1568/1576/1 1567/1575/1 9922/9930/1 9921/9929/1 +f 9934/9942/1 9917/9925/1 9920/9928/1 9935/9943/1 +f 3507/3515/1 15796/15804/1 9917/9925/1 9934/9942/1 +f 15796/15804/1 15795/15803/1 9918/9926/1 9917/9925/1 +f 3522/3530/1 9913/9921/1 9916/9924/1 3523/3531/1 +f 9935/9943/1 9920/9928/1 9913/9921/1 3522/3530/1 +f 9920/9928/1 9919/9927/1 9914/9922/1 9913/9921/1 +f 9906/9914/1 9909/9917/1 9912/9920/1 9907/9915/1 +f 9891/9899/1 3536/3544/1 9909/9917/1 9906/9914/1 +f 3536/3544/1 3535/3543/1 9910/9918/1 9909/9917/1 +f 15838/15846/1 9905/9913/1 9908/9916/1 15839/15847/1 +f 3551/3559/1 9892/9900/1 9905/9913/1 15838/15846/1 +f 9892/9900/1 9891/9899/1 9906/9914/1 9905/9913/1 +f 1554/1562/1 9901/9909/1 9904/9912/1 1555/1563/1 +f 15839/15847/1 9908/9916/1 9901/9909/1 1554/1562/1 +f 9908/9916/1 9907/9915/1 9902/9910/1 9901/9909/1 +f 9894/9902/1 9897/9905/1 9900/9908/1 9895/9903/1 +f 6483/6491/1 4672/4680/1 9897/9905/1 9894/9902/1 +f 4672/4680/1 4671/4679/1 9898/9906/1 9897/9905/1 +f 9850/9858/1 9893/9901/1 9896/9904/1 9851/9859/1 +f 1599/1607/1 6484/6492/1 9893/9901/1 9850/9858/1 +f 6484/6492/1 6483/6491/1 9894/9902/1 9893/9901/1 +f 3550/3558/1 9889/9897/1 9892/9900/1 3551/3559/1 +f 9851/9859/1 9896/9904/1 9889/9897/1 3550/3558/1 +f 9896/9904/1 9895/9903/1 9890/9898/1 9889/9897/1 +f 9882/9890/1 9885/9893/1 9888/9896/1 9883/9891/1 +f 16959/16967/1 1180/1188/1 9885/9893/1 9882/9890/1 +f 1180/1188/1 1179/1187/1 9886/9894/1 9885/9893/1 +f 9898/9906/1 9881/9889/1 9884/9892/1 9899/9907/1 +f 4671/4679/1 16960/16968/1 9881/9889/1 9898/9906/1 +f 16960/16968/1 16959/16967/1 9882/9890/1 9881/9889/1 +f 3534/3542/1 9877/9885/1 9880/9888/1 3535/3543/1 +f 9899/9907/1 9884/9892/1 9877/9885/1 3534/3542/1 +f 9884/9892/1 9883/9891/1 9878/9886/1 9877/9885/1 +f 9870/9878/1 9873/9881/1 9876/9884/1 9871/9879/1 +f 9855/9863/1 3548/3556/1 9873/9881/1 9870/9878/1 +f 3548/3556/1 3547/3555/1 9874/9882/1 9873/9881/1 +f 17591/17599/1 9869/9877/1 9872/9880/1 17592/17600/1 +f 17593/17601/1 9856/9864/1 9869/9877/1 17591/17599/1 +f 9856/9864/1 9855/9863/1 9870/9878/1 9869/9877/1 +f 17594/17602/1 9865/9873/1 9868/9876/1 17595/17603/1 +f 17592/17600/1 9872/9880/1 9865/9873/1 17594/17602/1 +f 9872/9880/1 9871/9879/1 9866/9874/1 9865/9873/1 +f 9858/9866/1 9861/9869/1 9864/9872/1 9859/9867/1 +f 10263/10271/1 3412/3420/1 9861/9869/1 9858/9866/1 +f 3412/3420/1 3411/3419/1 9862/9870/1 9861/9869/1 +f 17596/17604/1 9857/9865/1 9860/9868/1 17597/17605/1 +f 17524/17532/1 10264/10272/1 9857/9865/1 17596/17604/1 +f 10264/10272/1 10263/10271/1 9858/9866/1 9857/9865/1 +f 17598/17606/1 9853/9861/1 9856/9864/1 17593/17601/1 +f 17597/17605/1 9860/9868/1 9853/9861/1 17598/17606/1 +f 9860/9868/1 9859/9867/1 9854/9862/1 9853/9861/1 +f 9846/9854/1 9849/9857/1 9852/9860/1 9847/9855/1 +f 15699/15707/1 1600/1608/1 9849/9857/1 9846/9854/1 +f 1600/1608/1 1599/1607/1 9850/9858/1 9849/9857/1 +f 9862/9870/1 9845/9853/1 9848/9856/1 9863/9871/1 +f 3411/3419/1 15700/15708/1 9845/9853/1 9862/9870/1 +f 15700/15708/1 15699/15707/1 9846/9854/1 9845/9853/1 +f 3546/3554/1 9841/9849/1 9844/9852/1 3547/3555/1 +f 9863/9871/1 9848/9856/1 9841/9849/1 3546/3554/1 +f 9848/9856/1 9847/9855/1 9842/9850/1 9841/9849/1 +f 9834/9842/1 9837/9845/1 9840/9848/1 9835/9843/1 +f 9819/9827/1 3560/3568/1 9837/9845/1 9834/9842/1 +f 3560/3568/1 3559/3567/1 9838/9846/1 9837/9845/1 +f 17599/17607/1 9833/9841/1 9836/9844/1 17600/17608/1 +f 17601/17609/1 9820/9828/1 9833/9841/1 17599/17607/1 +f 9820/9828/1 9819/9827/1 9834/9842/1 9833/9841/1 +f 17602/17610/1 9829/9837/1 9832/9840/1 17582/17590/1 +f 17600/17608/1 9836/9844/1 9829/9837/1 17602/17610/1 +f 9836/9844/1 9835/9843/1 9830/9838/1 9829/9837/1 +f 9822/9830/1 9825/9833/1 9828/9836/1 9823/9831/1 +f 9867/9875/1 3544/3552/1 9825/9833/1 9822/9830/1 +f 3544/3552/1 3543/3551/1 9826/9834/1 9825/9833/1 +f 17603/17611/1 9821/9829/1 9824/9832/1 17604/17612/1 +f 17595/17603/1 9868/9876/1 9821/9829/1 17603/17611/1 +f 9868/9876/1 9867/9875/1 9822/9830/1 9821/9829/1 +f 17605/17613/1 9817/9825/1 9820/9828/1 17601/17609/1 +f 17604/17612/1 9824/9832/1 9817/9825/1 17605/17613/1 +f 9824/9832/1 9823/9831/1 9818/9826/1 9817/9825/1 +f 9810/9818/1 9813/9821/1 9816/9824/1 9811/9819/1 +f 15831/15839/1 1556/1564/1 9813/9821/1 9810/9818/1 +f 1556/1564/1 1555/1563/1 9814/9822/1 9813/9821/1 +f 9826/9834/1 9809/9817/1 9812/9820/1 9827/9835/1 +f 3543/3551/1 15832/15840/1 9809/9817/1 9826/9834/1 +f 15832/15840/1 15831/15839/1 9810/9818/1 9809/9817/1 +f 3558/3566/1 9805/9813/1 9808/9816/1 3559/3567/1 +f 9827/9835/1 9812/9820/1 9805/9813/1 3558/3566/1 +f 9812/9820/1 9811/9819/1 9806/9814/1 9805/9813/1 +f 9798/9806/1 9801/9809/1 9804/9812/1 9799/9807/1 +f 9783/9791/1 3572/3580/1 9801/9809/1 9798/9806/1 +f 3572/3580/1 3571/3579/1 9802/9810/1 9801/9809/1 +f 15874/15882/1 9797/9805/1 9800/9808/1 15875/15883/1 +f 3587/3595/1 9784/9792/1 9797/9805/1 15874/15882/1 +f 9784/9792/1 9783/9791/1 9798/9806/1 9797/9805/1 +f 1542/1550/1 9793/9801/1 9796/9804/1 1543/1551/1 +f 15875/15883/1 9800/9808/1 9793/9801/1 1542/1550/1 +f 9800/9808/1 9799/9807/1 9794/9802/1 9793/9801/1 +f 9786/9794/1 9789/9797/1 9792/9800/1 9787/9795/1 +f 5439/5447/1 5020/5028/1 9789/9797/1 9786/9794/1 +f 5020/5028/1 5019/5027/1 9790/9798/1 9789/9797/1 +f 9742/9750/1 9785/9793/1 9788/9796/1 9743/9751/1 +f 1947/1955/1 5440/5448/1 9785/9793/1 9742/9750/1 +f 5440/5448/1 5439/5447/1 9786/9794/1 9785/9793/1 +f 3586/3594/1 9781/9789/1 9784/9792/1 3587/3595/1 +f 9743/9751/1 9788/9796/1 9781/9789/1 3586/3594/1 +f 9788/9796/1 9787/9795/1 9782/9790/1 9781/9789/1 +f 9774/9782/1 9777/9785/1 9780/9788/1 9775/9783/1 +f 17307/17315/1 1064/1072/1 9777/9785/1 9774/9782/1 +f 1064/1072/1 1063/1071/1 9778/9786/1 9777/9785/1 +f 9790/9798/1 9773/9781/1 9776/9784/1 9791/9799/1 +f 5019/5027/1 17308/17316/1 9773/9781/1 9790/9798/1 +f 17308/17316/1 17307/17315/1 9774/9782/1 9773/9781/1 +f 3570/3578/1 9769/9777/1 9772/9780/1 3571/3579/1 +f 9791/9799/1 9776/9784/1 9769/9777/1 3570/3578/1 +f 9776/9784/1 9775/9783/1 9770/9778/1 9769/9777/1 +f 9762/9770/1 9765/9773/1 9768/9776/1 9763/9771/1 +f 9747/9755/1 3584/3592/1 9765/9773/1 9762/9770/1 +f 3584/3592/1 3583/3591/1 9766/9774/1 9765/9773/1 +f 15826/15834/1 9761/9769/1 9764/9772/1 15827/15835/1 +f 3539/3547/1 9748/9756/1 9761/9769/1 15826/15834/1 +f 9748/9756/1 9747/9755/1 9762/9770/1 9761/9769/1 +f 1558/1566/1 9757/9765/1 9760/9768/1 1559/1567/1 +f 15827/15835/1 9764/9772/1 9757/9765/1 1558/1566/1 +f 9764/9772/1 9763/9771/1 9758/9766/1 9757/9765/1 +f 9750/9758/1 9753/9761/1 9756/9764/1 9751/9759/1 +f 13395/13403/1 2368/2376/1 9753/9761/1 9750/9758/1 +f 2368/2376/1 2367/2375/1 9754/9762/1 9753/9761/1 +f 9886/9894/1 9749/9757/1 9752/9760/1 9887/9895/1 +f 1179/1187/1 13396/13404/1 9749/9757/1 9886/9894/1 +f 13396/13404/1 13395/13403/1 9750/9758/1 9749/9757/1 +f 3538/3546/1 9745/9753/1 9748/9756/1 3539/3547/1 +f 9887/9895/1 9752/9760/1 9745/9753/1 3538/3546/1 +f 9752/9760/1 9751/9759/1 9746/9754/1 9745/9753/1 +f 9738/9746/1 9741/9749/1 9744/9752/1 9739/9747/1 +f 14655/14663/1 1948/1956/1 9741/9749/1 9738/9746/1 +f 1948/1956/1 1947/1955/1 9742/9750/1 9741/9749/1 +f 9754/9762/1 9737/9745/1 9740/9748/1 9755/9763/1 +f 2367/2375/1 14656/14664/1 9737/9745/1 9754/9762/1 +f 14656/14664/1 14655/14663/1 9738/9746/1 9737/9745/1 +f 3582/3590/1 9733/9741/1 9736/9744/1 3583/3591/1 +f 9755/9763/1 9740/9748/1 9733/9741/1 3582/3590/1 +f 9740/9748/1 9739/9747/1 9734/9742/1 9733/9741/1 +f 9726/9734/1 9729/9737/1 9732/9740/1 9727/9735/1 +f 9711/9719/1 3596/3604/1 9729/9737/1 9726/9734/1 +f 3596/3604/1 3595/3603/1 9730/9738/1 9729/9737/1 +f 16918/16926/1 9725/9733/1 9728/9736/1 16919/16927/1 +f 4631/4639/1 9712/9720/1 9725/9733/1 16918/16926/1 +f 9712/9720/1 9711/9719/1 9726/9734/1 9725/9733/1 +f 1194/1202/1 9721/9729/1 9724/9732/1 1195/1203/1 +f 16919/16927/1 9728/9736/1 9721/9729/1 1194/1202/1 +f 9728/9736/1 9727/9735/1 9722/9730/1 9721/9729/1 +f 9714/9722/1 9717/9725/1 9720/9728/1 9715/9723/1 +f 9759/9767/1 3580/3588/1 9717/9725/1 9714/9722/1 +f 3580/3588/1 3579/3587/1 9718/9726/1 9717/9725/1 +f 6610/6618/1 9713/9721/1 9716/9724/1 6611/6619/1 +f 1559/1567/1 9760/9768/1 9713/9721/1 6610/6618/1 +f 9760/9768/1 9759/9767/1 9714/9722/1 9713/9721/1 +f 4630/4638/1 9709/9717/1 9712/9720/1 4631/4639/1 +f 6611/6619/1 9716/9724/1 9709/9717/1 4630/4638/1 +f 9716/9724/1 9715/9723/1 9710/9718/1 9709/9717/1 +f 9702/9710/1 9705/9713/1 9708/9716/1 9703/9711/1 +f 15867/15875/1 1544/1552/1 9705/9713/1 9702/9710/1 +f 1544/1552/1 1543/1551/1 9706/9714/1 9705/9713/1 +f 9718/9726/1 9701/9709/1 9704/9712/1 9719/9727/1 +f 3579/3587/1 15868/15876/1 9701/9709/1 9718/9726/1 +f 15868/15876/1 15867/15875/1 9702/9710/1 9701/9709/1 +f 3594/3602/1 9697/9705/1 9700/9708/1 3595/3603/1 +f 9719/9727/1 9704/9712/1 9697/9705/1 3594/3602/1 +f 9704/9712/1 9703/9711/1 9698/9706/1 9697/9705/1 +f 9690/9698/1 9693/9701/1 9696/9704/1 9691/9699/1 +f 9675/9683/1 3608/3616/1 9693/9701/1 9690/9698/1 +f 3608/3616/1 3607/3615/1 9694/9702/1 9693/9701/1 +f 15910/15918/1 9689/9697/1 9692/9700/1 15911/15919/1 +f 3623/3631/1 9676/9684/1 9689/9697/1 15910/15918/1 +f 9676/9684/1 9675/9683/1 9690/9698/1 9689/9697/1 +f 1530/1538/1 9685/9693/1 9688/9696/1 1531/1539/1 +f 15911/15919/1 9692/9700/1 9685/9693/1 1530/1538/1 +f 9692/9700/1 9691/9699/1 9686/9694/1 9685/9693/1 +f 9678/9686/1 9681/9689/1 9684/9692/1 9679/9687/1 +f 6735/6743/1 4588/4596/1 9681/9689/1 9678/9686/1 +f 4588/4596/1 4587/4595/1 9682/9690/1 9681/9689/1 +f 9634/9642/1 9677/9685/1 9680/9688/1 9635/9643/1 +f 1515/1523/1 6736/6744/1 9677/9685/1 9634/9642/1 +f 6736/6744/1 6735/6743/1 9678/9686/1 9677/9685/1 +f 3622/3630/1 9673/9681/1 9676/9684/1 3623/3631/1 +f 9635/9643/1 9680/9688/1 9673/9681/1 3622/3630/1 +f 9680/9688/1 9679/9687/1 9674/9682/1 9673/9681/1 +f 9666/9674/1 9669/9677/1 9672/9680/1 9667/9675/1 +f 16875/16883/1 1208/1216/1 9669/9677/1 9666/9674/1 +f 1208/1216/1 1207/1215/1 9670/9678/1 9669/9677/1 +f 9682/9690/1 9665/9673/1 9668/9676/1 9683/9691/1 +f 4587/4595/1 16876/16884/1 9665/9673/1 9682/9690/1 +f 16876/16884/1 16875/16883/1 9666/9674/1 9665/9673/1 +f 3606/3614/1 9661/9669/1 9664/9672/1 3607/3615/1 +f 9683/9691/1 9668/9676/1 9661/9669/1 3606/3614/1 +f 9668/9676/1 9667/9675/1 9662/9670/1 9661/9669/1 +f 9654/9662/1 9657/9665/1 9660/9668/1 9655/9663/1 +f 9639/9647/1 3620/3628/1 9657/9665/1 9654/9662/1 +f 3620/3628/1 3619/3627/1 9658/9666/1 9657/9665/1 +f 14530/14538/1 9653/9661/1 9656/9664/1 14531/14539/1 +f 2243/2251/1 9640/9648/1 9653/9661/1 14530/14538/1 +f 9640/9648/1 9639/9647/1 9654/9662/1 9653/9661/1 +f 1990/1998/1 9649/9657/1 9652/9660/1 1991/1999/1 +f 14531/14539/1 9656/9664/1 9649/9657/1 1990/1998/1 +f 9656/9664/1 9655/9663/1 9650/9658/1 9649/9657/1 +f 9642/9650/1 9645/9653/1 9648/9656/1 9643/9651/1 +f 9507/9515/1 3664/3672/1 9645/9653/1 9642/9650/1 +f 3664/3672/1 3663/3671/1 9646/9654/1 9645/9653/1 +f 13774/13782/1 9641/9649/1 9644/9652/1 13775/13783/1 +f 1223/1231/1 9508/9516/1 9641/9649/1 13774/13782/1 +f 9508/9516/1 9507/9515/1 9642/9650/1 9641/9649/1 +f 2242/2250/1 9637/9645/1 9640/9648/1 2243/2251/1 +f 13775/13783/1 9644/9652/1 9637/9645/1 2242/2250/1 +f 9644/9652/1 9643/9651/1 9638/9646/1 9637/9645/1 +f 9630/9638/1 9633/9641/1 9636/9644/1 9631/9639/1 +f 15951/15959/1 1516/1524/1 9633/9641/1 9630/9638/1 +f 1516/1524/1 1515/1523/1 9634/9642/1 9633/9641/1 +f 9646/9654/1 9629/9637/1 9632/9640/1 9647/9655/1 +f 3663/3671/1 15952/15960/1 9629/9637/1 9646/9654/1 +f 15952/15960/1 15951/15959/1 9630/9638/1 9629/9637/1 +f 3618/3626/1 9625/9633/1 9628/9636/1 3619/3627/1 +f 9647/9655/1 9632/9640/1 9625/9633/1 3618/3626/1 +f 9632/9640/1 9631/9639/1 9626/9634/1 9625/9633/1 +f 9618/9626/1 9621/9629/1 9624/9632/1 9619/9627/1 +f 9603/9611/1 3632/3640/1 9621/9629/1 9618/9626/1 +f 3632/3640/1 3631/3639/1 9622/9630/1 9621/9629/1 +f 17350/17358/1 9617/9625/1 9620/9628/1 17351/17359/1 +f 5063/5071/1 9604/9612/1 9617/9625/1 17350/17358/1 +f 9604/9612/1 9603/9611/1 9618/9626/1 9617/9625/1 +f 1050/1058/1 9613/9621/1 9616/9624/1 1051/1059/1 +f 17351/17359/1 9620/9628/1 9613/9621/1 1050/1058/1 +f 9620/9628/1 9619/9627/1 9614/9622/1 9613/9621/1 +f 9606/9614/1 9609/9617/1 9612/9620/1 9607/9615/1 +f 9651/9659/1 3616/3624/1 9609/9617/1 9606/9614/1 +f 3616/3624/1 3615/3623/1 9610/9618/1 9609/9617/1 +f 5314/5322/1 9605/9613/1 9608/9616/1 5315/5323/1 +f 1991/1999/1 9652/9660/1 9605/9613/1 5314/5322/1 +f 9652/9660/1 9651/9659/1 9606/9614/1 9605/9613/1 +f 5062/5070/1 9601/9609/1 9604/9612/1 5063/5071/1 +f 5315/5323/1 9608/9616/1 9601/9609/1 5062/5070/1 +f 9608/9616/1 9607/9615/1 9602/9610/1 9601/9609/1 +f 9594/9602/1 9597/9605/1 9600/9608/1 9595/9603/1 +f 15903/15911/1 1532/1540/1 9597/9605/1 9594/9602/1 +f 1532/1540/1 1531/1539/1 9598/9606/1 9597/9605/1 +f 9610/9618/1 9593/9601/1 9596/9604/1 9611/9619/1 +f 3615/3623/1 15904/15912/1 9593/9601/1 9610/9618/1 +f 15904/15912/1 15903/15911/1 9594/9602/1 9593/9601/1 +f 3630/3638/1 9589/9597/1 9592/9600/1 3631/3639/1 +f 9611/9619/1 9596/9604/1 9589/9597/1 3630/3638/1 +f 9596/9604/1 9595/9603/1 9590/9598/1 9589/9597/1 +f 9582/9590/1 9585/9593/1 9588/9596/1 9583/9591/1 +f 9567/9575/1 3644/3652/1 9585/9593/1 9582/9590/1 +f 3644/3652/1 3643/3651/1 9586/9594/1 9585/9593/1 +f 15946/15954/1 9581/9589/1 9584/9592/1 15947/15955/1 +f 3659/3667/1 9568/9576/1 9581/9589/1 15946/15954/1 +f 9568/9576/1 9567/9575/1 9582/9590/1 9581/9589/1 +f 1518/1526/1 9577/9585/1 9580/9588/1 1519/1527/1 +f 15947/15955/1 9584/9592/1 9577/9585/1 1518/1526/1 +f 9584/9592/1 9583/9591/1 9578/9586/1 9577/9585/1 +f 9570/9578/1 9573/9581/1 9576/9584/1 9571/9579/1 +f 17606/17614/1 17607/17615/1 9573/9581/1 9570/9578/1 +f 17607/17615/1 17608/17616/1 9574/9582/1 9573/9581/1 +f 9526/9534/1 9569/9577/1 9572/9580/1 9527/9535/1 +f 17609/17617/1 17610/17618/1 9569/9577/1 9526/9534/1 +f 17610/17618/1 17606/17614/1 9570/9578/1 9569/9577/1 +f 3658/3666/1 9565/9573/1 9568/9576/1 3659/3667/1 +f 9527/9535/1 9572/9580/1 9565/9573/1 3658/3666/1 +f 9572/9580/1 9571/9579/1 9566/9574/1 9565/9573/1 +f 9558/9566/1 9561/9569/1 9564/9572/1 9559/9567/1 +f 17611/17619/1 17612/17620/1 9561/9569/1 9558/9566/1 +f 17612/17620/1 17613/17621/1 9562/9570/1 9561/9569/1 +f 9574/9582/1 9557/9565/1 9560/9568/1 9575/9583/1 +f 17608/17616/1 17614/17622/1 9557/9565/1 9574/9582/1 +f 17614/17622/1 17611/17619/1 9558/9566/1 9557/9565/1 +f 3642/3650/1 9553/9561/1 9556/9564/1 3643/3651/1 +f 9575/9583/1 9560/9568/1 9553/9561/1 3642/3650/1 +f 9560/9568/1 9559/9567/1 9554/9562/1 9553/9561/1 +f 9546/9554/1 9549/9557/1 9552/9560/1 9547/9555/1 +f 9531/9539/1 3656/3664/1 9549/9557/1 9546/9554/1 +f 3656/3664/1 3655/3663/1 9550/9558/1 9549/9557/1 +f 16078/16086/1 9545/9553/1 9548/9556/1 16079/16087/1 +f 3791/3799/1 9532/9540/1 9545/9553/1 16078/16086/1 +f 9532/9540/1 9531/9539/1 9546/9554/1 9545/9553/1 +f 1474/1482/1 9541/9549/1 9544/9552/1 1475/1483/1 +f 16079/16087/1 9548/9556/1 9541/9549/1 1474/1482/1 +f 9548/9556/1 9547/9555/1 9542/9550/1 9541/9549/1 +f 9534/9542/1 9537/9545/1 9540/9548/1 9535/9543/1 +f 17615/17623/1 17616/17624/1 9537/9545/1 9534/9542/1 +f 17616/17624/1 17617/17625/1 9538/9546/1 9537/9545/1 +f 9130/9138/1 9533/9541/1 9536/9544/1 9131/9139/1 +f 17618/17626/1 17619/17627/1 9533/9541/1 9130/9138/1 +f 17619/17627/1 17615/17623/1 9534/9542/1 9533/9541/1 +f 3790/3798/1 9529/9537/1 9532/9540/1 3791/3799/1 +f 9131/9139/1 9536/9544/1 9529/9537/1 3790/3798/1 +f 9536/9544/1 9535/9543/1 9530/9538/1 9529/9537/1 +f 9522/9530/1 9525/9533/1 9528/9536/1 9523/9531/1 +f 17620/17628/1 17621/17629/1 9525/9533/1 9522/9530/1 +f 17621/17629/1 17609/17617/1 9526/9534/1 9525/9533/1 +f 9538/9546/1 9521/9529/1 9524/9532/1 9539/9547/1 +f 17617/17625/1 17622/17630/1 9521/9529/1 9538/9546/1 +f 17622/17630/1 17620/17628/1 9522/9530/1 9521/9529/1 +f 3654/3662/1 9517/9525/1 9520/9528/1 3655/3663/1 +f 9539/9547/1 9524/9532/1 9517/9525/1 3654/3662/1 +f 9524/9532/1 9523/9531/1 9518/9526/1 9517/9525/1 +f 9510/9518/1 9513/9521/1 9516/9524/1 9511/9519/1 +f 9495/9503/1 3668/3676/1 9513/9521/1 9510/9518/1 +f 3668/3676/1 3667/3675/1 9514/9522/1 9513/9521/1 +f 16834/16842/1 9509/9517/1 9512/9520/1 16835/16843/1 +f 4547/4555/1 9496/9504/1 9509/9517/1 16834/16842/1 +f 9496/9504/1 9495/9503/1 9510/9518/1 9509/9517/1 +f 1222/1230/1 9505/9513/1 9508/9516/1 1223/1231/1 +f 16835/16843/1 9512/9520/1 9505/9513/1 1222/1230/1 +f 9512/9520/1 9511/9519/1 9506/9514/1 9505/9513/1 +f 9498/9506/1 9501/9509/1 9504/9512/1 9499/9507/1 +f 9543/9551/1 3652/3660/1 9501/9509/1 9498/9506/1 +f 3652/3660/1 3651/3659/1 9502/9510/1 9501/9509/1 +f 6862/6870/1 9497/9505/1 9500/9508/1 6863/6871/1 +f 1475/1483/1 9544/9552/1 9497/9505/1 6862/6870/1 +f 9544/9552/1 9543/9551/1 9498/9506/1 9497/9505/1 +f 4546/4554/1 9493/9501/1 9496/9504/1 4547/4555/1 +f 6863/6871/1 9500/9508/1 9493/9501/1 4546/4554/1 +f 9500/9508/1 9499/9507/1 9494/9502/1 9493/9501/1 +f 9486/9494/1 9489/9497/1 9492/9500/1 9487/9495/1 +f 15939/15947/1 1520/1528/1 9489/9497/1 9486/9494/1 +f 1520/1528/1 1519/1527/1 9490/9498/1 9489/9497/1 +f 9502/9510/1 9485/9493/1 9488/9496/1 9503/9511/1 +f 3651/3659/1 15940/15948/1 9485/9493/1 9502/9510/1 +f 15940/15948/1 15939/15947/1 9486/9494/1 9485/9493/1 +f 3666/3674/1 9481/9489/1 9484/9492/1 3667/3675/1 +f 9503/9511/1 9488/9496/1 9481/9489/1 3666/3674/1 +f 9488/9496/1 9487/9495/1 9482/9490/1 9481/9489/1 +f 9474/9482/1 9477/9485/1 9480/9488/1 9475/9483/1 +f 9459/9467/1 3680/3688/1 9477/9485/1 9474/9482/1 +f 3680/3688/1 3679/3687/1 9478/9486/1 9477/9485/1 +f 15982/15990/1 9473/9481/1 9476/9484/1 15983/15991/1 +f 3695/3703/1 9460/9468/1 9473/9481/1 15982/15990/1 +f 9460/9468/1 9459/9467/1 9474/9482/1 9473/9481/1 +f 1506/1514/1 9469/9477/1 9472/9480/1 1507/1515/1 +f 15983/15991/1 9476/9484/1 9469/9477/1 1506/1514/1 +f 9476/9484/1 9475/9483/1 9470/9478/1 9469/9477/1 +f 9462/9470/1 9465/9473/1 9468/9476/1 9463/9471/1 +f 17623/17631/1 17624/17632/1 9465/9473/1 9462/9470/1 +f 17624/17632/1 17625/17633/1 9466/9474/1 9465/9473/1 +f 9418/9426/1 9461/9469/1 9464/9472/1 9419/9427/1 +f 17626/17634/1 17627/17635/1 9461/9469/1 9418/9426/1 +f 17627/17635/1 17623/17631/1 9462/9470/1 9461/9469/1 +f 3694/3702/1 9457/9465/1 9460/9468/1 3695/3703/1 +f 9419/9427/1 9464/9472/1 9457/9465/1 3694/3702/1 +f 9464/9472/1 9463/9471/1 9458/9466/1 9457/9465/1 +f 9450/9458/1 9453/9461/1 9456/9464/1 9451/9459/1 +f 17628/17636/1 17629/17637/1 9453/9461/1 9450/9458/1 +f 17629/17637/1 17630/17638/1 9454/9462/1 9453/9461/1 +f 9466/9474/1 9449/9457/1 9452/9460/1 9467/9475/1 +f 17625/17633/1 17631/17639/1 9449/9457/1 9466/9474/1 +f 17631/17639/1 17628/17636/1 9450/9458/1 9449/9457/1 +f 3678/3686/1 9445/9453/1 9448/9456/1 3679/3687/1 +f 9467/9475/1 9452/9460/1 9445/9453/1 3678/3686/1 +f 9452/9460/1 9451/9459/1 9446/9454/1 9445/9453/1 +f 9438/9446/1 9441/9449/1 9444/9452/1 9439/9447/1 +f 9423/9431/1 3692/3700/1 9441/9449/1 9438/9446/1 +f 3692/3700/1 3691/3699/1 9442/9450/1 9441/9449/1 +f 15934/15942/1 9437/9445/1 9440/9448/1 15935/15943/1 +f 3647/3655/1 9424/9432/1 9437/9445/1 15934/15942/1 +f 9424/9432/1 9423/9431/1 9438/9446/1 9437/9445/1 +f 1522/1530/1 9433/9441/1 9436/9444/1 1523/1531/1 +f 15935/15943/1 9440/9448/1 9433/9441/1 1522/1530/1 +f 9440/9448/1 9439/9447/1 9434/9442/1 9433/9441/1 +f 9426/9434/1 9429/9437/1 9432/9440/1 9427/9435/1 +f 17632/17640/1 17633/17641/1 9429/9437/1 9426/9434/1 +f 17633/17641/1 17634/17642/1 9430/9438/1 9429/9437/1 +f 9562/9570/1 9425/9433/1 9428/9436/1 9563/9571/1 +f 17613/17621/1 17635/17643/1 9425/9433/1 9562/9570/1 +f 17635/17643/1 17632/17640/1 9426/9434/1 9425/9433/1 +f 3646/3654/1 9421/9429/1 9424/9432/1 3647/3655/1 +f 9563/9571/1 9428/9436/1 9421/9429/1 3646/3654/1 +f 9428/9436/1 9427/9435/1 9422/9430/1 9421/9429/1 +f 9414/9422/1 9417/9425/1 9420/9428/1 9415/9423/1 +f 17636/17644/1 17637/17645/1 9417/9425/1 9414/9422/1 +f 17637/17645/1 17626/17634/1 9418/9426/1 9417/9425/1 +f 9430/9438/1 9413/9421/1 9416/9424/1 9431/9439/1 +f 17634/17642/1 17638/17646/1 9413/9421/1 9430/9438/1 +f 17638/17646/1 17636/17644/1 9414/9422/1 9413/9421/1 +f 3690/3698/1 9409/9417/1 9412/9420/1 3691/3699/1 +f 9431/9439/1 9416/9424/1 9409/9417/1 3690/3698/1 +f 9416/9424/1 9415/9423/1 9410/9418/1 9409/9417/1 +f 9402/9410/1 9405/9413/1 9408/9416/1 9403/9411/1 +f 9387/9395/1 3704/3712/1 9405/9413/1 9402/9410/1 +f 3704/3712/1 3703/3711/1 9406/9414/1 9405/9413/1 +f 16882/16890/1 9401/9409/1 9404/9412/1 16883/16891/1 +f 4595/4603/1 9388/9396/1 9401/9409/1 16882/16890/1 +f 9388/9396/1 9387/9395/1 9402/9410/1 9401/9409/1 +f 1206/1214/1 9397/9405/1 9400/9408/1 1207/1215/1 +f 16883/16891/1 9404/9412/1 9397/9405/1 1206/1214/1 +f 9404/9412/1 9403/9411/1 9398/9406/1 9397/9405/1 +f 9390/9398/1 9393/9401/1 9396/9404/1 9391/9399/1 +f 9435/9443/1 3688/3696/1 9393/9401/1 9390/9398/1 +f 3688/3696/1 3687/3695/1 9394/9402/1 9393/9401/1 +f 6718/6726/1 9389/9397/1 9392/9400/1 6719/6727/1 +f 1523/1531/1 9436/9444/1 9389/9397/1 6718/6726/1 +f 9436/9444/1 9435/9443/1 9390/9398/1 9389/9397/1 +f 4594/4602/1 9385/9393/1 9388/9396/1 4595/4603/1 +f 6719/6727/1 9392/9400/1 9385/9393/1 4594/4602/1 +f 9392/9400/1 9391/9399/1 9386/9394/1 9385/9393/1 +f 9378/9386/1 9381/9389/1 9384/9392/1 9379/9387/1 +f 15975/15983/1 1508/1516/1 9381/9389/1 9378/9386/1 +f 1508/1516/1 1507/1515/1 9382/9390/1 9381/9389/1 +f 9394/9402/1 9377/9385/1 9380/9388/1 9395/9403/1 +f 3687/3695/1 15976/15984/1 9377/9385/1 9394/9402/1 +f 15976/15984/1 15975/15983/1 9378/9386/1 9377/9385/1 +f 3702/3710/1 9373/9381/1 9376/9384/1 3703/3711/1 +f 9395/9403/1 9380/9388/1 9373/9381/1 3702/3710/1 +f 9380/9388/1 9379/9387/1 9374/9382/1 9373/9381/1 +f 9366/9374/1 9369/9377/1 9372/9380/1 9367/9375/1 +f 9351/9359/1 3716/3724/1 9369/9377/1 9366/9374/1 +f 3716/3724/1 3715/3723/1 9370/9378/1 9369/9377/1 +f 16018/16026/1 9365/9373/1 9368/9376/1 16019/16027/1 +f 3731/3739/1 9352/9360/1 9365/9373/1 16018/16026/1 +f 9352/9360/1 9351/9359/1 9366/9374/1 9365/9373/1 +f 1494/1502/1 9361/9369/1 9364/9372/1 1495/1503/1 +f 16019/16027/1 9368/9376/1 9361/9369/1 1494/1502/1 +f 9368/9376/1 9367/9375/1 9362/9370/1 9361/9369/1 +f 9354/9362/1 9357/9365/1 9360/9368/1 9355/9363/1 +f 6843/6851/1 4552/4560/1 9357/9365/1 9354/9362/1 +f 4552/4560/1 4551/4559/1 9358/9366/1 9357/9365/1 +f 9310/9318/1 9353/9361/1 9356/9364/1 9311/9319/1 +f 1479/1487/1 6844/6852/1 9353/9361/1 9310/9318/1 +f 6844/6852/1 6843/6851/1 9354/9362/1 9353/9361/1 +f 3730/3738/1 9349/9357/1 9352/9360/1 3731/3739/1 +f 9311/9319/1 9356/9364/1 9349/9357/1 3730/3738/1 +f 9356/9364/1 9355/9363/1 9350/9358/1 9349/9357/1 +f 9342/9350/1 9345/9353/1 9348/9356/1 9343/9351/1 +f 16839/16847/1 1220/1228/1 9345/9353/1 9342/9350/1 +f 1220/1228/1 1219/1227/1 9346/9354/1 9345/9353/1 +f 9358/9366/1 9341/9349/1 9344/9352/1 9359/9367/1 +f 4551/4559/1 16840/16848/1 9341/9349/1 9358/9366/1 +f 16840/16848/1 16839/16847/1 9342/9350/1 9341/9349/1 +f 3714/3722/1 9337/9345/1 9340/9348/1 3715/3723/1 +f 9359/9367/1 9344/9352/1 9337/9345/1 3714/3722/1 +f 9344/9352/1 9343/9351/1 9338/9346/1 9337/9345/1 +f 9330/9338/1 9333/9341/1 9336/9344/1 9331/9339/1 +f 9315/9323/1 3728/3736/1 9333/9341/1 9330/9338/1 +f 3728/3736/1 3727/3735/1 9334/9342/1 9333/9341/1 +f 14674/14682/1 9329/9337/1 9332/9340/1 14675/14683/1 +f 2387/2395/1 9316/9324/1 9329/9337/1 14674/14682/1 +f 9316/9324/1 9315/9323/1 9330/9338/1 9329/9337/1 +f 1942/1950/1 9325/9333/1 9328/9336/1 1943/1951/1 +f 14675/14683/1 9332/9340/1 9325/9333/1 1942/1950/1 +f 9332/9340/1 9331/9339/1 9326/9334/1 9325/9333/1 +f 9318/9326/1 9321/9329/1 9324/9332/1 9319/9327/1 +f 9183/9191/1 3772/3780/1 9321/9329/1 9318/9326/1 +f 3772/3780/1 3771/3779/1 9322/9330/1 9321/9329/1 +f 13342/13350/1 9317/9325/1 9320/9328/1 13343/13351/1 +f 1175/1183/1 9184/9192/1 9317/9325/1 13342/13350/1 +f 9184/9192/1 9183/9191/1 9318/9326/1 9317/9325/1 +f 2386/2394/1 9313/9321/1 9316/9324/1 2387/2395/1 +f 13343/13351/1 9320/9328/1 9313/9321/1 2386/2394/1 +f 9320/9328/1 9319/9327/1 9314/9322/1 9313/9321/1 +f 9306/9314/1 9309/9317/1 9312/9320/1 9307/9315/1 +f 16059/16067/1 1480/1488/1 9309/9317/1 9306/9314/1 +f 1480/1488/1 1479/1487/1 9310/9318/1 9309/9317/1 +f 9322/9330/1 9305/9313/1 9308/9316/1 9323/9331/1 +f 3771/3779/1 16060/16068/1 9305/9313/1 9322/9330/1 +f 16060/16068/1 16059/16067/1 9306/9314/1 9305/9313/1 +f 3726/3734/1 9301/9309/1 9304/9312/1 3727/3735/1 +f 9323/9331/1 9308/9316/1 9301/9309/1 3726/3734/1 +f 9308/9316/1 9307/9315/1 9302/9310/1 9301/9309/1 +f 9294/9302/1 9297/9305/1 9300/9308/1 9295/9303/1 +f 9279/9287/1 3740/3748/1 9297/9305/1 9294/9302/1 +f 3740/3748/1 3739/3747/1 9298/9306/1 9297/9305/1 +f 17302/17310/1 9293/9301/1 9296/9304/1 17303/17311/1 +f 5015/5023/1 9280/9288/1 9293/9301/1 17302/17310/1 +f 9280/9288/1 9279/9287/1 9294/9302/1 9293/9301/1 +f 1066/1074/1 9289/9297/1 9292/9300/1 1067/1075/1 +f 17303/17311/1 9296/9304/1 9289/9297/1 1066/1074/1 +f 9296/9304/1 9295/9303/1 9290/9298/1 9289/9297/1 +f 9282/9290/1 9285/9293/1 9288/9296/1 9283/9291/1 +f 9327/9335/1 3724/3732/1 9285/9293/1 9282/9290/1 +f 3724/3732/1 3723/3731/1 9286/9294/1 9285/9293/1 +f 5458/5466/1 9281/9289/1 9284/9292/1 5459/5467/1 +f 1943/1951/1 9328/9336/1 9281/9289/1 5458/5466/1 +f 9328/9336/1 9327/9335/1 9282/9290/1 9281/9289/1 +f 5014/5022/1 9277/9285/1 9280/9288/1 5015/5023/1 +f 5459/5467/1 9284/9292/1 9277/9285/1 5014/5022/1 +f 9284/9292/1 9283/9291/1 9278/9286/1 9277/9285/1 +f 9270/9278/1 9273/9281/1 9276/9284/1 9271/9279/1 +f 16011/16019/1 1496/1504/1 9273/9281/1 9270/9278/1 +f 1496/1504/1 1495/1503/1 9274/9282/1 9273/9281/1 +f 9286/9294/1 9269/9277/1 9272/9280/1 9287/9295/1 +f 3723/3731/1 16012/16020/1 9269/9277/1 9286/9294/1 +f 16012/16020/1 16011/16019/1 9270/9278/1 9269/9277/1 +f 3738/3746/1 9265/9273/1 9268/9276/1 3739/3747/1 +f 9287/9295/1 9272/9280/1 9265/9273/1 3738/3746/1 +f 9272/9280/1 9271/9279/1 9266/9274/1 9265/9273/1 +f 9258/9266/1 9261/9269/1 9264/9272/1 9259/9267/1 +f 9243/9251/1 3752/3760/1 9261/9269/1 9258/9266/1 +f 3752/3760/1 3751/3759/1 9262/9270/1 9261/9269/1 +f 16054/16062/1 9257/9265/1 9260/9268/1 16055/16063/1 +f 3767/3775/1 9244/9252/1 9257/9265/1 16054/16062/1 +f 9244/9252/1 9243/9251/1 9258/9266/1 9257/9265/1 +f 1482/1490/1 9253/9261/1 9256/9264/1 1483/1491/1 +f 16055/16063/1 9260/9268/1 9253/9261/1 1482/1490/1 +f 9260/9268/1 9259/9267/1 9254/9262/1 9253/9261/1 +f 9246/9254/1 9249/9257/1 9252/9260/1 9247/9255/1 +f 17639/17647/1 17640/17648/1 9249/9257/1 9246/9254/1 +f 17640/17648/1 17641/17649/1 9250/9258/1 9249/9257/1 +f 9202/9210/1 9245/9253/1 9248/9256/1 9203/9211/1 +f 17642/17650/1 17643/17651/1 9245/9253/1 9202/9210/1 +f 17643/17651/1 17639/17647/1 9246/9254/1 9245/9253/1 +f 3766/3774/1 9241/9249/1 9244/9252/1 3767/3775/1 +f 9203/9211/1 9248/9256/1 9241/9249/1 3766/3774/1 +f 9248/9256/1 9247/9255/1 9242/9250/1 9241/9249/1 +f 9234/9242/1 9237/9245/1 9240/9248/1 9235/9243/1 +f 17644/17652/1 17645/17653/1 9237/9245/1 9234/9242/1 +f 17645/17653/1 17646/17654/1 9238/9246/1 9237/9245/1 +f 9250/9258/1 9233/9241/1 9236/9244/1 9251/9259/1 +f 17641/17649/1 17647/17655/1 9233/9241/1 9250/9258/1 +f 17647/17655/1 17644/17652/1 9234/9242/1 9233/9241/1 +f 3750/3758/1 9229/9237/1 9232/9240/1 3751/3759/1 +f 9251/9259/1 9236/9244/1 9229/9237/1 3750/3758/1 +f 9236/9244/1 9235/9243/1 9230/9238/1 9229/9237/1 +f 9222/9230/1 9225/9233/1 9228/9236/1 9223/9231/1 +f 9207/9215/1 3764/3772/1 9225/9233/1 9222/9230/1 +f 3764/3772/1 3763/3771/1 9226/9234/1 9225/9233/1 +f 15646/15654/1 9221/9229/1 9224/9232/1 15647/15655/1 +f 3359/3367/1 9208/9216/1 9221/9229/1 15646/15654/1 +f 9208/9216/1 9207/9215/1 9222/9230/1 9221/9229/1 +f 1618/1626/1 9217/9225/1 9220/9228/1 1619/1627/1 +f 15647/15655/1 9224/9232/1 9217/9225/1 1618/1626/1 +f 9224/9232/1 9223/9231/1 9218/9226/1 9217/9225/1 +f 9210/9218/1 9213/9221/1 9216/9224/1 9211/9219/1 +f 17648/17656/1 17649/17657/1 9213/9221/1 9210/9218/1 +f 17649/17657/1 17650/17658/1 9214/9222/1 9213/9221/1 +f 10426/10434/1 9209/9217/1 9212/9220/1 10427/10435/1 +f 17502/17510/1 17651/17659/1 9209/9217/1 10426/10434/1 +f 17651/17659/1 17648/17656/1 9210/9218/1 9209/9217/1 +f 3358/3366/1 9205/9213/1 9208/9216/1 3359/3367/1 +f 10427/10435/1 9212/9220/1 9205/9213/1 3358/3366/1 +f 9212/9220/1 9211/9219/1 9206/9214/1 9205/9213/1 +f 9198/9206/1 9201/9209/1 9204/9212/1 9199/9207/1 +f 17652/17660/1 17653/17661/1 9201/9209/1 9198/9206/1 +f 17653/17661/1 17642/17650/1 9202/9210/1 9201/9209/1 +f 9214/9222/1 9197/9205/1 9200/9208/1 9215/9223/1 +f 17650/17658/1 17654/17662/1 9197/9205/1 9214/9222/1 +f 17654/17662/1 17652/17660/1 9198/9206/1 9197/9205/1 +f 3762/3770/1 9193/9201/1 9196/9204/1 3763/3771/1 +f 9215/9223/1 9200/9208/1 9193/9201/1 3762/3770/1 +f 9200/9208/1 9199/9207/1 9194/9202/1 9193/9201/1 +f 9186/9194/1 9189/9197/1 9192/9200/1 9187/9195/1 +f 9171/9179/1 3776/3784/1 9189/9197/1 9186/9194/1 +f 3776/3784/1 3775/3783/1 9190/9198/1 9189/9197/1 +f 16978/16986/1 9185/9193/1 9188/9196/1 16979/16987/1 +f 4691/4699/1 9172/9180/1 9185/9193/1 16978/16986/1 +f 9172/9180/1 9171/9179/1 9186/9194/1 9185/9193/1 +f 1174/1182/1 9181/9189/1 9184/9192/1 1175/1183/1 +f 16979/16987/1 9188/9196/1 9181/9189/1 1174/1182/1 +f 9188/9196/1 9187/9195/1 9182/9190/1 9181/9189/1 +f 9174/9182/1 9177/9185/1 9180/9188/1 9175/9183/1 +f 9219/9227/1 3760/3768/1 9177/9185/1 9174/9182/1 +f 3760/3768/1 3759/3767/1 9178/9186/1 9177/9185/1 +f 6430/6438/1 9173/9181/1 9176/9184/1 6431/6439/1 +f 1619/1627/1 9220/9228/1 9173/9181/1 6430/6438/1 +f 9220/9228/1 9219/9227/1 9174/9182/1 9173/9181/1 +f 4690/4698/1 9169/9177/1 9172/9180/1 4691/4699/1 +f 6431/6439/1 9176/9184/1 9169/9177/1 4690/4698/1 +f 9176/9184/1 9175/9183/1 9170/9178/1 9169/9177/1 +f 9162/9170/1 9165/9173/1 9168/9176/1 9163/9171/1 +f 16047/16055/1 1484/1492/1 9165/9173/1 9162/9170/1 +f 1484/1492/1 1483/1491/1 9166/9174/1 9165/9173/1 +f 9178/9186/1 9161/9169/1 9164/9172/1 9179/9187/1 +f 3759/3767/1 16048/16056/1 9161/9169/1 9178/9186/1 +f 16048/16056/1 16047/16055/1 9162/9170/1 9161/9169/1 +f 3774/3782/1 9157/9165/1 9160/9168/1 3775/3783/1 +f 9179/9187/1 9164/9172/1 9157/9165/1 3774/3782/1 +f 9164/9172/1 9163/9171/1 9158/9166/1 9157/9165/1 +f 9150/9158/1 9153/9161/1 9156/9164/1 9151/9159/1 +f 9135/9143/1 3788/3796/1 9153/9161/1 9150/9158/1 +f 3788/3796/1 3787/3795/1 9154/9162/1 9153/9161/1 +f 16090/16098/1 9149/9157/1 9152/9160/1 16091/16099/1 +f 3803/3811/1 9136/9144/1 9149/9157/1 16090/16098/1 +f 9136/9144/1 9135/9143/1 9150/9158/1 9149/9157/1 +f 1470/1478/1 9145/9153/1 9148/9156/1 1471/1479/1 +f 16091/16099/1 9152/9160/1 9145/9153/1 1470/1478/1 +f 9152/9160/1 9151/9159/1 9146/9154/1 9145/9153/1 +f 9138/9146/1 9141/9149/1 9144/9152/1 9139/9147/1 +f 17655/17663/1 17656/17664/1 9141/9149/1 9138/9146/1 +f 17656/17664/1 17657/17665/1 9142/9150/1 9141/9149/1 +f 9094/9102/1 9137/9145/1 9140/9148/1 9095/9103/1 +f 17658/17666/1 17659/17667/1 9137/9145/1 9094/9102/1 +f 17659/17667/1 17655/17663/1 9138/9146/1 9137/9145/1 +f 3802/3810/1 9133/9141/1 9136/9144/1 3803/3811/1 +f 9095/9103/1 9140/9148/1 9133/9141/1 3802/3810/1 +f 9140/9148/1 9139/9147/1 9134/9142/1 9133/9141/1 +f 9126/9134/1 9129/9137/1 9132/9140/1 9127/9135/1 +f 17660/17668/1 17661/17669/1 9129/9137/1 9126/9134/1 +f 17661/17669/1 17618/17626/1 9130/9138/1 9129/9137/1 +f 9142/9150/1 9125/9133/1 9128/9136/1 9143/9151/1 +f 17657/17665/1 17662/17670/1 9125/9133/1 9142/9150/1 +f 17662/17670/1 17660/17668/1 9126/9134/1 9125/9133/1 +f 3786/3794/1 9121/9129/1 9124/9132/1 3787/3795/1 +f 9143/9151/1 9128/9136/1 9121/9129/1 3786/3794/1 +f 9128/9136/1 9127/9135/1 9122/9130/1 9121/9129/1 +f 9114/9122/1 9117/9125/1 9120/9128/1 9115/9123/1 +f 9099/9107/1 3800/3808/1 9117/9125/1 9114/9122/1 +f 3800/3808/1 3799/3807/1 9118/9126/1 9117/9125/1 +f 16042/16050/1 9113/9121/1 9116/9124/1 16043/16051/1 +f 3755/3763/1 9100/9108/1 9113/9121/1 16042/16050/1 +f 9100/9108/1 9099/9107/1 9114/9122/1 9113/9121/1 +f 1486/1494/1 9109/9117/1 9112/9120/1 1487/1495/1 +f 16043/16051/1 9116/9124/1 9109/9117/1 1486/1494/1 +f 9116/9124/1 9115/9123/1 9110/9118/1 9109/9117/1 +f 9102/9110/1 9105/9113/1 9108/9116/1 9103/9111/1 +f 17663/17671/1 17664/17672/1 9105/9113/1 9102/9110/1 +f 17664/17672/1 17665/17673/1 9106/9114/1 9105/9113/1 +f 9238/9246/1 9101/9109/1 9104/9112/1 9239/9247/1 +f 17646/17654/1 17666/17674/1 9101/9109/1 9238/9246/1 +f 17666/17674/1 17663/17671/1 9102/9110/1 9101/9109/1 +f 3754/3762/1 9097/9105/1 9100/9108/1 3755/3763/1 +f 9239/9247/1 9104/9112/1 9097/9105/1 3754/3762/1 +f 9104/9112/1 9103/9111/1 9098/9106/1 9097/9105/1 +f 9090/9098/1 9093/9101/1 9096/9104/1 9091/9099/1 +f 17667/17675/1 17668/17676/1 9093/9101/1 9090/9098/1 +f 17668/17676/1 17658/17666/1 9094/9102/1 9093/9101/1 +f 9106/9114/1 9089/9097/1 9092/9100/1 9107/9115/1 +f 17665/17673/1 17669/17677/1 9089/9097/1 9106/9114/1 +f 17669/17677/1 17667/17675/1 9090/9098/1 9089/9097/1 +f 3798/3806/1 9085/9093/1 9088/9096/1 3799/3807/1 +f 9107/9115/1 9092/9100/1 9085/9093/1 3798/3806/1 +f 9092/9100/1 9091/9099/1 9086/9094/1 9085/9093/1 +f 9078/9086/1 9081/9089/1 9084/9092/1 9079/9087/1 +f 9063/9071/1 3812/3820/1 9081/9089/1 9078/9086/1 +f 3812/3820/1 3811/3819/1 9082/9090/1 9081/9089/1 +f 16846/16854/1 9077/9085/1 9080/9088/1 16847/16855/1 +f 4559/4567/1 9064/9072/1 9077/9085/1 16846/16854/1 +f 9064/9072/1 9063/9071/1 9078/9086/1 9077/9085/1 +f 1218/1226/1 9073/9081/1 9076/9084/1 1219/1227/1 +f 16847/16855/1 9080/9088/1 9073/9081/1 1218/1226/1 +f 9080/9088/1 9079/9087/1 9074/9082/1 9073/9081/1 +f 9066/9074/1 9069/9077/1 9072/9080/1 9067/9075/1 +f 9111/9119/1 3796/3804/1 9069/9077/1 9066/9074/1 +f 3796/3804/1 3795/3803/1 9070/9078/1 9069/9077/1 +f 6826/6834/1 9065/9073/1 9068/9076/1 6827/6835/1 +f 1487/1495/1 9112/9120/1 9065/9073/1 6826/6834/1 +f 9112/9120/1 9111/9119/1 9066/9074/1 9065/9073/1 +f 4558/4566/1 9061/9069/1 9064/9072/1 4559/4567/1 +f 6827/6835/1 9068/9076/1 9061/9069/1 4558/4566/1 +f 9068/9076/1 9067/9075/1 9062/9070/1 9061/9069/1 +f 9054/9062/1 9057/9065/1 9060/9068/1 9055/9063/1 +f 16083/16091/1 1472/1480/1 9057/9065/1 9054/9062/1 +f 1472/1480/1 1471/1479/1 9058/9066/1 9057/9065/1 +f 9070/9078/1 9053/9061/1 9056/9064/1 9071/9079/1 +f 3795/3803/1 16084/16092/1 9053/9061/1 9070/9078/1 +f 16084/16092/1 16083/16091/1 9054/9062/1 9053/9061/1 +f 3810/3818/1 9049/9057/1 9052/9060/1 3811/3819/1 +f 9071/9079/1 9056/9064/1 9049/9057/1 3810/3818/1 +f 9056/9064/1 9055/9063/1 9050/9058/1 9049/9057/1 +f 9042/9050/1 9045/9053/1 9048/9056/1 9043/9051/1 +f 9027/9035/1 3824/3832/1 9045/9053/1 9042/9050/1 +f 3824/3832/1 3823/3831/1 9046/9054/1 9045/9053/1 +f 16126/16134/1 9041/9049/1 9044/9052/1 16127/16135/1 +f 3839/3847/1 9028/9036/1 9041/9049/1 16126/16134/1 +f 9028/9036/1 9027/9035/1 9042/9050/1 9041/9049/1 +f 1458/1466/1 9037/9045/1 9040/9048/1 1459/1467/1 +f 16127/16135/1 9044/9052/1 9037/9045/1 1458/1466/1 +f 9044/9052/1 9043/9051/1 9038/9046/1 9037/9045/1 +f 9030/9038/1 9033/9041/1 9036/9044/1 9031/9039/1 +f 6951/6959/1 4516/4524/1 9033/9041/1 9030/9038/1 +f 4516/4524/1 4515/4523/1 9034/9042/1 9033/9041/1 +f 8986/8994/1 9029/9037/1 9032/9040/1 8987/8995/1 +f 1443/1451/1 6952/6960/1 9029/9037/1 8986/8994/1 +f 6952/6960/1 6951/6959/1 9030/9038/1 9029/9037/1 +f 3838/3846/1 9025/9033/1 9028/9036/1 3839/3847/1 +f 8987/8995/1 9032/9040/1 9025/9033/1 3838/3846/1 +f 9032/9040/1 9031/9039/1 9026/9034/1 9025/9033/1 +f 9018/9026/1 9021/9029/1 9024/9032/1 9019/9027/1 +f 16803/16811/1 1232/1240/1 9021/9029/1 9018/9026/1 +f 1232/1240/1 1231/1239/1 9022/9030/1 9021/9029/1 +f 9034/9042/1 9017/9025/1 9020/9028/1 9035/9043/1 +f 4515/4523/1 16804/16812/1 9017/9025/1 9034/9042/1 +f 16804/16812/1 16803/16811/1 9018/9026/1 9017/9025/1 +f 3822/3830/1 9013/9021/1 9016/9024/1 3823/3831/1 +f 9035/9043/1 9020/9028/1 9013/9021/1 3822/3830/1 +f 9020/9028/1 9019/9027/1 9014/9022/1 9013/9021/1 +f 9006/9014/1 9009/9017/1 9012/9020/1 9007/9015/1 +f 8991/8999/1 3836/3844/1 9009/9017/1 9006/9014/1 +f 3836/3844/1 3835/3843/1 9010/9018/1 9009/9017/1 +f 14422/14430/1 9005/9013/1 9008/9016/1 14423/14431/1 +f 2135/2143/1 8992/9000/1 9005/9013/1 14422/14430/1 +f 8992/9000/1 8991/8999/1 9006/9014/1 9005/9013/1 +f 2026/2034/1 9001/9009/1 9004/9012/1 2027/2035/1 +f 14423/14431/1 9008/9016/1 9001/9009/1 2026/2034/1 +f 9008/9016/1 9007/9015/1 9002/9010/1 9001/9009/1 +f 8994/9002/1 8997/9005/1 9000/9008/1 8995/9003/1 +f 8859/8867/1 3880/3888/1 8997/9005/1 8994/9002/1 +f 3880/3888/1 3879/3887/1 8998/9006/1 8997/9005/1 +f 14098/14106/1 8993/9001/1 8996/9004/1 14099/14107/1 +f 1259/1267/1 8860/8868/1 8993/9001/1 14098/14106/1 +f 8860/8868/1 8859/8867/1 8994/9002/1 8993/9001/1 +f 2134/2142/1 8989/8997/1 8992/9000/1 2135/2143/1 +f 14099/14107/1 8996/9004/1 8989/8997/1 2134/2142/1 +f 8996/9004/1 8995/9003/1 8990/8998/1 8989/8997/1 +f 8982/8990/1 8985/8993/1 8988/8996/1 8983/8991/1 +f 16167/16175/1 1444/1452/1 8985/8993/1 8982/8990/1 +f 1444/1452/1 1443/1451/1 8986/8994/1 8985/8993/1 +f 8998/9006/1 8981/8989/1 8984/8992/1 8999/9007/1 +f 3879/3887/1 16168/16176/1 8981/8989/1 8998/9006/1 +f 16168/16176/1 16167/16175/1 8982/8990/1 8981/8989/1 +f 3834/3842/1 8977/8985/1 8980/8988/1 3835/3843/1 +f 8999/9007/1 8984/8992/1 8977/8985/1 3834/3842/1 +f 8984/8992/1 8983/8991/1 8978/8986/1 8977/8985/1 +f 8970/8978/1 8973/8981/1 8976/8984/1 8971/8979/1 +f 8955/8963/1 3848/3856/1 8973/8981/1 8970/8978/1 +f 3848/3856/1 3847/3855/1 8974/8982/1 8973/8981/1 +f 17386/17394/1 8969/8977/1 8972/8980/1 17387/17395/1 +f 5099/5107/1 8956/8964/1 8969/8977/1 17386/17394/1 +f 8956/8964/1 8955/8963/1 8970/8978/1 8969/8977/1 +f 1038/1046/1 8965/8973/1 8968/8976/1 1039/1047/1 +f 17387/17395/1 8972/8980/1 8965/8973/1 1038/1046/1 +f 8972/8980/1 8971/8979/1 8966/8974/1 8965/8973/1 +f 8958/8966/1 8961/8969/1 8964/8972/1 8959/8967/1 +f 9003/9011/1 3832/3840/1 8961/8969/1 8958/8966/1 +f 3832/3840/1 3831/3839/1 8962/8970/1 8961/8969/1 +f 5206/5214/1 8957/8965/1 8960/8968/1 5207/5215/1 +f 2027/2035/1 9004/9012/1 8957/8965/1 5206/5214/1 +f 9004/9012/1 9003/9011/1 8958/8966/1 8957/8965/1 +f 5098/5106/1 8953/8961/1 8956/8964/1 5099/5107/1 +f 5207/5215/1 8960/8968/1 8953/8961/1 5098/5106/1 +f 8960/8968/1 8959/8967/1 8954/8962/1 8953/8961/1 +f 8946/8954/1 8949/8957/1 8952/8960/1 8947/8955/1 +f 16119/16127/1 1460/1468/1 8949/8957/1 8946/8954/1 +f 1460/1468/1 1459/1467/1 8950/8958/1 8949/8957/1 +f 8962/8970/1 8945/8953/1 8948/8956/1 8963/8971/1 +f 3831/3839/1 16120/16128/1 8945/8953/1 8962/8970/1 +f 16120/16128/1 16119/16127/1 8946/8954/1 8945/8953/1 +f 3846/3854/1 8941/8949/1 8944/8952/1 3847/3855/1 +f 8963/8971/1 8948/8956/1 8941/8949/1 3846/3854/1 +f 8948/8956/1 8947/8955/1 8942/8950/1 8941/8949/1 +f 8934/8942/1 8937/8945/1 8940/8948/1 8935/8943/1 +f 8919/8927/1 3860/3868/1 8937/8945/1 8934/8942/1 +f 3860/3868/1 3859/3867/1 8938/8946/1 8937/8945/1 +f 16162/16170/1 8933/8941/1 8936/8944/1 16163/16171/1 +f 3875/3883/1 8920/8928/1 8933/8941/1 16162/16170/1 +f 8920/8928/1 8919/8927/1 8934/8942/1 8933/8941/1 +f 1446/1454/1 8929/8937/1 8932/8940/1 1447/1455/1 +f 16163/16171/1 8936/8944/1 8929/8937/1 1446/1454/1 +f 8936/8944/1 8935/8943/1 8930/8938/1 8929/8937/1 +f 8922/8930/1 8925/8933/1 8928/8936/1 8923/8931/1 +f 6807/6815/1 4564/4572/1 8925/8933/1 8922/8930/1 +f 4564/4572/1 4563/4571/1 8926/8934/1 8925/8933/1 +f 8878/8886/1 8921/8929/1 8924/8932/1 8879/8887/1 +f 1491/1499/1 6808/6816/1 8921/8929/1 8878/8886/1 +f 6808/6816/1 6807/6815/1 8922/8930/1 8921/8929/1 +f 3874/3882/1 8917/8925/1 8920/8928/1 3875/3883/1 +f 8879/8887/1 8924/8932/1 8917/8925/1 3874/3882/1 +f 8924/8932/1 8923/8931/1 8918/8926/1 8917/8925/1 +f 8910/8918/1 8913/8921/1 8916/8924/1 8911/8919/1 +f 16851/16859/1 1216/1224/1 8913/8921/1 8910/8918/1 +f 1216/1224/1 1215/1223/1 8914/8922/1 8913/8921/1 +f 8926/8934/1 8909/8917/1 8912/8920/1 8927/8935/1 +f 4563/4571/1 16852/16860/1 8909/8917/1 8926/8934/1 +f 16852/16860/1 16851/16859/1 8910/8918/1 8909/8917/1 +f 3858/3866/1 8905/8913/1 8908/8916/1 3859/3867/1 +f 8927/8935/1 8912/8920/1 8905/8913/1 3858/3866/1 +f 8912/8920/1 8911/8919/1 8906/8914/1 8905/8913/1 +f 8898/8906/1 8901/8909/1 8904/8912/1 8899/8907/1 +f 8883/8891/1 3872/3880/1 8901/8909/1 8898/8906/1 +f 3872/3880/1 3871/3879/1 8902/8910/1 8901/8909/1 +f 16402/16410/1 8897/8905/1 8900/8908/1 16403/16411/1 +f 4115/4123/1 8884/8892/1 8897/8905/1 16402/16410/1 +f 8884/8892/1 8883/8891/1 8898/8906/1 8897/8905/1 +f 1366/1374/1 8893/8901/1 8896/8904/1 1367/1375/1 +f 16403/16411/1 8900/8908/1 8893/8901/1 1366/1374/1 +f 8900/8908/1 8899/8907/1 8894/8902/1 8893/8901/1 +f 8886/8894/1 8889/8897/1 8892/8900/1 8887/8895/1 +f 9291/9299/1 3736/3744/1 8889/8897/1 8886/8894/1 +f 3736/3744/1 3735/3743/1 8890/8898/1 8889/8897/1 +f 8158/8166/1 8885/8893/1 8888/8896/1 8159/8167/1 +f 1067/1075/1 9292/9300/1 8885/8893/1 8158/8166/1 +f 9292/9300/1 9291/9299/1 8886/8894/1 8885/8893/1 +f 4114/4122/1 8881/8889/1 8884/8892/1 4115/4123/1 +f 8159/8167/1 8888/8896/1 8881/8889/1 4114/4122/1 +f 8888/8896/1 8887/8895/1 8882/8890/1 8881/8889/1 +f 8874/8882/1 8877/8885/1 8880/8888/1 8875/8883/1 +f 16023/16031/1 1492/1500/1 8877/8885/1 8874/8882/1 +f 1492/1500/1 1491/1499/1 8878/8886/1 8877/8885/1 +f 8890/8898/1 8873/8881/1 8876/8884/1 8891/8899/1 +f 3735/3743/1 16024/16032/1 8873/8881/1 8890/8898/1 +f 16024/16032/1 16023/16031/1 8874/8882/1 8873/8881/1 +f 3870/3878/1 8869/8877/1 8872/8880/1 3871/3879/1 +f 8891/8899/1 8876/8884/1 8869/8877/1 3870/3878/1 +f 8876/8884/1 8875/8883/1 8870/8878/1 8869/8877/1 +f 8862/8870/1 8865/8873/1 8868/8876/1 8863/8871/1 +f 8847/8855/1 3884/3892/1 8865/8873/1 8862/8870/1 +f 3884/3892/1 3883/3891/1 8866/8874/1 8865/8873/1 +f 16726/16734/1 8861/8869/1 8864/8872/1 16727/16735/1 +f 4439/4447/1 8848/8856/1 8861/8869/1 16726/16734/1 +f 8848/8856/1 8847/8855/1 8862/8870/1 8861/8869/1 +f 1258/1266/1 8857/8865/1 8860/8868/1 1259/1267/1 +f 16727/16735/1 8864/8872/1 8857/8865/1 1258/1266/1 +f 8864/8872/1 8863/8871/1 8858/8866/1 8857/8865/1 +f 8850/8858/1 8853/8861/1 8856/8864/1 8851/8859/1 +f 8895/8903/1 3868/3876/1 8853/8861/1 8850/8858/1 +f 3868/3876/1 3867/3875/1 8854/8862/1 8853/8861/1 +f 7186/7194/1 8849/8857/1 8852/8860/1 7187/7195/1 +f 1367/1375/1 8896/8904/1 8849/8857/1 7186/7194/1 +f 8896/8904/1 8895/8903/1 8850/8858/1 8849/8857/1 +f 4438/4446/1 8845/8853/1 8848/8856/1 4439/4447/1 +f 7187/7195/1 8852/8860/1 8845/8853/1 4438/4446/1 +f 8852/8860/1 8851/8859/1 8846/8854/1 8845/8853/1 +f 8838/8846/1 8841/8849/1 8844/8852/1 8839/8847/1 +f 16155/16163/1 1448/1456/1 8841/8849/1 8838/8846/1 +f 1448/1456/1 1447/1455/1 8842/8850/1 8841/8849/1 +f 8854/8862/1 8837/8845/1 8840/8848/1 8855/8863/1 +f 3867/3875/1 16156/16164/1 8837/8845/1 8854/8862/1 +f 16156/16164/1 16155/16163/1 8838/8846/1 8837/8845/1 +f 3882/3890/1 8833/8841/1 8836/8844/1 3883/3891/1 +f 8855/8863/1 8840/8848/1 8833/8841/1 3882/3890/1 +f 8840/8848/1 8839/8847/1 8834/8842/1 8833/8841/1 +f 8826/8834/1 8829/8837/1 8832/8840/1 8827/8835/1 +f 8811/8819/1 3896/3904/1 8829/8837/1 8826/8834/1 +f 3896/3904/1 3895/3903/1 8830/8838/1 8829/8837/1 +f 16198/16206/1 8825/8833/1 8828/8836/1 16199/16207/1 +f 3911/3919/1 8812/8820/1 8825/8833/1 16198/16206/1 +f 8812/8820/1 8811/8819/1 8826/8834/1 8825/8833/1 +f 1434/1442/1 8821/8829/1 8824/8832/1 1435/1443/1 +f 16199/16207/1 8828/8836/1 8821/8829/1 1434/1442/1 +f 8828/8836/1 8827/8835/1 8822/8830/1 8821/8829/1 +f 8814/8822/1 8817/8825/1 8820/8828/1 8815/8823/1 +f 5331/5339/1 5056/5064/1 8817/8825/1 8814/8822/1 +f 5056/5064/1 5055/5063/1 8818/8826/1 8817/8825/1 +f 8770/8778/1 8813/8821/1 8816/8824/1 8771/8779/1 +f 1983/1991/1 5332/5340/1 8813/8821/1 8770/8778/1 +f 5332/5340/1 5331/5339/1 8814/8822/1 8813/8821/1 +f 3910/3918/1 8809/8817/1 8812/8820/1 3911/3919/1 +f 8771/8779/1 8816/8824/1 8809/8817/1 3910/3918/1 +f 8816/8824/1 8815/8823/1 8810/8818/1 8809/8817/1 +f 8802/8810/1 8805/8813/1 8808/8816/1 8803/8811/1 +f 17343/17351/1 1052/1060/1 8805/8813/1 8802/8810/1 +f 1052/1060/1 1051/1059/1 8806/8814/1 8805/8813/1 +f 8818/8826/1 8801/8809/1 8804/8812/1 8819/8827/1 +f 5055/5063/1 17344/17352/1 8801/8809/1 8818/8826/1 +f 17344/17352/1 17343/17351/1 8802/8810/1 8801/8809/1 +f 3894/3902/1 8797/8805/1 8800/8808/1 3895/3903/1 +f 8819/8827/1 8804/8812/1 8797/8805/1 3894/3902/1 +f 8804/8812/1 8803/8811/1 8798/8806/1 8797/8805/1 +f 8790/8798/1 8793/8801/1 8796/8804/1 8791/8799/1 +f 8775/8783/1 3908/3916/1 8793/8801/1 8790/8798/1 +f 3908/3916/1 3907/3915/1 8794/8802/1 8793/8801/1 +f 16150/16158/1 8789/8797/1 8792/8800/1 16151/16159/1 +f 3863/3871/1 8776/8784/1 8789/8797/1 16150/16158/1 +f 8776/8784/1 8775/8783/1 8790/8798/1 8789/8797/1 +f 1450/1458/1 8785/8793/1 8788/8796/1 1451/1459/1 +f 16151/16159/1 8792/8800/1 8785/8793/1 1450/1458/1 +f 8792/8800/1 8791/8799/1 8786/8794/1 8785/8793/1 +f 8778/8786/1 8781/8789/1 8784/8792/1 8779/8787/1 +f 13719/13727/1 2260/2268/1 8781/8789/1 8778/8786/1 +f 2260/2268/1 2259/2267/1 8782/8790/1 8781/8789/1 +f 8914/8922/1 8777/8785/1 8780/8788/1 8915/8923/1 +f 1215/1223/1 13720/13728/1 8777/8785/1 8914/8922/1 +f 13720/13728/1 13719/13727/1 8778/8786/1 8777/8785/1 +f 3862/3870/1 8773/8781/1 8776/8784/1 3863/3871/1 +f 8915/8923/1 8780/8788/1 8773/8781/1 3862/3870/1 +f 8780/8788/1 8779/8787/1 8774/8782/1 8773/8781/1 +f 8766/8774/1 8769/8777/1 8772/8780/1 8767/8775/1 +f 14547/14555/1 1984/1992/1 8769/8777/1 8766/8774/1 +f 1984/1992/1 1983/1991/1 8770/8778/1 8769/8777/1 +f 8782/8790/1 8765/8773/1 8768/8776/1 8783/8791/1 +f 2259/2267/1 14548/14556/1 8765/8773/1 8782/8790/1 +f 14548/14556/1 14547/14555/1 8766/8774/1 8765/8773/1 +f 3906/3914/1 8761/8769/1 8764/8772/1 3907/3915/1 +f 8783/8791/1 8768/8776/1 8761/8769/1 3906/3914/1 +f 8768/8776/1 8767/8775/1 8762/8770/1 8761/8769/1 +f 8754/8762/1 8757/8765/1 8760/8768/1 8755/8763/1 +f 8739/8747/1 3920/3928/1 8757/8765/1 8754/8762/1 +f 3920/3928/1 3919/3927/1 8758/8766/1 8757/8765/1 +f 16810/16818/1 8753/8761/1 8756/8764/1 16811/16819/1 +f 4523/4531/1 8740/8748/1 8753/8761/1 16810/16818/1 +f 8740/8748/1 8739/8747/1 8754/8762/1 8753/8761/1 +f 1230/1238/1 8749/8757/1 8752/8760/1 1231/1239/1 +f 16811/16819/1 8756/8764/1 8749/8757/1 1230/1238/1 +f 8756/8764/1 8755/8763/1 8750/8758/1 8749/8757/1 +f 8742/8750/1 8745/8753/1 8748/8756/1 8743/8751/1 +f 8787/8795/1 3904/3912/1 8745/8753/1 8742/8750/1 +f 3904/3912/1 3903/3911/1 8746/8754/1 8745/8753/1 +f 6934/6942/1 8741/8749/1 8744/8752/1 6935/6943/1 +f 1451/1459/1 8788/8796/1 8741/8749/1 6934/6942/1 +f 8788/8796/1 8787/8795/1 8742/8750/1 8741/8749/1 +f 4522/4530/1 8737/8745/1 8740/8748/1 4523/4531/1 +f 6935/6943/1 8744/8752/1 8737/8745/1 4522/4530/1 +f 8744/8752/1 8743/8751/1 8738/8746/1 8737/8745/1 +f 8730/8738/1 8733/8741/1 8736/8744/1 8731/8739/1 +f 16191/16199/1 1436/1444/1 8733/8741/1 8730/8738/1 +f 1436/1444/1 1435/1443/1 8734/8742/1 8733/8741/1 +f 8746/8754/1 8729/8737/1 8732/8740/1 8747/8755/1 +f 3903/3911/1 16192/16200/1 8729/8737/1 8746/8754/1 +f 16192/16200/1 16191/16199/1 8730/8738/1 8729/8737/1 +f 3918/3926/1 8725/8733/1 8728/8736/1 3919/3927/1 +f 8747/8755/1 8732/8740/1 8725/8733/1 3918/3926/1 +f 8732/8740/1 8731/8739/1 8726/8734/1 8725/8733/1 +f 8718/8726/1 8721/8729/1 8724/8732/1 8719/8727/1 +f 8703/8711/1 3932/3940/1 8721/8729/1 8718/8726/1 +f 3932/3940/1 3931/3939/1 8722/8730/1 8721/8729/1 +f 16234/16242/1 8717/8725/1 8720/8728/1 16235/16243/1 +f 3947/3955/1 8704/8712/1 8717/8725/1 16234/16242/1 +f 8704/8712/1 8703/8711/1 8718/8726/1 8717/8725/1 +f 1422/1430/1 8713/8721/1 8716/8724/1 1423/1431/1 +f 16235/16243/1 8720/8728/1 8713/8721/1 1422/1430/1 +f 8720/8728/1 8719/8727/1 8714/8722/1 8713/8721/1 +f 8706/8714/1 8709/8717/1 8712/8720/1 8707/8715/1 +f 7059/7067/1 4480/4488/1 8709/8717/1 8706/8714/1 +f 4480/4488/1 4479/4487/1 8710/8718/1 8709/8717/1 +f 8662/8670/1 8705/8713/1 8708/8716/1 8663/8671/1 +f 1407/1415/1 7060/7068/1 8705/8713/1 8662/8670/1 +f 7060/7068/1 7059/7067/1 8706/8714/1 8705/8713/1 +f 3946/3954/1 8701/8709/1 8704/8712/1 3947/3955/1 +f 8663/8671/1 8708/8716/1 8701/8709/1 3946/3954/1 +f 8708/8716/1 8707/8715/1 8702/8710/1 8701/8709/1 +f 8694/8702/1 8697/8705/1 8700/8708/1 8695/8703/1 +f 16767/16775/1 1244/1252/1 8697/8705/1 8694/8702/1 +f 1244/1252/1 1243/1251/1 8698/8706/1 8697/8705/1 +f 8710/8718/1 8693/8701/1 8696/8704/1 8711/8719/1 +f 4479/4487/1 16768/16776/1 8693/8701/1 8710/8718/1 +f 16768/16776/1 16767/16775/1 8694/8702/1 8693/8701/1 +f 3930/3938/1 8689/8697/1 8692/8700/1 3931/3939/1 +f 8711/8719/1 8696/8704/1 8689/8697/1 3930/3938/1 +f 8696/8704/1 8695/8703/1 8690/8698/1 8689/8697/1 +f 8682/8690/1 8685/8693/1 8688/8696/1 8683/8691/1 +f 8667/8675/1 3944/3952/1 8685/8693/1 8682/8690/1 +f 3944/3952/1 3943/3951/1 8686/8694/1 8685/8693/1 +f 14494/14502/1 8681/8689/1 8684/8692/1 14495/14503/1 +f 2207/2215/1 8668/8676/1 8681/8689/1 14494/14502/1 +f 8668/8676/1 8667/8675/1 8682/8690/1 8681/8689/1 +f 2002/2010/1 8677/8685/1 8680/8688/1 2003/2011/1 +f 14495/14503/1 8684/8692/1 8677/8685/1 2002/2010/1 +f 8684/8692/1 8683/8691/1 8678/8686/1 8677/8685/1 +f 8670/8678/1 8673/8681/1 8676/8684/1 8671/8679/1 +f 8535/8543/1 3988/3996/1 8673/8681/1 8670/8678/1 +f 3988/3996/1 3987/3995/1 8674/8682/1 8673/8681/1 +f 13882/13890/1 8669/8677/1 8672/8680/1 13883/13891/1 +f 1235/1243/1 8536/8544/1 8669/8677/1 13882/13890/1 +f 8536/8544/1 8535/8543/1 8670/8678/1 8669/8677/1 +f 2206/2214/1 8665/8673/1 8668/8676/1 2207/2215/1 +f 13883/13891/1 8672/8680/1 8665/8673/1 2206/2214/1 +f 8672/8680/1 8671/8679/1 8666/8674/1 8665/8673/1 +f 8658/8666/1 8661/8669/1 8664/8672/1 8659/8667/1 +f 16275/16283/1 1408/1416/1 8661/8669/1 8658/8666/1 +f 1408/1416/1 1407/1415/1 8662/8670/1 8661/8669/1 +f 8674/8682/1 8657/8665/1 8660/8668/1 8675/8683/1 +f 3987/3995/1 16276/16284/1 8657/8665/1 8674/8682/1 +f 16276/16284/1 16275/16283/1 8658/8666/1 8657/8665/1 +f 3942/3950/1 8653/8661/1 8656/8664/1 3943/3951/1 +f 8675/8683/1 8660/8668/1 8653/8661/1 3942/3950/1 +f 8660/8668/1 8659/8667/1 8654/8662/1 8653/8661/1 +f 8646/8654/1 8649/8657/1 8652/8660/1 8647/8655/1 +f 8631/8639/1 3956/3964/1 8649/8657/1 8646/8654/1 +f 3956/3964/1 3955/3963/1 8650/8658/1 8649/8657/1 +f 17362/17370/1 8645/8653/1 8648/8656/1 17363/17371/1 +f 5075/5083/1 8632/8640/1 8645/8653/1 17362/17370/1 +f 8632/8640/1 8631/8639/1 8646/8654/1 8645/8653/1 +f 1046/1054/1 8641/8649/1 8644/8652/1 1047/1055/1 +f 17363/17371/1 8648/8656/1 8641/8649/1 1046/1054/1 +f 8648/8656/1 8647/8655/1 8642/8650/1 8641/8649/1 +f 8634/8642/1 8637/8645/1 8640/8648/1 8635/8643/1 +f 8679/8687/1 3940/3948/1 8637/8645/1 8634/8642/1 +f 3940/3948/1 3939/3947/1 8638/8646/1 8637/8645/1 +f 5278/5286/1 8633/8641/1 8636/8644/1 5279/5287/1 +f 2003/2011/1 8680/8688/1 8633/8641/1 5278/5286/1 +f 8680/8688/1 8679/8687/1 8634/8642/1 8633/8641/1 +f 5074/5082/1 8629/8637/1 8632/8640/1 5075/5083/1 +f 5279/5287/1 8636/8644/1 8629/8637/1 5074/5082/1 +f 8636/8644/1 8635/8643/1 8630/8638/1 8629/8637/1 +f 8622/8630/1 8625/8633/1 8628/8636/1 8623/8631/1 +f 16227/16235/1 1424/1432/1 8625/8633/1 8622/8630/1 +f 1424/1432/1 1423/1431/1 8626/8634/1 8625/8633/1 +f 8638/8646/1 8621/8629/1 8624/8632/1 8639/8647/1 +f 3939/3947/1 16228/16236/1 8621/8629/1 8638/8646/1 +f 16228/16236/1 16227/16235/1 8622/8630/1 8621/8629/1 +f 3954/3962/1 8617/8625/1 8620/8628/1 3955/3963/1 +f 8639/8647/1 8624/8632/1 8617/8625/1 3954/3962/1 +f 8624/8632/1 8623/8631/1 8618/8626/1 8617/8625/1 +f 8610/8618/1 8613/8621/1 8616/8624/1 8611/8619/1 +f 8595/8603/1 3968/3976/1 8613/8621/1 8610/8618/1 +f 3968/3976/1 3967/3975/1 8614/8622/1 8613/8621/1 +f 16270/16278/1 8609/8617/1 8612/8620/1 16271/16279/1 +f 3983/3991/1 8596/8604/1 8609/8617/1 16270/16278/1 +f 8596/8604/1 8595/8603/1 8610/8618/1 8609/8617/1 +f 1410/1418/1 8605/8613/1 8608/8616/1 1411/1419/1 +f 16271/16279/1 8612/8620/1 8605/8613/1 1410/1418/1 +f 8612/8620/1 8611/8619/1 8606/8614/1 8605/8613/1 +f 8598/8606/1 8601/8609/1 8604/8612/1 8599/8607/1 +f 6699/6707/1 4600/4608/1 8601/8609/1 8598/8606/1 +f 4600/4608/1 4599/4607/1 8602/8610/1 8601/8609/1 +f 8554/8562/1 8597/8605/1 8600/8608/1 8555/8563/1 +f 1527/1535/1 6700/6708/1 8597/8605/1 8554/8562/1 +f 6700/6708/1 6699/6707/1 8598/8606/1 8597/8605/1 +f 3982/3990/1 8593/8601/1 8596/8604/1 3983/3991/1 +f 8555/8563/1 8600/8608/1 8593/8601/1 3982/3990/1 +f 8600/8608/1 8599/8607/1 8594/8602/1 8593/8601/1 +f 8586/8594/1 8589/8597/1 8592/8600/1 8587/8595/1 +f 16887/16895/1 1204/1212/1 8589/8597/1 8586/8594/1 +f 1204/1212/1 1203/1211/1 8590/8598/1 8589/8597/1 +f 8602/8610/1 8585/8593/1 8588/8596/1 8603/8611/1 +f 4599/4607/1 16888/16896/1 8585/8593/1 8602/8610/1 +f 16888/16896/1 16887/16895/1 8586/8594/1 8585/8593/1 +f 3966/3974/1 8581/8589/1 8584/8592/1 3967/3975/1 +f 8603/8611/1 8588/8596/1 8581/8589/1 3966/3974/1 +f 8588/8596/1 8587/8595/1 8582/8590/1 8581/8589/1 +f 8574/8582/1 8577/8585/1 8580/8588/1 8575/8583/1 +f 8559/8567/1 3980/3988/1 8577/8585/1 8574/8582/1 +f 3980/3988/1 3979/3987/1 8578/8586/1 8577/8585/1 +f 16186/16194/1 8573/8581/1 8576/8584/1 16187/16195/1 +f 3899/3907/1 8560/8568/1 8573/8581/1 16186/16194/1 +f 8560/8568/1 8559/8567/1 8574/8582/1 8573/8581/1 +f 1438/1446/1 8569/8577/1 8572/8580/1 1439/1447/1 +f 16187/16195/1 8576/8584/1 8569/8577/1 1438/1446/1 +f 8576/8584/1 8575/8583/1 8570/8578/1 8569/8577/1 +f 8562/8570/1 8565/8573/1 8568/8576/1 8563/8571/1 +f 9615/9623/1 3628/3636/1 8565/8573/1 8562/8570/1 +f 3628/3636/1 3627/3635/1 8566/8574/1 8565/8573/1 +f 8806/8814/1 8561/8569/1 8564/8572/1 8807/8815/1 +f 1051/1059/1 9616/9624/1 8561/8569/1 8806/8814/1 +f 9616/9624/1 9615/9623/1 8562/8570/1 8561/8569/1 +f 3898/3906/1 8557/8565/1 8560/8568/1 3899/3907/1 +f 8807/8815/1 8564/8572/1 8557/8565/1 3898/3906/1 +f 8564/8572/1 8563/8571/1 8558/8566/1 8557/8565/1 +f 8550/8558/1 8553/8561/1 8556/8564/1 8551/8559/1 +f 15915/15923/1 1528/1536/1 8553/8561/1 8550/8558/1 +f 1528/1536/1 1527/1535/1 8554/8562/1 8553/8561/1 +f 8566/8574/1 8549/8557/1 8552/8560/1 8567/8575/1 +f 3627/3635/1 15916/15924/1 8549/8557/1 8566/8574/1 +f 15916/15924/1 15915/15923/1 8550/8558/1 8549/8557/1 +f 3978/3986/1 8545/8553/1 8548/8556/1 3979/3987/1 +f 8567/8575/1 8552/8560/1 8545/8553/1 3978/3986/1 +f 8552/8560/1 8551/8559/1 8546/8554/1 8545/8553/1 +f 8538/8546/1 8541/8549/1 8544/8552/1 8539/8547/1 +f 8523/8531/1 3992/4000/1 8541/8549/1 8538/8546/1 +f 3992/4000/1 3991/3999/1 8542/8550/1 8541/8549/1 +f 16798/16806/1 8537/8545/1 8540/8548/1 16799/16807/1 +f 4511/4519/1 8524/8532/1 8537/8545/1 16798/16806/1 +f 8524/8532/1 8523/8531/1 8538/8546/1 8537/8545/1 +f 1234/1242/1 8533/8541/1 8536/8544/1 1235/1243/1 +f 16799/16807/1 8540/8548/1 8533/8541/1 1234/1242/1 +f 8540/8548/1 8539/8547/1 8534/8542/1 8533/8541/1 +f 8526/8534/1 8529/8537/1 8532/8540/1 8527/8535/1 +f 8571/8579/1 3976/3984/1 8529/8537/1 8526/8534/1 +f 3976/3984/1 3975/3983/1 8530/8538/1 8529/8537/1 +f 6970/6978/1 8525/8533/1 8528/8536/1 6971/6979/1 +f 1439/1447/1 8572/8580/1 8525/8533/1 6970/6978/1 +f 8572/8580/1 8571/8579/1 8526/8534/1 8525/8533/1 +f 4510/4518/1 8521/8529/1 8524/8532/1 4511/4519/1 +f 6971/6979/1 8528/8536/1 8521/8529/1 4510/4518/1 +f 8528/8536/1 8527/8535/1 8522/8530/1 8521/8529/1 +f 8514/8522/1 8517/8525/1 8520/8528/1 8515/8523/1 +f 16263/16271/1 1412/1420/1 8517/8525/1 8514/8522/1 +f 1412/1420/1 1411/1419/1 8518/8526/1 8517/8525/1 +f 8530/8538/1 8513/8521/1 8516/8524/1 8531/8539/1 +f 3975/3983/1 16264/16272/1 8513/8521/1 8530/8538/1 +f 16264/16272/1 16263/16271/1 8514/8522/1 8513/8521/1 +f 3990/3998/1 8509/8517/1 8512/8520/1 3991/3999/1 +f 8531/8539/1 8516/8524/1 8509/8517/1 3990/3998/1 +f 8516/8524/1 8515/8523/1 8510/8518/1 8509/8517/1 +f 8502/8510/1 8505/8513/1 8508/8516/1 8503/8511/1 +f 8487/8495/1 4004/4012/1 8505/8513/1 8502/8510/1 +f 4004/4012/1 4003/4011/1 8506/8514/1 8505/8513/1 +f 16306/16314/1 8501/8509/1 8504/8512/1 16307/16315/1 +f 4019/4027/1 8488/8496/1 8501/8509/1 16306/16314/1 +f 8488/8496/1 8487/8495/1 8502/8510/1 8501/8509/1 +f 1398/1406/1 8497/8505/1 8500/8508/1 1399/1407/1 +f 16307/16315/1 8504/8512/1 8497/8505/1 1398/1406/1 +f 8504/8512/1 8503/8511/1 8498/8506/1 8497/8505/1 +f 8490/8498/1 8493/8501/1 8496/8504/1 8491/8499/1 +f 5367/5375/1 5044/5052/1 8493/8501/1 8490/8498/1 +f 5044/5052/1 5043/5051/1 8494/8502/1 8493/8501/1 +f 8446/8454/1 8489/8497/1 8492/8500/1 8447/8455/1 +f 1971/1979/1 5368/5376/1 8489/8497/1 8446/8454/1 +f 5368/5376/1 5367/5375/1 8490/8498/1 8489/8497/1 +f 4018/4026/1 8485/8493/1 8488/8496/1 4019/4027/1 +f 8447/8455/1 8492/8500/1 8485/8493/1 4018/4026/1 +f 8492/8500/1 8491/8499/1 8486/8494/1 8485/8493/1 +f 8478/8486/1 8481/8489/1 8484/8492/1 8479/8487/1 +f 17331/17339/1 1056/1064/1 8481/8489/1 8478/8486/1 +f 1056/1064/1 1055/1063/1 8482/8490/1 8481/8489/1 +f 8494/8502/1 8477/8485/1 8480/8488/1 8495/8503/1 +f 5043/5051/1 17332/17340/1 8477/8485/1 8494/8502/1 +f 17332/17340/1 17331/17339/1 8478/8486/1 8477/8485/1 +f 4002/4010/1 8473/8481/1 8476/8484/1 4003/4011/1 +f 8495/8503/1 8480/8488/1 8473/8481/1 4002/4010/1 +f 8480/8488/1 8479/8487/1 8474/8482/1 8473/8481/1 +f 8466/8474/1 8469/8477/1 8472/8480/1 8467/8475/1 +f 8451/8459/1 4016/4024/1 8469/8477/1 8466/8474/1 +f 4016/4024/1 4015/4023/1 8470/8478/1 8469/8477/1 +f 16258/16266/1 8465/8473/1 8468/8476/1 16259/16267/1 +f 3971/3979/1 8452/8460/1 8465/8473/1 16258/16266/1 +f 8452/8460/1 8451/8459/1 8466/8474/1 8465/8473/1 +f 1414/1422/1 8461/8469/1 8464/8472/1 1415/1423/1 +f 16259/16267/1 8468/8476/1 8461/8469/1 1414/1422/1 +f 8468/8476/1 8467/8475/1 8462/8470/1 8461/8469/1 +f 8454/8462/1 8457/8465/1 8460/8468/1 8455/8463/1 +f 13611/13619/1 2296/2304/1 8457/8465/1 8454/8462/1 +f 2296/2304/1 2295/2303/1 8458/8466/1 8457/8465/1 +f 8590/8598/1 8453/8461/1 8456/8464/1 8591/8599/1 +f 1203/1211/1 13612/13620/1 8453/8461/1 8590/8598/1 +f 13612/13620/1 13611/13619/1 8454/8462/1 8453/8461/1 +f 3970/3978/1 8449/8457/1 8452/8460/1 3971/3979/1 +f 8591/8599/1 8456/8464/1 8449/8457/1 3970/3978/1 +f 8456/8464/1 8455/8463/1 8450/8458/1 8449/8457/1 +f 8442/8450/1 8445/8453/1 8448/8456/1 8443/8451/1 +f 14583/14591/1 1972/1980/1 8445/8453/1 8442/8450/1 +f 1972/1980/1 1971/1979/1 8446/8454/1 8445/8453/1 +f 8458/8466/1 8441/8449/1 8444/8452/1 8459/8467/1 +f 2295/2303/1 14584/14592/1 8441/8449/1 8458/8466/1 +f 14584/14592/1 14583/14591/1 8442/8450/1 8441/8449/1 +f 4014/4022/1 8437/8445/1 8440/8448/1 4015/4023/1 +f 8459/8467/1 8444/8452/1 8437/8445/1 4014/4022/1 +f 8444/8452/1 8443/8451/1 8438/8446/1 8437/8445/1 +f 8430/8438/1 8433/8441/1 8436/8444/1 8431/8439/1 +f 8415/8423/1 4028/4036/1 8433/8441/1 8430/8438/1 +f 4028/4036/1 4027/4035/1 8434/8442/1 8433/8441/1 +f 16774/16782/1 8429/8437/1 8432/8440/1 16775/16783/1 +f 4487/4495/1 8416/8424/1 8429/8437/1 16774/16782/1 +f 8416/8424/1 8415/8423/1 8430/8438/1 8429/8437/1 +f 1242/1250/1 8425/8433/1 8428/8436/1 1243/1251/1 +f 16775/16783/1 8432/8440/1 8425/8433/1 1242/1250/1 +f 8432/8440/1 8431/8439/1 8426/8434/1 8425/8433/1 +f 8418/8426/1 8421/8429/1 8424/8432/1 8419/8427/1 +f 8463/8471/1 4012/4020/1 8421/8429/1 8418/8426/1 +f 4012/4020/1 4011/4019/1 8422/8430/1 8421/8429/1 +f 7042/7050/1 8417/8425/1 8420/8428/1 7043/7051/1 +f 1415/1423/1 8464/8472/1 8417/8425/1 7042/7050/1 +f 8464/8472/1 8463/8471/1 8418/8426/1 8417/8425/1 +f 4486/4494/1 8413/8421/1 8416/8424/1 4487/4495/1 +f 7043/7051/1 8420/8428/1 8413/8421/1 4486/4494/1 +f 8420/8428/1 8419/8427/1 8414/8422/1 8413/8421/1 +f 8406/8414/1 8409/8417/1 8412/8420/1 8407/8415/1 +f 16299/16307/1 1400/1408/1 8409/8417/1 8406/8414/1 +f 1400/1408/1 1399/1407/1 8410/8418/1 8409/8417/1 +f 8422/8430/1 8405/8413/1 8408/8416/1 8423/8431/1 +f 4011/4019/1 16300/16308/1 8405/8413/1 8422/8430/1 +f 16300/16308/1 16299/16307/1 8406/8414/1 8405/8413/1 +f 4026/4034/1 8401/8409/1 8404/8412/1 4027/4035/1 +f 8423/8431/1 8408/8416/1 8401/8409/1 4026/4034/1 +f 8408/8416/1 8407/8415/1 8402/8410/1 8401/8409/1 +f 8394/8402/1 8397/8405/1 8400/8408/1 8395/8403/1 +f 8379/8387/1 4040/4048/1 8397/8405/1 8394/8402/1 +f 4040/4048/1 4039/4047/1 8398/8406/1 8397/8405/1 +f 16342/16350/1 8393/8401/1 8396/8404/1 16343/16351/1 +f 4055/4063/1 8380/8388/1 8393/8401/1 16342/16350/1 +f 8380/8388/1 8379/8387/1 8394/8402/1 8393/8401/1 +f 1386/1394/1 8389/8397/1 8392/8400/1 1387/1395/1 +f 16343/16351/1 8396/8404/1 8389/8397/1 1386/1394/1 +f 8396/8404/1 8395/8403/1 8390/8398/1 8389/8397/1 +f 8382/8390/1 8385/8393/1 8388/8396/1 8383/8391/1 +f 7167/7175/1 4444/4452/1 8385/8393/1 8382/8390/1 +f 4444/4452/1 4443/4451/1 8386/8394/1 8385/8393/1 +f 8338/8346/1 8381/8389/1 8384/8392/1 8339/8347/1 +f 1371/1379/1 7168/7176/1 8381/8389/1 8338/8346/1 +f 7168/7176/1 7167/7175/1 8382/8390/1 8381/8389/1 +f 4054/4062/1 8377/8385/1 8380/8388/1 4055/4063/1 +f 8339/8347/1 8384/8392/1 8377/8385/1 4054/4062/1 +f 8384/8392/1 8383/8391/1 8378/8386/1 8377/8385/1 +f 8370/8378/1 8373/8381/1 8376/8384/1 8371/8379/1 +f 16731/16739/1 1256/1264/1 8373/8381/1 8370/8378/1 +f 1256/1264/1 1255/1263/1 8374/8382/1 8373/8381/1 +f 8386/8394/1 8369/8377/1 8372/8380/1 8387/8395/1 +f 4443/4451/1 16732/16740/1 8369/8377/1 8386/8394/1 +f 16732/16740/1 16731/16739/1 8370/8378/1 8369/8377/1 +f 4038/4046/1 8365/8373/1 8368/8376/1 4039/4047/1 +f 8387/8395/1 8372/8380/1 8365/8373/1 4038/4046/1 +f 8372/8380/1 8371/8379/1 8366/8374/1 8365/8373/1 +f 8358/8366/1 8361/8369/1 8364/8372/1 8359/8367/1 +f 8343/8351/1 4052/4060/1 8361/8369/1 8358/8366/1 +f 4052/4060/1 4051/4059/1 8362/8370/1 8361/8369/1 +f 14602/14610/1 8357/8365/1 8360/8368/1 14603/14611/1 +f 2315/2323/1 8344/8352/1 8357/8365/1 14602/14610/1 +f 8344/8352/1 8343/8351/1 8358/8366/1 8357/8365/1 +f 1966/1974/1 8353/8361/1 8356/8364/1 1967/1975/1 +f 14603/14611/1 8360/8368/1 8353/8361/1 1966/1974/1 +f 8360/8368/1 8359/8367/1 8354/8362/1 8353/8361/1 +f 8346/8354/1 8349/8357/1 8352/8360/1 8347/8355/1 +f 8211/8219/1 4096/4104/1 8349/8357/1 8346/8354/1 +f 4096/4104/1 4095/4103/1 8350/8358/1 8349/8357/1 +f 13558/13566/1 8345/8353/1 8348/8356/1 13559/13567/1 +f 1199/1207/1 8212/8220/1 8345/8353/1 13558/13566/1 +f 8212/8220/1 8211/8219/1 8346/8354/1 8345/8353/1 +f 2314/2322/1 8341/8349/1 8344/8352/1 2315/2323/1 +f 13559/13567/1 8348/8356/1 8341/8349/1 2314/2322/1 +f 8348/8356/1 8347/8355/1 8342/8350/1 8341/8349/1 +f 8334/8342/1 8337/8345/1 8340/8348/1 8335/8343/1 +f 16383/16391/1 1372/1380/1 8337/8345/1 8334/8342/1 +f 1372/1380/1 1371/1379/1 8338/8346/1 8337/8345/1 +f 8350/8358/1 8333/8341/1 8336/8344/1 8351/8359/1 +f 4095/4103/1 16384/16392/1 8333/8341/1 8350/8358/1 +f 16384/16392/1 16383/16391/1 8334/8342/1 8333/8341/1 +f 4050/4058/1 8329/8337/1 8332/8340/1 4051/4059/1 +f 8351/8359/1 8336/8344/1 8329/8337/1 4050/4058/1 +f 8336/8344/1 8335/8343/1 8330/8338/1 8329/8337/1 +f 8322/8330/1 8325/8333/1 8328/8336/1 8323/8331/1 +f 8307/8315/1 4064/4072/1 8325/8333/1 8322/8330/1 +f 4064/4072/1 4063/4071/1 8326/8334/1 8325/8333/1 +f 17326/17334/1 8321/8329/1 8324/8332/1 17327/17335/1 +f 5039/5047/1 8308/8316/1 8321/8329/1 17326/17334/1 +f 8308/8316/1 8307/8315/1 8322/8330/1 8321/8329/1 +f 1058/1066/1 8317/8325/1 8320/8328/1 1059/1067/1 +f 17327/17335/1 8324/8332/1 8317/8325/1 1058/1066/1 +f 8324/8332/1 8323/8331/1 8318/8326/1 8317/8325/1 +f 8310/8318/1 8313/8321/1 8316/8324/1 8311/8319/1 +f 8355/8363/1 4048/4056/1 8313/8321/1 8310/8318/1 +f 4048/4056/1 4047/4055/1 8314/8322/1 8313/8321/1 +f 5386/5394/1 8309/8317/1 8312/8320/1 5387/5395/1 +f 1967/1975/1 8356/8364/1 8309/8317/1 5386/5394/1 +f 8356/8364/1 8355/8363/1 8310/8318/1 8309/8317/1 +f 5038/5046/1 8305/8313/1 8308/8316/1 5039/5047/1 +f 5387/5395/1 8312/8320/1 8305/8313/1 5038/5046/1 +f 8312/8320/1 8311/8319/1 8306/8314/1 8305/8313/1 +f 8298/8306/1 8301/8309/1 8304/8312/1 8299/8307/1 +f 16335/16343/1 1388/1396/1 8301/8309/1 8298/8306/1 +f 1388/1396/1 1387/1395/1 8302/8310/1 8301/8309/1 +f 8314/8322/1 8297/8305/1 8300/8308/1 8315/8323/1 +f 4047/4055/1 16336/16344/1 8297/8305/1 8314/8322/1 +f 16336/16344/1 16335/16343/1 8298/8306/1 8297/8305/1 +f 4062/4070/1 8293/8301/1 8296/8304/1 4063/4071/1 +f 8315/8323/1 8300/8308/1 8293/8301/1 4062/4070/1 +f 8300/8308/1 8299/8307/1 8294/8302/1 8293/8301/1 +f 8286/8294/1 8289/8297/1 8292/8300/1 8287/8295/1 +f 8271/8279/1 4076/4084/1 8289/8297/1 8286/8294/1 +f 4076/4084/1 4075/4083/1 8290/8298/1 8289/8297/1 +f 16378/16386/1 8285/8293/1 8288/8296/1 16379/16387/1 +f 4091/4099/1 8272/8280/1 8285/8293/1 16378/16386/1 +f 8272/8280/1 8271/8279/1 8286/8294/1 8285/8293/1 +f 1374/1382/1 8281/8289/1 8284/8292/1 1375/1383/1 +f 16379/16387/1 8288/8296/1 8281/8289/1 1374/1382/1 +f 8288/8296/1 8287/8295/1 8282/8290/1 8281/8289/1 +f 8274/8282/1 8277/8285/1 8280/8288/1 8275/8283/1 +f 6375/6383/1 4708/4716/1 8277/8285/1 8274/8282/1 +f 4708/4716/1 4707/4715/1 8278/8286/1 8277/8285/1 +f 8230/8238/1 8273/8281/1 8276/8284/1 8231/8239/1 +f 1635/1643/1 6376/6384/1 8273/8281/1 8230/8238/1 +f 6376/6384/1 6375/6383/1 8274/8282/1 8273/8281/1 +f 4090/4098/1 8269/8277/1 8272/8280/1 4091/4099/1 +f 8231/8239/1 8276/8284/1 8269/8277/1 4090/4098/1 +f 8276/8284/1 8275/8283/1 8270/8278/1 8269/8277/1 +f 8262/8270/1 8265/8273/1 8268/8276/1 8263/8271/1 +f 16995/17003/1 1168/1176/1 8265/8273/1 8262/8270/1 +f 1168/1176/1 1167/1175/1 8266/8274/1 8265/8273/1 +f 8278/8286/1 8261/8269/1 8264/8272/1 8279/8287/1 +f 4707/4715/1 16996/17004/1 8261/8269/1 8278/8286/1 +f 16996/17004/1 16995/17003/1 8262/8270/1 8261/8269/1 +f 4074/4082/1 8257/8265/1 8260/8268/1 4075/4083/1 +f 8279/8287/1 8264/8272/1 8257/8265/1 4074/4082/1 +f 8264/8272/1 8263/8271/1 8258/8266/1 8257/8265/1 +f 8250/8258/1 8253/8261/1 8256/8264/1 8251/8259/1 +f 8235/8243/1 4088/4096/1 8253/8261/1 8250/8258/1 +f 4088/4096/1 4087/4095/1 8254/8262/1 8253/8261/1 +f 15862/15870/1 8249/8257/1 8252/8260/1 15863/15871/1 +f 3575/3583/1 8236/8244/1 8249/8257/1 15862/15870/1 +f 8236/8244/1 8235/8243/1 8250/8258/1 8249/8257/1 +f 1546/1554/1 8245/8253/1 8248/8256/1 1547/1555/1 +f 15863/15871/1 8252/8260/1 8245/8253/1 1546/1554/1 +f 8252/8260/1 8251/8259/1 8246/8254/1 8245/8253/1 +f 8238/8246/1 8241/8249/1 8244/8252/1 8239/8247/1 +f 10587/10595/1 3304/3312/1 8241/8249/1 8238/8246/1 +f 3304/3312/1 3303/3311/1 8242/8250/1 8241/8249/1 +f 9778/9786/1 8237/8245/1 8240/8248/1 9779/9787/1 +f 1063/1071/1 10588/10596/1 8237/8245/1 9778/9786/1 +f 10588/10596/1 10587/10595/1 8238/8246/1 8237/8245/1 +f 3574/3582/1 8233/8241/1 8236/8244/1 3575/3583/1 +f 9779/9787/1 8240/8248/1 8233/8241/1 3574/3582/1 +f 8240/8248/1 8239/8247/1 8234/8242/1 8233/8241/1 +f 8226/8234/1 8229/8237/1 8232/8240/1 8227/8235/1 +f 15591/15599/1 1636/1644/1 8229/8237/1 8226/8234/1 +f 1636/1644/1 1635/1643/1 8230/8238/1 8229/8237/1 +f 8242/8250/1 8225/8233/1 8228/8236/1 8243/8251/1 +f 3303/3311/1 15592/15600/1 8225/8233/1 8242/8250/1 +f 15592/15600/1 15591/15599/1 8226/8234/1 8225/8233/1 +f 4086/4094/1 8221/8229/1 8224/8232/1 4087/4095/1 +f 8243/8251/1 8228/8236/1 8221/8229/1 4086/4094/1 +f 8228/8236/1 8227/8235/1 8222/8230/1 8221/8229/1 +f 8214/8222/1 8217/8225/1 8220/8228/1 8215/8223/1 +f 8199/8207/1 4100/4108/1 8217/8225/1 8214/8222/1 +f 4100/4108/1 4099/4107/1 8218/8226/1 8217/8225/1 +f 16906/16914/1 8213/8221/1 8216/8224/1 16907/16915/1 +f 4619/4627/1 8200/8208/1 8213/8221/1 16906/16914/1 +f 8200/8208/1 8199/8207/1 8214/8222/1 8213/8221/1 +f 1198/1206/1 8209/8217/1 8212/8220/1 1199/1207/1 +f 16907/16915/1 8216/8224/1 8209/8217/1 1198/1206/1 +f 8216/8224/1 8215/8223/1 8210/8218/1 8209/8217/1 +f 8202/8210/1 8205/8213/1 8208/8216/1 8203/8211/1 +f 8247/8255/1 4084/4092/1 8205/8213/1 8202/8210/1 +f 4084/4092/1 4083/4091/1 8206/8214/1 8205/8213/1 +f 6646/6654/1 8201/8209/1 8204/8212/1 6647/6655/1 +f 1547/1555/1 8248/8256/1 8201/8209/1 6646/6654/1 +f 8248/8256/1 8247/8255/1 8202/8210/1 8201/8209/1 +f 4618/4626/1 8197/8205/1 8200/8208/1 4619/4627/1 +f 6647/6655/1 8204/8212/1 8197/8205/1 4618/4626/1 +f 8204/8212/1 8203/8211/1 8198/8206/1 8197/8205/1 +f 8190/8198/1 8193/8201/1 8196/8204/1 8191/8199/1 +f 16371/16379/1 1376/1384/1 8193/8201/1 8190/8198/1 +f 1376/1384/1 1375/1383/1 8194/8202/1 8193/8201/1 +f 8206/8214/1 8189/8197/1 8192/8200/1 8207/8215/1 +f 4083/4091/1 16372/16380/1 8189/8197/1 8206/8214/1 +f 16372/16380/1 16371/16379/1 8190/8198/1 8189/8197/1 +f 4098/4106/1 8185/8193/1 8188/8196/1 4099/4107/1 +f 8207/8215/1 8192/8200/1 8185/8193/1 4098/4106/1 +f 8192/8200/1 8191/8199/1 8186/8194/1 8185/8193/1 +f 8178/8186/1 8181/8189/1 8184/8192/1 8179/8187/1 +f 8163/8171/1 4112/4120/1 8181/8189/1 8178/8186/1 +f 4112/4120/1 4111/4119/1 8182/8190/1 8181/8189/1 +f 16414/16422/1 8177/8185/1 8180/8188/1 16415/16423/1 +f 4127/4135/1 8164/8172/1 8177/8185/1 16414/16422/1 +f 8164/8172/1 8163/8171/1 8178/8186/1 8177/8185/1 +f 1362/1370/1 8173/8181/1 8176/8184/1 1363/1371/1 +f 16415/16423/1 8180/8188/1 8173/8181/1 1362/1370/1 +f 8180/8188/1 8179/8187/1 8174/8182/1 8173/8181/1 +f 8166/8174/1 8169/8177/1 8172/8180/1 8167/8175/1 +f 5475/5483/1 5008/5016/1 8169/8177/1 8166/8174/1 +f 5008/5016/1 5007/5015/1 8170/8178/1 8169/8177/1 +f 8122/8130/1 8165/8173/1 8168/8176/1 8123/8131/1 +f 1935/1943/1 5476/5484/1 8165/8173/1 8122/8130/1 +f 5476/5484/1 5475/5483/1 8166/8174/1 8165/8173/1 +f 4126/4134/1 8161/8169/1 8164/8172/1 4127/4135/1 +f 8123/8131/1 8168/8176/1 8161/8169/1 4126/4134/1 +f 8168/8176/1 8167/8175/1 8162/8170/1 8161/8169/1 +f 8154/8162/1 8157/8165/1 8160/8168/1 8155/8163/1 +f 17295/17303/1 1068/1076/1 8157/8165/1 8154/8162/1 +f 1068/1076/1 1067/1075/1 8158/8166/1 8157/8165/1 +f 8170/8178/1 8153/8161/1 8156/8164/1 8171/8179/1 +f 5007/5015/1 17296/17304/1 8153/8161/1 8170/8178/1 +f 17296/17304/1 17295/17303/1 8154/8162/1 8153/8161/1 +f 4110/4118/1 8149/8157/1 8152/8160/1 4111/4119/1 +f 8171/8179/1 8156/8164/1 8149/8157/1 4110/4118/1 +f 8156/8164/1 8155/8163/1 8150/8158/1 8149/8157/1 +f 8142/8150/1 8145/8153/1 8148/8156/1 8143/8151/1 +f 8127/8135/1 4124/4132/1 8145/8153/1 8142/8150/1 +f 4124/4132/1 4123/4131/1 8146/8154/1 8145/8153/1 +f 16366/16374/1 8141/8149/1 8144/8152/1 16367/16375/1 +f 4079/4087/1 8128/8136/1 8141/8149/1 16366/16374/1 +f 8128/8136/1 8127/8135/1 8142/8150/1 8141/8149/1 +f 1378/1386/1 8137/8145/1 8140/8148/1 1379/1387/1 +f 16367/16375/1 8144/8152/1 8137/8145/1 1378/1386/1 +f 8144/8152/1 8143/8151/1 8138/8146/1 8137/8145/1 +f 8130/8138/1 8133/8141/1 8136/8144/1 8131/8139/1 +f 13287/13295/1 2404/2412/1 8133/8141/1 8130/8138/1 +f 2404/2412/1 2403/2411/1 8134/8142/1 8133/8141/1 +f 8266/8274/1 8129/8137/1 8132/8140/1 8267/8275/1 +f 1167/1175/1 13288/13296/1 8129/8137/1 8266/8274/1 +f 13288/13296/1 13287/13295/1 8130/8138/1 8129/8137/1 +f 4078/4086/1 8125/8133/1 8128/8136/1 4079/4087/1 +f 8267/8275/1 8132/8140/1 8125/8133/1 4078/4086/1 +f 8132/8140/1 8131/8139/1 8126/8134/1 8125/8133/1 +f 8118/8126/1 8121/8129/1 8124/8132/1 8119/8127/1 +f 14691/14699/1 1936/1944/1 8121/8129/1 8118/8126/1 +f 1936/1944/1 1935/1943/1 8122/8130/1 8121/8129/1 +f 8134/8142/1 8117/8125/1 8120/8128/1 8135/8143/1 +f 2403/2411/1 14692/14700/1 8117/8125/1 8134/8142/1 +f 14692/14700/1 14691/14699/1 8118/8126/1 8117/8125/1 +f 4122/4130/1 8113/8121/1 8116/8124/1 4123/4131/1 +f 8135/8143/1 8120/8128/1 8113/8121/1 4122/4130/1 +f 8120/8128/1 8119/8127/1 8114/8122/1 8113/8121/1 +f 8106/8114/1 8109/8117/1 8112/8120/1 8107/8115/1 +f 8091/8099/1 4136/4144/1 8109/8117/1 8106/8114/1 +f 4136/4144/1 4135/4143/1 8110/8118/1 8109/8117/1 +f 16738/16746/1 8105/8113/1 8108/8116/1 16739/16747/1 +f 4451/4459/1 8092/8100/1 8105/8113/1 16738/16746/1 +f 8092/8100/1 8091/8099/1 8106/8114/1 8105/8113/1 +f 1254/1262/1 8101/8109/1 8104/8112/1 1255/1263/1 +f 16739/16747/1 8108/8116/1 8101/8109/1 1254/1262/1 +f 8108/8116/1 8107/8115/1 8102/8110/1 8101/8109/1 +f 8094/8102/1 8097/8105/1 8100/8108/1 8095/8103/1 +f 8139/8147/1 4120/4128/1 8097/8105/1 8094/8102/1 +f 4120/4128/1 4119/4127/1 8098/8106/1 8097/8105/1 +f 7150/7158/1 8093/8101/1 8096/8104/1 7151/7159/1 +f 1379/1387/1 8140/8148/1 8093/8101/1 7150/7158/1 +f 8140/8148/1 8139/8147/1 8094/8102/1 8093/8101/1 +f 4450/4458/1 8089/8097/1 8092/8100/1 4451/4459/1 +f 7151/7159/1 8096/8104/1 8089/8097/1 4450/4458/1 +f 8096/8104/1 8095/8103/1 8090/8098/1 8089/8097/1 +f 8082/8090/1 8085/8093/1 8088/8096/1 8083/8091/1 +f 16407/16415/1 1364/1372/1 8085/8093/1 8082/8090/1 +f 1364/1372/1 1363/1371/1 8086/8094/1 8085/8093/1 +f 8098/8106/1 8081/8089/1 8084/8092/1 8099/8107/1 +f 4119/4127/1 16408/16416/1 8081/8089/1 8098/8106/1 +f 16408/16416/1 16407/16415/1 8082/8090/1 8081/8089/1 +f 4134/4142/1 8077/8085/1 8080/8088/1 4135/4143/1 +f 8099/8107/1 8084/8092/1 8077/8085/1 4134/4142/1 +f 8084/8092/1 8083/8091/1 8078/8086/1 8077/8085/1 +f 8070/8078/1 8073/8081/1 8076/8084/1 8071/8079/1 +f 8055/8063/1 4148/4156/1 8073/8081/1 8070/8078/1 +f 4148/4156/1 4147/4155/1 8074/8082/1 8073/8081/1 +f 16450/16458/1 8069/8077/1 8072/8080/1 16451/16459/1 +f 4163/4171/1 8056/8064/1 8069/8077/1 16450/16458/1 +f 8056/8064/1 8055/8063/1 8070/8078/1 8069/8077/1 +f 1350/1358/1 8065/8073/1 8068/8076/1 1351/1359/1 +f 16451/16459/1 8072/8080/1 8065/8073/1 1350/1358/1 +f 8072/8080/1 8071/8079/1 8066/8074/1 8065/8073/1 +f 8058/8066/1 8061/8069/1 8064/8072/1 8059/8067/1 +f 7275/7283/1 4408/4416/1 8061/8069/1 8058/8066/1 +f 4408/4416/1 4407/4415/1 8062/8070/1 8061/8069/1 +f 8014/8022/1 8057/8065/1 8060/8068/1 8015/8023/1 +f 1335/1343/1 7276/7284/1 8057/8065/1 8014/8022/1 +f 7276/7284/1 7275/7283/1 8058/8066/1 8057/8065/1 +f 4162/4170/1 8053/8061/1 8056/8064/1 4163/4171/1 +f 8015/8023/1 8060/8068/1 8053/8061/1 4162/4170/1 +f 8060/8068/1 8059/8067/1 8054/8062/1 8053/8061/1 +f 8046/8054/1 8049/8057/1 8052/8060/1 8047/8055/1 +f 16695/16703/1 1268/1276/1 8049/8057/1 8046/8054/1 +f 1268/1276/1 1267/1275/1 8050/8058/1 8049/8057/1 +f 8062/8070/1 8045/8053/1 8048/8056/1 8063/8071/1 +f 4407/4415/1 16696/16704/1 8045/8053/1 8062/8070/1 +f 16696/16704/1 16695/16703/1 8046/8054/1 8045/8053/1 +f 4146/4154/1 8041/8049/1 8044/8052/1 4147/4155/1 +f 8063/8071/1 8048/8056/1 8041/8049/1 4146/4154/1 +f 8048/8056/1 8047/8055/1 8042/8050/1 8041/8049/1 +f 8034/8042/1 8037/8045/1 8040/8048/1 8035/8043/1 +f 8019/8027/1 4160/4168/1 8037/8045/1 8034/8042/1 +f 4160/4168/1 4159/4167/1 8038/8046/1 8037/8045/1 +f 14710/14718/1 8033/8041/1 8036/8044/1 14711/14719/1 +f 2423/2431/1 8020/8028/1 8033/8041/1 14710/14718/1 +f 8020/8028/1 8019/8027/1 8034/8042/1 8033/8041/1 +f 1930/1938/1 8029/8037/1 8032/8040/1 1931/1939/1 +f 14711/14719/1 8036/8044/1 8029/8037/1 1930/1938/1 +f 8036/8044/1 8035/8043/1 8030/8038/1 8029/8037/1 +f 8022/8030/1 8025/8033/1 8028/8036/1 8023/8031/1 +f 7887/7895/1 4204/4212/1 8025/8033/1 8022/8030/1 +f 4204/4212/1 4203/4211/1 8026/8034/1 8025/8033/1 +f 13234/13242/1 8021/8029/1 8024/8032/1 13235/13243/1 +f 1163/1171/1 7888/7896/1 8021/8029/1 13234/13242/1 +f 7888/7896/1 7887/7895/1 8022/8030/1 8021/8029/1 +f 2422/2430/1 8017/8025/1 8020/8028/1 2423/2431/1 +f 13235/13243/1 8024/8032/1 8017/8025/1 2422/2430/1 +f 8024/8032/1 8023/8031/1 8018/8026/1 8017/8025/1 +f 8010/8018/1 8013/8021/1 8016/8024/1 8011/8019/1 +f 16491/16499/1 1336/1344/1 8013/8021/1 8010/8018/1 +f 1336/1344/1 1335/1343/1 8014/8022/1 8013/8021/1 +f 8026/8034/1 8009/8017/1 8012/8020/1 8027/8035/1 +f 4203/4211/1 16492/16500/1 8009/8017/1 8026/8034/1 +f 16492/16500/1 16491/16499/1 8010/8018/1 8009/8017/1 +f 4158/4166/1 8005/8013/1 8008/8016/1 4159/4167/1 +f 8027/8035/1 8012/8020/1 8005/8013/1 4158/4166/1 +f 8012/8020/1 8011/8019/1 8006/8014/1 8005/8013/1 +f 7998/8006/1 8001/8009/1 8004/8012/1 7999/8007/1 +f 7983/7991/1 4172/4180/1 8001/8009/1 7998/8006/1 +f 4172/4180/1 4171/4179/1 8002/8010/1 8001/8009/1 +f 17290/17298/1 7997/8005/1 8000/8008/1 17291/17299/1 +f 5003/5011/1 7984/7992/1 7997/8005/1 17290/17298/1 +f 7984/7992/1 7983/7991/1 7998/8006/1 7997/8005/1 +f 1070/1078/1 7993/8001/1 7996/8004/1 1071/1079/1 +f 17291/17299/1 8000/8008/1 7993/8001/1 1070/1078/1 +f 8000/8008/1 7999/8007/1 7994/8002/1 7993/8001/1 +f 7986/7994/1 7989/7997/1 7992/8000/1 7987/7995/1 +f 8031/8039/1 4156/4164/1 7989/7997/1 7986/7994/1 +f 4156/4164/1 4155/4163/1 7990/7998/1 7989/7997/1 +f 5494/5502/1 7985/7993/1 7988/7996/1 5495/5503/1 +f 1931/1939/1 8032/8040/1 7985/7993/1 5494/5502/1 +f 8032/8040/1 8031/8039/1 7986/7994/1 7985/7993/1 +f 5002/5010/1 7981/7989/1 7984/7992/1 5003/5011/1 +f 5495/5503/1 7988/7996/1 7981/7989/1 5002/5010/1 +f 7988/7996/1 7987/7995/1 7982/7990/1 7981/7989/1 +f 7974/7982/1 7977/7985/1 7980/7988/1 7975/7983/1 +f 16443/16451/1 1352/1360/1 7977/7985/1 7974/7982/1 +f 1352/1360/1 1351/1359/1 7978/7986/1 7977/7985/1 +f 7990/7998/1 7973/7981/1 7976/7984/1 7991/7999/1 +f 4155/4163/1 16444/16452/1 7973/7981/1 7990/7998/1 +f 16444/16452/1 16443/16451/1 7974/7982/1 7973/7981/1 +f 4170/4178/1 7969/7977/1 7972/7980/1 4171/4179/1 +f 7991/7999/1 7976/7984/1 7969/7977/1 4170/4178/1 +f 7976/7984/1 7975/7983/1 7970/7978/1 7969/7977/1 +f 7962/7970/1 7965/7973/1 7968/7976/1 7963/7971/1 +f 7947/7955/1 4184/4192/1 7965/7973/1 7962/7970/1 +f 4184/4192/1 4183/4191/1 7966/7974/1 7965/7973/1 +f 16486/16494/1 7961/7969/1 7964/7972/1 16487/16495/1 +f 4199/4207/1 7948/7956/1 7961/7969/1 16486/16494/1 +f 7948/7956/1 7947/7955/1 7962/7970/1 7961/7969/1 +f 1338/1346/1 7957/7965/1 7960/7968/1 1339/1347/1 +f 16487/16495/1 7964/7972/1 7957/7965/1 1338/1346/1 +f 7964/7972/1 7963/7971/1 7958/7966/1 7957/7965/1 +f 7950/7958/1 7953/7961/1 7956/7964/1 7951/7959/1 +f 6051/6059/1 4816/4824/1 7953/7961/1 7950/7958/1 +f 4816/4824/1 4815/4823/1 7954/7962/1 7953/7961/1 +f 7906/7914/1 7949/7957/1 7952/7960/1 7907/7915/1 +f 1743/1751/1 6052/6060/1 7949/7957/1 7906/7914/1 +f 6052/6060/1 6051/6059/1 7950/7958/1 7949/7957/1 +f 4198/4206/1 7945/7953/1 7948/7956/1 4199/4207/1 +f 7907/7915/1 7952/7960/1 7945/7953/1 4198/4206/1 +f 7952/7960/1 7951/7959/1 7946/7954/1 7945/7953/1 +f 7938/7946/1 7941/7949/1 7944/7952/1 7939/7947/1 +f 17103/17111/1 1132/1140/1 7941/7949/1 7938/7946/1 +f 1132/1140/1 1131/1139/1 7942/7950/1 7941/7949/1 +f 7954/7962/1 7937/7945/1 7940/7948/1 7955/7963/1 +f 4815/4823/1 17104/17112/1 7937/7945/1 7954/7962/1 +f 17104/17112/1 17103/17111/1 7938/7946/1 7937/7945/1 +f 4182/4190/1 7933/7941/1 7936/7944/1 4183/4191/1 +f 7955/7963/1 7940/7948/1 7933/7941/1 4182/4190/1 +f 7940/7948/1 7939/7947/1 7934/7942/1 7933/7941/1 +f 7926/7934/1 7929/7937/1 7932/7940/1 7927/7935/1 +f 7911/7919/1 4196/4204/1 7929/7937/1 7926/7934/1 +f 4196/4204/1 4195/4203/1 7930/7938/1 7929/7937/1 +f 15538/15546/1 7925/7933/1 7928/7936/1 15539/15547/1 +f 3251/3259/1 7912/7920/1 7925/7933/1 15538/15546/1 +f 7912/7920/1 7911/7919/1 7926/7934/1 7925/7933/1 +f 1654/1662/1 7921/7929/1 7924/7932/1 1655/1663/1 +f 15539/15547/1 7928/7936/1 7921/7929/1 1654/1662/1 +f 7928/7936/1 7927/7935/1 7922/7930/1 7921/7929/1 +f 7914/7922/1 7917/7925/1 7920/7928/1 7915/7923/1 +f 11559/11567/1 2980/2988/1 7917/7925/1 7914/7922/1 +f 2980/2988/1 2979/2987/1 7918/7926/1 7917/7925/1 +f 10750/10758/1 7913/7921/1 7916/7924/1 10751/10759/1 +f 1075/1083/1 11560/11568/1 7913/7921/1 10750/10758/1 +f 11560/11568/1 11559/11567/1 7914/7922/1 7913/7921/1 +f 3250/3258/1 7909/7917/1 7912/7920/1 3251/3259/1 +f 10751/10759/1 7916/7924/1 7909/7917/1 3250/3258/1 +f 7916/7924/1 7915/7923/1 7910/7918/1 7909/7917/1 +f 7902/7910/1 7905/7913/1 7908/7916/1 7903/7911/1 +f 15267/15275/1 1744/1752/1 7905/7913/1 7902/7910/1 +f 1744/1752/1 1743/1751/1 7906/7914/1 7905/7913/1 +f 7918/7926/1 7901/7909/1 7904/7912/1 7919/7927/1 +f 2979/2987/1 15268/15276/1 7901/7909/1 7918/7926/1 +f 15268/15276/1 15267/15275/1 7902/7910/1 7901/7909/1 +f 4194/4202/1 7897/7905/1 7900/7908/1 4195/4203/1 +f 7919/7927/1 7904/7912/1 7897/7905/1 4194/4202/1 +f 7904/7912/1 7903/7911/1 7898/7906/1 7897/7905/1 +f 7890/7898/1 7893/7901/1 7896/7904/1 7891/7899/1 +f 7875/7883/1 4208/4216/1 7893/7901/1 7890/7898/1 +f 4208/4216/1 4207/4215/1 7894/7902/1 7893/7901/1 +f 17014/17022/1 7889/7897/1 7892/7900/1 17015/17023/1 +f 4727/4735/1 7876/7884/1 7889/7897/1 17014/17022/1 +f 7876/7884/1 7875/7883/1 7890/7898/1 7889/7897/1 +f 1162/1170/1 7885/7893/1 7888/7896/1 1163/1171/1 +f 17015/17023/1 7892/7900/1 7885/7893/1 1162/1170/1 +f 7892/7900/1 7891/7899/1 7886/7894/1 7885/7893/1 +f 7878/7886/1 7881/7889/1 7884/7892/1 7879/7887/1 +f 7923/7931/1 4192/4200/1 7881/7889/1 7878/7886/1 +f 4192/4200/1 4191/4199/1 7882/7890/1 7881/7889/1 +f 6322/6330/1 7877/7885/1 7880/7888/1 6323/6331/1 +f 1655/1663/1 7924/7932/1 7877/7885/1 6322/6330/1 +f 7924/7932/1 7923/7931/1 7878/7886/1 7877/7885/1 +f 4726/4734/1 7873/7881/1 7876/7884/1 4727/4735/1 +f 6323/6331/1 7880/7888/1 7873/7881/1 4726/4734/1 +f 7880/7888/1 7879/7887/1 7874/7882/1 7873/7881/1 +f 7866/7874/1 7869/7877/1 7872/7880/1 7867/7875/1 +f 16479/16487/1 1340/1348/1 7869/7877/1 7866/7874/1 +f 1340/1348/1 1339/1347/1 7870/7878/1 7869/7877/1 +f 7882/7890/1 7865/7873/1 7868/7876/1 7883/7891/1 +f 4191/4199/1 16480/16488/1 7865/7873/1 7882/7890/1 +f 16480/16488/1 16479/16487/1 7866/7874/1 7865/7873/1 +f 4206/4214/1 7861/7869/1 7864/7872/1 4207/4215/1 +f 7883/7891/1 7868/7876/1 7861/7869/1 4206/4214/1 +f 7868/7876/1 7867/7875/1 7862/7870/1 7861/7869/1 +f 7854/7862/1 7857/7865/1 7860/7868/1 7855/7863/1 +f 7839/7847/1 4220/4228/1 7857/7865/1 7854/7862/1 +f 4220/4228/1 4219/4227/1 7858/7866/1 7857/7865/1 +f 16522/16530/1 7853/7861/1 7856/7864/1 16523/16531/1 +f 4235/4243/1 7840/7848/1 7853/7861/1 16522/16530/1 +f 7840/7848/1 7839/7847/1 7854/7862/1 7853/7861/1 +f 1326/1334/1 7849/7857/1 7852/7860/1 1327/1335/1 +f 16523/16531/1 7856/7864/1 7849/7857/1 1326/1334/1 +f 7856/7864/1 7855/7863/1 7850/7858/1 7849/7857/1 +f 7842/7850/1 7845/7853/1 7848/7856/1 7843/7851/1 +f 5583/5591/1 4972/4980/1 7845/7853/1 7842/7850/1 +f 4972/4980/1 4971/4979/1 7846/7854/1 7845/7853/1 +f 7798/7806/1 7841/7849/1 7844/7852/1 7799/7807/1 +f 1899/1907/1 5584/5592/1 7841/7849/1 7798/7806/1 +f 5584/5592/1 5583/5591/1 7842/7850/1 7841/7849/1 +f 4234/4242/1 7837/7845/1 7840/7848/1 4235/4243/1 +f 7799/7807/1 7844/7852/1 7837/7845/1 4234/4242/1 +f 7844/7852/1 7843/7851/1 7838/7846/1 7837/7845/1 +f 7830/7838/1 7833/7841/1 7836/7844/1 7831/7839/1 +f 17259/17267/1 1080/1088/1 7833/7841/1 7830/7838/1 +f 1080/1088/1 1079/1087/1 7834/7842/1 7833/7841/1 +f 7846/7854/1 7829/7837/1 7832/7840/1 7847/7855/1 +f 4971/4979/1 17260/17268/1 7829/7837/1 7846/7854/1 +f 17260/17268/1 17259/17267/1 7830/7838/1 7829/7837/1 +f 4218/4226/1 7825/7833/1 7828/7836/1 4219/4227/1 +f 7847/7855/1 7832/7840/1 7825/7833/1 4218/4226/1 +f 7832/7840/1 7831/7839/1 7826/7834/1 7825/7833/1 +f 7818/7826/1 7821/7829/1 7824/7832/1 7819/7827/1 +f 7803/7811/1 4232/4240/1 7821/7829/1 7818/7826/1 +f 4232/4240/1 4231/4239/1 7822/7830/1 7821/7829/1 +f 16474/16482/1 7817/7825/1 7820/7828/1 16475/16483/1 +f 4187/4195/1 7804/7812/1 7817/7825/1 16474/16482/1 +f 7804/7812/1 7803/7811/1 7818/7826/1 7817/7825/1 +f 1342/1350/1 7813/7821/1 7816/7824/1 1343/1351/1 +f 16475/16483/1 7820/7828/1 7813/7821/1 1342/1350/1 +f 7820/7828/1 7819/7827/1 7814/7822/1 7813/7821/1 +f 7806/7814/1 7809/7817/1 7812/7820/1 7807/7815/1 +f 12963/12971/1 2512/2520/1 7809/7817/1 7806/7814/1 +f 2512/2520/1 2511/2519/1 7810/7818/1 7809/7817/1 +f 7942/7950/1 7805/7813/1 7808/7816/1 7943/7951/1 +f 1131/1139/1 12964/12972/1 7805/7813/1 7942/7950/1 +f 12964/12972/1 12963/12971/1 7806/7814/1 7805/7813/1 +f 4186/4194/1 7801/7809/1 7804/7812/1 4187/4195/1 +f 7943/7951/1 7808/7816/1 7801/7809/1 4186/4194/1 +f 7808/7816/1 7807/7815/1 7802/7810/1 7801/7809/1 +f 7794/7802/1 7797/7805/1 7800/7808/1 7795/7803/1 +f 14799/14807/1 1900/1908/1 7797/7805/1 7794/7802/1 +f 1900/1908/1 1899/1907/1 7798/7806/1 7797/7805/1 +f 7810/7818/1 7793/7801/1 7796/7804/1 7811/7819/1 +f 2511/2519/1 14800/14808/1 7793/7801/1 7810/7818/1 +f 14800/14808/1 14799/14807/1 7794/7802/1 7793/7801/1 +f 4230/4238/1 7789/7797/1 7792/7800/1 4231/4239/1 +f 7811/7819/1 7796/7804/1 7789/7797/1 4230/4238/1 +f 7796/7804/1 7795/7803/1 7790/7798/1 7789/7797/1 +f 7782/7790/1 7785/7793/1 7788/7796/1 7783/7791/1 +f 7767/7775/1 4244/4252/1 7785/7793/1 7782/7790/1 +f 4244/4252/1 4243/4251/1 7786/7794/1 7785/7793/1 +f 16702/16710/1 7781/7789/1 7784/7792/1 16703/16711/1 +f 4415/4423/1 7768/7776/1 7781/7789/1 16702/16710/1 +f 7768/7776/1 7767/7775/1 7782/7790/1 7781/7789/1 +f 1266/1274/1 7777/7785/1 7780/7788/1 1267/1275/1 +f 16703/16711/1 7784/7792/1 7777/7785/1 1266/1274/1 +f 7784/7792/1 7783/7791/1 7778/7786/1 7777/7785/1 +f 7770/7778/1 7773/7781/1 7776/7784/1 7771/7779/1 +f 7815/7823/1 4228/4236/1 7773/7781/1 7770/7778/1 +f 4228/4236/1 4227/4235/1 7774/7782/1 7773/7781/1 +f 7258/7266/1 7769/7777/1 7772/7780/1 7259/7267/1 +f 1343/1351/1 7816/7824/1 7769/7777/1 7258/7266/1 +f 7816/7824/1 7815/7823/1 7770/7778/1 7769/7777/1 +f 4414/4422/1 7765/7773/1 7768/7776/1 4415/4423/1 +f 7259/7267/1 7772/7780/1 7765/7773/1 4414/4422/1 +f 7772/7780/1 7771/7779/1 7766/7774/1 7765/7773/1 +f 7758/7766/1 7761/7769/1 7764/7772/1 7759/7767/1 +f 16515/16523/1 1328/1336/1 7761/7769/1 7758/7766/1 +f 1328/1336/1 1327/1335/1 7762/7770/1 7761/7769/1 +f 7774/7782/1 7757/7765/1 7760/7768/1 7775/7783/1 +f 4227/4235/1 16516/16524/1 7757/7765/1 7774/7782/1 +f 16516/16524/1 16515/16523/1 7758/7766/1 7757/7765/1 +f 4242/4250/1 7753/7761/1 7756/7764/1 4243/4251/1 +f 7775/7783/1 7760/7768/1 7753/7761/1 4242/4250/1 +f 7760/7768/1 7759/7767/1 7754/7762/1 7753/7761/1 +f 7746/7754/1 7749/7757/1 7752/7760/1 7747/7755/1 +f 7731/7739/1 4256/4264/1 7749/7757/1 7746/7754/1 +f 4256/4264/1 4255/4263/1 7750/7758/1 7749/7757/1 +f 16558/16566/1 7745/7753/1 7748/7756/1 16559/16567/1 +f 4271/4279/1 7732/7740/1 7745/7753/1 16558/16566/1 +f 7732/7740/1 7731/7739/1 7746/7754/1 7745/7753/1 +f 1314/1322/1 7741/7749/1 7744/7752/1 1315/1323/1 +f 16559/16567/1 7748/7756/1 7741/7749/1 1314/1322/1 +f 7748/7756/1 7747/7755/1 7742/7750/1 7741/7749/1 +f 7734/7742/1 7737/7745/1 7740/7748/1 7735/7743/1 +f 7383/7391/1 4372/4380/1 7737/7745/1 7734/7742/1 +f 4372/4380/1 4371/4379/1 7738/7746/1 7737/7745/1 +f 7690/7698/1 7733/7741/1 7736/7744/1 7691/7699/1 +f 1299/1307/1 7384/7392/1 7733/7741/1 7690/7698/1 +f 7384/7392/1 7383/7391/1 7734/7742/1 7733/7741/1 +f 4270/4278/1 7729/7737/1 7732/7740/1 4271/4279/1 +f 7691/7699/1 7736/7744/1 7729/7737/1 4270/4278/1 +f 7736/7744/1 7735/7743/1 7730/7738/1 7729/7737/1 +f 7722/7730/1 7725/7733/1 7728/7736/1 7723/7731/1 +f 16659/16667/1 1280/1288/1 7725/7733/1 7722/7730/1 +f 1280/1288/1 1279/1287/1 7726/7734/1 7725/7733/1 +f 7738/7746/1 7721/7729/1 7724/7732/1 7739/7747/1 +f 4371/4379/1 16660/16668/1 7721/7729/1 7738/7746/1 +f 16660/16668/1 16659/16667/1 7722/7730/1 7721/7729/1 +f 4254/4262/1 7717/7725/1 7720/7728/1 4255/4263/1 +f 7739/7747/1 7724/7732/1 7717/7725/1 4254/4262/1 +f 7724/7732/1 7723/7731/1 7718/7726/1 7717/7725/1 +f 7710/7718/1 7713/7721/1 7716/7724/1 7711/7719/1 +f 7695/7703/1 4268/4276/1 7713/7721/1 7710/7718/1 +f 4268/4276/1 4267/4275/1 7714/7722/1 7713/7721/1 +f 14818/14826/1 7709/7717/1 7712/7720/1 14819/14827/1 +f 2531/2539/1 7696/7704/1 7709/7717/1 14818/14826/1 +f 7696/7704/1 7695/7703/1 7710/7718/1 7709/7717/1 +f 1894/1902/1 7705/7713/1 7708/7716/1 1895/1903/1 +f 14819/14827/1 7712/7720/1 7705/7713/1 1894/1902/1 +f 7712/7720/1 7711/7719/1 7706/7714/1 7705/7713/1 +f 7698/7706/1 7701/7709/1 7704/7712/1 7699/7707/1 +f 7563/7571/1 4312/4320/1 7701/7709/1 7698/7706/1 +f 4312/4320/1 4311/4319/1 7702/7710/1 7701/7709/1 +f 12910/12918/1 7697/7705/1 7700/7708/1 12911/12919/1 +f 1127/1135/1 7564/7572/1 7697/7705/1 12910/12918/1 +f 7564/7572/1 7563/7571/1 7698/7706/1 7697/7705/1 +f 2530/2538/1 7693/7701/1 7696/7704/1 2531/2539/1 +f 12911/12919/1 7700/7708/1 7693/7701/1 2530/2538/1 +f 7700/7708/1 7699/7707/1 7694/7702/1 7693/7701/1 +f 7686/7694/1 7689/7697/1 7692/7700/1 7687/7695/1 +f 16599/16607/1 1300/1308/1 7689/7697/1 7686/7694/1 +f 1300/1308/1 1299/1307/1 7690/7698/1 7689/7697/1 +f 7702/7710/1 7685/7693/1 7688/7696/1 7703/7711/1 +f 4311/4319/1 16600/16608/1 7685/7693/1 7702/7710/1 +f 16600/16608/1 16599/16607/1 7686/7694/1 7685/7693/1 +f 4266/4274/1 7681/7689/1 7684/7692/1 4267/4275/1 +f 7703/7711/1 7688/7696/1 7681/7689/1 4266/4274/1 +f 7688/7696/1 7687/7695/1 7682/7690/1 7681/7689/1 +f 7674/7682/1 7677/7685/1 7680/7688/1 7675/7683/1 +f 7659/7667/1 4280/4288/1 7677/7685/1 7674/7682/1 +f 4280/4288/1 4279/4287/1 7678/7686/1 7677/7685/1 +f 17254/17262/1 7673/7681/1 7676/7684/1 17255/17263/1 +f 4967/4975/1 7660/7668/1 7673/7681/1 17254/17262/1 +f 7660/7668/1 7659/7667/1 7674/7682/1 7673/7681/1 +f 1082/1090/1 7669/7677/1 7672/7680/1 1083/1091/1 +f 17255/17263/1 7676/7684/1 7669/7677/1 1082/1090/1 +f 7676/7684/1 7675/7683/1 7670/7678/1 7669/7677/1 +f 7662/7670/1 7665/7673/1 7668/7676/1 7663/7671/1 +f 7707/7715/1 4264/4272/1 7665/7673/1 7662/7670/1 +f 4264/4272/1 4263/4271/1 7666/7674/1 7665/7673/1 +f 5602/5610/1 7661/7669/1 7664/7672/1 5603/5611/1 +f 1895/1903/1 7708/7716/1 7661/7669/1 5602/5610/1 +f 7708/7716/1 7707/7715/1 7662/7670/1 7661/7669/1 +f 4966/4974/1 7657/7665/1 7660/7668/1 4967/4975/1 +f 5603/5611/1 7664/7672/1 7657/7665/1 4966/4974/1 +f 7664/7672/1 7663/7671/1 7658/7666/1 7657/7665/1 +f 7650/7658/1 7653/7661/1 7656/7664/1 7651/7659/1 +f 16551/16559/1 1316/1324/1 7653/7661/1 7650/7658/1 +f 1316/1324/1 1315/1323/1 7654/7662/1 7653/7661/1 +f 7666/7674/1 7649/7657/1 7652/7660/1 7667/7675/1 +f 4263/4271/1 16552/16560/1 7649/7657/1 7666/7674/1 +f 16552/16560/1 16551/16559/1 7650/7658/1 7649/7657/1 +f 4278/4286/1 7645/7653/1 7648/7656/1 4279/4287/1 +f 7667/7675/1 7652/7660/1 7645/7653/1 4278/4286/1 +f 7652/7660/1 7651/7659/1 7646/7654/1 7645/7653/1 +f 7638/7646/1 7641/7649/1 7644/7652/1 7639/7647/1 +f 7623/7631/1 4292/4300/1 7641/7649/1 7638/7646/1 +f 4292/4300/1 4291/4299/1 7642/7650/1 7641/7649/1 +f 16594/16602/1 7637/7645/1 7640/7648/1 16595/16603/1 +f 4307/4315/1 7624/7632/1 7637/7645/1 16594/16602/1 +f 7624/7632/1 7623/7631/1 7638/7646/1 7637/7645/1 +f 1302/1310/1 7633/7641/1 7636/7644/1 1303/1311/1 +f 16595/16603/1 7640/7648/1 7633/7641/1 1302/1310/1 +f 7640/7648/1 7639/7647/1 7634/7642/1 7633/7641/1 +f 7626/7634/1 7629/7637/1 7632/7640/1 7627/7635/1 +f 5727/5735/1 4924/4932/1 7629/7637/1 7626/7634/1 +f 4924/4932/1 4923/4931/1 7630/7638/1 7629/7637/1 +f 7582/7590/1 7625/7633/1 7628/7636/1 7583/7591/1 +f 1851/1859/1 5728/5736/1 7625/7633/1 7582/7590/1 +f 5728/5736/1 5727/5735/1 7626/7634/1 7625/7633/1 +f 4306/4314/1 7621/7629/1 7624/7632/1 4307/4315/1 +f 7583/7591/1 7628/7636/1 7621/7629/1 4306/4314/1 +f 7628/7636/1 7627/7635/1 7622/7630/1 7621/7629/1 +f 7614/7622/1 7617/7625/1 7620/7628/1 7615/7623/1 +f 17211/17219/1 1096/1104/1 7617/7625/1 7614/7622/1 +f 1096/1104/1 1095/1103/1 7618/7626/1 7617/7625/1 +f 7630/7638/1 7613/7621/1 7616/7624/1 7631/7639/1 +f 4923/4931/1 17212/17220/1 7613/7621/1 7630/7638/1 +f 17212/17220/1 17211/17219/1 7614/7622/1 7613/7621/1 +f 4290/4298/1 7609/7617/1 7612/7620/1 4291/4299/1 +f 7631/7639/1 7616/7624/1 7609/7617/1 4290/4298/1 +f 7616/7624/1 7615/7623/1 7610/7618/1 7609/7617/1 +f 7602/7610/1 7605/7613/1 7608/7616/1 7603/7611/1 +f 7587/7595/1 4304/4312/1 7605/7613/1 7602/7610/1 +f 4304/4312/1 4303/4311/1 7606/7614/1 7605/7613/1 +f 15214/15222/1 7601/7609/1 7604/7612/1 15215/15223/1 +f 2927/2935/1 7588/7596/1 7601/7609/1 15214/15222/1 +f 7588/7596/1 7587/7595/1 7602/7610/1 7601/7609/1 +f 1762/1770/1 7597/7605/1 7600/7608/1 1763/1771/1 +f 15215/15223/1 7604/7612/1 7597/7605/1 1762/1770/1 +f 7604/7612/1 7603/7611/1 7598/7606/1 7597/7605/1 +f 7590/7598/1 7593/7601/1 7596/7604/1 7591/7599/1 +f 12531/12539/1 2656/2664/1 7593/7601/1 7590/7598/1 +f 2656/2664/1 2655/2663/1 7594/7602/1 7593/7601/1 +f 11722/11730/1 7589/7597/1 7592/7600/1 11723/11731/1 +f 1087/1095/1 12532/12540/1 7589/7597/1 11722/11730/1 +f 12532/12540/1 12531/12539/1 7590/7598/1 7589/7597/1 +f 2926/2934/1 7585/7593/1 7588/7596/1 2927/2935/1 +f 11723/11731/1 7592/7600/1 7585/7593/1 2926/2934/1 +f 7592/7600/1 7591/7599/1 7586/7594/1 7585/7593/1 +f 7578/7586/1 7581/7589/1 7584/7592/1 7579/7587/1 +f 14943/14951/1 1852/1860/1 7581/7589/1 7578/7586/1 +f 1852/1860/1 1851/1859/1 7582/7590/1 7581/7589/1 +f 7594/7602/1 7577/7585/1 7580/7588/1 7595/7603/1 +f 2655/2663/1 14944/14952/1 7577/7585/1 7594/7602/1 +f 14944/14952/1 14943/14951/1 7578/7586/1 7577/7585/1 +f 4302/4310/1 7573/7581/1 7576/7584/1 4303/4311/1 +f 7595/7603/1 7580/7588/1 7573/7581/1 4302/4310/1 +f 7580/7588/1 7579/7587/1 7574/7582/1 7573/7581/1 +f 7566/7574/1 7569/7577/1 7572/7580/1 7567/7575/1 +f 7551/7559/1 4316/4324/1 7569/7577/1 7566/7574/1 +f 4316/4324/1 4315/4323/1 7570/7578/1 7569/7577/1 +f 17122/17130/1 7565/7573/1 7568/7576/1 17123/17131/1 +f 4835/4843/1 7552/7560/1 7565/7573/1 17122/17130/1 +f 7552/7560/1 7551/7559/1 7566/7574/1 7565/7573/1 +f 1126/1134/1 7561/7569/1 7564/7572/1 1127/1135/1 +f 17123/17131/1 7568/7576/1 7561/7569/1 1126/1134/1 +f 7568/7576/1 7567/7575/1 7562/7570/1 7561/7569/1 +f 7554/7562/1 7557/7565/1 7560/7568/1 7555/7563/1 +f 7599/7607/1 4300/4308/1 7557/7565/1 7554/7562/1 +f 4300/4308/1 4299/4307/1 7558/7566/1 7557/7565/1 +f 5998/6006/1 7553/7561/1 7556/7564/1 5999/6007/1 +f 1763/1771/1 7600/7608/1 7553/7561/1 5998/6006/1 +f 7600/7608/1 7599/7607/1 7554/7562/1 7553/7561/1 +f 4834/4842/1 7549/7557/1 7552/7560/1 4835/4843/1 +f 5999/6007/1 7556/7564/1 7549/7557/1 4834/4842/1 +f 7556/7564/1 7555/7563/1 7550/7558/1 7549/7557/1 +f 7542/7550/1 7545/7553/1 7548/7556/1 7543/7551/1 +f 16587/16595/1 1304/1312/1 7545/7553/1 7542/7550/1 +f 1304/1312/1 1303/1311/1 7546/7554/1 7545/7553/1 +f 7558/7566/1 7541/7549/1 7544/7552/1 7559/7567/1 +f 4299/4307/1 16588/16596/1 7541/7549/1 7558/7566/1 +f 16588/16596/1 16587/16595/1 7542/7550/1 7541/7549/1 +f 4314/4322/1 7537/7545/1 7540/7548/1 4315/4323/1 +f 7559/7567/1 7544/7552/1 7537/7545/1 4314/4322/1 +f 7544/7552/1 7543/7551/1 7538/7546/1 7537/7545/1 +f 7530/7538/1 7533/7541/1 7536/7544/1 7531/7539/1 +f 7515/7523/1 4328/4336/1 7533/7541/1 7530/7538/1 +f 4328/4336/1 4327/4335/1 7534/7542/1 7533/7541/1 +f 16630/16638/1 7529/7537/1 7532/7540/1 16631/16639/1 +f 4343/4351/1 7516/7524/1 7529/7537/1 16630/16638/1 +f 7516/7524/1 7515/7523/1 7530/7538/1 7529/7537/1 +f 1290/1298/1 7525/7533/1 7528/7536/1 1291/1299/1 +f 16631/16639/1 7532/7540/1 7525/7533/1 1290/1298/1 +f 7532/7540/1 7531/7539/1 7526/7534/1 7525/7533/1 +f 7518/7526/1 7521/7529/1 7524/7532/1 7519/7527/1 +f 5691/5699/1 4936/4944/1 7521/7529/1 7518/7526/1 +f 4936/4944/1 4935/4943/1 7522/7530/1 7521/7529/1 +f 7474/7482/1 7517/7525/1 7520/7528/1 7475/7483/1 +f 1863/1871/1 5692/5700/1 7517/7525/1 7474/7482/1 +f 5692/5700/1 5691/5699/1 7518/7526/1 7517/7525/1 +f 4342/4350/1 7513/7521/1 7516/7524/1 4343/4351/1 +f 7475/7483/1 7520/7528/1 7513/7521/1 4342/4350/1 +f 7520/7528/1 7519/7527/1 7514/7522/1 7513/7521/1 +f 7506/7514/1 7509/7517/1 7512/7520/1 7507/7515/1 +f 17223/17231/1 1092/1100/1 7509/7517/1 7506/7514/1 +f 1092/1100/1 1091/1099/1 7510/7518/1 7509/7517/1 +f 7522/7530/1 7505/7513/1 7508/7516/1 7523/7531/1 +f 4935/4943/1 17224/17232/1 7505/7513/1 7522/7530/1 +f 17224/17232/1 17223/17231/1 7506/7514/1 7505/7513/1 +f 4326/4334/1 7501/7509/1 7504/7512/1 4327/4335/1 +f 7523/7531/1 7508/7516/1 7501/7509/1 4326/4334/1 +f 7508/7516/1 7507/7515/1 7502/7510/1 7501/7509/1 +f 7494/7502/1 7497/7505/1 7500/7508/1 7495/7503/1 +f 7479/7487/1 4340/4348/1 7497/7505/1 7494/7502/1 +f 4340/4348/1 4339/4347/1 7498/7506/1 7497/7505/1 +f 16582/16590/1 7493/7501/1 7496/7504/1 16583/16591/1 +f 4295/4303/1 7480/7488/1 7493/7501/1 16582/16590/1 +f 7480/7488/1 7479/7487/1 7494/7502/1 7493/7501/1 +f 1306/1314/1 7489/7497/1 7492/7500/1 1307/1315/1 +f 16583/16591/1 7496/7504/1 7489/7497/1 1306/1314/1 +f 7496/7504/1 7495/7503/1 7490/7498/1 7489/7497/1 +f 7482/7490/1 7485/7493/1 7488/7496/1 7483/7491/1 +f 12639/12647/1 2620/2628/1 7485/7493/1 7482/7490/1 +f 2620/2628/1 2619/2627/1 7486/7494/1 7485/7493/1 +f 7618/7626/1 7481/7489/1 7484/7492/1 7619/7627/1 +f 1095/1103/1 12640/12648/1 7481/7489/1 7618/7626/1 +f 12640/12648/1 12639/12647/1 7482/7490/1 7481/7489/1 +f 4294/4302/1 7477/7485/1 7480/7488/1 4295/4303/1 +f 7619/7627/1 7484/7492/1 7477/7485/1 4294/4302/1 +f 7484/7492/1 7483/7491/1 7478/7486/1 7477/7485/1 +f 7470/7478/1 7473/7481/1 7476/7484/1 7471/7479/1 +f 14907/14915/1 1864/1872/1 7473/7481/1 7470/7478/1 +f 1864/1872/1 1863/1871/1 7474/7482/1 7473/7481/1 +f 7486/7494/1 7469/7477/1 7472/7480/1 7487/7495/1 +f 2619/2627/1 14908/14916/1 7469/7477/1 7486/7494/1 +f 14908/14916/1 14907/14915/1 7470/7478/1 7469/7477/1 +f 4338/4346/1 7465/7473/1 7468/7476/1 4339/4347/1 +f 7487/7495/1 7472/7480/1 7465/7473/1 4338/4346/1 +f 7472/7480/1 7471/7479/1 7466/7474/1 7465/7473/1 +f 7458/7466/1 7461/7469/1 7464/7472/1 7459/7467/1 +f 7443/7451/1 4352/4360/1 7461/7469/1 7458/7466/1 +f 4352/4360/1 4351/4359/1 7462/7470/1 7461/7469/1 +f 16666/16674/1 7457/7465/1 7460/7468/1 16667/16675/1 +f 4379/4387/1 7444/7452/1 7457/7465/1 16666/16674/1 +f 7444/7452/1 7443/7451/1 7458/7466/1 7457/7465/1 +f 1278/1286/1 7453/7461/1 7456/7464/1 1279/1287/1 +f 16667/16675/1 7460/7468/1 7453/7461/1 1278/1286/1 +f 7460/7468/1 7459/7467/1 7454/7462/1 7453/7461/1 +f 7446/7454/1 7449/7457/1 7452/7460/1 7447/7455/1 +f 7491/7499/1 4336/4344/1 7449/7457/1 7446/7454/1 +f 4336/4344/1 4335/4343/1 7450/7458/1 7449/7457/1 +f 7366/7374/1 7445/7453/1 7448/7456/1 7367/7375/1 +f 1307/1315/1 7492/7500/1 7445/7453/1 7366/7374/1 +f 7492/7500/1 7491/7499/1 7446/7454/1 7445/7453/1 +f 4378/4386/1 7441/7449/1 7444/7452/1 4379/4387/1 +f 7367/7375/1 7448/7456/1 7441/7449/1 4378/4386/1 +f 7448/7456/1 7447/7455/1 7442/7450/1 7441/7449/1 +f 7434/7442/1 7437/7445/1 7440/7448/1 7435/7443/1 +f 16623/16631/1 1292/1300/1 7437/7445/1 7434/7442/1 +f 1292/1300/1 1291/1299/1 7438/7446/1 7437/7445/1 +f 7450/7458/1 7433/7441/1 7436/7444/1 7451/7459/1 +f 4335/4343/1 16624/16632/1 7433/7441/1 7450/7458/1 +f 16624/16632/1 16623/16631/1 7434/7442/1 7433/7441/1 +f 4350/4358/1 7429/7437/1 7432/7440/1 4351/4359/1 +f 7451/7459/1 7436/7444/1 7429/7437/1 4350/4358/1 +f 7436/7444/1 7435/7443/1 7430/7438/1 7429/7437/1 +f 7422/7430/1 7425/7433/1 7428/7436/1 7423/7431/1 +f 7407/7415/1 4364/4372/1 7425/7433/1 7422/7430/1 +f 4364/4372/1 4363/4371/1 7426/7434/1 7425/7433/1 +f 16642/16650/1 7421/7429/1 7424/7432/1 16643/16651/1 +f 4355/4363/1 7408/7416/1 7421/7429/1 16642/16650/1 +f 7408/7416/1 7407/7415/1 7422/7430/1 7421/7429/1 +f 1286/1294/1 7417/7425/1 7420/7428/1 1287/1295/1 +f 16643/16651/1 7424/7432/1 7417/7425/1 1286/1294/1 +f 7424/7432/1 7423/7431/1 7418/7426/1 7417/7425/1 +f 7410/7418/1 7413/7421/1 7416/7424/1 7411/7419/1 +f 7527/7535/1 4324/4332/1 7413/7421/1 7410/7418/1 +f 4324/4332/1 4323/4331/1 7414/7422/1 7413/7421/1 +f 7438/7446/1 7409/7417/1 7412/7420/1 7439/7447/1 +f 1291/1299/1 7528/7536/1 7409/7417/1 7438/7446/1 +f 7528/7536/1 7527/7535/1 7410/7418/1 7409/7417/1 +f 4354/4362/1 7405/7413/1 7408/7416/1 4355/4363/1 +f 7439/7447/1 7412/7420/1 7405/7413/1 4354/4362/1 +f 7412/7420/1 7411/7419/1 7406/7414/1 7405/7413/1 +f 7398/7406/1 7401/7409/1 7404/7412/1 7399/7407/1 +f 16611/16619/1 1296/1304/1 7401/7409/1 7398/7406/1 +f 1296/1304/1 1295/1303/1 7402/7410/1 7401/7409/1 +f 7414/7422/1 7397/7405/1 7400/7408/1 7415/7423/1 +f 4323/4331/1 16612/16620/1 7397/7405/1 7414/7422/1 +f 16612/16620/1 16611/16619/1 7398/7406/1 7397/7405/1 +f 4362/4370/1 7393/7401/1 7396/7404/1 4363/4371/1 +f 7415/7423/1 7400/7408/1 7393/7401/1 4362/4370/1 +f 7400/7408/1 7399/7407/1 7394/7402/1 7393/7401/1 +f 7386/7394/1 7389/7397/1 7392/7400/1 7387/7395/1 +f 7371/7379/1 4376/4384/1 7389/7397/1 7386/7394/1 +f 4376/4384/1 4375/4383/1 7390/7398/1 7389/7397/1 +f 16606/16614/1 7385/7393/1 7388/7396/1 16607/16615/1 +f 4319/4327/1 7372/7380/1 7385/7393/1 16606/16614/1 +f 7372/7380/1 7371/7379/1 7386/7394/1 7385/7393/1 +f 1298/1306/1 7381/7389/1 7384/7392/1 1299/1307/1 +f 16607/16615/1 7388/7396/1 7381/7389/1 1298/1306/1 +f 7388/7396/1 7387/7395/1 7382/7390/1 7381/7389/1 +f 7374/7382/1 7377/7385/1 7380/7388/1 7375/7383/1 +f 7635/7643/1 4288/4296/1 7377/7385/1 7374/7382/1 +f 4288/4296/1 4287/4295/1 7378/7386/1 7377/7385/1 +f 7546/7554/1 7373/7381/1 7376/7384/1 7547/7555/1 +f 1303/1311/1 7636/7644/1 7373/7381/1 7546/7554/1 +f 7636/7644/1 7635/7643/1 7374/7382/1 7373/7381/1 +f 4318/4326/1 7369/7377/1 7372/7380/1 4319/4327/1 +f 7547/7555/1 7376/7384/1 7369/7377/1 4318/4326/1 +f 7376/7384/1 7375/7383/1 7370/7378/1 7369/7377/1 +f 7362/7370/1 7365/7373/1 7368/7376/1 7363/7371/1 +f 16575/16583/1 1308/1316/1 7365/7373/1 7362/7370/1 +f 1308/1316/1 1307/1315/1 7366/7374/1 7365/7373/1 +f 7378/7386/1 7361/7369/1 7364/7372/1 7379/7387/1 +f 4287/4295/1 16576/16584/1 7361/7369/1 7378/7386/1 +f 16576/16584/1 16575/16583/1 7362/7370/1 7361/7369/1 +f 4374/4382/1 7357/7365/1 7360/7368/1 4375/4383/1 +f 7379/7387/1 7364/7372/1 7357/7365/1 4374/4382/1 +f 7364/7372/1 7363/7371/1 7358/7366/1 7357/7365/1 +f 7350/7358/1 7353/7361/1 7356/7364/1 7351/7359/1 +f 7335/7343/1 4388/4396/1 7353/7361/1 7350/7358/1 +f 4388/4396/1 4387/4395/1 7354/7362/1 7353/7361/1 +f 16570/16578/1 7349/7357/1 7352/7360/1 16571/16579/1 +f 4283/4291/1 7336/7344/1 7349/7357/1 16570/16578/1 +f 7336/7344/1 7335/7343/1 7350/7358/1 7349/7357/1 +f 1310/1318/1 7345/7353/1 7348/7356/1 1311/1319/1 +f 16571/16579/1 7352/7360/1 7345/7353/1 1310/1318/1 +f 7352/7360/1 7351/7359/1 7346/7354/1 7345/7353/1 +f 7338/7346/1 7341/7349/1 7344/7352/1 7339/7347/1 +f 7743/7751/1 4252/4260/1 7341/7349/1 7338/7346/1 +f 4252/4260/1 4251/4259/1 7342/7350/1 7341/7349/1 +f 7654/7662/1 7337/7345/1 7340/7348/1 7655/7663/1 +f 1315/1323/1 7744/7752/1 7337/7345/1 7654/7662/1 +f 7744/7752/1 7743/7751/1 7338/7346/1 7337/7345/1 +f 4282/4290/1 7333/7341/1 7336/7344/1 4283/4291/1 +f 7655/7663/1 7340/7348/1 7333/7341/1 4282/4290/1 +f 7340/7348/1 7339/7347/1 7334/7342/1 7333/7341/1 +f 7326/7334/1 7329/7337/1 7332/7340/1 7327/7335/1 +f 16539/16547/1 1320/1328/1 7329/7337/1 7326/7334/1 +f 1320/1328/1 1319/1327/1 7330/7338/1 7329/7337/1 +f 7342/7350/1 7325/7333/1 7328/7336/1 7343/7351/1 +f 4251/4259/1 16540/16548/1 7325/7333/1 7342/7350/1 +f 16540/16548/1 16539/16547/1 7326/7334/1 7325/7333/1 +f 4386/4394/1 7321/7329/1 7324/7332/1 4387/4395/1 +f 7343/7351/1 7328/7336/1 7321/7329/1 4386/4394/1 +f 7328/7336/1 7327/7335/1 7322/7330/1 7321/7329/1 +f 7314/7322/1 7317/7325/1 7320/7328/1 7315/7323/1 +f 7299/7307/1 4400/4408/1 7317/7325/1 7314/7322/1 +f 4400/4408/1 4399/4407/1 7318/7326/1 7317/7325/1 +f 16534/16542/1 7313/7321/1 7316/7324/1 16535/16543/1 +f 4247/4255/1 7300/7308/1 7313/7321/1 16534/16542/1 +f 7300/7308/1 7299/7307/1 7314/7322/1 7313/7321/1 +f 1322/1330/1 7309/7317/1 7312/7320/1 1323/1331/1 +f 16535/16543/1 7316/7324/1 7309/7317/1 1322/1330/1 +f 7316/7324/1 7315/7323/1 7310/7318/1 7309/7317/1 +f 7302/7310/1 7305/7313/1 7308/7316/1 7303/7311/1 +f 7851/7859/1 4216/4224/1 7305/7313/1 7302/7310/1 +f 4216/4224/1 4215/4223/1 7306/7314/1 7305/7313/1 +f 7762/7770/1 7301/7309/1 7304/7312/1 7763/7771/1 +f 1327/1335/1 7852/7860/1 7301/7309/1 7762/7770/1 +f 7852/7860/1 7851/7859/1 7302/7310/1 7301/7309/1 +f 4246/4254/1 7297/7305/1 7300/7308/1 4247/4255/1 +f 7763/7771/1 7304/7312/1 7297/7305/1 4246/4254/1 +f 7304/7312/1 7303/7311/1 7298/7306/1 7297/7305/1 +f 7290/7298/1 7293/7301/1 7296/7304/1 7291/7299/1 +f 16503/16511/1 1332/1340/1 7293/7301/1 7290/7298/1 +f 1332/1340/1 1331/1339/1 7294/7302/1 7293/7301/1 +f 7306/7314/1 7289/7297/1 7292/7300/1 7307/7315/1 +f 4215/4223/1 16504/16512/1 7289/7297/1 7306/7314/1 +f 16504/16512/1 16503/16511/1 7290/7298/1 7289/7297/1 +f 4398/4406/1 7285/7293/1 7288/7296/1 4399/4407/1 +f 7307/7315/1 7292/7300/1 7285/7293/1 4398/4406/1 +f 7292/7300/1 7291/7299/1 7286/7294/1 7285/7293/1 +f 7278/7286/1 7281/7289/1 7284/7292/1 7279/7287/1 +f 7263/7271/1 4412/4420/1 7281/7289/1 7278/7286/1 +f 4412/4420/1 4411/4419/1 7282/7290/1 7281/7289/1 +f 16498/16506/1 7277/7285/1 7280/7288/1 16499/16507/1 +f 4211/4219/1 7264/7272/1 7277/7285/1 16498/16506/1 +f 7264/7272/1 7263/7271/1 7278/7286/1 7277/7285/1 +f 1334/1342/1 7273/7281/1 7276/7284/1 1335/1343/1 +f 16499/16507/1 7280/7288/1 7273/7281/1 1334/1342/1 +f 7280/7288/1 7279/7287/1 7274/7282/1 7273/7281/1 +f 7266/7274/1 7269/7277/1 7272/7280/1 7267/7275/1 +f 7959/7967/1 4180/4188/1 7269/7277/1 7266/7274/1 +f 4180/4188/1 4179/4187/1 7270/7278/1 7269/7277/1 +f 7870/7878/1 7265/7273/1 7268/7276/1 7871/7879/1 +f 1339/1347/1 7960/7968/1 7265/7273/1 7870/7878/1 +f 7960/7968/1 7959/7967/1 7266/7274/1 7265/7273/1 +f 4210/4218/1 7261/7269/1 7264/7272/1 4211/4219/1 +f 7871/7879/1 7268/7276/1 7261/7269/1 4210/4218/1 +f 7268/7276/1 7267/7275/1 7262/7270/1 7261/7269/1 +f 7254/7262/1 7257/7265/1 7260/7268/1 7255/7263/1 +f 16467/16475/1 1344/1352/1 7257/7265/1 7254/7262/1 +f 1344/1352/1 1343/1351/1 7258/7266/1 7257/7265/1 +f 7270/7278/1 7253/7261/1 7256/7264/1 7271/7279/1 +f 4179/4187/1 16468/16476/1 7253/7261/1 7270/7278/1 +f 16468/16476/1 16467/16475/1 7254/7262/1 7253/7261/1 +f 4410/4418/1 7249/7257/1 7252/7260/1 4411/4419/1 +f 7271/7279/1 7256/7264/1 7249/7257/1 4410/4418/1 +f 7256/7264/1 7255/7263/1 7250/7258/1 7249/7257/1 +f 7242/7250/1 7245/7253/1 7248/7256/1 7243/7251/1 +f 7227/7235/1 4424/4432/1 7245/7253/1 7242/7250/1 +f 4424/4432/1 4423/4431/1 7246/7254/1 7245/7253/1 +f 16462/16470/1 7241/7249/1 7244/7252/1 16463/16471/1 +f 4175/4183/1 7228/7236/1 7241/7249/1 16462/16470/1 +f 7228/7236/1 7227/7235/1 7242/7250/1 7241/7249/1 +f 1346/1354/1 7237/7245/1 7240/7248/1 1347/1355/1 +f 16463/16471/1 7244/7252/1 7237/7245/1 1346/1354/1 +f 7244/7252/1 7243/7251/1 7238/7246/1 7237/7245/1 +f 7230/7238/1 7233/7241/1 7236/7244/1 7231/7239/1 +f 8067/8075/1 4144/4152/1 7233/7241/1 7230/7238/1 +f 4144/4152/1 4143/4151/1 7234/7242/1 7233/7241/1 +f 7978/7986/1 7229/7237/1 7232/7240/1 7979/7987/1 +f 1351/1359/1 8068/8076/1 7229/7237/1 7978/7986/1 +f 8068/8076/1 8067/8075/1 7230/7238/1 7229/7237/1 +f 4174/4182/1 7225/7233/1 7228/7236/1 4175/4183/1 +f 7979/7987/1 7232/7240/1 7225/7233/1 4174/4182/1 +f 7232/7240/1 7231/7239/1 7226/7234/1 7225/7233/1 +f 7218/7226/1 7221/7229/1 7224/7232/1 7219/7227/1 +f 16431/16439/1 1356/1364/1 7221/7229/1 7218/7226/1 +f 1356/1364/1 1355/1363/1 7222/7230/1 7221/7229/1 +f 7234/7242/1 7217/7225/1 7220/7228/1 7235/7243/1 +f 4143/4151/1 16432/16440/1 7217/7225/1 7234/7242/1 +f 16432/16440/1 16431/16439/1 7218/7226/1 7217/7225/1 +f 4422/4430/1 7213/7221/1 7216/7224/1 4423/4431/1 +f 7235/7243/1 7220/7228/1 7213/7221/1 4422/4430/1 +f 7220/7228/1 7219/7227/1 7214/7222/1 7213/7221/1 +f 7206/7214/1 7209/7217/1 7212/7220/1 7207/7215/1 +f 7191/7199/1 4436/4444/1 7209/7217/1 7206/7214/1 +f 4436/4444/1 4435/4443/1 7210/7218/1 7209/7217/1 +f 16426/16434/1 7205/7213/1 7208/7216/1 16427/16435/1 +f 4139/4147/1 7192/7200/1 7205/7213/1 16426/16434/1 +f 7192/7200/1 7191/7199/1 7206/7214/1 7205/7213/1 +f 1358/1366/1 7201/7209/1 7204/7212/1 1359/1367/1 +f 16427/16435/1 7208/7216/1 7201/7209/1 1358/1366/1 +f 7208/7216/1 7207/7215/1 7202/7210/1 7201/7209/1 +f 7194/7202/1 7197/7205/1 7200/7208/1 7195/7203/1 +f 8175/8183/1 4108/4116/1 7197/7205/1 7194/7202/1 +f 4108/4116/1 4107/4115/1 7198/7206/1 7197/7205/1 +f 8086/8094/1 7193/7201/1 7196/7204/1 8087/8095/1 +f 1363/1371/1 8176/8184/1 7193/7201/1 8086/8094/1 +f 8176/8184/1 8175/8183/1 7194/7202/1 7193/7201/1 +f 4138/4146/1 7189/7197/1 7192/7200/1 4139/4147/1 +f 8087/8095/1 7196/7204/1 7189/7197/1 4138/4146/1 +f 7196/7204/1 7195/7203/1 7190/7198/1 7189/7197/1 +f 7182/7190/1 7185/7193/1 7188/7196/1 7183/7191/1 +f 16395/16403/1 1368/1376/1 7185/7193/1 7182/7190/1 +f 1368/1376/1 1367/1375/1 7186/7194/1 7185/7193/1 +f 7198/7206/1 7181/7189/1 7184/7192/1 7199/7207/1 +f 4107/4115/1 16396/16404/1 7181/7189/1 7198/7206/1 +f 16396/16404/1 16395/16403/1 7182/7190/1 7181/7189/1 +f 4434/4442/1 7177/7185/1 7180/7188/1 4435/4443/1 +f 7199/7207/1 7184/7192/1 7177/7185/1 4434/4442/1 +f 7184/7192/1 7183/7191/1 7178/7186/1 7177/7185/1 +f 7170/7178/1 7173/7181/1 7176/7184/1 7171/7179/1 +f 7155/7163/1 4448/4456/1 7173/7181/1 7170/7178/1 +f 4448/4456/1 4447/4455/1 7174/7182/1 7173/7181/1 +f 16390/16398/1 7169/7177/1 7172/7180/1 16391/16399/1 +f 4103/4111/1 7156/7164/1 7169/7177/1 16390/16398/1 +f 7156/7164/1 7155/7163/1 7170/7178/1 7169/7177/1 +f 1370/1378/1 7165/7173/1 7168/7176/1 1371/1379/1 +f 16391/16399/1 7172/7180/1 7165/7173/1 1370/1378/1 +f 7172/7180/1 7171/7179/1 7166/7174/1 7165/7173/1 +f 7158/7166/1 7161/7169/1 7164/7172/1 7159/7167/1 +f 8283/8291/1 4072/4080/1 7161/7169/1 7158/7166/1 +f 4072/4080/1 4071/4079/1 7162/7170/1 7161/7169/1 +f 8194/8202/1 7157/7165/1 7160/7168/1 8195/8203/1 +f 1375/1383/1 8284/8292/1 7157/7165/1 8194/8202/1 +f 8284/8292/1 8283/8291/1 7158/7166/1 7157/7165/1 +f 4102/4110/1 7153/7161/1 7156/7164/1 4103/4111/1 +f 8195/8203/1 7160/7168/1 7153/7161/1 4102/4110/1 +f 7160/7168/1 7159/7167/1 7154/7162/1 7153/7161/1 +f 7146/7154/1 7149/7157/1 7152/7160/1 7147/7155/1 +f 16359/16367/1 1380/1388/1 7149/7157/1 7146/7154/1 +f 1380/1388/1 1379/1387/1 7150/7158/1 7149/7157/1 +f 7162/7170/1 7145/7153/1 7148/7156/1 7163/7171/1 +f 4071/4079/1 16360/16368/1 7145/7153/1 7162/7170/1 +f 16360/16368/1 16359/16367/1 7146/7154/1 7145/7153/1 +f 4446/4454/1 7141/7149/1 7144/7152/1 4447/4455/1 +f 7163/7171/1 7148/7156/1 7141/7149/1 4446/4454/1 +f 7148/7156/1 7147/7155/1 7142/7150/1 7141/7149/1 +f 7134/7142/1 7137/7145/1 7140/7148/1 7135/7143/1 +f 7119/7127/1 4460/4468/1 7137/7145/1 7134/7142/1 +f 4460/4468/1 4459/4467/1 7138/7146/1 7137/7145/1 +f 16354/16362/1 7133/7141/1 7136/7144/1 16355/16363/1 +f 4067/4075/1 7120/7128/1 7133/7141/1 16354/16362/1 +f 7120/7128/1 7119/7127/1 7134/7142/1 7133/7141/1 +f 1382/1390/1 7129/7137/1 7132/7140/1 1383/1391/1 +f 16355/16363/1 7136/7144/1 7129/7137/1 1382/1390/1 +f 7136/7144/1 7135/7143/1 7130/7138/1 7129/7137/1 +f 7122/7130/1 7125/7133/1 7128/7136/1 7123/7131/1 +f 8391/8399/1 4036/4044/1 7125/7133/1 7122/7130/1 +f 4036/4044/1 4035/4043/1 7126/7134/1 7125/7133/1 +f 8302/8310/1 7121/7129/1 7124/7132/1 8303/8311/1 +f 1387/1395/1 8392/8400/1 7121/7129/1 8302/8310/1 +f 8392/8400/1 8391/8399/1 7122/7130/1 7121/7129/1 +f 4066/4074/1 7117/7125/1 7120/7128/1 4067/4075/1 +f 8303/8311/1 7124/7132/1 7117/7125/1 4066/4074/1 +f 7124/7132/1 7123/7131/1 7118/7126/1 7117/7125/1 +f 7110/7118/1 7113/7121/1 7116/7124/1 7111/7119/1 +f 16323/16331/1 1392/1400/1 7113/7121/1 7110/7118/1 +f 1392/1400/1 1391/1399/1 7114/7122/1 7113/7121/1 +f 7126/7134/1 7109/7117/1 7112/7120/1 7127/7135/1 +f 4035/4043/1 16324/16332/1 7109/7117/1 7126/7134/1 +f 16324/16332/1 16323/16331/1 7110/7118/1 7109/7117/1 +f 4458/4466/1 7105/7113/1 7108/7116/1 4459/4467/1 +f 7127/7135/1 7112/7120/1 7105/7113/1 4458/4466/1 +f 7112/7120/1 7111/7119/1 7106/7114/1 7105/7113/1 +f 7098/7106/1 7101/7109/1 7104/7112/1 7099/7107/1 +f 7083/7091/1 4472/4480/1 7101/7109/1 7098/7106/1 +f 4472/4480/1 4471/4479/1 7102/7110/1 7101/7109/1 +f 16318/16326/1 7097/7105/1 7100/7108/1 16319/16327/1 +f 4031/4039/1 7084/7092/1 7097/7105/1 16318/16326/1 +f 7084/7092/1 7083/7091/1 7098/7106/1 7097/7105/1 +f 1394/1402/1 7093/7101/1 7096/7104/1 1395/1403/1 +f 16319/16327/1 7100/7108/1 7093/7101/1 1394/1402/1 +f 7100/7108/1 7099/7107/1 7094/7102/1 7093/7101/1 +f 7086/7094/1 7089/7097/1 7092/7100/1 7087/7095/1 +f 8499/8507/1 4000/4008/1 7089/7097/1 7086/7094/1 +f 4000/4008/1 3999/4007/1 7090/7098/1 7089/7097/1 +f 8410/8418/1 7085/7093/1 7088/7096/1 8411/8419/1 +f 1399/1407/1 8500/8508/1 7085/7093/1 8410/8418/1 +f 8500/8508/1 8499/8507/1 7086/7094/1 7085/7093/1 +f 4030/4038/1 7081/7089/1 7084/7092/1 4031/4039/1 +f 8411/8419/1 7088/7096/1 7081/7089/1 4030/4038/1 +f 7088/7096/1 7087/7095/1 7082/7090/1 7081/7089/1 +f 7074/7082/1 7077/7085/1 7080/7088/1 7075/7083/1 +f 16287/16295/1 1404/1412/1 7077/7085/1 7074/7082/1 +f 1404/1412/1 1403/1411/1 7078/7086/1 7077/7085/1 +f 7090/7098/1 7073/7081/1 7076/7084/1 7091/7099/1 +f 3999/4007/1 16288/16296/1 7073/7081/1 7090/7098/1 +f 16288/16296/1 16287/16295/1 7074/7082/1 7073/7081/1 +f 4470/4478/1 7069/7077/1 7072/7080/1 4471/4479/1 +f 7091/7099/1 7076/7084/1 7069/7077/1 4470/4478/1 +f 7076/7084/1 7075/7083/1 7070/7078/1 7069/7077/1 +f 7062/7070/1 7065/7073/1 7068/7076/1 7063/7071/1 +f 7047/7055/1 4484/4492/1 7065/7073/1 7062/7070/1 +f 4484/4492/1 4483/4491/1 7066/7074/1 7065/7073/1 +f 16282/16290/1 7061/7069/1 7064/7072/1 16283/16291/1 +f 3995/4003/1 7048/7056/1 7061/7069/1 16282/16290/1 +f 7048/7056/1 7047/7055/1 7062/7070/1 7061/7069/1 +f 1406/1414/1 7057/7065/1 7060/7068/1 1407/1415/1 +f 16283/16291/1 7064/7072/1 7057/7065/1 1406/1414/1 +f 7064/7072/1 7063/7071/1 7058/7066/1 7057/7065/1 +f 7050/7058/1 7053/7061/1 7056/7064/1 7051/7059/1 +f 8607/8615/1 3964/3972/1 7053/7061/1 7050/7058/1 +f 3964/3972/1 3963/3971/1 7054/7062/1 7053/7061/1 +f 8518/8526/1 7049/7057/1 7052/7060/1 8519/8527/1 +f 1411/1419/1 8608/8616/1 7049/7057/1 8518/8526/1 +f 8608/8616/1 8607/8615/1 7050/7058/1 7049/7057/1 +f 3994/4002/1 7045/7053/1 7048/7056/1 3995/4003/1 +f 8519/8527/1 7052/7060/1 7045/7053/1 3994/4002/1 +f 7052/7060/1 7051/7059/1 7046/7054/1 7045/7053/1 +f 7038/7046/1 7041/7049/1 7044/7052/1 7039/7047/1 +f 16251/16259/1 1416/1424/1 7041/7049/1 7038/7046/1 +f 1416/1424/1 1415/1423/1 7042/7050/1 7041/7049/1 +f 7054/7062/1 7037/7045/1 7040/7048/1 7055/7063/1 +f 3963/3971/1 16252/16260/1 7037/7045/1 7054/7062/1 +f 16252/16260/1 16251/16259/1 7038/7046/1 7037/7045/1 +f 4482/4490/1 7033/7041/1 7036/7044/1 4483/4491/1 +f 7055/7063/1 7040/7048/1 7033/7041/1 4482/4490/1 +f 7040/7048/1 7039/7047/1 7034/7042/1 7033/7041/1 +f 7026/7034/1 7029/7037/1 7032/7040/1 7027/7035/1 +f 7011/7019/1 4496/4504/1 7029/7037/1 7026/7034/1 +f 4496/4504/1 4495/4503/1 7030/7038/1 7029/7037/1 +f 16246/16254/1 7025/7033/1 7028/7036/1 16247/16255/1 +f 3959/3967/1 7012/7020/1 7025/7033/1 16246/16254/1 +f 7012/7020/1 7011/7019/1 7026/7034/1 7025/7033/1 +f 1418/1426/1 7021/7029/1 7024/7032/1 1419/1427/1 +f 16247/16255/1 7028/7036/1 7021/7029/1 1418/1426/1 +f 7028/7036/1 7027/7035/1 7022/7030/1 7021/7029/1 +f 7014/7022/1 7017/7025/1 7020/7028/1 7015/7023/1 +f 8715/8723/1 3928/3936/1 7017/7025/1 7014/7022/1 +f 3928/3936/1 3927/3935/1 7018/7026/1 7017/7025/1 +f 8626/8634/1 7013/7021/1 7016/7024/1 8627/8635/1 +f 1423/1431/1 8716/8724/1 7013/7021/1 8626/8634/1 +f 8716/8724/1 8715/8723/1 7014/7022/1 7013/7021/1 +f 3958/3966/1 7009/7017/1 7012/7020/1 3959/3967/1 +f 8627/8635/1 7016/7024/1 7009/7017/1 3958/3966/1 +f 7016/7024/1 7015/7023/1 7010/7018/1 7009/7017/1 +f 7002/7010/1 7005/7013/1 7008/7016/1 7003/7011/1 +f 16215/16223/1 1428/1436/1 7005/7013/1 7002/7010/1 +f 1428/1436/1 1427/1435/1 7006/7014/1 7005/7013/1 +f 7018/7026/1 7001/7009/1 7004/7012/1 7019/7027/1 +f 3927/3935/1 16216/16224/1 7001/7009/1 7018/7026/1 +f 16216/16224/1 16215/16223/1 7002/7010/1 7001/7009/1 +f 4494/4502/1 6997/7005/1 7000/7008/1 4495/4503/1 +f 7019/7027/1 7004/7012/1 6997/7005/1 4494/4502/1 +f 7004/7012/1 7003/7011/1 6998/7006/1 6997/7005/1 +f 6990/6998/1 6993/7001/1 6996/7004/1 6991/6999/1 +f 6975/6983/1 4508/4516/1 6993/7001/1 6990/6998/1 +f 4508/4516/1 4507/4515/1 6994/7002/1 6993/7001/1 +f 16210/16218/1 6989/6997/1 6992/7000/1 16211/16219/1 +f 3923/3931/1 6976/6984/1 6989/6997/1 16210/16218/1 +f 6976/6984/1 6975/6983/1 6990/6998/1 6989/6997/1 +f 1430/1438/1 6985/6993/1 6988/6996/1 1431/1439/1 +f 16211/16219/1 6992/7000/1 6985/6993/1 1430/1438/1 +f 6992/7000/1 6991/6999/1 6986/6994/1 6985/6993/1 +f 6978/6986/1 6981/6989/1 6984/6992/1 6979/6987/1 +f 8823/8831/1 3892/3900/1 6981/6989/1 6978/6986/1 +f 3892/3900/1 3891/3899/1 6982/6990/1 6981/6989/1 +f 8734/8742/1 6977/6985/1 6980/6988/1 8735/8743/1 +f 1435/1443/1 8824/8832/1 6977/6985/1 8734/8742/1 +f 8824/8832/1 8823/8831/1 6978/6986/1 6977/6985/1 +f 3922/3930/1 6973/6981/1 6976/6984/1 3923/3931/1 +f 8735/8743/1 6980/6988/1 6973/6981/1 3922/3930/1 +f 6980/6988/1 6979/6987/1 6974/6982/1 6973/6981/1 +f 6966/6974/1 6969/6977/1 6972/6980/1 6967/6975/1 +f 16179/16187/1 1440/1448/1 6969/6977/1 6966/6974/1 +f 1440/1448/1 1439/1447/1 6970/6978/1 6969/6977/1 +f 6982/6990/1 6965/6973/1 6968/6976/1 6983/6991/1 +f 3891/3899/1 16180/16188/1 6965/6973/1 6982/6990/1 +f 16180/16188/1 16179/16187/1 6966/6974/1 6965/6973/1 +f 4506/4514/1 6961/6969/1 6964/6972/1 4507/4515/1 +f 6983/6991/1 6968/6976/1 6961/6969/1 4506/4514/1 +f 6968/6976/1 6967/6975/1 6962/6970/1 6961/6969/1 +f 6954/6962/1 6957/6965/1 6960/6968/1 6955/6963/1 +f 6939/6947/1 4520/4528/1 6957/6965/1 6954/6962/1 +f 4520/4528/1 4519/4527/1 6958/6966/1 6957/6965/1 +f 16174/16182/1 6953/6961/1 6956/6964/1 16175/16183/1 +f 3887/3895/1 6940/6948/1 6953/6961/1 16174/16182/1 +f 6940/6948/1 6939/6947/1 6954/6962/1 6953/6961/1 +f 1442/1450/1 6949/6957/1 6952/6960/1 1443/1451/1 +f 16175/16183/1 6956/6964/1 6949/6957/1 1442/1450/1 +f 6956/6964/1 6955/6963/1 6950/6958/1 6949/6957/1 +f 6942/6950/1 6945/6953/1 6948/6956/1 6943/6951/1 +f 8931/8939/1 3856/3864/1 6945/6953/1 6942/6950/1 +f 3856/3864/1 3855/3863/1 6946/6954/1 6945/6953/1 +f 8842/8850/1 6941/6949/1 6944/6952/1 8843/8851/1 +f 1447/1455/1 8932/8940/1 6941/6949/1 8842/8850/1 +f 8932/8940/1 8931/8939/1 6942/6950/1 6941/6949/1 +f 3886/3894/1 6937/6945/1 6940/6948/1 3887/3895/1 +f 8843/8851/1 6944/6952/1 6937/6945/1 3886/3894/1 +f 6944/6952/1 6943/6951/1 6938/6946/1 6937/6945/1 +f 6930/6938/1 6933/6941/1 6936/6944/1 6931/6939/1 +f 16143/16151/1 1452/1460/1 6933/6941/1 6930/6938/1 +f 1452/1460/1 1451/1459/1 6934/6942/1 6933/6941/1 +f 6946/6954/1 6929/6937/1 6932/6940/1 6947/6955/1 +f 3855/3863/1 16144/16152/1 6929/6937/1 6946/6954/1 +f 16144/16152/1 16143/16151/1 6930/6938/1 6929/6937/1 +f 4518/4526/1 6925/6933/1 6928/6936/1 4519/4527/1 +f 6947/6955/1 6932/6940/1 6925/6933/1 4518/4526/1 +f 6932/6940/1 6931/6939/1 6926/6934/1 6925/6933/1 +f 6918/6926/1 6921/6929/1 6924/6932/1 6919/6927/1 +f 6903/6911/1 4532/4540/1 6921/6929/1 6918/6926/1 +f 4532/4540/1 4531/4539/1 6922/6930/1 6921/6929/1 +f 16138/16146/1 6917/6925/1 6920/6928/1 16139/16147/1 +f 3851/3859/1 6904/6912/1 6917/6925/1 16138/16146/1 +f 6904/6912/1 6903/6911/1 6918/6926/1 6917/6925/1 +f 1454/1462/1 6913/6921/1 6916/6924/1 1455/1463/1 +f 16139/16147/1 6920/6928/1 6913/6921/1 1454/1462/1 +f 6920/6928/1 6919/6927/1 6914/6922/1 6913/6921/1 +f 6906/6914/1 6909/6917/1 6912/6920/1 6907/6915/1 +f 9039/9047/1 3820/3828/1 6909/6917/1 6906/6914/1 +f 3820/3828/1 3819/3827/1 6910/6918/1 6909/6917/1 +f 8950/8958/1 6905/6913/1 6908/6916/1 8951/8959/1 +f 1459/1467/1 9040/9048/1 6905/6913/1 8950/8958/1 +f 9040/9048/1 9039/9047/1 6906/6914/1 6905/6913/1 +f 3850/3858/1 6901/6909/1 6904/6912/1 3851/3859/1 +f 8951/8959/1 6908/6916/1 6901/6909/1 3850/3858/1 +f 6908/6916/1 6907/6915/1 6902/6910/1 6901/6909/1 +f 6894/6902/1 6897/6905/1 6900/6908/1 6895/6903/1 +f 16107/16115/1 1464/1472/1 6897/6905/1 6894/6902/1 +f 1464/1472/1 1463/1471/1 6898/6906/1 6897/6905/1 +f 6910/6918/1 6893/6901/1 6896/6904/1 6911/6919/1 +f 3819/3827/1 16108/16116/1 6893/6901/1 6910/6918/1 +f 16108/16116/1 16107/16115/1 6894/6902/1 6893/6901/1 +f 4530/4538/1 6889/6897/1 6892/6900/1 4531/4539/1 +f 6911/6919/1 6896/6904/1 6889/6897/1 4530/4538/1 +f 6896/6904/1 6895/6903/1 6890/6898/1 6889/6897/1 +f 6882/6890/1 6885/6893/1 6888/6896/1 6883/6891/1 +f 6867/6875/1 4544/4552/1 6885/6893/1 6882/6890/1 +f 4544/4552/1 4543/4551/1 6886/6894/1 6885/6893/1 +f 16102/16110/1 6881/6889/1 6884/6892/1 16103/16111/1 +f 3815/3823/1 6868/6876/1 6881/6889/1 16102/16110/1 +f 6868/6876/1 6867/6875/1 6882/6890/1 6881/6889/1 +f 1466/1474/1 6877/6885/1 6880/6888/1 1467/1475/1 +f 16103/16111/1 6884/6892/1 6877/6885/1 1466/1474/1 +f 6884/6892/1 6883/6891/1 6878/6886/1 6877/6885/1 +f 6870/6878/1 6873/6881/1 6876/6884/1 6871/6879/1 +f 9147/9155/1 3784/3792/1 6873/6881/1 6870/6878/1 +f 3784/3792/1 3783/3791/1 6874/6882/1 6873/6881/1 +f 9058/9066/1 6869/6877/1 6872/6880/1 9059/9067/1 +f 1471/1479/1 9148/9156/1 6869/6877/1 9058/9066/1 +f 9148/9156/1 9147/9155/1 6870/6878/1 6869/6877/1 +f 3814/3822/1 6865/6873/1 6868/6876/1 3815/3823/1 +f 9059/9067/1 6872/6880/1 6865/6873/1 3814/3822/1 +f 6872/6880/1 6871/6879/1 6866/6874/1 6865/6873/1 +f 6858/6866/1 6861/6869/1 6864/6872/1 6859/6867/1 +f 16071/16079/1 1476/1484/1 6861/6869/1 6858/6866/1 +f 1476/1484/1 1475/1483/1 6862/6870/1 6861/6869/1 +f 6874/6882/1 6857/6865/1 6860/6868/1 6875/6883/1 +f 3783/3791/1 16072/16080/1 6857/6865/1 6874/6882/1 +f 16072/16080/1 16071/16079/1 6858/6866/1 6857/6865/1 +f 4542/4550/1 6853/6861/1 6856/6864/1 4543/4551/1 +f 6875/6883/1 6860/6868/1 6853/6861/1 4542/4550/1 +f 6860/6868/1 6859/6867/1 6854/6862/1 6853/6861/1 +f 6846/6854/1 6849/6857/1 6852/6860/1 6847/6855/1 +f 6831/6839/1 4556/4564/1 6849/6857/1 6846/6854/1 +f 4556/4564/1 4555/4563/1 6850/6858/1 6849/6857/1 +f 16066/16074/1 6845/6853/1 6848/6856/1 16067/16075/1 +f 3779/3787/1 6832/6840/1 6845/6853/1 16066/16074/1 +f 6832/6840/1 6831/6839/1 6846/6854/1 6845/6853/1 +f 1478/1486/1 6841/6849/1 6844/6852/1 1479/1487/1 +f 16067/16075/1 6848/6856/1 6841/6849/1 1478/1486/1 +f 6848/6856/1 6847/6855/1 6842/6850/1 6841/6849/1 +f 6834/6842/1 6837/6845/1 6840/6848/1 6835/6843/1 +f 9255/9263/1 3748/3756/1 6837/6845/1 6834/6842/1 +f 3748/3756/1 3747/3755/1 6838/6846/1 6837/6845/1 +f 9166/9174/1 6833/6841/1 6836/6844/1 9167/9175/1 +f 1483/1491/1 9256/9264/1 6833/6841/1 9166/9174/1 +f 9256/9264/1 9255/9263/1 6834/6842/1 6833/6841/1 +f 3778/3786/1 6829/6837/1 6832/6840/1 3779/3787/1 +f 9167/9175/1 6836/6844/1 6829/6837/1 3778/3786/1 +f 6836/6844/1 6835/6843/1 6830/6838/1 6829/6837/1 +f 6822/6830/1 6825/6833/1 6828/6836/1 6823/6831/1 +f 16035/16043/1 1488/1496/1 6825/6833/1 6822/6830/1 +f 1488/1496/1 1487/1495/1 6826/6834/1 6825/6833/1 +f 6838/6846/1 6821/6829/1 6824/6832/1 6839/6847/1 +f 3747/3755/1 16036/16044/1 6821/6829/1 6838/6846/1 +f 16036/16044/1 16035/16043/1 6822/6830/1 6821/6829/1 +f 4554/4562/1 6817/6825/1 6820/6828/1 4555/4563/1 +f 6839/6847/1 6824/6832/1 6817/6825/1 4554/4562/1 +f 6824/6832/1 6823/6831/1 6818/6826/1 6817/6825/1 +f 6810/6818/1 6813/6821/1 6816/6824/1 6811/6819/1 +f 6795/6803/1 4568/4576/1 6813/6821/1 6810/6818/1 +f 4568/4576/1 4567/4575/1 6814/6822/1 6813/6821/1 +f 16030/16038/1 6809/6817/1 6812/6820/1 16031/16039/1 +f 3743/3751/1 6796/6804/1 6809/6817/1 16030/16038/1 +f 6796/6804/1 6795/6803/1 6810/6818/1 6809/6817/1 +f 1490/1498/1 6805/6813/1 6808/6816/1 1491/1499/1 +f 16031/16039/1 6812/6820/1 6805/6813/1 1490/1498/1 +f 6812/6820/1 6811/6819/1 6806/6814/1 6805/6813/1 +f 6798/6806/1 6801/6809/1 6804/6812/1 6799/6807/1 +f 9363/9371/1 3712/3720/1 6801/6809/1 6798/6806/1 +f 3712/3720/1 3711/3719/1 6802/6810/1 6801/6809/1 +f 9274/9282/1 6797/6805/1 6800/6808/1 9275/9283/1 +f 1495/1503/1 9364/9372/1 6797/6805/1 9274/9282/1 +f 9364/9372/1 9363/9371/1 6798/6806/1 6797/6805/1 +f 3742/3750/1 6793/6801/1 6796/6804/1 3743/3751/1 +f 9275/9283/1 6800/6808/1 6793/6801/1 3742/3750/1 +f 6800/6808/1 6799/6807/1 6794/6802/1 6793/6801/1 +f 6786/6794/1 6789/6797/1 6792/6800/1 6787/6795/1 +f 15999/16007/1 1500/1508/1 6789/6797/1 6786/6794/1 +f 1500/1508/1 1499/1507/1 6790/6798/1 6789/6797/1 +f 6802/6810/1 6785/6793/1 6788/6796/1 6803/6811/1 +f 3711/3719/1 16000/16008/1 6785/6793/1 6802/6810/1 +f 16000/16008/1 15999/16007/1 6786/6794/1 6785/6793/1 +f 4566/4574/1 6781/6789/1 6784/6792/1 4567/4575/1 +f 6803/6811/1 6788/6796/1 6781/6789/1 4566/4574/1 +f 6788/6796/1 6787/6795/1 6782/6790/1 6781/6789/1 +f 6774/6782/1 6777/6785/1 6780/6788/1 6775/6783/1 +f 6759/6767/1 4580/4588/1 6777/6785/1 6774/6782/1 +f 4580/4588/1 4579/4587/1 6778/6786/1 6777/6785/1 +f 15994/16002/1 6773/6781/1 6776/6784/1 15995/16003/1 +f 3707/3715/1 6760/6768/1 6773/6781/1 15994/16002/1 +f 6760/6768/1 6759/6767/1 6774/6782/1 6773/6781/1 +f 1502/1510/1 6769/6777/1 6772/6780/1 1503/1511/1 +f 15995/16003/1 6776/6784/1 6769/6777/1 1502/1510/1 +f 6776/6784/1 6775/6783/1 6770/6778/1 6769/6777/1 +f 6762/6770/1 6765/6773/1 6768/6776/1 6763/6771/1 +f 9471/9479/1 3676/3684/1 6765/6773/1 6762/6770/1 +f 3676/3684/1 3675/3683/1 6766/6774/1 6765/6773/1 +f 9382/9390/1 6761/6769/1 6764/6772/1 9383/9391/1 +f 1507/1515/1 9472/9480/1 6761/6769/1 9382/9390/1 +f 9472/9480/1 9471/9479/1 6762/6770/1 6761/6769/1 +f 3706/3714/1 6757/6765/1 6760/6768/1 3707/3715/1 +f 9383/9391/1 6764/6772/1 6757/6765/1 3706/3714/1 +f 6764/6772/1 6763/6771/1 6758/6766/1 6757/6765/1 +f 6750/6758/1 6753/6761/1 6756/6764/1 6751/6759/1 +f 15963/15971/1 1512/1520/1 6753/6761/1 6750/6758/1 +f 1512/1520/1 1511/1519/1 6754/6762/1 6753/6761/1 +f 6766/6774/1 6749/6757/1 6752/6760/1 6767/6775/1 +f 3675/3683/1 15964/15972/1 6749/6757/1 6766/6774/1 +f 15964/15972/1 15963/15971/1 6750/6758/1 6749/6757/1 +f 4578/4586/1 6745/6753/1 6748/6756/1 4579/4587/1 +f 6767/6775/1 6752/6760/1 6745/6753/1 4578/4586/1 +f 6752/6760/1 6751/6759/1 6746/6754/1 6745/6753/1 +f 6738/6746/1 6741/6749/1 6744/6752/1 6739/6747/1 +f 6723/6731/1 4592/4600/1 6741/6749/1 6738/6746/1 +f 4592/4600/1 4591/4599/1 6742/6750/1 6741/6749/1 +f 15958/15966/1 6737/6745/1 6740/6748/1 15959/15967/1 +f 3671/3679/1 6724/6732/1 6737/6745/1 15958/15966/1 +f 6724/6732/1 6723/6731/1 6738/6746/1 6737/6745/1 +f 1514/1522/1 6733/6741/1 6736/6744/1 1515/1523/1 +f 15959/15967/1 6740/6748/1 6733/6741/1 1514/1522/1 +f 6740/6748/1 6739/6747/1 6734/6742/1 6733/6741/1 +f 6726/6734/1 6729/6737/1 6732/6740/1 6727/6735/1 +f 9579/9587/1 3640/3648/1 6729/6737/1 6726/6734/1 +f 3640/3648/1 3639/3647/1 6730/6738/1 6729/6737/1 +f 9490/9498/1 6725/6733/1 6728/6736/1 9491/9499/1 +f 1519/1527/1 9580/9588/1 6725/6733/1 9490/9498/1 +f 9580/9588/1 9579/9587/1 6726/6734/1 6725/6733/1 +f 3670/3678/1 6721/6729/1 6724/6732/1 3671/3679/1 +f 9491/9499/1 6728/6736/1 6721/6729/1 3670/3678/1 +f 6728/6736/1 6727/6735/1 6722/6730/1 6721/6729/1 +f 6714/6722/1 6717/6725/1 6720/6728/1 6715/6723/1 +f 15927/15935/1 1524/1532/1 6717/6725/1 6714/6722/1 +f 1524/1532/1 1523/1531/1 6718/6726/1 6717/6725/1 +f 6730/6738/1 6713/6721/1 6716/6724/1 6731/6739/1 +f 3639/3647/1 15928/15936/1 6713/6721/1 6730/6738/1 +f 15928/15936/1 15927/15935/1 6714/6722/1 6713/6721/1 +f 4590/4598/1 6709/6717/1 6712/6720/1 4591/4599/1 +f 6731/6739/1 6716/6724/1 6709/6717/1 4590/4598/1 +f 6716/6724/1 6715/6723/1 6710/6718/1 6709/6717/1 +f 6702/6710/1 6705/6713/1 6708/6716/1 6703/6711/1 +f 6687/6695/1 4604/4612/1 6705/6713/1 6702/6710/1 +f 4604/4612/1 4603/4611/1 6706/6714/1 6705/6713/1 +f 15922/15930/1 6701/6709/1 6704/6712/1 15923/15931/1 +f 3635/3643/1 6688/6696/1 6701/6709/1 15922/15930/1 +f 6688/6696/1 6687/6695/1 6702/6710/1 6701/6709/1 +f 1526/1534/1 6697/6705/1 6700/6708/1 1527/1535/1 +f 15923/15931/1 6704/6712/1 6697/6705/1 1526/1534/1 +f 6704/6712/1 6703/6711/1 6698/6706/1 6697/6705/1 +f 6690/6698/1 6693/6701/1 6696/6704/1 6691/6699/1 +f 9687/9695/1 3604/3612/1 6693/6701/1 6690/6698/1 +f 3604/3612/1 3603/3611/1 6694/6702/1 6693/6701/1 +f 9598/9606/1 6689/6697/1 6692/6700/1 9599/9607/1 +f 1531/1539/1 9688/9696/1 6689/6697/1 9598/9606/1 +f 9688/9696/1 9687/9695/1 6690/6698/1 6689/6697/1 +f 3634/3642/1 6685/6693/1 6688/6696/1 3635/3643/1 +f 9599/9607/1 6692/6700/1 6685/6693/1 3634/3642/1 +f 6692/6700/1 6691/6699/1 6686/6694/1 6685/6693/1 +f 6678/6686/1 6681/6689/1 6684/6692/1 6679/6687/1 +f 15891/15899/1 1536/1544/1 6681/6689/1 6678/6686/1 +f 1536/1544/1 1535/1543/1 6682/6690/1 6681/6689/1 +f 6694/6702/1 6677/6685/1 6680/6688/1 6695/6703/1 +f 3603/3611/1 15892/15900/1 6677/6685/1 6694/6702/1 +f 15892/15900/1 15891/15899/1 6678/6686/1 6677/6685/1 +f 4602/4610/1 6673/6681/1 6676/6684/1 4603/4611/1 +f 6695/6703/1 6680/6688/1 6673/6681/1 4602/4610/1 +f 6680/6688/1 6679/6687/1 6674/6682/1 6673/6681/1 +f 6666/6674/1 6669/6677/1 6672/6680/1 6667/6675/1 +f 6651/6659/1 4616/4624/1 6669/6677/1 6666/6674/1 +f 4616/4624/1 4615/4623/1 6670/6678/1 6669/6677/1 +f 15886/15894/1 6665/6673/1 6668/6676/1 15887/15895/1 +f 3599/3607/1 6652/6660/1 6665/6673/1 15886/15894/1 +f 6652/6660/1 6651/6659/1 6666/6674/1 6665/6673/1 +f 1538/1546/1 6661/6669/1 6664/6672/1 1539/1547/1 +f 15887/15895/1 6668/6676/1 6661/6669/1 1538/1546/1 +f 6668/6676/1 6667/6675/1 6662/6670/1 6661/6669/1 +f 6654/6662/1 6657/6665/1 6660/6668/1 6655/6663/1 +f 9795/9803/1 3568/3576/1 6657/6665/1 6654/6662/1 +f 3568/3576/1 3567/3575/1 6658/6666/1 6657/6665/1 +f 9706/9714/1 6653/6661/1 6656/6664/1 9707/9715/1 +f 1543/1551/1 9796/9804/1 6653/6661/1 9706/9714/1 +f 9796/9804/1 9795/9803/1 6654/6662/1 6653/6661/1 +f 3598/3606/1 6649/6657/1 6652/6660/1 3599/3607/1 +f 9707/9715/1 6656/6664/1 6649/6657/1 3598/3606/1 +f 6656/6664/1 6655/6663/1 6650/6658/1 6649/6657/1 +f 6642/6650/1 6645/6653/1 6648/6656/1 6643/6651/1 +f 15855/15863/1 1548/1556/1 6645/6653/1 6642/6650/1 +f 1548/1556/1 1547/1555/1 6646/6654/1 6645/6653/1 +f 6658/6666/1 6641/6649/1 6644/6652/1 6659/6667/1 +f 3567/3575/1 15856/15864/1 6641/6649/1 6658/6666/1 +f 15856/15864/1 15855/15863/1 6642/6650/1 6641/6649/1 +f 4614/4622/1 6637/6645/1 6640/6648/1 4615/4623/1 +f 6659/6667/1 6644/6652/1 6637/6645/1 4614/4622/1 +f 6644/6652/1 6643/6651/1 6638/6646/1 6637/6645/1 +f 6630/6638/1 6633/6641/1 6636/6644/1 6631/6639/1 +f 6615/6623/1 4628/4636/1 6633/6641/1 6630/6638/1 +f 4628/4636/1 4627/4635/1 6634/6642/1 6633/6641/1 +f 15850/15858/1 6629/6637/1 6632/6640/1 15851/15859/1 +f 3563/3571/1 6616/6624/1 6629/6637/1 15850/15858/1 +f 6616/6624/1 6615/6623/1 6630/6638/1 6629/6637/1 +f 1550/1558/1 6625/6633/1 6628/6636/1 1551/1559/1 +f 15851/15859/1 6632/6640/1 6625/6633/1 1550/1558/1 +f 6632/6640/1 6631/6639/1 6626/6634/1 6625/6633/1 +f 6618/6626/1 6621/6629/1 6624/6632/1 6619/6627/1 +f 9903/9911/1 3532/3540/1 6621/6629/1 6618/6626/1 +f 3532/3540/1 3531/3539/1 6622/6630/1 6621/6629/1 +f 9814/9822/1 6617/6625/1 6620/6628/1 9815/9823/1 +f 1555/1563/1 9904/9912/1 6617/6625/1 9814/9822/1 +f 9904/9912/1 9903/9911/1 6618/6626/1 6617/6625/1 +f 3562/3570/1 6613/6621/1 6616/6624/1 3563/3571/1 +f 9815/9823/1 6620/6628/1 6613/6621/1 3562/3570/1 +f 6620/6628/1 6619/6627/1 6614/6622/1 6613/6621/1 +f 6606/6614/1 6609/6617/1 6612/6620/1 6607/6615/1 +f 15819/15827/1 1560/1568/1 6609/6617/1 6606/6614/1 +f 1560/1568/1 1559/1567/1 6610/6618/1 6609/6617/1 +f 6622/6630/1 6605/6613/1 6608/6616/1 6623/6631/1 +f 3531/3539/1 15820/15828/1 6605/6613/1 6622/6630/1 +f 15820/15828/1 15819/15827/1 6606/6614/1 6605/6613/1 +f 4626/4634/1 6601/6609/1 6604/6612/1 4627/4635/1 +f 6623/6631/1 6608/6616/1 6601/6609/1 4626/4634/1 +f 6608/6616/1 6607/6615/1 6602/6610/1 6601/6609/1 +f 6594/6602/1 6597/6605/1 6600/6608/1 6595/6603/1 +f 6579/6587/1 4640/4648/1 6597/6605/1 6594/6602/1 +f 4640/4648/1 4639/4647/1 6598/6606/1 6597/6605/1 +f 15814/15822/1 6593/6601/1 6596/6604/1 15815/15823/1 +f 3527/3535/1 6580/6588/1 6593/6601/1 15814/15822/1 +f 6580/6588/1 6579/6587/1 6594/6602/1 6593/6601/1 +f 1562/1570/1 6589/6597/1 6592/6600/1 1563/1571/1 +f 15815/15823/1 6596/6604/1 6589/6597/1 1562/1570/1 +f 6596/6604/1 6595/6603/1 6590/6598/1 6589/6597/1 +f 6582/6590/1 6585/6593/1 6588/6596/1 6583/6591/1 +f 10011/10019/1 3496/3504/1 6585/6593/1 6582/6590/1 +f 3496/3504/1 3495/3503/1 6586/6594/1 6585/6593/1 +f 9922/9930/1 6581/6589/1 6584/6592/1 9923/9931/1 +f 1567/1575/1 10012/10020/1 6581/6589/1 9922/9930/1 +f 10012/10020/1 10011/10019/1 6582/6590/1 6581/6589/1 +f 3526/3534/1 6577/6585/1 6580/6588/1 3527/3535/1 +f 9923/9931/1 6584/6592/1 6577/6585/1 3526/3534/1 +f 6584/6592/1 6583/6591/1 6578/6586/1 6577/6585/1 +f 6570/6578/1 6573/6581/1 6576/6584/1 6571/6579/1 +f 15783/15791/1 1572/1580/1 6573/6581/1 6570/6578/1 +f 1572/1580/1 1571/1579/1 6574/6582/1 6573/6581/1 +f 6586/6594/1 6569/6577/1 6572/6580/1 6587/6595/1 +f 3495/3503/1 15784/15792/1 6569/6577/1 6586/6594/1 +f 15784/15792/1 15783/15791/1 6570/6578/1 6569/6577/1 +f 4638/4646/1 6565/6573/1 6568/6576/1 4639/4647/1 +f 6587/6595/1 6572/6580/1 6565/6573/1 4638/4646/1 +f 6572/6580/1 6571/6579/1 6566/6574/1 6565/6573/1 +f 6558/6566/1 6561/6569/1 6564/6572/1 6559/6567/1 +f 6543/6551/1 4652/4660/1 6561/6569/1 6558/6566/1 +f 4652/4660/1 4651/4659/1 6562/6570/1 6561/6569/1 +f 15778/15786/1 6557/6565/1 6560/6568/1 15779/15787/1 +f 3491/3499/1 6544/6552/1 6557/6565/1 15778/15786/1 +f 6544/6552/1 6543/6551/1 6558/6566/1 6557/6565/1 +f 1574/1582/1 6553/6561/1 6556/6564/1 1575/1583/1 +f 15779/15787/1 6560/6568/1 6553/6561/1 1574/1582/1 +f 6560/6568/1 6559/6567/1 6554/6562/1 6553/6561/1 +f 6546/6554/1 6549/6557/1 6552/6560/1 6547/6555/1 +f 10119/10127/1 3460/3468/1 6549/6557/1 6546/6554/1 +f 3460/3468/1 3459/3467/1 6550/6558/1 6549/6557/1 +f 10030/10038/1 6545/6553/1 6548/6556/1 10031/10039/1 +f 1579/1587/1 10120/10128/1 6545/6553/1 10030/10038/1 +f 10120/10128/1 10119/10127/1 6546/6554/1 6545/6553/1 +f 3490/3498/1 6541/6549/1 6544/6552/1 3491/3499/1 +f 10031/10039/1 6548/6556/1 6541/6549/1 3490/3498/1 +f 6548/6556/1 6547/6555/1 6542/6550/1 6541/6549/1 +f 6534/6542/1 6537/6545/1 6540/6548/1 6535/6543/1 +f 15747/15755/1 1584/1592/1 6537/6545/1 6534/6542/1 +f 1584/1592/1 1583/1591/1 6538/6546/1 6537/6545/1 +f 6550/6558/1 6533/6541/1 6536/6544/1 6551/6559/1 +f 3459/3467/1 15748/15756/1 6533/6541/1 6550/6558/1 +f 15748/15756/1 15747/15755/1 6534/6542/1 6533/6541/1 +f 4650/4658/1 6529/6537/1 6532/6540/1 4651/4659/1 +f 6551/6559/1 6536/6544/1 6529/6537/1 4650/4658/1 +f 6536/6544/1 6535/6543/1 6530/6538/1 6529/6537/1 +f 6522/6530/1 6525/6533/1 6528/6536/1 6523/6531/1 +f 6507/6515/1 4664/4672/1 6525/6533/1 6522/6530/1 +f 4664/4672/1 4663/4671/1 6526/6534/1 6525/6533/1 +f 15742/15750/1 6521/6529/1 6524/6532/1 15743/15751/1 +f 3455/3463/1 6508/6516/1 6521/6529/1 15742/15750/1 +f 6508/6516/1 6507/6515/1 6522/6530/1 6521/6529/1 +f 1586/1594/1 6517/6525/1 6520/6528/1 1587/1595/1 +f 15743/15751/1 6524/6532/1 6517/6525/1 1586/1594/1 +f 6524/6532/1 6523/6531/1 6518/6526/1 6517/6525/1 +f 6510/6518/1 6513/6521/1 6516/6524/1 6511/6519/1 +f 10227/10235/1 3424/3432/1 6513/6521/1 6510/6518/1 +f 3424/3432/1 3423/3431/1 6514/6522/1 6513/6521/1 +f 10138/10146/1 6509/6517/1 6512/6520/1 10139/10147/1 +f 1591/1599/1 10228/10236/1 6509/6517/1 10138/10146/1 +f 10228/10236/1 10227/10235/1 6510/6518/1 6509/6517/1 +f 3454/3462/1 6505/6513/1 6508/6516/1 3455/3463/1 +f 10139/10147/1 6512/6520/1 6505/6513/1 3454/3462/1 +f 6512/6520/1 6511/6519/1 6506/6514/1 6505/6513/1 +f 6498/6506/1 6501/6509/1 6504/6512/1 6499/6507/1 +f 15711/15719/1 1596/1604/1 6501/6509/1 6498/6506/1 +f 1596/1604/1 1595/1603/1 6502/6510/1 6501/6509/1 +f 6514/6522/1 6497/6505/1 6500/6508/1 6515/6523/1 +f 3423/3431/1 15712/15720/1 6497/6505/1 6514/6522/1 +f 15712/15720/1 15711/15719/1 6498/6506/1 6497/6505/1 +f 4662/4670/1 6493/6501/1 6496/6504/1 4663/4671/1 +f 6515/6523/1 6500/6508/1 6493/6501/1 4662/4670/1 +f 6500/6508/1 6499/6507/1 6494/6502/1 6493/6501/1 +f 6486/6494/1 6489/6497/1 6492/6500/1 6487/6495/1 +f 6471/6479/1 4676/4684/1 6489/6497/1 6486/6494/1 +f 4676/4684/1 4675/4683/1 6490/6498/1 6489/6497/1 +f 15706/15714/1 6485/6493/1 6488/6496/1 15707/15715/1 +f 3419/3427/1 6472/6480/1 6485/6493/1 15706/15714/1 +f 6472/6480/1 6471/6479/1 6486/6494/1 6485/6493/1 +f 1598/1606/1 6481/6489/1 6484/6492/1 1599/1607/1 +f 15707/15715/1 6488/6496/1 6481/6489/1 1598/1606/1 +f 6488/6496/1 6487/6495/1 6482/6490/1 6481/6489/1 +f 6474/6482/1 6477/6485/1 6480/6488/1 6475/6483/1 +f 10335/10343/1 3388/3396/1 6477/6485/1 6474/6482/1 +f 3388/3396/1 3387/3395/1 6478/6486/1 6477/6485/1 +f 10246/10254/1 6473/6481/1 6476/6484/1 10247/10255/1 +f 1603/1611/1 10336/10344/1 6473/6481/1 10246/10254/1 +f 10336/10344/1 10335/10343/1 6474/6482/1 6473/6481/1 +f 3418/3426/1 6469/6477/1 6472/6480/1 3419/3427/1 +f 10247/10255/1 6476/6484/1 6469/6477/1 3418/3426/1 +f 6476/6484/1 6475/6483/1 6470/6478/1 6469/6477/1 +f 6462/6470/1 6465/6473/1 6468/6476/1 6463/6471/1 +f 15675/15683/1 1608/1616/1 6465/6473/1 6462/6470/1 +f 1608/1616/1 1607/1615/1 6466/6474/1 6465/6473/1 +f 6478/6486/1 6461/6469/1 6464/6472/1 6479/6487/1 +f 3387/3395/1 15676/15684/1 6461/6469/1 6478/6486/1 +f 15676/15684/1 15675/15683/1 6462/6470/1 6461/6469/1 +f 4674/4682/1 6457/6465/1 6460/6468/1 4675/4683/1 +f 6479/6487/1 6464/6472/1 6457/6465/1 4674/4682/1 +f 6464/6472/1 6463/6471/1 6458/6466/1 6457/6465/1 +f 6450/6458/1 6453/6461/1 6456/6464/1 6451/6459/1 +f 6435/6443/1 4688/4696/1 6453/6461/1 6450/6458/1 +f 4688/4696/1 4687/4695/1 6454/6462/1 6453/6461/1 +f 15670/15678/1 6449/6457/1 6452/6460/1 15671/15679/1 +f 3383/3391/1 6436/6444/1 6449/6457/1 15670/15678/1 +f 6436/6444/1 6435/6443/1 6450/6458/1 6449/6457/1 +f 1610/1618/1 6445/6453/1 6448/6456/1 1611/1619/1 +f 15671/15679/1 6452/6460/1 6445/6453/1 1610/1618/1 +f 6452/6460/1 6451/6459/1 6446/6454/1 6445/6453/1 +f 6438/6446/1 6441/6449/1 6444/6452/1 6439/6447/1 +f 10443/10451/1 3352/3360/1 6441/6449/1 6438/6446/1 +f 3352/3360/1 3351/3359/1 6442/6450/1 6441/6449/1 +f 10354/10362/1 6437/6445/1 6440/6448/1 10355/10363/1 +f 1615/1623/1 10444/10452/1 6437/6445/1 10354/10362/1 +f 10444/10452/1 10443/10451/1 6438/6446/1 6437/6445/1 +f 3382/3390/1 6433/6441/1 6436/6444/1 3383/3391/1 +f 10355/10363/1 6440/6448/1 6433/6441/1 3382/3390/1 +f 6440/6448/1 6439/6447/1 6434/6442/1 6433/6441/1 +f 6426/6434/1 6429/6437/1 6432/6440/1 6427/6435/1 +f 15639/15647/1 1620/1628/1 6429/6437/1 6426/6434/1 +f 1620/1628/1 1619/1627/1 6430/6438/1 6429/6437/1 +f 6442/6450/1 6425/6433/1 6428/6436/1 6443/6451/1 +f 3351/3359/1 15640/15648/1 6425/6433/1 6442/6450/1 +f 15640/15648/1 15639/15647/1 6426/6434/1 6425/6433/1 +f 4686/4694/1 6421/6429/1 6424/6432/1 4687/4695/1 +f 6443/6451/1 6428/6436/1 6421/6429/1 4686/4694/1 +f 6428/6436/1 6427/6435/1 6422/6430/1 6421/6429/1 +f 6414/6422/1 6417/6425/1 6420/6428/1 6415/6423/1 +f 6399/6407/1 4700/4708/1 6417/6425/1 6414/6422/1 +f 4700/4708/1 4699/4707/1 6418/6426/1 6417/6425/1 +f 15634/15642/1 6413/6421/1 6416/6424/1 15635/15643/1 +f 3347/3355/1 6400/6408/1 6413/6421/1 15634/15642/1 +f 6400/6408/1 6399/6407/1 6414/6422/1 6413/6421/1 +f 1622/1630/1 6409/6417/1 6412/6420/1 1623/1631/1 +f 15635/15643/1 6416/6424/1 6409/6417/1 1622/1630/1 +f 6416/6424/1 6415/6423/1 6410/6418/1 6409/6417/1 +f 6402/6410/1 6405/6413/1 6408/6416/1 6403/6411/1 +f 10551/10559/1 3316/3324/1 6405/6413/1 6402/6410/1 +f 3316/3324/1 3315/3323/1 6406/6414/1 6405/6413/1 +f 10462/10470/1 6401/6409/1 6404/6412/1 10463/10471/1 +f 1627/1635/1 10552/10560/1 6401/6409/1 10462/10470/1 +f 10552/10560/1 10551/10559/1 6402/6410/1 6401/6409/1 +f 3346/3354/1 6397/6405/1 6400/6408/1 3347/3355/1 +f 10463/10471/1 6404/6412/1 6397/6405/1 3346/3354/1 +f 6404/6412/1 6403/6411/1 6398/6406/1 6397/6405/1 +f 6390/6398/1 6393/6401/1 6396/6404/1 6391/6399/1 +f 15603/15611/1 1632/1640/1 6393/6401/1 6390/6398/1 +f 1632/1640/1 1631/1639/1 6394/6402/1 6393/6401/1 +f 6406/6414/1 6389/6397/1 6392/6400/1 6407/6415/1 +f 3315/3323/1 15604/15612/1 6389/6397/1 6406/6414/1 +f 15604/15612/1 15603/15611/1 6390/6398/1 6389/6397/1 +f 4698/4706/1 6385/6393/1 6388/6396/1 4699/4707/1 +f 6407/6415/1 6392/6400/1 6385/6393/1 4698/4706/1 +f 6392/6400/1 6391/6399/1 6386/6394/1 6385/6393/1 +f 6378/6386/1 6381/6389/1 6384/6392/1 6379/6387/1 +f 6363/6371/1 4712/4720/1 6381/6389/1 6378/6386/1 +f 4712/4720/1 4711/4719/1 6382/6390/1 6381/6389/1 +f 15598/15606/1 6377/6385/1 6380/6388/1 15599/15607/1 +f 3311/3319/1 6364/6372/1 6377/6385/1 15598/15606/1 +f 6364/6372/1 6363/6371/1 6378/6386/1 6377/6385/1 +f 1634/1642/1 6373/6381/1 6376/6384/1 1635/1643/1 +f 15599/15607/1 6380/6388/1 6373/6381/1 1634/1642/1 +f 6380/6388/1 6379/6387/1 6374/6382/1 6373/6381/1 +f 6366/6374/1 6369/6377/1 6372/6380/1 6367/6375/1 +f 10659/10667/1 3280/3288/1 6369/6377/1 6366/6374/1 +f 3280/3288/1 3279/3287/1 6370/6378/1 6369/6377/1 +f 10570/10578/1 6365/6373/1 6368/6376/1 10571/10579/1 +f 1639/1647/1 10660/10668/1 6365/6373/1 10570/10578/1 +f 10660/10668/1 10659/10667/1 6366/6374/1 6365/6373/1 +f 3310/3318/1 6361/6369/1 6364/6372/1 3311/3319/1 +f 10571/10579/1 6368/6376/1 6361/6369/1 3310/3318/1 +f 6368/6376/1 6367/6375/1 6362/6370/1 6361/6369/1 +f 6354/6362/1 6357/6365/1 6360/6368/1 6355/6363/1 +f 15567/15575/1 1644/1652/1 6357/6365/1 6354/6362/1 +f 1644/1652/1 1643/1651/1 6358/6366/1 6357/6365/1 +f 6370/6378/1 6353/6361/1 6356/6364/1 6371/6379/1 +f 3279/3287/1 15568/15576/1 6353/6361/1 6370/6378/1 +f 15568/15576/1 15567/15575/1 6354/6362/1 6353/6361/1 +f 4710/4718/1 6349/6357/1 6352/6360/1 4711/4719/1 +f 6371/6379/1 6356/6364/1 6349/6357/1 4710/4718/1 +f 6356/6364/1 6355/6363/1 6350/6358/1 6349/6357/1 +f 6342/6350/1 6345/6353/1 6348/6356/1 6343/6351/1 +f 6327/6335/1 4724/4732/1 6345/6353/1 6342/6350/1 +f 4724/4732/1 4723/4731/1 6346/6354/1 6345/6353/1 +f 15562/15570/1 6341/6349/1 6344/6352/1 15563/15571/1 +f 3275/3283/1 6328/6336/1 6341/6349/1 15562/15570/1 +f 6328/6336/1 6327/6335/1 6342/6350/1 6341/6349/1 +f 1646/1654/1 6337/6345/1 6340/6348/1 1647/1655/1 +f 15563/15571/1 6344/6352/1 6337/6345/1 1646/1654/1 +f 6344/6352/1 6343/6351/1 6338/6346/1 6337/6345/1 +f 6330/6338/1 6333/6341/1 6336/6344/1 6331/6339/1 +f 10767/10775/1 3244/3252/1 6333/6341/1 6330/6338/1 +f 3244/3252/1 3243/3251/1 6334/6342/1 6333/6341/1 +f 10678/10686/1 6329/6337/1 6332/6340/1 10679/10687/1 +f 1651/1659/1 10768/10776/1 6329/6337/1 10678/10686/1 +f 10768/10776/1 10767/10775/1 6330/6338/1 6329/6337/1 +f 3274/3282/1 6325/6333/1 6328/6336/1 3275/3283/1 +f 10679/10687/1 6332/6340/1 6325/6333/1 3274/3282/1 +f 6332/6340/1 6331/6339/1 6326/6334/1 6325/6333/1 +f 6318/6326/1 6321/6329/1 6324/6332/1 6319/6327/1 +f 15531/15539/1 1656/1664/1 6321/6329/1 6318/6326/1 +f 1656/1664/1 1655/1663/1 6322/6330/1 6321/6329/1 +f 6334/6342/1 6317/6325/1 6320/6328/1 6335/6343/1 +f 3243/3251/1 15532/15540/1 6317/6325/1 6334/6342/1 +f 15532/15540/1 15531/15539/1 6318/6326/1 6317/6325/1 +f 4722/4730/1 6313/6321/1 6316/6324/1 4723/4731/1 +f 6335/6343/1 6320/6328/1 6313/6321/1 4722/4730/1 +f 6320/6328/1 6319/6327/1 6314/6322/1 6313/6321/1 +f 6306/6314/1 6309/6317/1 6312/6320/1 6307/6315/1 +f 6291/6299/1 4736/4744/1 6309/6317/1 6306/6314/1 +f 4736/4744/1 4735/4743/1 6310/6318/1 6309/6317/1 +f 15526/15534/1 6305/6313/1 6308/6316/1 15527/15535/1 +f 3239/3247/1 6292/6300/1 6305/6313/1 15526/15534/1 +f 6292/6300/1 6291/6299/1 6306/6314/1 6305/6313/1 +f 1658/1666/1 6301/6309/1 6304/6312/1 1659/1667/1 +f 15527/15535/1 6308/6316/1 6301/6309/1 1658/1666/1 +f 6308/6316/1 6307/6315/1 6302/6310/1 6301/6309/1 +f 6294/6302/1 6297/6305/1 6300/6308/1 6295/6303/1 +f 10875/10883/1 3208/3216/1 6297/6305/1 6294/6302/1 +f 3208/3216/1 3207/3215/1 6298/6306/1 6297/6305/1 +f 10786/10794/1 6293/6301/1 6296/6304/1 10787/10795/1 +f 1663/1671/1 10876/10884/1 6293/6301/1 10786/10794/1 +f 10876/10884/1 10875/10883/1 6294/6302/1 6293/6301/1 +f 3238/3246/1 6289/6297/1 6292/6300/1 3239/3247/1 +f 10787/10795/1 6296/6304/1 6289/6297/1 3238/3246/1 +f 6296/6304/1 6295/6303/1 6290/6298/1 6289/6297/1 +f 6282/6290/1 6285/6293/1 6288/6296/1 6283/6291/1 +f 15495/15503/1 1668/1676/1 6285/6293/1 6282/6290/1 +f 1668/1676/1 1667/1675/1 6286/6294/1 6285/6293/1 +f 6298/6306/1 6281/6289/1 6284/6292/1 6299/6307/1 +f 3207/3215/1 15496/15504/1 6281/6289/1 6298/6306/1 +f 15496/15504/1 15495/15503/1 6282/6290/1 6281/6289/1 +f 4734/4742/1 6277/6285/1 6280/6288/1 4735/4743/1 +f 6299/6307/1 6284/6292/1 6277/6285/1 4734/4742/1 +f 6284/6292/1 6283/6291/1 6278/6286/1 6277/6285/1 +f 6270/6278/1 6273/6281/1 6276/6284/1 6271/6279/1 +f 6255/6263/1 4748/4756/1 6273/6281/1 6270/6278/1 +f 4748/4756/1 4747/4755/1 6274/6282/1 6273/6281/1 +f 15490/15498/1 6269/6277/1 6272/6280/1 15491/15499/1 +f 3203/3211/1 6256/6264/1 6269/6277/1 15490/15498/1 +f 6256/6264/1 6255/6263/1 6270/6278/1 6269/6277/1 +f 1670/1678/1 6265/6273/1 6268/6276/1 1671/1679/1 +f 15491/15499/1 6272/6280/1 6265/6273/1 1670/1678/1 +f 6272/6280/1 6271/6279/1 6266/6274/1 6265/6273/1 +f 6258/6266/1 6261/6269/1 6264/6272/1 6259/6267/1 +f 10983/10991/1 3172/3180/1 6261/6269/1 6258/6266/1 +f 3172/3180/1 3171/3179/1 6262/6270/1 6261/6269/1 +f 10894/10902/1 6257/6265/1 6260/6268/1 10895/10903/1 +f 1675/1683/1 10984/10992/1 6257/6265/1 10894/10902/1 +f 10984/10992/1 10983/10991/1 6258/6266/1 6257/6265/1 +f 3202/3210/1 6253/6261/1 6256/6264/1 3203/3211/1 +f 10895/10903/1 6260/6268/1 6253/6261/1 3202/3210/1 +f 6260/6268/1 6259/6267/1 6254/6262/1 6253/6261/1 +f 6246/6254/1 6249/6257/1 6252/6260/1 6247/6255/1 +f 15459/15467/1 1680/1688/1 6249/6257/1 6246/6254/1 +f 1680/1688/1 1679/1687/1 6250/6258/1 6249/6257/1 +f 6262/6270/1 6245/6253/1 6248/6256/1 6263/6271/1 +f 3171/3179/1 15460/15468/1 6245/6253/1 6262/6270/1 +f 15460/15468/1 15459/15467/1 6246/6254/1 6245/6253/1 +f 4746/4754/1 6241/6249/1 6244/6252/1 4747/4755/1 +f 6263/6271/1 6248/6256/1 6241/6249/1 4746/4754/1 +f 6248/6256/1 6247/6255/1 6242/6250/1 6241/6249/1 +f 6234/6242/1 6237/6245/1 6240/6248/1 6235/6243/1 +f 6219/6227/1 4760/4768/1 6237/6245/1 6234/6242/1 +f 4760/4768/1 4759/4767/1 6238/6246/1 6237/6245/1 +f 15454/15462/1 6233/6241/1 6236/6244/1 15455/15463/1 +f 3167/3175/1 6220/6228/1 6233/6241/1 15454/15462/1 +f 6220/6228/1 6219/6227/1 6234/6242/1 6233/6241/1 +f 1682/1690/1 6229/6237/1 6232/6240/1 1683/1691/1 +f 15455/15463/1 6236/6244/1 6229/6237/1 1682/1690/1 +f 6236/6244/1 6235/6243/1 6230/6238/1 6229/6237/1 +f 6222/6230/1 6225/6233/1 6228/6236/1 6223/6231/1 +f 11091/11099/1 3136/3144/1 6225/6233/1 6222/6230/1 +f 3136/3144/1 3135/3143/1 6226/6234/1 6225/6233/1 +f 11002/11010/1 6221/6229/1 6224/6232/1 11003/11011/1 +f 1687/1695/1 11092/11100/1 6221/6229/1 11002/11010/1 +f 11092/11100/1 11091/11099/1 6222/6230/1 6221/6229/1 +f 3166/3174/1 6217/6225/1 6220/6228/1 3167/3175/1 +f 11003/11011/1 6224/6232/1 6217/6225/1 3166/3174/1 +f 6224/6232/1 6223/6231/1 6218/6226/1 6217/6225/1 +f 6210/6218/1 6213/6221/1 6216/6224/1 6211/6219/1 +f 15423/15431/1 1692/1700/1 6213/6221/1 6210/6218/1 +f 1692/1700/1 1691/1699/1 6214/6222/1 6213/6221/1 +f 6226/6234/1 6209/6217/1 6212/6220/1 6227/6235/1 +f 3135/3143/1 15424/15432/1 6209/6217/1 6226/6234/1 +f 15424/15432/1 15423/15431/1 6210/6218/1 6209/6217/1 +f 4758/4766/1 6205/6213/1 6208/6216/1 4759/4767/1 +f 6227/6235/1 6212/6220/1 6205/6213/1 4758/4766/1 +f 6212/6220/1 6211/6219/1 6206/6214/1 6205/6213/1 +f 6198/6206/1 6201/6209/1 6204/6212/1 6199/6207/1 +f 6183/6191/1 4772/4780/1 6201/6209/1 6198/6206/1 +f 4772/4780/1 4771/4779/1 6202/6210/1 6201/6209/1 +f 15418/15426/1 6197/6205/1 6200/6208/1 15419/15427/1 +f 3131/3139/1 6184/6192/1 6197/6205/1 15418/15426/1 +f 6184/6192/1 6183/6191/1 6198/6206/1 6197/6205/1 +f 1694/1702/1 6193/6201/1 6196/6204/1 1695/1703/1 +f 15419/15427/1 6200/6208/1 6193/6201/1 1694/1702/1 +f 6200/6208/1 6199/6207/1 6194/6202/1 6193/6201/1 +f 6186/6194/1 6189/6197/1 6192/6200/1 6187/6195/1 +f 11199/11207/1 3100/3108/1 6189/6197/1 6186/6194/1 +f 3100/3108/1 3099/3107/1 6190/6198/1 6189/6197/1 +f 11110/11118/1 6185/6193/1 6188/6196/1 11111/11119/1 +f 1699/1707/1 11200/11208/1 6185/6193/1 11110/11118/1 +f 11200/11208/1 11199/11207/1 6186/6194/1 6185/6193/1 +f 3130/3138/1 6181/6189/1 6184/6192/1 3131/3139/1 +f 11111/11119/1 6188/6196/1 6181/6189/1 3130/3138/1 +f 6188/6196/1 6187/6195/1 6182/6190/1 6181/6189/1 +f 6174/6182/1 6177/6185/1 6180/6188/1 6175/6183/1 +f 15387/15395/1 1704/1712/1 6177/6185/1 6174/6182/1 +f 1704/1712/1 1703/1711/1 6178/6186/1 6177/6185/1 +f 6190/6198/1 6173/6181/1 6176/6184/1 6191/6199/1 +f 3099/3107/1 15388/15396/1 6173/6181/1 6190/6198/1 +f 15388/15396/1 15387/15395/1 6174/6182/1 6173/6181/1 +f 4770/4778/1 6169/6177/1 6172/6180/1 4771/4779/1 +f 6191/6199/1 6176/6184/1 6169/6177/1 4770/4778/1 +f 6176/6184/1 6175/6183/1 6170/6178/1 6169/6177/1 +f 6162/6170/1 6165/6173/1 6168/6176/1 6163/6171/1 +f 6147/6155/1 4784/4792/1 6165/6173/1 6162/6170/1 +f 4784/4792/1 4783/4791/1 6166/6174/1 6165/6173/1 +f 15382/15390/1 6161/6169/1 6164/6172/1 15383/15391/1 +f 3095/3103/1 6148/6156/1 6161/6169/1 15382/15390/1 +f 6148/6156/1 6147/6155/1 6162/6170/1 6161/6169/1 +f 1706/1714/1 6157/6165/1 6160/6168/1 1707/1715/1 +f 15383/15391/1 6164/6172/1 6157/6165/1 1706/1714/1 +f 6164/6172/1 6163/6171/1 6158/6166/1 6157/6165/1 +f 6150/6158/1 6153/6161/1 6156/6164/1 6151/6159/1 +f 11307/11315/1 3064/3072/1 6153/6161/1 6150/6158/1 +f 3064/3072/1 3063/3071/1 6154/6162/1 6153/6161/1 +f 11218/11226/1 6149/6157/1 6152/6160/1 11219/11227/1 +f 1711/1719/1 11308/11316/1 6149/6157/1 11218/11226/1 +f 11308/11316/1 11307/11315/1 6150/6158/1 6149/6157/1 +f 3094/3102/1 6145/6153/1 6148/6156/1 3095/3103/1 +f 11219/11227/1 6152/6160/1 6145/6153/1 3094/3102/1 +f 6152/6160/1 6151/6159/1 6146/6154/1 6145/6153/1 +f 6138/6146/1 6141/6149/1 6144/6152/1 6139/6147/1 +f 15351/15359/1 1716/1724/1 6141/6149/1 6138/6146/1 +f 1716/1724/1 1715/1723/1 6142/6150/1 6141/6149/1 +f 6154/6162/1 6137/6145/1 6140/6148/1 6155/6163/1 +f 3063/3071/1 15352/15360/1 6137/6145/1 6154/6162/1 +f 15352/15360/1 15351/15359/1 6138/6146/1 6137/6145/1 +f 4782/4790/1 6133/6141/1 6136/6144/1 4783/4791/1 +f 6155/6163/1 6140/6148/1 6133/6141/1 4782/4790/1 +f 6140/6148/1 6139/6147/1 6134/6142/1 6133/6141/1 +f 6126/6134/1 6129/6137/1 6132/6140/1 6127/6135/1 +f 6111/6119/1 4796/4804/1 6129/6137/1 6126/6134/1 +f 4796/4804/1 4795/4803/1 6130/6138/1 6129/6137/1 +f 15346/15354/1 6125/6133/1 6128/6136/1 15347/15355/1 +f 3059/3067/1 6112/6120/1 6125/6133/1 15346/15354/1 +f 6112/6120/1 6111/6119/1 6126/6134/1 6125/6133/1 +f 1718/1726/1 6121/6129/1 6124/6132/1 1719/1727/1 +f 15347/15355/1 6128/6136/1 6121/6129/1 1718/1726/1 +f 6128/6136/1 6127/6135/1 6122/6130/1 6121/6129/1 +f 6114/6122/1 6117/6125/1 6120/6128/1 6115/6123/1 +f 11415/11423/1 3028/3036/1 6117/6125/1 6114/6122/1 +f 3028/3036/1 3027/3035/1 6118/6126/1 6117/6125/1 +f 11326/11334/1 6113/6121/1 6116/6124/1 11327/11335/1 +f 1723/1731/1 11416/11424/1 6113/6121/1 11326/11334/1 +f 11416/11424/1 11415/11423/1 6114/6122/1 6113/6121/1 +f 3058/3066/1 6109/6117/1 6112/6120/1 3059/3067/1 +f 11327/11335/1 6116/6124/1 6109/6117/1 3058/3066/1 +f 6116/6124/1 6115/6123/1 6110/6118/1 6109/6117/1 +f 6102/6110/1 6105/6113/1 6108/6116/1 6103/6111/1 +f 15315/15323/1 1728/1736/1 6105/6113/1 6102/6110/1 +f 1728/1736/1 1727/1735/1 6106/6114/1 6105/6113/1 +f 6118/6126/1 6101/6109/1 6104/6112/1 6119/6127/1 +f 3027/3035/1 15316/15324/1 6101/6109/1 6118/6126/1 +f 15316/15324/1 15315/15323/1 6102/6110/1 6101/6109/1 +f 4794/4802/1 6097/6105/1 6100/6108/1 4795/4803/1 +f 6119/6127/1 6104/6112/1 6097/6105/1 4794/4802/1 +f 6104/6112/1 6103/6111/1 6098/6106/1 6097/6105/1 +f 6090/6098/1 6093/6101/1 6096/6104/1 6091/6099/1 +f 6075/6083/1 4808/4816/1 6093/6101/1 6090/6098/1 +f 4808/4816/1 4807/4815/1 6094/6102/1 6093/6101/1 +f 15310/15318/1 6089/6097/1 6092/6100/1 15311/15319/1 +f 3023/3031/1 6076/6084/1 6089/6097/1 15310/15318/1 +f 6076/6084/1 6075/6083/1 6090/6098/1 6089/6097/1 +f 1730/1738/1 6085/6093/1 6088/6096/1 1731/1739/1 +f 15311/15319/1 6092/6100/1 6085/6093/1 1730/1738/1 +f 6092/6100/1 6091/6099/1 6086/6094/1 6085/6093/1 +f 6078/6086/1 6081/6089/1 6084/6092/1 6079/6087/1 +f 11523/11531/1 2992/3000/1 6081/6089/1 6078/6086/1 +f 2992/3000/1 2991/2999/1 6082/6090/1 6081/6089/1 +f 11434/11442/1 6077/6085/1 6080/6088/1 11435/11443/1 +f 1735/1743/1 11524/11532/1 6077/6085/1 11434/11442/1 +f 11524/11532/1 11523/11531/1 6078/6086/1 6077/6085/1 +f 3022/3030/1 6073/6081/1 6076/6084/1 3023/3031/1 +f 11435/11443/1 6080/6088/1 6073/6081/1 3022/3030/1 +f 6080/6088/1 6079/6087/1 6074/6082/1 6073/6081/1 +f 6066/6074/1 6069/6077/1 6072/6080/1 6067/6075/1 +f 15279/15287/1 1740/1748/1 6069/6077/1 6066/6074/1 +f 1740/1748/1 1739/1747/1 6070/6078/1 6069/6077/1 +f 6082/6090/1 6065/6073/1 6068/6076/1 6083/6091/1 +f 2991/2999/1 15280/15288/1 6065/6073/1 6082/6090/1 +f 15280/15288/1 15279/15287/1 6066/6074/1 6065/6073/1 +f 4806/4814/1 6061/6069/1 6064/6072/1 4807/4815/1 +f 6083/6091/1 6068/6076/1 6061/6069/1 4806/4814/1 +f 6068/6076/1 6067/6075/1 6062/6070/1 6061/6069/1 +f 6054/6062/1 6057/6065/1 6060/6068/1 6055/6063/1 +f 6039/6047/1 4820/4828/1 6057/6065/1 6054/6062/1 +f 4820/4828/1 4819/4827/1 6058/6066/1 6057/6065/1 +f 15274/15282/1 6053/6061/1 6056/6064/1 15275/15283/1 +f 2987/2995/1 6040/6048/1 6053/6061/1 15274/15282/1 +f 6040/6048/1 6039/6047/1 6054/6062/1 6053/6061/1 +f 1742/1750/1 6049/6057/1 6052/6060/1 1743/1751/1 +f 15275/15283/1 6056/6064/1 6049/6057/1 1742/1750/1 +f 6056/6064/1 6055/6063/1 6050/6058/1 6049/6057/1 +f 6042/6050/1 6045/6053/1 6048/6056/1 6043/6051/1 +f 11631/11639/1 2956/2964/1 6045/6053/1 6042/6050/1 +f 2956/2964/1 2955/2963/1 6046/6054/1 6045/6053/1 +f 11542/11550/1 6041/6049/1 6044/6052/1 11543/11551/1 +f 1747/1755/1 11632/11640/1 6041/6049/1 11542/11550/1 +f 11632/11640/1 11631/11639/1 6042/6050/1 6041/6049/1 +f 2986/2994/1 6037/6045/1 6040/6048/1 2987/2995/1 +f 11543/11551/1 6044/6052/1 6037/6045/1 2986/2994/1 +f 6044/6052/1 6043/6051/1 6038/6046/1 6037/6045/1 +f 6030/6038/1 6033/6041/1 6036/6044/1 6031/6039/1 +f 15243/15251/1 1752/1760/1 6033/6041/1 6030/6038/1 +f 1752/1760/1 1751/1759/1 6034/6042/1 6033/6041/1 +f 6046/6054/1 6029/6037/1 6032/6040/1 6047/6055/1 +f 2955/2963/1 15244/15252/1 6029/6037/1 6046/6054/1 +f 15244/15252/1 15243/15251/1 6030/6038/1 6029/6037/1 +f 4818/4826/1 6025/6033/1 6028/6036/1 4819/4827/1 +f 6047/6055/1 6032/6040/1 6025/6033/1 4818/4826/1 +f 6032/6040/1 6031/6039/1 6026/6034/1 6025/6033/1 +f 6018/6026/1 6021/6029/1 6024/6032/1 6019/6027/1 +f 6003/6011/1 4832/4840/1 6021/6029/1 6018/6026/1 +f 4832/4840/1 4831/4839/1 6022/6030/1 6021/6029/1 +f 15238/15246/1 6017/6025/1 6020/6028/1 15239/15247/1 +f 2951/2959/1 6004/6012/1 6017/6025/1 15238/15246/1 +f 6004/6012/1 6003/6011/1 6018/6026/1 6017/6025/1 +f 1754/1762/1 6013/6021/1 6016/6024/1 1755/1763/1 +f 15239/15247/1 6020/6028/1 6013/6021/1 1754/1762/1 +f 6020/6028/1 6019/6027/1 6014/6022/1 6013/6021/1 +f 6006/6014/1 6009/6017/1 6012/6020/1 6007/6015/1 +f 11739/11747/1 2920/2928/1 6009/6017/1 6006/6014/1 +f 2920/2928/1 2919/2927/1 6010/6018/1 6009/6017/1 +f 11650/11658/1 6005/6013/1 6008/6016/1 11651/11659/1 +f 1759/1767/1 11740/11748/1 6005/6013/1 11650/11658/1 +f 11740/11748/1 11739/11747/1 6006/6014/1 6005/6013/1 +f 2950/2958/1 6001/6009/1 6004/6012/1 2951/2959/1 +f 11651/11659/1 6008/6016/1 6001/6009/1 2950/2958/1 +f 6008/6016/1 6007/6015/1 6002/6010/1 6001/6009/1 +f 5994/6002/1 5997/6005/1 6000/6008/1 5995/6003/1 +f 15207/15215/1 1764/1772/1 5997/6005/1 5994/6002/1 +f 1764/1772/1 1763/1771/1 5998/6006/1 5997/6005/1 +f 6010/6018/1 5993/6001/1 5996/6004/1 6011/6019/1 +f 2919/2927/1 15208/15216/1 5993/6001/1 6010/6018/1 +f 15208/15216/1 15207/15215/1 5994/6002/1 5993/6001/1 +f 4830/4838/1 5989/5997/1 5992/6000/1 4831/4839/1 +f 6011/6019/1 5996/6004/1 5989/5997/1 4830/4838/1 +f 5996/6004/1 5995/6003/1 5990/5998/1 5989/5997/1 +f 5982/5990/1 5985/5993/1 5988/5996/1 5983/5991/1 +f 5967/5975/1 4844/4852/1 5985/5993/1 5982/5990/1 +f 4844/4852/1 4843/4851/1 5986/5994/1 5985/5993/1 +f 15202/15210/1 5981/5989/1 5984/5992/1 15203/15211/1 +f 2915/2923/1 5968/5976/1 5981/5989/1 15202/15210/1 +f 5968/5976/1 5967/5975/1 5982/5990/1 5981/5989/1 +f 1766/1774/1 5977/5985/1 5980/5988/1 1767/1775/1 +f 15203/15211/1 5984/5992/1 5977/5985/1 1766/1774/1 +f 5984/5992/1 5983/5991/1 5978/5986/1 5977/5985/1 +f 5970/5978/1 5973/5981/1 5976/5984/1 5971/5979/1 +f 11847/11855/1 2884/2892/1 5973/5981/1 5970/5978/1 +f 2884/2892/1 2883/2891/1 5974/5982/1 5973/5981/1 +f 11758/11766/1 5969/5977/1 5972/5980/1 11759/11767/1 +f 1771/1779/1 11848/11856/1 5969/5977/1 11758/11766/1 +f 11848/11856/1 11847/11855/1 5970/5978/1 5969/5977/1 +f 2914/2922/1 5965/5973/1 5968/5976/1 2915/2923/1 +f 11759/11767/1 5972/5980/1 5965/5973/1 2914/2922/1 +f 5972/5980/1 5971/5979/1 5966/5974/1 5965/5973/1 +f 5958/5966/1 5961/5969/1 5964/5972/1 5959/5967/1 +f 15171/15179/1 1776/1784/1 5961/5969/1 5958/5966/1 +f 1776/1784/1 1775/1783/1 5962/5970/1 5961/5969/1 +f 5974/5982/1 5957/5965/1 5960/5968/1 5975/5983/1 +f 2883/2891/1 15172/15180/1 5957/5965/1 5974/5982/1 +f 15172/15180/1 15171/15179/1 5958/5966/1 5957/5965/1 +f 4842/4850/1 5953/5961/1 5956/5964/1 4843/4851/1 +f 5975/5983/1 5960/5968/1 5953/5961/1 4842/4850/1 +f 5960/5968/1 5959/5967/1 5954/5962/1 5953/5961/1 +f 5946/5954/1 5949/5957/1 5952/5960/1 5947/5955/1 +f 5931/5939/1 4856/4864/1 5949/5957/1 5946/5954/1 +f 4856/4864/1 4855/4863/1 5950/5958/1 5949/5957/1 +f 15166/15174/1 5945/5953/1 5948/5956/1 15167/15175/1 +f 2879/2887/1 5932/5940/1 5945/5953/1 15166/15174/1 +f 5932/5940/1 5931/5939/1 5946/5954/1 5945/5953/1 +f 1778/1786/1 5941/5949/1 5944/5952/1 1779/1787/1 +f 15167/15175/1 5948/5956/1 5941/5949/1 1778/1786/1 +f 5948/5956/1 5947/5955/1 5942/5950/1 5941/5949/1 +f 5934/5942/1 5937/5945/1 5940/5948/1 5935/5943/1 +f 11955/11963/1 2848/2856/1 5937/5945/1 5934/5942/1 +f 2848/2856/1 2847/2855/1 5938/5946/1 5937/5945/1 +f 11866/11874/1 5933/5941/1 5936/5944/1 11867/11875/1 +f 1783/1791/1 11956/11964/1 5933/5941/1 11866/11874/1 +f 11956/11964/1 11955/11963/1 5934/5942/1 5933/5941/1 +f 2878/2886/1 5929/5937/1 5932/5940/1 2879/2887/1 +f 11867/11875/1 5936/5944/1 5929/5937/1 2878/2886/1 +f 5936/5944/1 5935/5943/1 5930/5938/1 5929/5937/1 +f 5922/5930/1 5925/5933/1 5928/5936/1 5923/5931/1 +f 15135/15143/1 1788/1796/1 5925/5933/1 5922/5930/1 +f 1788/1796/1 1787/1795/1 5926/5934/1 5925/5933/1 +f 5938/5946/1 5921/5929/1 5924/5932/1 5939/5947/1 +f 2847/2855/1 15136/15144/1 5921/5929/1 5938/5946/1 +f 15136/15144/1 15135/15143/1 5922/5930/1 5921/5929/1 +f 4854/4862/1 5917/5925/1 5920/5928/1 4855/4863/1 +f 5939/5947/1 5924/5932/1 5917/5925/1 4854/4862/1 +f 5924/5932/1 5923/5931/1 5918/5926/1 5917/5925/1 +f 5910/5918/1 5913/5921/1 5916/5924/1 5911/5919/1 +f 5895/5903/1 4868/4876/1 5913/5921/1 5910/5918/1 +f 4868/4876/1 4867/4875/1 5914/5922/1 5913/5921/1 +f 15130/15138/1 5909/5917/1 5912/5920/1 15131/15139/1 +f 2843/2851/1 5896/5904/1 5909/5917/1 15130/15138/1 +f 5896/5904/1 5895/5903/1 5910/5918/1 5909/5917/1 +f 1790/1798/1 5905/5913/1 5908/5916/1 1791/1799/1 +f 15131/15139/1 5912/5920/1 5905/5913/1 1790/1798/1 +f 5912/5920/1 5911/5919/1 5906/5914/1 5905/5913/1 +f 5898/5906/1 5901/5909/1 5904/5912/1 5899/5907/1 +f 12063/12071/1 2812/2820/1 5901/5909/1 5898/5906/1 +f 2812/2820/1 2811/2819/1 5902/5910/1 5901/5909/1 +f 11974/11982/1 5897/5905/1 5900/5908/1 11975/11983/1 +f 1795/1803/1 12064/12072/1 5897/5905/1 11974/11982/1 +f 12064/12072/1 12063/12071/1 5898/5906/1 5897/5905/1 +f 2842/2850/1 5893/5901/1 5896/5904/1 2843/2851/1 +f 11975/11983/1 5900/5908/1 5893/5901/1 2842/2850/1 +f 5900/5908/1 5899/5907/1 5894/5902/1 5893/5901/1 +f 5886/5894/1 5889/5897/1 5892/5900/1 5887/5895/1 +f 15099/15107/1 1800/1808/1 5889/5897/1 5886/5894/1 +f 1800/1808/1 1799/1807/1 5890/5898/1 5889/5897/1 +f 5902/5910/1 5885/5893/1 5888/5896/1 5903/5911/1 +f 2811/2819/1 15100/15108/1 5885/5893/1 5902/5910/1 +f 15100/15108/1 15099/15107/1 5886/5894/1 5885/5893/1 +f 4866/4874/1 5881/5889/1 5884/5892/1 4867/4875/1 +f 5903/5911/1 5888/5896/1 5881/5889/1 4866/4874/1 +f 5888/5896/1 5887/5895/1 5882/5890/1 5881/5889/1 +f 5874/5882/1 5877/5885/1 5880/5888/1 5875/5883/1 +f 5859/5867/1 4880/4888/1 5877/5885/1 5874/5882/1 +f 4880/4888/1 4879/4887/1 5878/5886/1 5877/5885/1 +f 15094/15102/1 5873/5881/1 5876/5884/1 15095/15103/1 +f 2807/2815/1 5860/5868/1 5873/5881/1 15094/15102/1 +f 5860/5868/1 5859/5867/1 5874/5882/1 5873/5881/1 +f 1802/1810/1 5869/5877/1 5872/5880/1 1803/1811/1 +f 15095/15103/1 5876/5884/1 5869/5877/1 1802/1810/1 +f 5876/5884/1 5875/5883/1 5870/5878/1 5869/5877/1 +f 5862/5870/1 5865/5873/1 5868/5876/1 5863/5871/1 +f 12171/12179/1 2776/2784/1 5865/5873/1 5862/5870/1 +f 2776/2784/1 2775/2783/1 5866/5874/1 5865/5873/1 +f 12082/12090/1 5861/5869/1 5864/5872/1 12083/12091/1 +f 1807/1815/1 12172/12180/1 5861/5869/1 12082/12090/1 +f 12172/12180/1 12171/12179/1 5862/5870/1 5861/5869/1 +f 2806/2814/1 5857/5865/1 5860/5868/1 2807/2815/1 +f 12083/12091/1 5864/5872/1 5857/5865/1 2806/2814/1 +f 5864/5872/1 5863/5871/1 5858/5866/1 5857/5865/1 +f 5850/5858/1 5853/5861/1 5856/5864/1 5851/5859/1 +f 15063/15071/1 1812/1820/1 5853/5861/1 5850/5858/1 +f 1812/1820/1 1811/1819/1 5854/5862/1 5853/5861/1 +f 5866/5874/1 5849/5857/1 5852/5860/1 5867/5875/1 +f 2775/2783/1 15064/15072/1 5849/5857/1 5866/5874/1 +f 15064/15072/1 15063/15071/1 5850/5858/1 5849/5857/1 +f 4878/4886/1 5845/5853/1 5848/5856/1 4879/4887/1 +f 5867/5875/1 5852/5860/1 5845/5853/1 4878/4886/1 +f 5852/5860/1 5851/5859/1 5846/5854/1 5845/5853/1 +f 5838/5846/1 5841/5849/1 5844/5852/1 5839/5847/1 +f 5823/5831/1 4892/4900/1 5841/5849/1 5838/5846/1 +f 4892/4900/1 4891/4899/1 5842/5850/1 5841/5849/1 +f 15058/15066/1 5837/5845/1 5840/5848/1 15059/15067/1 +f 2771/2779/1 5824/5832/1 5837/5845/1 15058/15066/1 +f 5824/5832/1 5823/5831/1 5838/5846/1 5837/5845/1 +f 1814/1822/1 5833/5841/1 5836/5844/1 1815/1823/1 +f 15059/15067/1 5840/5848/1 5833/5841/1 1814/1822/1 +f 5840/5848/1 5839/5847/1 5834/5842/1 5833/5841/1 +f 5826/5834/1 5829/5837/1 5832/5840/1 5827/5835/1 +f 12279/12287/1 2740/2748/1 5829/5837/1 5826/5834/1 +f 2740/2748/1 2739/2747/1 5830/5838/1 5829/5837/1 +f 12190/12198/1 5825/5833/1 5828/5836/1 12191/12199/1 +f 1819/1827/1 12280/12288/1 5825/5833/1 12190/12198/1 +f 12280/12288/1 12279/12287/1 5826/5834/1 5825/5833/1 +f 2770/2778/1 5821/5829/1 5824/5832/1 2771/2779/1 +f 12191/12199/1 5828/5836/1 5821/5829/1 2770/2778/1 +f 5828/5836/1 5827/5835/1 5822/5830/1 5821/5829/1 +f 5814/5822/1 5817/5825/1 5820/5828/1 5815/5823/1 +f 15027/15035/1 1824/1832/1 5817/5825/1 5814/5822/1 +f 1824/1832/1 1823/1831/1 5818/5826/1 5817/5825/1 +f 5830/5838/1 5813/5821/1 5816/5824/1 5831/5839/1 +f 2739/2747/1 15028/15036/1 5813/5821/1 5830/5838/1 +f 15028/15036/1 15027/15035/1 5814/5822/1 5813/5821/1 +f 4890/4898/1 5809/5817/1 5812/5820/1 4891/4899/1 +f 5831/5839/1 5816/5824/1 5809/5817/1 4890/4898/1 +f 5816/5824/1 5815/5823/1 5810/5818/1 5809/5817/1 +f 5802/5810/1 5805/5813/1 5808/5816/1 5803/5811/1 +f 5787/5795/1 4904/4912/1 5805/5813/1 5802/5810/1 +f 4904/4912/1 4903/4911/1 5806/5814/1 5805/5813/1 +f 15022/15030/1 5801/5809/1 5804/5812/1 15023/15031/1 +f 2735/2743/1 5788/5796/1 5801/5809/1 15022/15030/1 +f 5788/5796/1 5787/5795/1 5802/5810/1 5801/5809/1 +f 1826/1834/1 5797/5805/1 5800/5808/1 1827/1835/1 +f 15023/15031/1 5804/5812/1 5797/5805/1 1826/1834/1 +f 5804/5812/1 5803/5811/1 5798/5806/1 5797/5805/1 +f 5790/5798/1 5793/5801/1 5796/5804/1 5791/5799/1 +f 12387/12395/1 2704/2712/1 5793/5801/1 5790/5798/1 +f 2704/2712/1 2703/2711/1 5794/5802/1 5793/5801/1 +f 12298/12306/1 5789/5797/1 5792/5800/1 12299/12307/1 +f 1831/1839/1 12388/12396/1 5789/5797/1 12298/12306/1 +f 12388/12396/1 12387/12395/1 5790/5798/1 5789/5797/1 +f 2734/2742/1 5785/5793/1 5788/5796/1 2735/2743/1 +f 12299/12307/1 5792/5800/1 5785/5793/1 2734/2742/1 +f 5792/5800/1 5791/5799/1 5786/5794/1 5785/5793/1 +f 5778/5786/1 5781/5789/1 5784/5792/1 5779/5787/1 +f 14991/14999/1 1836/1844/1 5781/5789/1 5778/5786/1 +f 1836/1844/1 1835/1843/1 5782/5790/1 5781/5789/1 +f 5794/5802/1 5777/5785/1 5780/5788/1 5795/5803/1 +f 2703/2711/1 14992/15000/1 5777/5785/1 5794/5802/1 +f 14992/15000/1 14991/14999/1 5778/5786/1 5777/5785/1 +f 4902/4910/1 5773/5781/1 5776/5784/1 4903/4911/1 +f 5795/5803/1 5780/5788/1 5773/5781/1 4902/4910/1 +f 5780/5788/1 5779/5787/1 5774/5782/1 5773/5781/1 +f 5766/5774/1 5769/5777/1 5772/5780/1 5767/5775/1 +f 5751/5759/1 4916/4924/1 5769/5777/1 5766/5774/1 +f 4916/4924/1 4915/4923/1 5770/5778/1 5769/5777/1 +f 14986/14994/1 5765/5773/1 5768/5776/1 14987/14995/1 +f 2699/2707/1 5752/5760/1 5765/5773/1 14986/14994/1 +f 5752/5760/1 5751/5759/1 5766/5774/1 5765/5773/1 +f 1838/1846/1 5761/5769/1 5764/5772/1 1839/1847/1 +f 14987/14995/1 5768/5776/1 5761/5769/1 1838/1846/1 +f 5768/5776/1 5767/5775/1 5762/5770/1 5761/5769/1 +f 5754/5762/1 5757/5765/1 5760/5768/1 5755/5763/1 +f 12495/12503/1 2668/2676/1 5757/5765/1 5754/5762/1 +f 2668/2676/1 2667/2675/1 5758/5766/1 5757/5765/1 +f 12406/12414/1 5753/5761/1 5756/5764/1 12407/12415/1 +f 1843/1851/1 12496/12504/1 5753/5761/1 12406/12414/1 +f 12496/12504/1 12495/12503/1 5754/5762/1 5753/5761/1 +f 2698/2706/1 5749/5757/1 5752/5760/1 2699/2707/1 +f 12407/12415/1 5756/5764/1 5749/5757/1 2698/2706/1 +f 5756/5764/1 5755/5763/1 5750/5758/1 5749/5757/1 +f 5742/5750/1 5745/5753/1 5748/5756/1 5743/5751/1 +f 14955/14963/1 1848/1856/1 5745/5753/1 5742/5750/1 +f 1848/1856/1 1847/1855/1 5746/5754/1 5745/5753/1 +f 5758/5766/1 5741/5749/1 5744/5752/1 5759/5767/1 +f 2667/2675/1 14956/14964/1 5741/5749/1 5758/5766/1 +f 14956/14964/1 14955/14963/1 5742/5750/1 5741/5749/1 +f 4914/4922/1 5737/5745/1 5740/5748/1 4915/4923/1 +f 5759/5767/1 5744/5752/1 5737/5745/1 4914/4922/1 +f 5744/5752/1 5743/5751/1 5738/5746/1 5737/5745/1 +f 5730/5738/1 5733/5741/1 5736/5744/1 5731/5739/1 +f 5715/5723/1 4928/4936/1 5733/5741/1 5730/5738/1 +f 4928/4936/1 4927/4935/1 5734/5742/1 5733/5741/1 +f 14950/14958/1 5729/5737/1 5732/5740/1 14951/14959/1 +f 2663/2671/1 5716/5724/1 5729/5737/1 14950/14958/1 +f 5716/5724/1 5715/5723/1 5730/5738/1 5729/5737/1 +f 1850/1858/1 5725/5733/1 5728/5736/1 1851/1859/1 +f 14951/14959/1 5732/5740/1 5725/5733/1 1850/1858/1 +f 5732/5740/1 5731/5739/1 5726/5734/1 5725/5733/1 +f 5718/5726/1 5721/5729/1 5724/5732/1 5719/5727/1 +f 12603/12611/1 2632/2640/1 5721/5729/1 5718/5726/1 +f 2632/2640/1 2631/2639/1 5722/5730/1 5721/5729/1 +f 12514/12522/1 5717/5725/1 5720/5728/1 12515/12523/1 +f 1855/1863/1 12604/12612/1 5717/5725/1 12514/12522/1 +f 12604/12612/1 12603/12611/1 5718/5726/1 5717/5725/1 +f 2662/2670/1 5713/5721/1 5716/5724/1 2663/2671/1 +f 12515/12523/1 5720/5728/1 5713/5721/1 2662/2670/1 +f 5720/5728/1 5719/5727/1 5714/5722/1 5713/5721/1 +f 5706/5714/1 5709/5717/1 5712/5720/1 5707/5715/1 +f 14919/14927/1 1860/1868/1 5709/5717/1 5706/5714/1 +f 1860/1868/1 1859/1867/1 5710/5718/1 5709/5717/1 +f 5722/5730/1 5705/5713/1 5708/5716/1 5723/5731/1 +f 2631/2639/1 14920/14928/1 5705/5713/1 5722/5730/1 +f 14920/14928/1 14919/14927/1 5706/5714/1 5705/5713/1 +f 4926/4934/1 5701/5709/1 5704/5712/1 4927/4935/1 +f 5723/5731/1 5708/5716/1 5701/5709/1 4926/4934/1 +f 5708/5716/1 5707/5715/1 5702/5710/1 5701/5709/1 +f 5694/5702/1 5697/5705/1 5700/5708/1 5695/5703/1 +f 5679/5687/1 4940/4948/1 5697/5705/1 5694/5702/1 +f 4940/4948/1 4939/4947/1 5698/5706/1 5697/5705/1 +f 14914/14922/1 5693/5701/1 5696/5704/1 14915/14923/1 +f 2627/2635/1 5680/5688/1 5693/5701/1 14914/14922/1 +f 5680/5688/1 5679/5687/1 5694/5702/1 5693/5701/1 +f 1862/1870/1 5689/5697/1 5692/5700/1 1863/1871/1 +f 14915/14923/1 5696/5704/1 5689/5697/1 1862/1870/1 +f 5696/5704/1 5695/5703/1 5690/5698/1 5689/5697/1 +f 5682/5690/1 5685/5693/1 5688/5696/1 5683/5691/1 +f 12711/12719/1 2596/2604/1 5685/5693/1 5682/5690/1 +f 2596/2604/1 2595/2603/1 5686/5694/1 5685/5693/1 +f 12622/12630/1 5681/5689/1 5684/5692/1 12623/12631/1 +f 1867/1875/1 12712/12720/1 5681/5689/1 12622/12630/1 +f 12712/12720/1 12711/12719/1 5682/5690/1 5681/5689/1 +f 2626/2634/1 5677/5685/1 5680/5688/1 2627/2635/1 +f 12623/12631/1 5684/5692/1 5677/5685/1 2626/2634/1 +f 5684/5692/1 5683/5691/1 5678/5686/1 5677/5685/1 +f 5670/5678/1 5673/5681/1 5676/5684/1 5671/5679/1 +f 14883/14891/1 1872/1880/1 5673/5681/1 5670/5678/1 +f 1872/1880/1 1871/1879/1 5674/5682/1 5673/5681/1 +f 5686/5694/1 5669/5677/1 5672/5680/1 5687/5695/1 +f 2595/2603/1 14884/14892/1 5669/5677/1 5686/5694/1 +f 14884/14892/1 14883/14891/1 5670/5678/1 5669/5677/1 +f 4938/4946/1 5665/5673/1 5668/5676/1 4939/4947/1 +f 5687/5695/1 5672/5680/1 5665/5673/1 4938/4946/1 +f 5672/5680/1 5671/5679/1 5666/5674/1 5665/5673/1 +f 5658/5666/1 5661/5669/1 5664/5672/1 5659/5667/1 +f 5643/5651/1 4952/4960/1 5661/5669/1 5658/5666/1 +f 4952/4960/1 4951/4959/1 5662/5670/1 5661/5669/1 +f 14878/14886/1 5657/5665/1 5660/5668/1 14879/14887/1 +f 2591/2599/1 5644/5652/1 5657/5665/1 14878/14886/1 +f 5644/5652/1 5643/5651/1 5658/5666/1 5657/5665/1 +f 1874/1882/1 5653/5661/1 5656/5664/1 1875/1883/1 +f 14879/14887/1 5660/5668/1 5653/5661/1 1874/1882/1 +f 5660/5668/1 5659/5667/1 5654/5662/1 5653/5661/1 +f 5646/5654/1 5649/5657/1 5652/5660/1 5647/5655/1 +f 12819/12827/1 2560/2568/1 5649/5657/1 5646/5654/1 +f 2560/2568/1 2559/2567/1 5650/5658/1 5649/5657/1 +f 12730/12738/1 5645/5653/1 5648/5656/1 12731/12739/1 +f 1879/1887/1 12820/12828/1 5645/5653/1 12730/12738/1 +f 12820/12828/1 12819/12827/1 5646/5654/1 5645/5653/1 +f 2590/2598/1 5641/5649/1 5644/5652/1 2591/2599/1 +f 12731/12739/1 5648/5656/1 5641/5649/1 2590/2598/1 +f 5648/5656/1 5647/5655/1 5642/5650/1 5641/5649/1 +f 5634/5642/1 5637/5645/1 5640/5648/1 5635/5643/1 +f 14847/14855/1 1884/1892/1 5637/5645/1 5634/5642/1 +f 1884/1892/1 1883/1891/1 5638/5646/1 5637/5645/1 +f 5650/5658/1 5633/5641/1 5636/5644/1 5651/5659/1 +f 2559/2567/1 14848/14856/1 5633/5641/1 5650/5658/1 +f 14848/14856/1 14847/14855/1 5634/5642/1 5633/5641/1 +f 4950/4958/1 5629/5637/1 5632/5640/1 4951/4959/1 +f 5651/5659/1 5636/5644/1 5629/5637/1 4950/4958/1 +f 5636/5644/1 5635/5643/1 5630/5638/1 5629/5637/1 +f 5622/5630/1 5625/5633/1 5628/5636/1 5623/5631/1 +f 5607/5615/1 4964/4972/1 5625/5633/1 5622/5630/1 +f 4964/4972/1 4963/4971/1 5626/5634/1 5625/5633/1 +f 14842/14850/1 5621/5629/1 5624/5632/1 14843/14851/1 +f 2555/2563/1 5608/5616/1 5621/5629/1 14842/14850/1 +f 5608/5616/1 5607/5615/1 5622/5630/1 5621/5629/1 +f 1886/1894/1 5617/5625/1 5620/5628/1 1887/1895/1 +f 14843/14851/1 5624/5632/1 5617/5625/1 1886/1894/1 +f 5624/5632/1 5623/5631/1 5618/5626/1 5617/5625/1 +f 5610/5618/1 5613/5621/1 5616/5624/1 5611/5619/1 +f 12927/12935/1 2524/2532/1 5613/5621/1 5610/5618/1 +f 2524/2532/1 2523/2531/1 5614/5622/1 5613/5621/1 +f 12838/12846/1 5609/5617/1 5612/5620/1 12839/12847/1 +f 1891/1899/1 12928/12936/1 5609/5617/1 12838/12846/1 +f 12928/12936/1 12927/12935/1 5610/5618/1 5609/5617/1 +f 2554/2562/1 5605/5613/1 5608/5616/1 2555/2563/1 +f 12839/12847/1 5612/5620/1 5605/5613/1 2554/2562/1 +f 5612/5620/1 5611/5619/1 5606/5614/1 5605/5613/1 +f 5598/5606/1 5601/5609/1 5604/5612/1 5599/5607/1 +f 14811/14819/1 1896/1904/1 5601/5609/1 5598/5606/1 +f 1896/1904/1 1895/1903/1 5602/5610/1 5601/5609/1 +f 5614/5622/1 5597/5605/1 5600/5608/1 5615/5623/1 +f 2523/2531/1 14812/14820/1 5597/5605/1 5614/5622/1 +f 14812/14820/1 14811/14819/1 5598/5606/1 5597/5605/1 +f 4962/4970/1 5593/5601/1 5596/5604/1 4963/4971/1 +f 5615/5623/1 5600/5608/1 5593/5601/1 4962/4970/1 +f 5600/5608/1 5599/5607/1 5594/5602/1 5593/5601/1 +f 5586/5594/1 5589/5597/1 5592/5600/1 5587/5595/1 +f 5571/5579/1 4976/4984/1 5589/5597/1 5586/5594/1 +f 4976/4984/1 4975/4983/1 5590/5598/1 5589/5597/1 +f 14806/14814/1 5585/5593/1 5588/5596/1 14807/14815/1 +f 2519/2527/1 5572/5580/1 5585/5593/1 14806/14814/1 +f 5572/5580/1 5571/5579/1 5586/5594/1 5585/5593/1 +f 1898/1906/1 5581/5589/1 5584/5592/1 1899/1907/1 +f 14807/14815/1 5588/5596/1 5581/5589/1 1898/1906/1 +f 5588/5596/1 5587/5595/1 5582/5590/1 5581/5589/1 +f 5574/5582/1 5577/5585/1 5580/5588/1 5575/5583/1 +f 13035/13043/1 2488/2496/1 5577/5585/1 5574/5582/1 +f 2488/2496/1 2487/2495/1 5578/5586/1 5577/5585/1 +f 12946/12954/1 5573/5581/1 5576/5584/1 12947/12955/1 +f 1903/1911/1 13036/13044/1 5573/5581/1 12946/12954/1 +f 13036/13044/1 13035/13043/1 5574/5582/1 5573/5581/1 +f 2518/2526/1 5569/5577/1 5572/5580/1 2519/2527/1 +f 12947/12955/1 5576/5584/1 5569/5577/1 2518/2526/1 +f 5576/5584/1 5575/5583/1 5570/5578/1 5569/5577/1 +f 5562/5570/1 5565/5573/1 5568/5576/1 5563/5571/1 +f 14775/14783/1 1908/1916/1 5565/5573/1 5562/5570/1 +f 1908/1916/1 1907/1915/1 5566/5574/1 5565/5573/1 +f 5578/5586/1 5561/5569/1 5564/5572/1 5579/5587/1 +f 2487/2495/1 14776/14784/1 5561/5569/1 5578/5586/1 +f 14776/14784/1 14775/14783/1 5562/5570/1 5561/5569/1 +f 4974/4982/1 5557/5565/1 5560/5568/1 4975/4983/1 +f 5579/5587/1 5564/5572/1 5557/5565/1 4974/4982/1 +f 5564/5572/1 5563/5571/1 5558/5566/1 5557/5565/1 +f 5550/5558/1 5553/5561/1 5556/5564/1 5551/5559/1 +f 5535/5543/1 4988/4996/1 5553/5561/1 5550/5558/1 +f 4988/4996/1 4987/4995/1 5554/5562/1 5553/5561/1 +f 14770/14778/1 5549/5557/1 5552/5560/1 14771/14779/1 +f 2483/2491/1 5536/5544/1 5549/5557/1 14770/14778/1 +f 5536/5544/1 5535/5543/1 5550/5558/1 5549/5557/1 +f 1910/1918/1 5545/5553/1 5548/5556/1 1911/1919/1 +f 14771/14779/1 5552/5560/1 5545/5553/1 1910/1918/1 +f 5552/5560/1 5551/5559/1 5546/5554/1 5545/5553/1 +f 5538/5546/1 5541/5549/1 5544/5552/1 5539/5547/1 +f 13143/13151/1 2452/2460/1 5541/5549/1 5538/5546/1 +f 2452/2460/1 2451/2459/1 5542/5550/1 5541/5549/1 +f 13054/13062/1 5537/5545/1 5540/5548/1 13055/13063/1 +f 1915/1923/1 13144/13152/1 5537/5545/1 13054/13062/1 +f 13144/13152/1 13143/13151/1 5538/5546/1 5537/5545/1 +f 2482/2490/1 5533/5541/1 5536/5544/1 2483/2491/1 +f 13055/13063/1 5540/5548/1 5533/5541/1 2482/2490/1 +f 5540/5548/1 5539/5547/1 5534/5542/1 5533/5541/1 +f 5526/5534/1 5529/5537/1 5532/5540/1 5527/5535/1 +f 14739/14747/1 1920/1928/1 5529/5537/1 5526/5534/1 +f 1920/1928/1 1919/1927/1 5530/5538/1 5529/5537/1 +f 5542/5550/1 5525/5533/1 5528/5536/1 5543/5551/1 +f 2451/2459/1 14740/14748/1 5525/5533/1 5542/5550/1 +f 14740/14748/1 14739/14747/1 5526/5534/1 5525/5533/1 +f 4986/4994/1 5521/5529/1 5524/5532/1 4987/4995/1 +f 5543/5551/1 5528/5536/1 5521/5529/1 4986/4994/1 +f 5528/5536/1 5527/5535/1 5522/5530/1 5521/5529/1 +f 5514/5522/1 5517/5525/1 5520/5528/1 5515/5523/1 +f 5499/5507/1 5000/5008/1 5517/5525/1 5514/5522/1 +f 5000/5008/1 4999/5007/1 5518/5526/1 5517/5525/1 +f 14734/14742/1 5513/5521/1 5516/5524/1 14735/14743/1 +f 2447/2455/1 5500/5508/1 5513/5521/1 14734/14742/1 +f 5500/5508/1 5499/5507/1 5514/5522/1 5513/5521/1 +f 1922/1930/1 5509/5517/1 5512/5520/1 1923/1931/1 +f 14735/14743/1 5516/5524/1 5509/5517/1 1922/1930/1 +f 5516/5524/1 5515/5523/1 5510/5518/1 5509/5517/1 +f 5502/5510/1 5505/5513/1 5508/5516/1 5503/5511/1 +f 13251/13259/1 2416/2424/1 5505/5513/1 5502/5510/1 +f 2416/2424/1 2415/2423/1 5506/5514/1 5505/5513/1 +f 13162/13170/1 5501/5509/1 5504/5512/1 13163/13171/1 +f 1927/1935/1 13252/13260/1 5501/5509/1 13162/13170/1 +f 13252/13260/1 13251/13259/1 5502/5510/1 5501/5509/1 +f 2446/2454/1 5497/5505/1 5500/5508/1 2447/2455/1 +f 13163/13171/1 5504/5512/1 5497/5505/1 2446/2454/1 +f 5504/5512/1 5503/5511/1 5498/5506/1 5497/5505/1 +f 5490/5498/1 5493/5501/1 5496/5504/1 5491/5499/1 +f 14703/14711/1 1932/1940/1 5493/5501/1 5490/5498/1 +f 1932/1940/1 1931/1939/1 5494/5502/1 5493/5501/1 +f 5506/5514/1 5489/5497/1 5492/5500/1 5507/5515/1 +f 2415/2423/1 14704/14712/1 5489/5497/1 5506/5514/1 +f 14704/14712/1 14703/14711/1 5490/5498/1 5489/5497/1 +f 4998/5006/1 5485/5493/1 5488/5496/1 4999/5007/1 +f 5507/5515/1 5492/5500/1 5485/5493/1 4998/5006/1 +f 5492/5500/1 5491/5499/1 5486/5494/1 5485/5493/1 +f 5478/5486/1 5481/5489/1 5484/5492/1 5479/5487/1 +f 5463/5471/1 5012/5020/1 5481/5489/1 5478/5486/1 +f 5012/5020/1 5011/5019/1 5482/5490/1 5481/5489/1 +f 14698/14706/1 5477/5485/1 5480/5488/1 14699/14707/1 +f 2411/2419/1 5464/5472/1 5477/5485/1 14698/14706/1 +f 5464/5472/1 5463/5471/1 5478/5486/1 5477/5485/1 +f 1934/1942/1 5473/5481/1 5476/5484/1 1935/1943/1 +f 14699/14707/1 5480/5488/1 5473/5481/1 1934/1942/1 +f 5480/5488/1 5479/5487/1 5474/5482/1 5473/5481/1 +f 5466/5474/1 5469/5477/1 5472/5480/1 5467/5475/1 +f 13359/13367/1 2380/2388/1 5469/5477/1 5466/5474/1 +f 2380/2388/1 2379/2387/1 5470/5478/1 5469/5477/1 +f 13270/13278/1 5465/5473/1 5468/5476/1 13271/13279/1 +f 1939/1947/1 13360/13368/1 5465/5473/1 13270/13278/1 +f 13360/13368/1 13359/13367/1 5466/5474/1 5465/5473/1 +f 2410/2418/1 5461/5469/1 5464/5472/1 2411/2419/1 +f 13271/13279/1 5468/5476/1 5461/5469/1 2410/2418/1 +f 5468/5476/1 5467/5475/1 5462/5470/1 5461/5469/1 +f 5454/5462/1 5457/5465/1 5460/5468/1 5455/5463/1 +f 14667/14675/1 1944/1952/1 5457/5465/1 5454/5462/1 +f 1944/1952/1 1943/1951/1 5458/5466/1 5457/5465/1 +f 5470/5478/1 5453/5461/1 5456/5464/1 5471/5479/1 +f 2379/2387/1 14668/14676/1 5453/5461/1 5470/5478/1 +f 14668/14676/1 14667/14675/1 5454/5462/1 5453/5461/1 +f 5010/5018/1 5449/5457/1 5452/5460/1 5011/5019/1 +f 5471/5479/1 5456/5464/1 5449/5457/1 5010/5018/1 +f 5456/5464/1 5455/5463/1 5450/5458/1 5449/5457/1 +f 5442/5450/1 5445/5453/1 5448/5456/1 5443/5451/1 +f 5427/5435/1 5024/5032/1 5445/5453/1 5442/5450/1 +f 5024/5032/1 5023/5031/1 5446/5454/1 5445/5453/1 +f 14662/14670/1 5441/5449/1 5444/5452/1 14663/14671/1 +f 2375/2383/1 5428/5436/1 5441/5449/1 14662/14670/1 +f 5428/5436/1 5427/5435/1 5442/5450/1 5441/5449/1 +f 1946/1954/1 5437/5445/1 5440/5448/1 1947/1955/1 +f 14663/14671/1 5444/5452/1 5437/5445/1 1946/1954/1 +f 5444/5452/1 5443/5451/1 5438/5446/1 5437/5445/1 +f 5430/5438/1 5433/5441/1 5436/5444/1 5431/5439/1 +f 13467/13475/1 2344/2352/1 5433/5441/1 5430/5438/1 +f 2344/2352/1 2343/2351/1 5434/5442/1 5433/5441/1 +f 13378/13386/1 5429/5437/1 5432/5440/1 13379/13387/1 +f 1951/1959/1 13468/13476/1 5429/5437/1 13378/13386/1 +f 13468/13476/1 13467/13475/1 5430/5438/1 5429/5437/1 +f 2374/2382/1 5425/5433/1 5428/5436/1 2375/2383/1 +f 13379/13387/1 5432/5440/1 5425/5433/1 2374/2382/1 +f 5432/5440/1 5431/5439/1 5426/5434/1 5425/5433/1 +f 5418/5426/1 5421/5429/1 5424/5432/1 5419/5427/1 +f 14631/14639/1 1956/1964/1 5421/5429/1 5418/5426/1 +f 1956/1964/1 1955/1963/1 5422/5430/1 5421/5429/1 +f 5434/5442/1 5417/5425/1 5420/5428/1 5435/5443/1 +f 2343/2351/1 14632/14640/1 5417/5425/1 5434/5442/1 +f 14632/14640/1 14631/14639/1 5418/5426/1 5417/5425/1 +f 5022/5030/1 5413/5421/1 5416/5424/1 5023/5031/1 +f 5435/5443/1 5420/5428/1 5413/5421/1 5022/5030/1 +f 5420/5428/1 5419/5427/1 5414/5422/1 5413/5421/1 +f 5406/5414/1 5409/5417/1 5412/5420/1 5407/5415/1 +f 5391/5399/1 5036/5044/1 5409/5417/1 5406/5414/1 +f 5036/5044/1 5035/5043/1 5410/5418/1 5409/5417/1 +f 14626/14634/1 5405/5413/1 5408/5416/1 14627/14635/1 +f 2339/2347/1 5392/5400/1 5405/5413/1 14626/14634/1 +f 5392/5400/1 5391/5399/1 5406/5414/1 5405/5413/1 +f 1958/1966/1 5401/5409/1 5404/5412/1 1959/1967/1 +f 14627/14635/1 5408/5416/1 5401/5409/1 1958/1966/1 +f 5408/5416/1 5407/5415/1 5402/5410/1 5401/5409/1 +f 5394/5402/1 5397/5405/1 5400/5408/1 5395/5403/1 +f 13575/13583/1 2308/2316/1 5397/5405/1 5394/5402/1 +f 2308/2316/1 2307/2315/1 5398/5406/1 5397/5405/1 +f 13486/13494/1 5393/5401/1 5396/5404/1 13487/13495/1 +f 1963/1971/1 13576/13584/1 5393/5401/1 13486/13494/1 +f 13576/13584/1 13575/13583/1 5394/5402/1 5393/5401/1 +f 2338/2346/1 5389/5397/1 5392/5400/1 2339/2347/1 +f 13487/13495/1 5396/5404/1 5389/5397/1 2338/2346/1 +f 5396/5404/1 5395/5403/1 5390/5398/1 5389/5397/1 +f 5382/5390/1 5385/5393/1 5388/5396/1 5383/5391/1 +f 14595/14603/1 1968/1976/1 5385/5393/1 5382/5390/1 +f 1968/1976/1 1967/1975/1 5386/5394/1 5385/5393/1 +f 5398/5406/1 5381/5389/1 5384/5392/1 5399/5407/1 +f 2307/2315/1 14596/14604/1 5381/5389/1 5398/5406/1 +f 14596/14604/1 14595/14603/1 5382/5390/1 5381/5389/1 +f 5034/5042/1 5377/5385/1 5380/5388/1 5035/5043/1 +f 5399/5407/1 5384/5392/1 5377/5385/1 5034/5042/1 +f 5384/5392/1 5383/5391/1 5378/5386/1 5377/5385/1 +f 5370/5378/1 5373/5381/1 5376/5384/1 5371/5379/1 +f 5355/5363/1 5048/5056/1 5373/5381/1 5370/5378/1 +f 5048/5056/1 5047/5055/1 5374/5382/1 5373/5381/1 +f 14590/14598/1 5369/5377/1 5372/5380/1 14591/14599/1 +f 2303/2311/1 5356/5364/1 5369/5377/1 14590/14598/1 +f 5356/5364/1 5355/5363/1 5370/5378/1 5369/5377/1 +f 1970/1978/1 5365/5373/1 5368/5376/1 1971/1979/1 +f 14591/14599/1 5372/5380/1 5365/5373/1 1970/1978/1 +f 5372/5380/1 5371/5379/1 5366/5374/1 5365/5373/1 +f 5358/5366/1 5361/5369/1 5364/5372/1 5359/5367/1 +f 13683/13691/1 2272/2280/1 5361/5369/1 5358/5366/1 +f 2272/2280/1 2271/2279/1 5362/5370/1 5361/5369/1 +f 13594/13602/1 5357/5365/1 5360/5368/1 13595/13603/1 +f 1975/1983/1 13684/13692/1 5357/5365/1 13594/13602/1 +f 13684/13692/1 13683/13691/1 5358/5366/1 5357/5365/1 +f 2302/2310/1 5353/5361/1 5356/5364/1 2303/2311/1 +f 13595/13603/1 5360/5368/1 5353/5361/1 2302/2310/1 +f 5360/5368/1 5359/5367/1 5354/5362/1 5353/5361/1 +f 5346/5354/1 5349/5357/1 5352/5360/1 5347/5355/1 +f 14559/14567/1 1980/1988/1 5349/5357/1 5346/5354/1 +f 1980/1988/1 1979/1987/1 5350/5358/1 5349/5357/1 +f 5362/5370/1 5345/5353/1 5348/5356/1 5363/5371/1 +f 2271/2279/1 14560/14568/1 5345/5353/1 5362/5370/1 +f 14560/14568/1 14559/14567/1 5346/5354/1 5345/5353/1 +f 5046/5054/1 5341/5349/1 5344/5352/1 5047/5055/1 +f 5363/5371/1 5348/5356/1 5341/5349/1 5046/5054/1 +f 5348/5356/1 5347/5355/1 5342/5350/1 5341/5349/1 +f 5334/5342/1 5337/5345/1 5340/5348/1 5335/5343/1 +f 5319/5327/1 5060/5068/1 5337/5345/1 5334/5342/1 +f 5060/5068/1 5059/5067/1 5338/5346/1 5337/5345/1 +f 14554/14562/1 5333/5341/1 5336/5344/1 14555/14563/1 +f 2267/2275/1 5320/5328/1 5333/5341/1 14554/14562/1 +f 5320/5328/1 5319/5327/1 5334/5342/1 5333/5341/1 +f 1982/1990/1 5329/5337/1 5332/5340/1 1983/1991/1 +f 14555/14563/1 5336/5344/1 5329/5337/1 1982/1990/1 +f 5336/5344/1 5335/5343/1 5330/5338/1 5329/5337/1 +f 5322/5330/1 5325/5333/1 5328/5336/1 5323/5331/1 +f 13791/13799/1 2236/2244/1 5325/5333/1 5322/5330/1 +f 2236/2244/1 2235/2243/1 5326/5334/1 5325/5333/1 +f 13702/13710/1 5321/5329/1 5324/5332/1 13703/13711/1 +f 1987/1995/1 13792/13800/1 5321/5329/1 13702/13710/1 +f 13792/13800/1 13791/13799/1 5322/5330/1 5321/5329/1 +f 2266/2274/1 5317/5325/1 5320/5328/1 2267/2275/1 +f 13703/13711/1 5324/5332/1 5317/5325/1 2266/2274/1 +f 5324/5332/1 5323/5331/1 5318/5326/1 5317/5325/1 +f 5310/5318/1 5313/5321/1 5316/5324/1 5311/5319/1 +f 14523/14531/1 1992/2000/1 5313/5321/1 5310/5318/1 +f 1992/2000/1 1991/1999/1 5314/5322/1 5313/5321/1 +f 5326/5334/1 5309/5317/1 5312/5320/1 5327/5335/1 +f 2235/2243/1 14524/14532/1 5309/5317/1 5326/5334/1 +f 14524/14532/1 14523/14531/1 5310/5318/1 5309/5317/1 +f 5058/5066/1 5305/5313/1 5308/5316/1 5059/5067/1 +f 5327/5335/1 5312/5320/1 5305/5313/1 5058/5066/1 +f 5312/5320/1 5311/5319/1 5306/5314/1 5305/5313/1 +f 5298/5306/1 5301/5309/1 5304/5312/1 5299/5307/1 +f 5283/5291/1 5072/5080/1 5301/5309/1 5298/5306/1 +f 5072/5080/1 5071/5079/1 5302/5310/1 5301/5309/1 +f 14518/14526/1 5297/5305/1 5300/5308/1 14519/14527/1 +f 2231/2239/1 5284/5292/1 5297/5305/1 14518/14526/1 +f 5284/5292/1 5283/5291/1 5298/5306/1 5297/5305/1 +f 1994/2002/1 5293/5301/1 5296/5304/1 1995/2003/1 +f 14519/14527/1 5300/5308/1 5293/5301/1 1994/2002/1 +f 5300/5308/1 5299/5307/1 5294/5302/1 5293/5301/1 +f 5286/5294/1 5289/5297/1 5292/5300/1 5287/5295/1 +f 13899/13907/1 2200/2208/1 5289/5297/1 5286/5294/1 +f 2200/2208/1 2199/2207/1 5290/5298/1 5289/5297/1 +f 13810/13818/1 5285/5293/1 5288/5296/1 13811/13819/1 +f 1999/2007/1 13900/13908/1 5285/5293/1 13810/13818/1 +f 13900/13908/1 13899/13907/1 5286/5294/1 5285/5293/1 +f 2230/2238/1 5281/5289/1 5284/5292/1 2231/2239/1 +f 13811/13819/1 5288/5296/1 5281/5289/1 2230/2238/1 +f 5288/5296/1 5287/5295/1 5282/5290/1 5281/5289/1 +f 5274/5282/1 5277/5285/1 5280/5288/1 5275/5283/1 +f 14487/14495/1 2004/2012/1 5277/5285/1 5274/5282/1 +f 2004/2012/1 2003/2011/1 5278/5286/1 5277/5285/1 +f 5290/5298/1 5273/5281/1 5276/5284/1 5291/5299/1 +f 2199/2207/1 14488/14496/1 5273/5281/1 5290/5298/1 +f 14488/14496/1 14487/14495/1 5274/5282/1 5273/5281/1 +f 5070/5078/1 5269/5277/1 5272/5280/1 5071/5079/1 +f 5291/5299/1 5276/5284/1 5269/5277/1 5070/5078/1 +f 5276/5284/1 5275/5283/1 5270/5278/1 5269/5277/1 +f 5262/5270/1 5265/5273/1 5268/5276/1 5263/5271/1 +f 5247/5255/1 5084/5092/1 5265/5273/1 5262/5270/1 +f 5084/5092/1 5083/5091/1 5266/5274/1 5265/5273/1 +f 14482/14490/1 5261/5269/1 5264/5272/1 14483/14491/1 +f 2195/2203/1 5248/5256/1 5261/5269/1 14482/14490/1 +f 5248/5256/1 5247/5255/1 5262/5270/1 5261/5269/1 +f 2006/2014/1 5257/5265/1 5260/5268/1 2007/2015/1 +f 14483/14491/1 5264/5272/1 5257/5265/1 2006/2014/1 +f 5264/5272/1 5263/5271/1 5258/5266/1 5257/5265/1 +f 5250/5258/1 5253/5261/1 5256/5264/1 5251/5259/1 +f 14007/14015/1 2164/2172/1 5253/5261/1 5250/5258/1 +f 2164/2172/1 2163/2171/1 5254/5262/1 5253/5261/1 +f 13918/13926/1 5249/5257/1 5252/5260/1 13919/13927/1 +f 2011/2019/1 14008/14016/1 5249/5257/1 13918/13926/1 +f 14008/14016/1 14007/14015/1 5250/5258/1 5249/5257/1 +f 2194/2202/1 5245/5253/1 5248/5256/1 2195/2203/1 +f 13919/13927/1 5252/5260/1 5245/5253/1 2194/2202/1 +f 5252/5260/1 5251/5259/1 5246/5254/1 5245/5253/1 +f 5238/5246/1 5241/5249/1 5244/5252/1 5239/5247/1 +f 14451/14459/1 2016/2024/1 5241/5249/1 5238/5246/1 +f 2016/2024/1 2015/2023/1 5242/5250/1 5241/5249/1 +f 5254/5262/1 5237/5245/1 5240/5248/1 5255/5263/1 +f 2163/2171/1 14452/14460/1 5237/5245/1 5254/5262/1 +f 14452/14460/1 14451/14459/1 5238/5246/1 5237/5245/1 +f 5082/5090/1 5233/5241/1 5236/5244/1 5083/5091/1 +f 5255/5263/1 5240/5248/1 5233/5241/1 5082/5090/1 +f 5240/5248/1 5239/5247/1 5234/5242/1 5233/5241/1 +f 5226/5234/1 5229/5237/1 5232/5240/1 5227/5235/1 +f 5211/5219/1 5096/5104/1 5229/5237/1 5226/5234/1 +f 5096/5104/1 5095/5103/1 5230/5238/1 5229/5237/1 +f 14446/14454/1 5225/5233/1 5228/5236/1 14447/14455/1 +f 2159/2167/1 5212/5220/1 5225/5233/1 14446/14454/1 +f 5212/5220/1 5211/5219/1 5226/5234/1 5225/5233/1 +f 2018/2026/1 5221/5229/1 5224/5232/1 2019/2027/1 +f 14447/14455/1 5228/5236/1 5221/5229/1 2018/2026/1 +f 5228/5236/1 5227/5235/1 5222/5230/1 5221/5229/1 +f 5214/5222/1 5217/5225/1 5220/5228/1 5215/5223/1 +f 14115/14123/1 2128/2136/1 5217/5225/1 5214/5222/1 +f 2128/2136/1 2127/2135/1 5218/5226/1 5217/5225/1 +f 14026/14034/1 5213/5221/1 5216/5224/1 14027/14035/1 +f 2023/2031/1 14116/14124/1 5213/5221/1 14026/14034/1 +f 14116/14124/1 14115/14123/1 5214/5222/1 5213/5221/1 +f 2158/2166/1 5209/5217/1 5212/5220/1 2159/2167/1 +f 14027/14035/1 5216/5224/1 5209/5217/1 2158/2166/1 +f 5216/5224/1 5215/5223/1 5210/5218/1 5209/5217/1 +f 5202/5210/1 5205/5213/1 5208/5216/1 5203/5211/1 +f 14415/14423/1 2028/2036/1 5205/5213/1 5202/5210/1 +f 2028/2036/1 2027/2035/1 5206/5214/1 5205/5213/1 +f 5218/5226/1 5201/5209/1 5204/5212/1 5219/5227/1 +f 2127/2135/1 14416/14424/1 5201/5209/1 5218/5226/1 +f 14416/14424/1 14415/14423/1 5202/5210/1 5201/5209/1 +f 5094/5102/1 5197/5205/1 5200/5208/1 5095/5103/1 +f 5219/5227/1 5204/5212/1 5197/5205/1 5094/5102/1 +f 5204/5212/1 5203/5211/1 5198/5206/1 5197/5205/1 +f 5190/5198/1 5193/5201/1 5196/5204/1 5191/5199/1 +f 5175/5183/1 5108/5116/1 5193/5201/1 5190/5198/1 +f 5108/5116/1 5107/5115/1 5194/5202/1 5193/5201/1 +f 14410/14418/1 5189/5197/1 5192/5200/1 14411/14419/1 +f 2123/2131/1 5176/5184/1 5189/5197/1 14410/14418/1 +f 5176/5184/1 5175/5183/1 5190/5198/1 5189/5197/1 +f 2030/2038/1 5185/5193/1 5188/5196/1 2031/2039/1 +f 14411/14419/1 5192/5200/1 5185/5193/1 2030/2038/1 +f 5192/5200/1 5191/5199/1 5186/5194/1 5185/5193/1 +f 5178/5186/1 5181/5189/1 5184/5192/1 5179/5187/1 +f 14223/14231/1 2092/2100/1 5181/5189/1 5178/5186/1 +f 2092/2100/1 2091/2099/1 5182/5190/1 5181/5189/1 +f 14134/14142/1 5177/5185/1 5180/5188/1 14135/14143/1 +f 2035/2043/1 14224/14232/1 5177/5185/1 14134/14142/1 +f 14224/14232/1 14223/14231/1 5178/5186/1 5177/5185/1 +f 2122/2130/1 5173/5181/1 5176/5184/1 2123/2131/1 +f 14135/14143/1 5180/5188/1 5173/5181/1 2122/2130/1 +f 5180/5188/1 5179/5187/1 5174/5182/1 5173/5181/1 +f 5166/5174/1 5169/5177/1 5172/5180/1 5167/5175/1 +f 14379/14387/1 2040/2048/1 5169/5177/1 5166/5174/1 +f 2040/2048/1 2039/2047/1 5170/5178/1 5169/5177/1 +f 5182/5190/1 5165/5173/1 5168/5176/1 5183/5191/1 +f 2091/2099/1 14380/14388/1 5165/5173/1 5182/5190/1 +f 14380/14388/1 14379/14387/1 5166/5174/1 5165/5173/1 +f 5106/5114/1 5161/5169/1 5164/5172/1 5107/5115/1 +f 5183/5191/1 5168/5176/1 5161/5169/1 5106/5114/1 +f 5168/5176/1 5167/5175/1 5162/5170/1 5161/5169/1 +f 5154/5162/1 5157/5165/1 5160/5168/1 5155/5163/1 +f 5139/5147/1 5120/5128/1 5157/5165/1 5154/5162/1 +f 5120/5128/1 5119/5127/1 5158/5166/1 5157/5165/1 +f 14374/14382/1 5153/5161/1 5156/5164/1 14375/14383/1 +f 2087/2095/1 5140/5148/1 5153/5161/1 14374/14382/1 +f 5140/5148/1 5139/5147/1 5154/5162/1 5153/5161/1 +f 2042/2050/1 5149/5157/1 5152/5160/1 2043/2051/1 +f 14375/14383/1 5156/5164/1 5149/5157/1 2042/2050/1 +f 5156/5164/1 5155/5163/1 5150/5158/1 5149/5157/1 +f 5142/5150/1 5145/5153/1 5148/5156/1 5143/5151/1 +f 14331/14339/1 2056/2064/1 5145/5153/1 5142/5150/1 +f 2056/2064/1 2055/2063/1 5146/5154/1 5145/5153/1 +f 14242/14250/1 5141/5149/1 5144/5152/1 14243/14251/1 +f 2047/2055/1 14332/14340/1 5141/5149/1 14242/14250/1 +f 14332/14340/1 14331/14339/1 5142/5150/1 5141/5149/1 +f 2086/2094/1 5137/5145/1 5140/5148/1 2087/2095/1 +f 14243/14251/1 5144/5152/1 5137/5145/1 2086/2094/1 +f 5144/5152/1 5143/5151/1 5138/5146/1 5137/5145/1 +f 5130/5138/1 5133/5141/1 5136/5144/1 5131/5139/1 +f 14343/14351/1 2052/2060/1 5133/5141/1 5130/5138/1 +f 2052/2060/1 2051/2059/1 5134/5142/1 5133/5141/1 +f 5146/5154/1 5129/5137/1 5132/5140/1 5147/5155/1 +f 2055/2063/1 14344/14352/1 5129/5137/1 5146/5154/1 +f 14344/14352/1 14343/14351/1 5130/5138/1 5129/5137/1 +f 5118/5126/1 5125/5133/1 5128/5136/1 5119/5127/1 +f 5147/5155/1 5132/5140/1 5125/5133/1 5118/5126/1 +f 5132/5140/1 5131/5139/1 5126/5134/1 5125/5133/1 +f 5126/5134/1 5121/5129/1 5124/5132/1 5127/5135/1 +f 5131/5139/1 5136/5144/1 5121/5129/1 5126/5134/1 +f 5136/5144/1 5135/5143/1 5122/5130/1 5121/5129/1 +f 5138/5146/1 5117/5125/1 5120/5128/1 5139/5147/1 +f 5143/5151/1 5148/5156/1 5117/5125/1 5138/5146/1 +f 5148/5156/1 5147/5155/1 5118/5126/1 5117/5125/1 +f 5150/5158/1 5113/5121/1 5116/5124/1 5151/5159/1 +f 5155/5163/1 5160/5168/1 5113/5121/1 5150/5158/1 +f 5160/5168/1 5159/5167/1 5114/5122/1 5113/5121/1 +f 5162/5170/1 5109/5117/1 5112/5120/1 5163/5171/1 +f 5167/5175/1 5172/5180/1 5109/5117/1 5162/5170/1 +f 5172/5180/1 5171/5179/1 5110/5118/1 5109/5117/1 +f 5174/5182/1 5105/5113/1 5108/5116/1 5175/5183/1 +f 5179/5187/1 5184/5192/1 5105/5113/1 5174/5182/1 +f 5184/5192/1 5183/5191/1 5106/5114/1 5105/5113/1 +f 5186/5194/1 5101/5109/1 5104/5112/1 5187/5195/1 +f 5191/5199/1 5196/5204/1 5101/5109/1 5186/5194/1 +f 5196/5204/1 5195/5203/1 5102/5110/1 5101/5109/1 +f 5198/5206/1 5097/5105/1 5100/5108/1 5199/5207/1 +f 5203/5211/1 5208/5216/1 5097/5105/1 5198/5206/1 +f 5208/5216/1 5207/5215/1 5098/5106/1 5097/5105/1 +f 5210/5218/1 5093/5101/1 5096/5104/1 5211/5219/1 +f 5215/5223/1 5220/5228/1 5093/5101/1 5210/5218/1 +f 5220/5228/1 5219/5227/1 5094/5102/1 5093/5101/1 +f 5222/5230/1 5089/5097/1 5092/5100/1 5223/5231/1 +f 5227/5235/1 5232/5240/1 5089/5097/1 5222/5230/1 +f 5232/5240/1 5231/5239/1 5090/5098/1 5089/5097/1 +f 5234/5242/1 5085/5093/1 5088/5096/1 5235/5243/1 +f 5239/5247/1 5244/5252/1 5085/5093/1 5234/5242/1 +f 5244/5252/1 5243/5251/1 5086/5094/1 5085/5093/1 +f 5246/5254/1 5081/5089/1 5084/5092/1 5247/5255/1 +f 5251/5259/1 5256/5264/1 5081/5089/1 5246/5254/1 +f 5256/5264/1 5255/5263/1 5082/5090/1 5081/5089/1 +f 5258/5266/1 5077/5085/1 5080/5088/1 5259/5267/1 +f 5263/5271/1 5268/5276/1 5077/5085/1 5258/5266/1 +f 5268/5276/1 5267/5275/1 5078/5086/1 5077/5085/1 +f 5270/5278/1 5073/5081/1 5076/5084/1 5271/5279/1 +f 5275/5283/1 5280/5288/1 5073/5081/1 5270/5278/1 +f 5280/5288/1 5279/5287/1 5074/5082/1 5073/5081/1 +f 5282/5290/1 5069/5077/1 5072/5080/1 5283/5291/1 +f 5287/5295/1 5292/5300/1 5069/5077/1 5282/5290/1 +f 5292/5300/1 5291/5299/1 5070/5078/1 5069/5077/1 +f 5294/5302/1 5065/5073/1 5068/5076/1 5295/5303/1 +f 5299/5307/1 5304/5312/1 5065/5073/1 5294/5302/1 +f 5304/5312/1 5303/5311/1 5066/5074/1 5065/5073/1 +f 5306/5314/1 5061/5069/1 5064/5072/1 5307/5315/1 +f 5311/5319/1 5316/5324/1 5061/5069/1 5306/5314/1 +f 5316/5324/1 5315/5323/1 5062/5070/1 5061/5069/1 +f 5318/5326/1 5057/5065/1 5060/5068/1 5319/5327/1 +f 5323/5331/1 5328/5336/1 5057/5065/1 5318/5326/1 +f 5328/5336/1 5327/5335/1 5058/5066/1 5057/5065/1 +f 5330/5338/1 5053/5061/1 5056/5064/1 5331/5339/1 +f 5335/5343/1 5340/5348/1 5053/5061/1 5330/5338/1 +f 5340/5348/1 5339/5347/1 5054/5062/1 5053/5061/1 +f 5342/5350/1 5049/5057/1 5052/5060/1 5343/5351/1 +f 5347/5355/1 5352/5360/1 5049/5057/1 5342/5350/1 +f 5352/5360/1 5351/5359/1 5050/5058/1 5049/5057/1 +f 5354/5362/1 5045/5053/1 5048/5056/1 5355/5363/1 +f 5359/5367/1 5364/5372/1 5045/5053/1 5354/5362/1 +f 5364/5372/1 5363/5371/1 5046/5054/1 5045/5053/1 +f 5366/5374/1 5041/5049/1 5044/5052/1 5367/5375/1 +f 5371/5379/1 5376/5384/1 5041/5049/1 5366/5374/1 +f 5376/5384/1 5375/5383/1 5042/5050/1 5041/5049/1 +f 5378/5386/1 5037/5045/1 5040/5048/1 5379/5387/1 +f 5383/5391/1 5388/5396/1 5037/5045/1 5378/5386/1 +f 5388/5396/1 5387/5395/1 5038/5046/1 5037/5045/1 +f 5390/5398/1 5033/5041/1 5036/5044/1 5391/5399/1 +f 5395/5403/1 5400/5408/1 5033/5041/1 5390/5398/1 +f 5400/5408/1 5399/5407/1 5034/5042/1 5033/5041/1 +f 5402/5410/1 5029/5037/1 5032/5040/1 5403/5411/1 +f 5407/5415/1 5412/5420/1 5029/5037/1 5402/5410/1 +f 5412/5420/1 5411/5419/1 5030/5038/1 5029/5037/1 +f 5414/5422/1 5025/5033/1 5028/5036/1 5415/5423/1 +f 5419/5427/1 5424/5432/1 5025/5033/1 5414/5422/1 +f 5424/5432/1 5423/5431/1 5026/5034/1 5025/5033/1 +f 5426/5434/1 5021/5029/1 5024/5032/1 5427/5435/1 +f 5431/5439/1 5436/5444/1 5021/5029/1 5426/5434/1 +f 5436/5444/1 5435/5443/1 5022/5030/1 5021/5029/1 +f 5438/5446/1 5017/5025/1 5020/5028/1 5439/5447/1 +f 5443/5451/1 5448/5456/1 5017/5025/1 5438/5446/1 +f 5448/5456/1 5447/5455/1 5018/5026/1 5017/5025/1 +f 5450/5458/1 5013/5021/1 5016/5024/1 5451/5459/1 +f 5455/5463/1 5460/5468/1 5013/5021/1 5450/5458/1 +f 5460/5468/1 5459/5467/1 5014/5022/1 5013/5021/1 +f 5462/5470/1 5009/5017/1 5012/5020/1 5463/5471/1 +f 5467/5475/1 5472/5480/1 5009/5017/1 5462/5470/1 +f 5472/5480/1 5471/5479/1 5010/5018/1 5009/5017/1 +f 5474/5482/1 5005/5013/1 5008/5016/1 5475/5483/1 +f 5479/5487/1 5484/5492/1 5005/5013/1 5474/5482/1 +f 5484/5492/1 5483/5491/1 5006/5014/1 5005/5013/1 +f 5486/5494/1 5001/5009/1 5004/5012/1 5487/5495/1 +f 5491/5499/1 5496/5504/1 5001/5009/1 5486/5494/1 +f 5496/5504/1 5495/5503/1 5002/5010/1 5001/5009/1 +f 5498/5506/1 4997/5005/1 5000/5008/1 5499/5507/1 +f 5503/5511/1 5508/5516/1 4997/5005/1 5498/5506/1 +f 5508/5516/1 5507/5515/1 4998/5006/1 4997/5005/1 +f 5510/5518/1 4993/5001/1 4996/5004/1 5511/5519/1 +f 5515/5523/1 5520/5528/1 4993/5001/1 5510/5518/1 +f 5520/5528/1 5519/5527/1 4994/5002/1 4993/5001/1 +f 5522/5530/1 4989/4997/1 4992/5000/1 5523/5531/1 +f 5527/5535/1 5532/5540/1 4989/4997/1 5522/5530/1 +f 5532/5540/1 5531/5539/1 4990/4998/1 4989/4997/1 +f 5534/5542/1 4985/4993/1 4988/4996/1 5535/5543/1 +f 5539/5547/1 5544/5552/1 4985/4993/1 5534/5542/1 +f 5544/5552/1 5543/5551/1 4986/4994/1 4985/4993/1 +f 5546/5554/1 4981/4989/1 4984/4992/1 5547/5555/1 +f 5551/5559/1 5556/5564/1 4981/4989/1 5546/5554/1 +f 5556/5564/1 5555/5563/1 4982/4990/1 4981/4989/1 +f 5558/5566/1 4977/4985/1 4980/4988/1 5559/5567/1 +f 5563/5571/1 5568/5576/1 4977/4985/1 5558/5566/1 +f 5568/5576/1 5567/5575/1 4978/4986/1 4977/4985/1 +f 5570/5578/1 4973/4981/1 4976/4984/1 5571/5579/1 +f 5575/5583/1 5580/5588/1 4973/4981/1 5570/5578/1 +f 5580/5588/1 5579/5587/1 4974/4982/1 4973/4981/1 +f 5582/5590/1 4969/4977/1 4972/4980/1 5583/5591/1 +f 5587/5595/1 5592/5600/1 4969/4977/1 5582/5590/1 +f 5592/5600/1 5591/5599/1 4970/4978/1 4969/4977/1 +f 5594/5602/1 4965/4973/1 4968/4976/1 5595/5603/1 +f 5599/5607/1 5604/5612/1 4965/4973/1 5594/5602/1 +f 5604/5612/1 5603/5611/1 4966/4974/1 4965/4973/1 +f 5606/5614/1 4961/4969/1 4964/4972/1 5607/5615/1 +f 5611/5619/1 5616/5624/1 4961/4969/1 5606/5614/1 +f 5616/5624/1 5615/5623/1 4962/4970/1 4961/4969/1 +f 5618/5626/1 4957/4965/1 4960/4968/1 5619/5627/1 +f 5623/5631/1 5628/5636/1 4957/4965/1 5618/5626/1 +f 5628/5636/1 5627/5635/1 4958/4966/1 4957/4965/1 +f 5630/5638/1 4953/4961/1 4956/4964/1 5631/5639/1 +f 5635/5643/1 5640/5648/1 4953/4961/1 5630/5638/1 +f 5640/5648/1 5639/5647/1 4954/4962/1 4953/4961/1 +f 5642/5650/1 4949/4957/1 4952/4960/1 5643/5651/1 +f 5647/5655/1 5652/5660/1 4949/4957/1 5642/5650/1 +f 5652/5660/1 5651/5659/1 4950/4958/1 4949/4957/1 +f 5654/5662/1 4945/4953/1 4948/4956/1 5655/5663/1 +f 5659/5667/1 5664/5672/1 4945/4953/1 5654/5662/1 +f 5664/5672/1 5663/5671/1 4946/4954/1 4945/4953/1 +f 5666/5674/1 4941/4949/1 4944/4952/1 5667/5675/1 +f 5671/5679/1 5676/5684/1 4941/4949/1 5666/5674/1 +f 5676/5684/1 5675/5683/1 4942/4950/1 4941/4949/1 +f 5678/5686/1 4937/4945/1 4940/4948/1 5679/5687/1 +f 5683/5691/1 5688/5696/1 4937/4945/1 5678/5686/1 +f 5688/5696/1 5687/5695/1 4938/4946/1 4937/4945/1 +f 5690/5698/1 4933/4941/1 4936/4944/1 5691/5699/1 +f 5695/5703/1 5700/5708/1 4933/4941/1 5690/5698/1 +f 5700/5708/1 5699/5707/1 4934/4942/1 4933/4941/1 +f 5702/5710/1 4929/4937/1 4932/4940/1 5703/5711/1 +f 5707/5715/1 5712/5720/1 4929/4937/1 5702/5710/1 +f 5712/5720/1 5711/5719/1 4930/4938/1 4929/4937/1 +f 5714/5722/1 4925/4933/1 4928/4936/1 5715/5723/1 +f 5719/5727/1 5724/5732/1 4925/4933/1 5714/5722/1 +f 5724/5732/1 5723/5731/1 4926/4934/1 4925/4933/1 +f 5726/5734/1 4921/4929/1 4924/4932/1 5727/5735/1 +f 5731/5739/1 5736/5744/1 4921/4929/1 5726/5734/1 +f 5736/5744/1 5735/5743/1 4922/4930/1 4921/4929/1 +f 5738/5746/1 4917/4925/1 4920/4928/1 5739/5747/1 +f 5743/5751/1 5748/5756/1 4917/4925/1 5738/5746/1 +f 5748/5756/1 5747/5755/1 4918/4926/1 4917/4925/1 +f 5750/5758/1 4913/4921/1 4916/4924/1 5751/5759/1 +f 5755/5763/1 5760/5768/1 4913/4921/1 5750/5758/1 +f 5760/5768/1 5759/5767/1 4914/4922/1 4913/4921/1 +f 5762/5770/1 4909/4917/1 4912/4920/1 5763/5771/1 +f 5767/5775/1 5772/5780/1 4909/4917/1 5762/5770/1 +f 5772/5780/1 5771/5779/1 4910/4918/1 4909/4917/1 +f 5774/5782/1 4905/4913/1 4908/4916/1 5775/5783/1 +f 5779/5787/1 5784/5792/1 4905/4913/1 5774/5782/1 +f 5784/5792/1 5783/5791/1 4906/4914/1 4905/4913/1 +f 5786/5794/1 4901/4909/1 4904/4912/1 5787/5795/1 +f 5791/5799/1 5796/5804/1 4901/4909/1 5786/5794/1 +f 5796/5804/1 5795/5803/1 4902/4910/1 4901/4909/1 +f 5798/5806/1 4897/4905/1 4900/4908/1 5799/5807/1 +f 5803/5811/1 5808/5816/1 4897/4905/1 5798/5806/1 +f 5808/5816/1 5807/5815/1 4898/4906/1 4897/4905/1 +f 5810/5818/1 4893/4901/1 4896/4904/1 5811/5819/1 +f 5815/5823/1 5820/5828/1 4893/4901/1 5810/5818/1 +f 5820/5828/1 5819/5827/1 4894/4902/1 4893/4901/1 +f 5822/5830/1 4889/4897/1 4892/4900/1 5823/5831/1 +f 5827/5835/1 5832/5840/1 4889/4897/1 5822/5830/1 +f 5832/5840/1 5831/5839/1 4890/4898/1 4889/4897/1 +f 5834/5842/1 4885/4893/1 4888/4896/1 5835/5843/1 +f 5839/5847/1 5844/5852/1 4885/4893/1 5834/5842/1 +f 5844/5852/1 5843/5851/1 4886/4894/1 4885/4893/1 +f 5846/5854/1 4881/4889/1 4884/4892/1 5847/5855/1 +f 5851/5859/1 5856/5864/1 4881/4889/1 5846/5854/1 +f 5856/5864/1 5855/5863/1 4882/4890/1 4881/4889/1 +f 5858/5866/1 4877/4885/1 4880/4888/1 5859/5867/1 +f 5863/5871/1 5868/5876/1 4877/4885/1 5858/5866/1 +f 5868/5876/1 5867/5875/1 4878/4886/1 4877/4885/1 +f 5870/5878/1 4873/4881/1 4876/4884/1 5871/5879/1 +f 5875/5883/1 5880/5888/1 4873/4881/1 5870/5878/1 +f 5880/5888/1 5879/5887/1 4874/4882/1 4873/4881/1 +f 5882/5890/1 4869/4877/1 4872/4880/1 5883/5891/1 +f 5887/5895/1 5892/5900/1 4869/4877/1 5882/5890/1 +f 5892/5900/1 5891/5899/1 4870/4878/1 4869/4877/1 +f 5894/5902/1 4865/4873/1 4868/4876/1 5895/5903/1 +f 5899/5907/1 5904/5912/1 4865/4873/1 5894/5902/1 +f 5904/5912/1 5903/5911/1 4866/4874/1 4865/4873/1 +f 5906/5914/1 4861/4869/1 4864/4872/1 5907/5915/1 +f 5911/5919/1 5916/5924/1 4861/4869/1 5906/5914/1 +f 5916/5924/1 5915/5923/1 4862/4870/1 4861/4869/1 +f 5918/5926/1 4857/4865/1 4860/4868/1 5919/5927/1 +f 5923/5931/1 5928/5936/1 4857/4865/1 5918/5926/1 +f 5928/5936/1 5927/5935/1 4858/4866/1 4857/4865/1 +f 5930/5938/1 4853/4861/1 4856/4864/1 5931/5939/1 +f 5935/5943/1 5940/5948/1 4853/4861/1 5930/5938/1 +f 5940/5948/1 5939/5947/1 4854/4862/1 4853/4861/1 +f 5942/5950/1 4849/4857/1 4852/4860/1 5943/5951/1 +f 5947/5955/1 5952/5960/1 4849/4857/1 5942/5950/1 +f 5952/5960/1 5951/5959/1 4850/4858/1 4849/4857/1 +f 5954/5962/1 4845/4853/1 4848/4856/1 5955/5963/1 +f 5959/5967/1 5964/5972/1 4845/4853/1 5954/5962/1 +f 5964/5972/1 5963/5971/1 4846/4854/1 4845/4853/1 +f 5966/5974/1 4841/4849/1 4844/4852/1 5967/5975/1 +f 5971/5979/1 5976/5984/1 4841/4849/1 5966/5974/1 +f 5976/5984/1 5975/5983/1 4842/4850/1 4841/4849/1 +f 5978/5986/1 4837/4845/1 4840/4848/1 5979/5987/1 +f 5983/5991/1 5988/5996/1 4837/4845/1 5978/5986/1 +f 5988/5996/1 5987/5995/1 4838/4846/1 4837/4845/1 +f 5990/5998/1 4833/4841/1 4836/4844/1 5991/5999/1 +f 5995/6003/1 6000/6008/1 4833/4841/1 5990/5998/1 +f 6000/6008/1 5999/6007/1 4834/4842/1 4833/4841/1 +f 6002/6010/1 4829/4837/1 4832/4840/1 6003/6011/1 +f 6007/6015/1 6012/6020/1 4829/4837/1 6002/6010/1 +f 6012/6020/1 6011/6019/1 4830/4838/1 4829/4837/1 +f 6014/6022/1 4825/4833/1 4828/4836/1 6015/6023/1 +f 6019/6027/1 6024/6032/1 4825/4833/1 6014/6022/1 +f 6024/6032/1 6023/6031/1 4826/4834/1 4825/4833/1 +f 6026/6034/1 4821/4829/1 4824/4832/1 6027/6035/1 +f 6031/6039/1 6036/6044/1 4821/4829/1 6026/6034/1 +f 6036/6044/1 6035/6043/1 4822/4830/1 4821/4829/1 +f 6038/6046/1 4817/4825/1 4820/4828/1 6039/6047/1 +f 6043/6051/1 6048/6056/1 4817/4825/1 6038/6046/1 +f 6048/6056/1 6047/6055/1 4818/4826/1 4817/4825/1 +f 6050/6058/1 4813/4821/1 4816/4824/1 6051/6059/1 +f 6055/6063/1 6060/6068/1 4813/4821/1 6050/6058/1 +f 6060/6068/1 6059/6067/1 4814/4822/1 4813/4821/1 +f 6062/6070/1 4809/4817/1 4812/4820/1 6063/6071/1 +f 6067/6075/1 6072/6080/1 4809/4817/1 6062/6070/1 +f 6072/6080/1 6071/6079/1 4810/4818/1 4809/4817/1 +f 6074/6082/1 4805/4813/1 4808/4816/1 6075/6083/1 +f 6079/6087/1 6084/6092/1 4805/4813/1 6074/6082/1 +f 6084/6092/1 6083/6091/1 4806/4814/1 4805/4813/1 +f 6086/6094/1 4801/4809/1 4804/4812/1 6087/6095/1 +f 6091/6099/1 6096/6104/1 4801/4809/1 6086/6094/1 +f 6096/6104/1 6095/6103/1 4802/4810/1 4801/4809/1 +f 6098/6106/1 4797/4805/1 4800/4808/1 6099/6107/1 +f 6103/6111/1 6108/6116/1 4797/4805/1 6098/6106/1 +f 6108/6116/1 6107/6115/1 4798/4806/1 4797/4805/1 +f 6110/6118/1 4793/4801/1 4796/4804/1 6111/6119/1 +f 6115/6123/1 6120/6128/1 4793/4801/1 6110/6118/1 +f 6120/6128/1 6119/6127/1 4794/4802/1 4793/4801/1 +f 6122/6130/1 4789/4797/1 4792/4800/1 6123/6131/1 +f 6127/6135/1 6132/6140/1 4789/4797/1 6122/6130/1 +f 6132/6140/1 6131/6139/1 4790/4798/1 4789/4797/1 +f 6134/6142/1 4785/4793/1 4788/4796/1 6135/6143/1 +f 6139/6147/1 6144/6152/1 4785/4793/1 6134/6142/1 +f 6144/6152/1 6143/6151/1 4786/4794/1 4785/4793/1 +f 6146/6154/1 4781/4789/1 4784/4792/1 6147/6155/1 +f 6151/6159/1 6156/6164/1 4781/4789/1 6146/6154/1 +f 6156/6164/1 6155/6163/1 4782/4790/1 4781/4789/1 +f 6158/6166/1 4777/4785/1 4780/4788/1 6159/6167/1 +f 6163/6171/1 6168/6176/1 4777/4785/1 6158/6166/1 +f 6168/6176/1 6167/6175/1 4778/4786/1 4777/4785/1 +f 6170/6178/1 4773/4781/1 4776/4784/1 6171/6179/1 +f 6175/6183/1 6180/6188/1 4773/4781/1 6170/6178/1 +f 6180/6188/1 6179/6187/1 4774/4782/1 4773/4781/1 +f 6182/6190/1 4769/4777/1 4772/4780/1 6183/6191/1 +f 6187/6195/1 6192/6200/1 4769/4777/1 6182/6190/1 +f 6192/6200/1 6191/6199/1 4770/4778/1 4769/4777/1 +f 6194/6202/1 4765/4773/1 4768/4776/1 6195/6203/1 +f 6199/6207/1 6204/6212/1 4765/4773/1 6194/6202/1 +f 6204/6212/1 6203/6211/1 4766/4774/1 4765/4773/1 +f 6206/6214/1 4761/4769/1 4764/4772/1 6207/6215/1 +f 6211/6219/1 6216/6224/1 4761/4769/1 6206/6214/1 +f 6216/6224/1 6215/6223/1 4762/4770/1 4761/4769/1 +f 6218/6226/1 4757/4765/1 4760/4768/1 6219/6227/1 +f 6223/6231/1 6228/6236/1 4757/4765/1 6218/6226/1 +f 6228/6236/1 6227/6235/1 4758/4766/1 4757/4765/1 +f 6230/6238/1 4753/4761/1 4756/4764/1 6231/6239/1 +f 6235/6243/1 6240/6248/1 4753/4761/1 6230/6238/1 +f 6240/6248/1 6239/6247/1 4754/4762/1 4753/4761/1 +f 6242/6250/1 4749/4757/1 4752/4760/1 6243/6251/1 +f 6247/6255/1 6252/6260/1 4749/4757/1 6242/6250/1 +f 6252/6260/1 6251/6259/1 4750/4758/1 4749/4757/1 +f 6254/6262/1 4745/4753/1 4748/4756/1 6255/6263/1 +f 6259/6267/1 6264/6272/1 4745/4753/1 6254/6262/1 +f 6264/6272/1 6263/6271/1 4746/4754/1 4745/4753/1 +f 6266/6274/1 4741/4749/1 4744/4752/1 6267/6275/1 +f 6271/6279/1 6276/6284/1 4741/4749/1 6266/6274/1 +f 6276/6284/1 6275/6283/1 4742/4750/1 4741/4749/1 +f 6278/6286/1 4737/4745/1 4740/4748/1 6279/6287/1 +f 6283/6291/1 6288/6296/1 4737/4745/1 6278/6286/1 +f 6288/6296/1 6287/6295/1 4738/4746/1 4737/4745/1 +f 6290/6298/1 4733/4741/1 4736/4744/1 6291/6299/1 +f 6295/6303/1 6300/6308/1 4733/4741/1 6290/6298/1 +f 6300/6308/1 6299/6307/1 4734/4742/1 4733/4741/1 +f 6302/6310/1 4729/4737/1 4732/4740/1 6303/6311/1 +f 6307/6315/1 6312/6320/1 4729/4737/1 6302/6310/1 +f 6312/6320/1 6311/6319/1 4730/4738/1 4729/4737/1 +f 6314/6322/1 4725/4733/1 4728/4736/1 6315/6323/1 +f 6319/6327/1 6324/6332/1 4725/4733/1 6314/6322/1 +f 6324/6332/1 6323/6331/1 4726/4734/1 4725/4733/1 +f 6326/6334/1 4721/4729/1 4724/4732/1 6327/6335/1 +f 6331/6339/1 6336/6344/1 4721/4729/1 6326/6334/1 +f 6336/6344/1 6335/6343/1 4722/4730/1 4721/4729/1 +f 6338/6346/1 4717/4725/1 4720/4728/1 6339/6347/1 +f 6343/6351/1 6348/6356/1 4717/4725/1 6338/6346/1 +f 6348/6356/1 6347/6355/1 4718/4726/1 4717/4725/1 +f 6350/6358/1 4713/4721/1 4716/4724/1 6351/6359/1 +f 6355/6363/1 6360/6368/1 4713/4721/1 6350/6358/1 +f 6360/6368/1 6359/6367/1 4714/4722/1 4713/4721/1 +f 6362/6370/1 4709/4717/1 4712/4720/1 6363/6371/1 +f 6367/6375/1 6372/6380/1 4709/4717/1 6362/6370/1 +f 6372/6380/1 6371/6379/1 4710/4718/1 4709/4717/1 +f 6374/6382/1 4705/4713/1 4708/4716/1 6375/6383/1 +f 6379/6387/1 6384/6392/1 4705/4713/1 6374/6382/1 +f 6384/6392/1 6383/6391/1 4706/4714/1 4705/4713/1 +f 6386/6394/1 4701/4709/1 4704/4712/1 6387/6395/1 +f 6391/6399/1 6396/6404/1 4701/4709/1 6386/6394/1 +f 6396/6404/1 6395/6403/1 4702/4710/1 4701/4709/1 +f 6398/6406/1 4697/4705/1 4700/4708/1 6399/6407/1 +f 6403/6411/1 6408/6416/1 4697/4705/1 6398/6406/1 +f 6408/6416/1 6407/6415/1 4698/4706/1 4697/4705/1 +f 6410/6418/1 4693/4701/1 4696/4704/1 6411/6419/1 +f 6415/6423/1 6420/6428/1 4693/4701/1 6410/6418/1 +f 6420/6428/1 6419/6427/1 4694/4702/1 4693/4701/1 +f 6422/6430/1 4689/4697/1 4692/4700/1 6423/6431/1 +f 6427/6435/1 6432/6440/1 4689/4697/1 6422/6430/1 +f 6432/6440/1 6431/6439/1 4690/4698/1 4689/4697/1 +f 6434/6442/1 4685/4693/1 4688/4696/1 6435/6443/1 +f 6439/6447/1 6444/6452/1 4685/4693/1 6434/6442/1 +f 6444/6452/1 6443/6451/1 4686/4694/1 4685/4693/1 +f 6446/6454/1 4681/4689/1 4684/4692/1 6447/6455/1 +f 6451/6459/1 6456/6464/1 4681/4689/1 6446/6454/1 +f 6456/6464/1 6455/6463/1 4682/4690/1 4681/4689/1 +f 6458/6466/1 4677/4685/1 4680/4688/1 6459/6467/1 +f 6463/6471/1 6468/6476/1 4677/4685/1 6458/6466/1 +f 6468/6476/1 6467/6475/1 4678/4686/1 4677/4685/1 +f 6470/6478/1 4673/4681/1 4676/4684/1 6471/6479/1 +f 6475/6483/1 6480/6488/1 4673/4681/1 6470/6478/1 +f 6480/6488/1 6479/6487/1 4674/4682/1 4673/4681/1 +f 6482/6490/1 4669/4677/1 4672/4680/1 6483/6491/1 +f 6487/6495/1 6492/6500/1 4669/4677/1 6482/6490/1 +f 6492/6500/1 6491/6499/1 4670/4678/1 4669/4677/1 +f 6494/6502/1 4665/4673/1 4668/4676/1 6495/6503/1 +f 6499/6507/1 6504/6512/1 4665/4673/1 6494/6502/1 +f 6504/6512/1 6503/6511/1 4666/4674/1 4665/4673/1 +f 6506/6514/1 4661/4669/1 4664/4672/1 6507/6515/1 +f 6511/6519/1 6516/6524/1 4661/4669/1 6506/6514/1 +f 6516/6524/1 6515/6523/1 4662/4670/1 4661/4669/1 +f 6518/6526/1 4657/4665/1 4660/4668/1 6519/6527/1 +f 6523/6531/1 6528/6536/1 4657/4665/1 6518/6526/1 +f 6528/6536/1 6527/6535/1 4658/4666/1 4657/4665/1 +f 6530/6538/1 4653/4661/1 4656/4664/1 6531/6539/1 +f 6535/6543/1 6540/6548/1 4653/4661/1 6530/6538/1 +f 6540/6548/1 6539/6547/1 4654/4662/1 4653/4661/1 +f 6542/6550/1 4649/4657/1 4652/4660/1 6543/6551/1 +f 6547/6555/1 6552/6560/1 4649/4657/1 6542/6550/1 +f 6552/6560/1 6551/6559/1 4650/4658/1 4649/4657/1 +f 6554/6562/1 4645/4653/1 4648/4656/1 6555/6563/1 +f 6559/6567/1 6564/6572/1 4645/4653/1 6554/6562/1 +f 6564/6572/1 6563/6571/1 4646/4654/1 4645/4653/1 +f 6566/6574/1 4641/4649/1 4644/4652/1 6567/6575/1 +f 6571/6579/1 6576/6584/1 4641/4649/1 6566/6574/1 +f 6576/6584/1 6575/6583/1 4642/4650/1 4641/4649/1 +f 6578/6586/1 4637/4645/1 4640/4648/1 6579/6587/1 +f 6583/6591/1 6588/6596/1 4637/4645/1 6578/6586/1 +f 6588/6596/1 6587/6595/1 4638/4646/1 4637/4645/1 +f 6590/6598/1 4633/4641/1 4636/4644/1 6591/6599/1 +f 6595/6603/1 6600/6608/1 4633/4641/1 6590/6598/1 +f 6600/6608/1 6599/6607/1 4634/4642/1 4633/4641/1 +f 6602/6610/1 4629/4637/1 4632/4640/1 6603/6611/1 +f 6607/6615/1 6612/6620/1 4629/4637/1 6602/6610/1 +f 6612/6620/1 6611/6619/1 4630/4638/1 4629/4637/1 +f 6614/6622/1 4625/4633/1 4628/4636/1 6615/6623/1 +f 6619/6627/1 6624/6632/1 4625/4633/1 6614/6622/1 +f 6624/6632/1 6623/6631/1 4626/4634/1 4625/4633/1 +f 6626/6634/1 4621/4629/1 4624/4632/1 6627/6635/1 +f 6631/6639/1 6636/6644/1 4621/4629/1 6626/6634/1 +f 6636/6644/1 6635/6643/1 4622/4630/1 4621/4629/1 +f 6638/6646/1 4617/4625/1 4620/4628/1 6639/6647/1 +f 6643/6651/1 6648/6656/1 4617/4625/1 6638/6646/1 +f 6648/6656/1 6647/6655/1 4618/4626/1 4617/4625/1 +f 6650/6658/1 4613/4621/1 4616/4624/1 6651/6659/1 +f 6655/6663/1 6660/6668/1 4613/4621/1 6650/6658/1 +f 6660/6668/1 6659/6667/1 4614/4622/1 4613/4621/1 +f 6662/6670/1 4609/4617/1 4612/4620/1 6663/6671/1 +f 6667/6675/1 6672/6680/1 4609/4617/1 6662/6670/1 +f 6672/6680/1 6671/6679/1 4610/4618/1 4609/4617/1 +f 6674/6682/1 4605/4613/1 4608/4616/1 6675/6683/1 +f 6679/6687/1 6684/6692/1 4605/4613/1 6674/6682/1 +f 6684/6692/1 6683/6691/1 4606/4614/1 4605/4613/1 +f 6686/6694/1 4601/4609/1 4604/4612/1 6687/6695/1 +f 6691/6699/1 6696/6704/1 4601/4609/1 6686/6694/1 +f 6696/6704/1 6695/6703/1 4602/4610/1 4601/4609/1 +f 6698/6706/1 4597/4605/1 4600/4608/1 6699/6707/1 +f 6703/6711/1 6708/6716/1 4597/4605/1 6698/6706/1 +f 6708/6716/1 6707/6715/1 4598/4606/1 4597/4605/1 +f 6710/6718/1 4593/4601/1 4596/4604/1 6711/6719/1 +f 6715/6723/1 6720/6728/1 4593/4601/1 6710/6718/1 +f 6720/6728/1 6719/6727/1 4594/4602/1 4593/4601/1 +f 6722/6730/1 4589/4597/1 4592/4600/1 6723/6731/1 +f 6727/6735/1 6732/6740/1 4589/4597/1 6722/6730/1 +f 6732/6740/1 6731/6739/1 4590/4598/1 4589/4597/1 +f 6734/6742/1 4585/4593/1 4588/4596/1 6735/6743/1 +f 6739/6747/1 6744/6752/1 4585/4593/1 6734/6742/1 +f 6744/6752/1 6743/6751/1 4586/4594/1 4585/4593/1 +f 6746/6754/1 4581/4589/1 4584/4592/1 6747/6755/1 +f 6751/6759/1 6756/6764/1 4581/4589/1 6746/6754/1 +f 6756/6764/1 6755/6763/1 4582/4590/1 4581/4589/1 +f 6758/6766/1 4577/4585/1 4580/4588/1 6759/6767/1 +f 6763/6771/1 6768/6776/1 4577/4585/1 6758/6766/1 +f 6768/6776/1 6767/6775/1 4578/4586/1 4577/4585/1 +f 6770/6778/1 4573/4581/1 4576/4584/1 6771/6779/1 +f 6775/6783/1 6780/6788/1 4573/4581/1 6770/6778/1 +f 6780/6788/1 6779/6787/1 4574/4582/1 4573/4581/1 +f 6782/6790/1 4569/4577/1 4572/4580/1 6783/6791/1 +f 6787/6795/1 6792/6800/1 4569/4577/1 6782/6790/1 +f 6792/6800/1 6791/6799/1 4570/4578/1 4569/4577/1 +f 6794/6802/1 4565/4573/1 4568/4576/1 6795/6803/1 +f 6799/6807/1 6804/6812/1 4565/4573/1 6794/6802/1 +f 6804/6812/1 6803/6811/1 4566/4574/1 4565/4573/1 +f 6806/6814/1 4561/4569/1 4564/4572/1 6807/6815/1 +f 6811/6819/1 6816/6824/1 4561/4569/1 6806/6814/1 +f 6816/6824/1 6815/6823/1 4562/4570/1 4561/4569/1 +f 6818/6826/1 4557/4565/1 4560/4568/1 6819/6827/1 +f 6823/6831/1 6828/6836/1 4557/4565/1 6818/6826/1 +f 6828/6836/1 6827/6835/1 4558/4566/1 4557/4565/1 +f 6830/6838/1 4553/4561/1 4556/4564/1 6831/6839/1 +f 6835/6843/1 6840/6848/1 4553/4561/1 6830/6838/1 +f 6840/6848/1 6839/6847/1 4554/4562/1 4553/4561/1 +f 6842/6850/1 4549/4557/1 4552/4560/1 6843/6851/1 +f 6847/6855/1 6852/6860/1 4549/4557/1 6842/6850/1 +f 6852/6860/1 6851/6859/1 4550/4558/1 4549/4557/1 +f 6854/6862/1 4545/4553/1 4548/4556/1 6855/6863/1 +f 6859/6867/1 6864/6872/1 4545/4553/1 6854/6862/1 +f 6864/6872/1 6863/6871/1 4546/4554/1 4545/4553/1 +f 6866/6874/1 4541/4549/1 4544/4552/1 6867/6875/1 +f 6871/6879/1 6876/6884/1 4541/4549/1 6866/6874/1 +f 6876/6884/1 6875/6883/1 4542/4550/1 4541/4549/1 +f 6878/6886/1 4537/4545/1 4540/4548/1 6879/6887/1 +f 6883/6891/1 6888/6896/1 4537/4545/1 6878/6886/1 +f 6888/6896/1 6887/6895/1 4538/4546/1 4537/4545/1 +f 6890/6898/1 4533/4541/1 4536/4544/1 6891/6899/1 +f 6895/6903/1 6900/6908/1 4533/4541/1 6890/6898/1 +f 6900/6908/1 6899/6907/1 4534/4542/1 4533/4541/1 +f 6902/6910/1 4529/4537/1 4532/4540/1 6903/6911/1 +f 6907/6915/1 6912/6920/1 4529/4537/1 6902/6910/1 +f 6912/6920/1 6911/6919/1 4530/4538/1 4529/4537/1 +f 6914/6922/1 4525/4533/1 4528/4536/1 6915/6923/1 +f 6919/6927/1 6924/6932/1 4525/4533/1 6914/6922/1 +f 6924/6932/1 6923/6931/1 4526/4534/1 4525/4533/1 +f 6926/6934/1 4521/4529/1 4524/4532/1 6927/6935/1 +f 6931/6939/1 6936/6944/1 4521/4529/1 6926/6934/1 +f 6936/6944/1 6935/6943/1 4522/4530/1 4521/4529/1 +f 6938/6946/1 4517/4525/1 4520/4528/1 6939/6947/1 +f 6943/6951/1 6948/6956/1 4517/4525/1 6938/6946/1 +f 6948/6956/1 6947/6955/1 4518/4526/1 4517/4525/1 +f 6950/6958/1 4513/4521/1 4516/4524/1 6951/6959/1 +f 6955/6963/1 6960/6968/1 4513/4521/1 6950/6958/1 +f 6960/6968/1 6959/6967/1 4514/4522/1 4513/4521/1 +f 6962/6970/1 4509/4517/1 4512/4520/1 6963/6971/1 +f 6967/6975/1 6972/6980/1 4509/4517/1 6962/6970/1 +f 6972/6980/1 6971/6979/1 4510/4518/1 4509/4517/1 +f 6974/6982/1 4505/4513/1 4508/4516/1 6975/6983/1 +f 6979/6987/1 6984/6992/1 4505/4513/1 6974/6982/1 +f 6984/6992/1 6983/6991/1 4506/4514/1 4505/4513/1 +f 6986/6994/1 4501/4509/1 4504/4512/1 6987/6995/1 +f 6991/6999/1 6996/7004/1 4501/4509/1 6986/6994/1 +f 6996/7004/1 6995/7003/1 4502/4510/1 4501/4509/1 +f 6998/7006/1 4497/4505/1 4500/4508/1 6999/7007/1 +f 7003/7011/1 7008/7016/1 4497/4505/1 6998/7006/1 +f 7008/7016/1 7007/7015/1 4498/4506/1 4497/4505/1 +f 7010/7018/1 4493/4501/1 4496/4504/1 7011/7019/1 +f 7015/7023/1 7020/7028/1 4493/4501/1 7010/7018/1 +f 7020/7028/1 7019/7027/1 4494/4502/1 4493/4501/1 +f 7022/7030/1 4489/4497/1 4492/4500/1 7023/7031/1 +f 7027/7035/1 7032/7040/1 4489/4497/1 7022/7030/1 +f 7032/7040/1 7031/7039/1 4490/4498/1 4489/4497/1 +f 7034/7042/1 4485/4493/1 4488/4496/1 7035/7043/1 +f 7039/7047/1 7044/7052/1 4485/4493/1 7034/7042/1 +f 7044/7052/1 7043/7051/1 4486/4494/1 4485/4493/1 +f 7046/7054/1 4481/4489/1 4484/4492/1 7047/7055/1 +f 7051/7059/1 7056/7064/1 4481/4489/1 7046/7054/1 +f 7056/7064/1 7055/7063/1 4482/4490/1 4481/4489/1 +f 7058/7066/1 4477/4485/1 4480/4488/1 7059/7067/1 +f 7063/7071/1 7068/7076/1 4477/4485/1 7058/7066/1 +f 7068/7076/1 7067/7075/1 4478/4486/1 4477/4485/1 +f 7070/7078/1 4473/4481/1 4476/4484/1 7071/7079/1 +f 7075/7083/1 7080/7088/1 4473/4481/1 7070/7078/1 +f 7080/7088/1 7079/7087/1 4474/4482/1 4473/4481/1 +f 7082/7090/1 4469/4477/1 4472/4480/1 7083/7091/1 +f 7087/7095/1 7092/7100/1 4469/4477/1 7082/7090/1 +f 7092/7100/1 7091/7099/1 4470/4478/1 4469/4477/1 +f 7094/7102/1 4465/4473/1 4468/4476/1 7095/7103/1 +f 7099/7107/1 7104/7112/1 4465/4473/1 7094/7102/1 +f 7104/7112/1 7103/7111/1 4466/4474/1 4465/4473/1 +f 7106/7114/1 4461/4469/1 4464/4472/1 7107/7115/1 +f 7111/7119/1 7116/7124/1 4461/4469/1 7106/7114/1 +f 7116/7124/1 7115/7123/1 4462/4470/1 4461/4469/1 +f 7118/7126/1 4457/4465/1 4460/4468/1 7119/7127/1 +f 7123/7131/1 7128/7136/1 4457/4465/1 7118/7126/1 +f 7128/7136/1 7127/7135/1 4458/4466/1 4457/4465/1 +f 7130/7138/1 4453/4461/1 4456/4464/1 7131/7139/1 +f 7135/7143/1 7140/7148/1 4453/4461/1 7130/7138/1 +f 7140/7148/1 7139/7147/1 4454/4462/1 4453/4461/1 +f 7142/7150/1 4449/4457/1 4452/4460/1 7143/7151/1 +f 7147/7155/1 7152/7160/1 4449/4457/1 7142/7150/1 +f 7152/7160/1 7151/7159/1 4450/4458/1 4449/4457/1 +f 7154/7162/1 4445/4453/1 4448/4456/1 7155/7163/1 +f 7159/7167/1 7164/7172/1 4445/4453/1 7154/7162/1 +f 7164/7172/1 7163/7171/1 4446/4454/1 4445/4453/1 +f 7166/7174/1 4441/4449/1 4444/4452/1 7167/7175/1 +f 7171/7179/1 7176/7184/1 4441/4449/1 7166/7174/1 +f 7176/7184/1 7175/7183/1 4442/4450/1 4441/4449/1 +f 7178/7186/1 4437/4445/1 4440/4448/1 7179/7187/1 +f 7183/7191/1 7188/7196/1 4437/4445/1 7178/7186/1 +f 7188/7196/1 7187/7195/1 4438/4446/1 4437/4445/1 +f 7190/7198/1 4433/4441/1 4436/4444/1 7191/7199/1 +f 7195/7203/1 7200/7208/1 4433/4441/1 7190/7198/1 +f 7200/7208/1 7199/7207/1 4434/4442/1 4433/4441/1 +f 7202/7210/1 4429/4437/1 4432/4440/1 7203/7211/1 +f 7207/7215/1 7212/7220/1 4429/4437/1 7202/7210/1 +f 7212/7220/1 7211/7219/1 4430/4438/1 4429/4437/1 +f 7214/7222/1 4425/4433/1 4428/4436/1 7215/7223/1 +f 7219/7227/1 7224/7232/1 4425/4433/1 7214/7222/1 +f 7224/7232/1 7223/7231/1 4426/4434/1 4425/4433/1 +f 7226/7234/1 4421/4429/1 4424/4432/1 7227/7235/1 +f 7231/7239/1 7236/7244/1 4421/4429/1 7226/7234/1 +f 7236/7244/1 7235/7243/1 4422/4430/1 4421/4429/1 +f 7238/7246/1 4417/4425/1 4420/4428/1 7239/7247/1 +f 7243/7251/1 7248/7256/1 4417/4425/1 7238/7246/1 +f 7248/7256/1 7247/7255/1 4418/4426/1 4417/4425/1 +f 7250/7258/1 4413/4421/1 4416/4424/1 7251/7259/1 +f 7255/7263/1 7260/7268/1 4413/4421/1 7250/7258/1 +f 7260/7268/1 7259/7267/1 4414/4422/1 4413/4421/1 +f 7262/7270/1 4409/4417/1 4412/4420/1 7263/7271/1 +f 7267/7275/1 7272/7280/1 4409/4417/1 7262/7270/1 +f 7272/7280/1 7271/7279/1 4410/4418/1 4409/4417/1 +f 7274/7282/1 4405/4413/1 4408/4416/1 7275/7283/1 +f 7279/7287/1 7284/7292/1 4405/4413/1 7274/7282/1 +f 7284/7292/1 7283/7291/1 4406/4414/1 4405/4413/1 +f 7286/7294/1 4401/4409/1 4404/4412/1 7287/7295/1 +f 7291/7299/1 7296/7304/1 4401/4409/1 7286/7294/1 +f 7296/7304/1 7295/7303/1 4402/4410/1 4401/4409/1 +f 7298/7306/1 4397/4405/1 4400/4408/1 7299/7307/1 +f 7303/7311/1 7308/7316/1 4397/4405/1 7298/7306/1 +f 7308/7316/1 7307/7315/1 4398/4406/1 4397/4405/1 +f 7310/7318/1 4393/4401/1 4396/4404/1 7311/7319/1 +f 7315/7323/1 7320/7328/1 4393/4401/1 7310/7318/1 +f 7320/7328/1 7319/7327/1 4394/4402/1 4393/4401/1 +f 7322/7330/1 4389/4397/1 4392/4400/1 7323/7331/1 +f 7327/7335/1 7332/7340/1 4389/4397/1 7322/7330/1 +f 7332/7340/1 7331/7339/1 4390/4398/1 4389/4397/1 +f 7334/7342/1 4385/4393/1 4388/4396/1 7335/7343/1 +f 7339/7347/1 7344/7352/1 4385/4393/1 7334/7342/1 +f 7344/7352/1 7343/7351/1 4386/4394/1 4385/4393/1 +f 7346/7354/1 4381/4389/1 4384/4392/1 7347/7355/1 +f 7351/7359/1 7356/7364/1 4381/4389/1 7346/7354/1 +f 7356/7364/1 7355/7363/1 4382/4390/1 4381/4389/1 +f 7358/7366/1 4377/4385/1 4380/4388/1 7359/7367/1 +f 7363/7371/1 7368/7376/1 4377/4385/1 7358/7366/1 +f 7368/7376/1 7367/7375/1 4378/4386/1 4377/4385/1 +f 7370/7378/1 4373/4381/1 4376/4384/1 7371/7379/1 +f 7375/7383/1 7380/7388/1 4373/4381/1 7370/7378/1 +f 7380/7388/1 7379/7387/1 4374/4382/1 4373/4381/1 +f 7382/7390/1 4369/4377/1 4372/4380/1 7383/7391/1 +f 7387/7395/1 7392/7400/1 4369/4377/1 7382/7390/1 +f 7392/7400/1 7391/7399/1 4370/4378/1 4369/4377/1 +f 7394/7402/1 4365/4373/1 4368/4376/1 7395/7403/1 +f 7399/7407/1 7404/7412/1 4365/4373/1 7394/7402/1 +f 7404/7412/1 7403/7411/1 4366/4374/1 4365/4373/1 +f 7406/7414/1 4361/4369/1 4364/4372/1 7407/7415/1 +f 7411/7419/1 7416/7424/1 4361/4369/1 7406/7414/1 +f 7416/7424/1 7415/7423/1 4362/4370/1 4361/4369/1 +f 7418/7426/1 4357/4365/1 4360/4368/1 7419/7427/1 +f 7423/7431/1 7428/7436/1 4357/4365/1 7418/7426/1 +f 7428/7436/1 7427/7435/1 4358/4366/1 4357/4365/1 +f 7430/7438/1 4353/4361/1 4356/4364/1 7431/7439/1 +f 7435/7443/1 7440/7448/1 4353/4361/1 7430/7438/1 +f 7440/7448/1 7439/7447/1 4354/4362/1 4353/4361/1 +f 7442/7450/1 4349/4357/1 4352/4360/1 7443/7451/1 +f 7447/7455/1 7452/7460/1 4349/4357/1 7442/7450/1 +f 7452/7460/1 7451/7459/1 4350/4358/1 4349/4357/1 +f 7454/7462/1 4345/4353/1 4348/4356/1 7455/7463/1 +f 7459/7467/1 7464/7472/1 4345/4353/1 7454/7462/1 +f 7464/7472/1 7463/7471/1 4346/4354/1 4345/4353/1 +f 7466/7474/1 4341/4349/1 4344/4352/1 7467/7475/1 +f 7471/7479/1 7476/7484/1 4341/4349/1 7466/7474/1 +f 7476/7484/1 7475/7483/1 4342/4350/1 4341/4349/1 +f 7478/7486/1 4337/4345/1 4340/4348/1 7479/7487/1 +f 7483/7491/1 7488/7496/1 4337/4345/1 7478/7486/1 +f 7488/7496/1 7487/7495/1 4338/4346/1 4337/4345/1 +f 7490/7498/1 4333/4341/1 4336/4344/1 7491/7499/1 +f 7495/7503/1 7500/7508/1 4333/4341/1 7490/7498/1 +f 7500/7508/1 7499/7507/1 4334/4342/1 4333/4341/1 +f 7502/7510/1 4329/4337/1 4332/4340/1 7503/7511/1 +f 7507/7515/1 7512/7520/1 4329/4337/1 7502/7510/1 +f 7512/7520/1 7511/7519/1 4330/4338/1 4329/4337/1 +f 7514/7522/1 4325/4333/1 4328/4336/1 7515/7523/1 +f 7519/7527/1 7524/7532/1 4325/4333/1 7514/7522/1 +f 7524/7532/1 7523/7531/1 4326/4334/1 4325/4333/1 +f 7526/7534/1 4321/4329/1 4324/4332/1 7527/7535/1 +f 7531/7539/1 7536/7544/1 4321/4329/1 7526/7534/1 +f 7536/7544/1 7535/7543/1 4322/4330/1 4321/4329/1 +f 7538/7546/1 4317/4325/1 4320/4328/1 7539/7547/1 +f 7543/7551/1 7548/7556/1 4317/4325/1 7538/7546/1 +f 7548/7556/1 7547/7555/1 4318/4326/1 4317/4325/1 +f 7550/7558/1 4313/4321/1 4316/4324/1 7551/7559/1 +f 7555/7563/1 7560/7568/1 4313/4321/1 7550/7558/1 +f 7560/7568/1 7559/7567/1 4314/4322/1 4313/4321/1 +f 7562/7570/1 4309/4317/1 4312/4320/1 7563/7571/1 +f 7567/7575/1 7572/7580/1 4309/4317/1 7562/7570/1 +f 7572/7580/1 7571/7579/1 4310/4318/1 4309/4317/1 +f 7574/7582/1 4305/4313/1 4308/4316/1 7575/7583/1 +f 7579/7587/1 7584/7592/1 4305/4313/1 7574/7582/1 +f 7584/7592/1 7583/7591/1 4306/4314/1 4305/4313/1 +f 7586/7594/1 4301/4309/1 4304/4312/1 7587/7595/1 +f 7591/7599/1 7596/7604/1 4301/4309/1 7586/7594/1 +f 7596/7604/1 7595/7603/1 4302/4310/1 4301/4309/1 +f 7598/7606/1 4297/4305/1 4300/4308/1 7599/7607/1 +f 7603/7611/1 7608/7616/1 4297/4305/1 7598/7606/1 +f 7608/7616/1 7607/7615/1 4298/4306/1 4297/4305/1 +f 7610/7618/1 4293/4301/1 4296/4304/1 7611/7619/1 +f 7615/7623/1 7620/7628/1 4293/4301/1 7610/7618/1 +f 7620/7628/1 7619/7627/1 4294/4302/1 4293/4301/1 +f 7622/7630/1 4289/4297/1 4292/4300/1 7623/7631/1 +f 7627/7635/1 7632/7640/1 4289/4297/1 7622/7630/1 +f 7632/7640/1 7631/7639/1 4290/4298/1 4289/4297/1 +f 7634/7642/1 4285/4293/1 4288/4296/1 7635/7643/1 +f 7639/7647/1 7644/7652/1 4285/4293/1 7634/7642/1 +f 7644/7652/1 7643/7651/1 4286/4294/1 4285/4293/1 +f 7646/7654/1 4281/4289/1 4284/4292/1 7647/7655/1 +f 7651/7659/1 7656/7664/1 4281/4289/1 7646/7654/1 +f 7656/7664/1 7655/7663/1 4282/4290/1 4281/4289/1 +f 7658/7666/1 4277/4285/1 4280/4288/1 7659/7667/1 +f 7663/7671/1 7668/7676/1 4277/4285/1 7658/7666/1 +f 7668/7676/1 7667/7675/1 4278/4286/1 4277/4285/1 +f 7670/7678/1 4273/4281/1 4276/4284/1 7671/7679/1 +f 7675/7683/1 7680/7688/1 4273/4281/1 7670/7678/1 +f 7680/7688/1 7679/7687/1 4274/4282/1 4273/4281/1 +f 7682/7690/1 4269/4277/1 4272/4280/1 7683/7691/1 +f 7687/7695/1 7692/7700/1 4269/4277/1 7682/7690/1 +f 7692/7700/1 7691/7699/1 4270/4278/1 4269/4277/1 +f 7694/7702/1 4265/4273/1 4268/4276/1 7695/7703/1 +f 7699/7707/1 7704/7712/1 4265/4273/1 7694/7702/1 +f 7704/7712/1 7703/7711/1 4266/4274/1 4265/4273/1 +f 7706/7714/1 4261/4269/1 4264/4272/1 7707/7715/1 +f 7711/7719/1 7716/7724/1 4261/4269/1 7706/7714/1 +f 7716/7724/1 7715/7723/1 4262/4270/1 4261/4269/1 +f 7718/7726/1 4257/4265/1 4260/4268/1 7719/7727/1 +f 7723/7731/1 7728/7736/1 4257/4265/1 7718/7726/1 +f 7728/7736/1 7727/7735/1 4258/4266/1 4257/4265/1 +f 7730/7738/1 4253/4261/1 4256/4264/1 7731/7739/1 +f 7735/7743/1 7740/7748/1 4253/4261/1 7730/7738/1 +f 7740/7748/1 7739/7747/1 4254/4262/1 4253/4261/1 +f 7742/7750/1 4249/4257/1 4252/4260/1 7743/7751/1 +f 7747/7755/1 7752/7760/1 4249/4257/1 7742/7750/1 +f 7752/7760/1 7751/7759/1 4250/4258/1 4249/4257/1 +f 7754/7762/1 4245/4253/1 4248/4256/1 7755/7763/1 +f 7759/7767/1 7764/7772/1 4245/4253/1 7754/7762/1 +f 7764/7772/1 7763/7771/1 4246/4254/1 4245/4253/1 +f 7766/7774/1 4241/4249/1 4244/4252/1 7767/7775/1 +f 7771/7779/1 7776/7784/1 4241/4249/1 7766/7774/1 +f 7776/7784/1 7775/7783/1 4242/4250/1 4241/4249/1 +f 7778/7786/1 4237/4245/1 4240/4248/1 7779/7787/1 +f 7783/7791/1 7788/7796/1 4237/4245/1 7778/7786/1 +f 7788/7796/1 7787/7795/1 4238/4246/1 4237/4245/1 +f 7790/7798/1 4233/4241/1 4236/4244/1 7791/7799/1 +f 7795/7803/1 7800/7808/1 4233/4241/1 7790/7798/1 +f 7800/7808/1 7799/7807/1 4234/4242/1 4233/4241/1 +f 7802/7810/1 4229/4237/1 4232/4240/1 7803/7811/1 +f 7807/7815/1 7812/7820/1 4229/4237/1 7802/7810/1 +f 7812/7820/1 7811/7819/1 4230/4238/1 4229/4237/1 +f 7814/7822/1 4225/4233/1 4228/4236/1 7815/7823/1 +f 7819/7827/1 7824/7832/1 4225/4233/1 7814/7822/1 +f 7824/7832/1 7823/7831/1 4226/4234/1 4225/4233/1 +f 7826/7834/1 4221/4229/1 4224/4232/1 7827/7835/1 +f 7831/7839/1 7836/7844/1 4221/4229/1 7826/7834/1 +f 7836/7844/1 7835/7843/1 4222/4230/1 4221/4229/1 +f 7838/7846/1 4217/4225/1 4220/4228/1 7839/7847/1 +f 7843/7851/1 7848/7856/1 4217/4225/1 7838/7846/1 +f 7848/7856/1 7847/7855/1 4218/4226/1 4217/4225/1 +f 7850/7858/1 4213/4221/1 4216/4224/1 7851/7859/1 +f 7855/7863/1 7860/7868/1 4213/4221/1 7850/7858/1 +f 7860/7868/1 7859/7867/1 4214/4222/1 4213/4221/1 +f 7862/7870/1 4209/4217/1 4212/4220/1 7863/7871/1 +f 7867/7875/1 7872/7880/1 4209/4217/1 7862/7870/1 +f 7872/7880/1 7871/7879/1 4210/4218/1 4209/4217/1 +f 7874/7882/1 4205/4213/1 4208/4216/1 7875/7883/1 +f 7879/7887/1 7884/7892/1 4205/4213/1 7874/7882/1 +f 7884/7892/1 7883/7891/1 4206/4214/1 4205/4213/1 +f 7886/7894/1 4201/4209/1 4204/4212/1 7887/7895/1 +f 7891/7899/1 7896/7904/1 4201/4209/1 7886/7894/1 +f 7896/7904/1 7895/7903/1 4202/4210/1 4201/4209/1 +f 7898/7906/1 4197/4205/1 4200/4208/1 7899/7907/1 +f 7903/7911/1 7908/7916/1 4197/4205/1 7898/7906/1 +f 7908/7916/1 7907/7915/1 4198/4206/1 4197/4205/1 +f 7910/7918/1 4193/4201/1 4196/4204/1 7911/7919/1 +f 7915/7923/1 7920/7928/1 4193/4201/1 7910/7918/1 +f 7920/7928/1 7919/7927/1 4194/4202/1 4193/4201/1 +f 7922/7930/1 4189/4197/1 4192/4200/1 7923/7931/1 +f 7927/7935/1 7932/7940/1 4189/4197/1 7922/7930/1 +f 7932/7940/1 7931/7939/1 4190/4198/1 4189/4197/1 +f 7934/7942/1 4185/4193/1 4188/4196/1 7935/7943/1 +f 7939/7947/1 7944/7952/1 4185/4193/1 7934/7942/1 +f 7944/7952/1 7943/7951/1 4186/4194/1 4185/4193/1 +f 7946/7954/1 4181/4189/1 4184/4192/1 7947/7955/1 +f 7951/7959/1 7956/7964/1 4181/4189/1 7946/7954/1 +f 7956/7964/1 7955/7963/1 4182/4190/1 4181/4189/1 +f 7958/7966/1 4177/4185/1 4180/4188/1 7959/7967/1 +f 7963/7971/1 7968/7976/1 4177/4185/1 7958/7966/1 +f 7968/7976/1 7967/7975/1 4178/4186/1 4177/4185/1 +f 7970/7978/1 4173/4181/1 4176/4184/1 7971/7979/1 +f 7975/7983/1 7980/7988/1 4173/4181/1 7970/7978/1 +f 7980/7988/1 7979/7987/1 4174/4182/1 4173/4181/1 +f 7982/7990/1 4169/4177/1 4172/4180/1 7983/7991/1 +f 7987/7995/1 7992/8000/1 4169/4177/1 7982/7990/1 +f 7992/8000/1 7991/7999/1 4170/4178/1 4169/4177/1 +f 7994/8002/1 4165/4173/1 4168/4176/1 7995/8003/1 +f 7999/8007/1 8004/8012/1 4165/4173/1 7994/8002/1 +f 8004/8012/1 8003/8011/1 4166/4174/1 4165/4173/1 +f 8006/8014/1 4161/4169/1 4164/4172/1 8007/8015/1 +f 8011/8019/1 8016/8024/1 4161/4169/1 8006/8014/1 +f 8016/8024/1 8015/8023/1 4162/4170/1 4161/4169/1 +f 8018/8026/1 4157/4165/1 4160/4168/1 8019/8027/1 +f 8023/8031/1 8028/8036/1 4157/4165/1 8018/8026/1 +f 8028/8036/1 8027/8035/1 4158/4166/1 4157/4165/1 +f 8030/8038/1 4153/4161/1 4156/4164/1 8031/8039/1 +f 8035/8043/1 8040/8048/1 4153/4161/1 8030/8038/1 +f 8040/8048/1 8039/8047/1 4154/4162/1 4153/4161/1 +f 8042/8050/1 4149/4157/1 4152/4160/1 8043/8051/1 +f 8047/8055/1 8052/8060/1 4149/4157/1 8042/8050/1 +f 8052/8060/1 8051/8059/1 4150/4158/1 4149/4157/1 +f 8054/8062/1 4145/4153/1 4148/4156/1 8055/8063/1 +f 8059/8067/1 8064/8072/1 4145/4153/1 8054/8062/1 +f 8064/8072/1 8063/8071/1 4146/4154/1 4145/4153/1 +f 8066/8074/1 4141/4149/1 4144/4152/1 8067/8075/1 +f 8071/8079/1 8076/8084/1 4141/4149/1 8066/8074/1 +f 8076/8084/1 8075/8083/1 4142/4150/1 4141/4149/1 +f 8078/8086/1 4137/4145/1 4140/4148/1 8079/8087/1 +f 8083/8091/1 8088/8096/1 4137/4145/1 8078/8086/1 +f 8088/8096/1 8087/8095/1 4138/4146/1 4137/4145/1 +f 8090/8098/1 4133/4141/1 4136/4144/1 8091/8099/1 +f 8095/8103/1 8100/8108/1 4133/4141/1 8090/8098/1 +f 8100/8108/1 8099/8107/1 4134/4142/1 4133/4141/1 +f 8102/8110/1 4129/4137/1 4132/4140/1 8103/8111/1 +f 8107/8115/1 8112/8120/1 4129/4137/1 8102/8110/1 +f 8112/8120/1 8111/8119/1 4130/4138/1 4129/4137/1 +f 8114/8122/1 4125/4133/1 4128/4136/1 8115/8123/1 +f 8119/8127/1 8124/8132/1 4125/4133/1 8114/8122/1 +f 8124/8132/1 8123/8131/1 4126/4134/1 4125/4133/1 +f 8126/8134/1 4121/4129/1 4124/4132/1 8127/8135/1 +f 8131/8139/1 8136/8144/1 4121/4129/1 8126/8134/1 +f 8136/8144/1 8135/8143/1 4122/4130/1 4121/4129/1 +f 8138/8146/1 4117/4125/1 4120/4128/1 8139/8147/1 +f 8143/8151/1 8148/8156/1 4117/4125/1 8138/8146/1 +f 8148/8156/1 8147/8155/1 4118/4126/1 4117/4125/1 +f 8150/8158/1 4113/4121/1 4116/4124/1 8151/8159/1 +f 8155/8163/1 8160/8168/1 4113/4121/1 8150/8158/1 +f 8160/8168/1 8159/8167/1 4114/4122/1 4113/4121/1 +f 8162/8170/1 4109/4117/1 4112/4120/1 8163/8171/1 +f 8167/8175/1 8172/8180/1 4109/4117/1 8162/8170/1 +f 8172/8180/1 8171/8179/1 4110/4118/1 4109/4117/1 +f 8174/8182/1 4105/4113/1 4108/4116/1 8175/8183/1 +f 8179/8187/1 8184/8192/1 4105/4113/1 8174/8182/1 +f 8184/8192/1 8183/8191/1 4106/4114/1 4105/4113/1 +f 8186/8194/1 4101/4109/1 4104/4112/1 8187/8195/1 +f 8191/8199/1 8196/8204/1 4101/4109/1 8186/8194/1 +f 8196/8204/1 8195/8203/1 4102/4110/1 4101/4109/1 +f 8198/8206/1 4097/4105/1 4100/4108/1 8199/8207/1 +f 8203/8211/1 8208/8216/1 4097/4105/1 8198/8206/1 +f 8208/8216/1 8207/8215/1 4098/4106/1 4097/4105/1 +f 8210/8218/1 4093/4101/1 4096/4104/1 8211/8219/1 +f 8215/8223/1 8220/8228/1 4093/4101/1 8210/8218/1 +f 8220/8228/1 8219/8227/1 4094/4102/1 4093/4101/1 +f 8222/8230/1 4089/4097/1 4092/4100/1 8223/8231/1 +f 8227/8235/1 8232/8240/1 4089/4097/1 8222/8230/1 +f 8232/8240/1 8231/8239/1 4090/4098/1 4089/4097/1 +f 8234/8242/1 4085/4093/1 4088/4096/1 8235/8243/1 +f 8239/8247/1 8244/8252/1 4085/4093/1 8234/8242/1 +f 8244/8252/1 8243/8251/1 4086/4094/1 4085/4093/1 +f 8246/8254/1 4081/4089/1 4084/4092/1 8247/8255/1 +f 8251/8259/1 8256/8264/1 4081/4089/1 8246/8254/1 +f 8256/8264/1 8255/8263/1 4082/4090/1 4081/4089/1 +f 8258/8266/1 4077/4085/1 4080/4088/1 8259/8267/1 +f 8263/8271/1 8268/8276/1 4077/4085/1 8258/8266/1 +f 8268/8276/1 8267/8275/1 4078/4086/1 4077/4085/1 +f 8270/8278/1 4073/4081/1 4076/4084/1 8271/8279/1 +f 8275/8283/1 8280/8288/1 4073/4081/1 8270/8278/1 +f 8280/8288/1 8279/8287/1 4074/4082/1 4073/4081/1 +f 8282/8290/1 4069/4077/1 4072/4080/1 8283/8291/1 +f 8287/8295/1 8292/8300/1 4069/4077/1 8282/8290/1 +f 8292/8300/1 8291/8299/1 4070/4078/1 4069/4077/1 +f 8294/8302/1 4065/4073/1 4068/4076/1 8295/8303/1 +f 8299/8307/1 8304/8312/1 4065/4073/1 8294/8302/1 +f 8304/8312/1 8303/8311/1 4066/4074/1 4065/4073/1 +f 8306/8314/1 4061/4069/1 4064/4072/1 8307/8315/1 +f 8311/8319/1 8316/8324/1 4061/4069/1 8306/8314/1 +f 8316/8324/1 8315/8323/1 4062/4070/1 4061/4069/1 +f 8318/8326/1 4057/4065/1 4060/4068/1 8319/8327/1 +f 8323/8331/1 8328/8336/1 4057/4065/1 8318/8326/1 +f 8328/8336/1 8327/8335/1 4058/4066/1 4057/4065/1 +f 8330/8338/1 4053/4061/1 4056/4064/1 8331/8339/1 +f 8335/8343/1 8340/8348/1 4053/4061/1 8330/8338/1 +f 8340/8348/1 8339/8347/1 4054/4062/1 4053/4061/1 +f 8342/8350/1 4049/4057/1 4052/4060/1 8343/8351/1 +f 8347/8355/1 8352/8360/1 4049/4057/1 8342/8350/1 +f 8352/8360/1 8351/8359/1 4050/4058/1 4049/4057/1 +f 8354/8362/1 4045/4053/1 4048/4056/1 8355/8363/1 +f 8359/8367/1 8364/8372/1 4045/4053/1 8354/8362/1 +f 8364/8372/1 8363/8371/1 4046/4054/1 4045/4053/1 +f 8366/8374/1 4041/4049/1 4044/4052/1 8367/8375/1 +f 8371/8379/1 8376/8384/1 4041/4049/1 8366/8374/1 +f 8376/8384/1 8375/8383/1 4042/4050/1 4041/4049/1 +f 8378/8386/1 4037/4045/1 4040/4048/1 8379/8387/1 +f 8383/8391/1 8388/8396/1 4037/4045/1 8378/8386/1 +f 8388/8396/1 8387/8395/1 4038/4046/1 4037/4045/1 +f 8390/8398/1 4033/4041/1 4036/4044/1 8391/8399/1 +f 8395/8403/1 8400/8408/1 4033/4041/1 8390/8398/1 +f 8400/8408/1 8399/8407/1 4034/4042/1 4033/4041/1 +f 8402/8410/1 4029/4037/1 4032/4040/1 8403/8411/1 +f 8407/8415/1 8412/8420/1 4029/4037/1 8402/8410/1 +f 8412/8420/1 8411/8419/1 4030/4038/1 4029/4037/1 +f 8414/8422/1 4025/4033/1 4028/4036/1 8415/8423/1 +f 8419/8427/1 8424/8432/1 4025/4033/1 8414/8422/1 +f 8424/8432/1 8423/8431/1 4026/4034/1 4025/4033/1 +f 8426/8434/1 4021/4029/1 4024/4032/1 8427/8435/1 +f 8431/8439/1 8436/8444/1 4021/4029/1 8426/8434/1 +f 8436/8444/1 8435/8443/1 4022/4030/1 4021/4029/1 +f 8438/8446/1 4017/4025/1 4020/4028/1 8439/8447/1 +f 8443/8451/1 8448/8456/1 4017/4025/1 8438/8446/1 +f 8448/8456/1 8447/8455/1 4018/4026/1 4017/4025/1 +f 8450/8458/1 4013/4021/1 4016/4024/1 8451/8459/1 +f 8455/8463/1 8460/8468/1 4013/4021/1 8450/8458/1 +f 8460/8468/1 8459/8467/1 4014/4022/1 4013/4021/1 +f 8462/8470/1 4009/4017/1 4012/4020/1 8463/8471/1 +f 8467/8475/1 8472/8480/1 4009/4017/1 8462/8470/1 +f 8472/8480/1 8471/8479/1 4010/4018/1 4009/4017/1 +f 8474/8482/1 4005/4013/1 4008/4016/1 8475/8483/1 +f 8479/8487/1 8484/8492/1 4005/4013/1 8474/8482/1 +f 8484/8492/1 8483/8491/1 4006/4014/1 4005/4013/1 +f 8486/8494/1 4001/4009/1 4004/4012/1 8487/8495/1 +f 8491/8499/1 8496/8504/1 4001/4009/1 8486/8494/1 +f 8496/8504/1 8495/8503/1 4002/4010/1 4001/4009/1 +f 8498/8506/1 3997/4005/1 4000/4008/1 8499/8507/1 +f 8503/8511/1 8508/8516/1 3997/4005/1 8498/8506/1 +f 8508/8516/1 8507/8515/1 3998/4006/1 3997/4005/1 +f 8510/8518/1 3993/4001/1 3996/4004/1 8511/8519/1 +f 8515/8523/1 8520/8528/1 3993/4001/1 8510/8518/1 +f 8520/8528/1 8519/8527/1 3994/4002/1 3993/4001/1 +f 8522/8530/1 3989/3997/1 3992/4000/1 8523/8531/1 +f 8527/8535/1 8532/8540/1 3989/3997/1 8522/8530/1 +f 8532/8540/1 8531/8539/1 3990/3998/1 3989/3997/1 +f 8534/8542/1 3985/3993/1 3988/3996/1 8535/8543/1 +f 8539/8547/1 8544/8552/1 3985/3993/1 8534/8542/1 +f 8544/8552/1 8543/8551/1 3986/3994/1 3985/3993/1 +f 8546/8554/1 3981/3989/1 3984/3992/1 8547/8555/1 +f 8551/8559/1 8556/8564/1 3981/3989/1 8546/8554/1 +f 8556/8564/1 8555/8563/1 3982/3990/1 3981/3989/1 +f 8558/8566/1 3977/3985/1 3980/3988/1 8559/8567/1 +f 8563/8571/1 8568/8576/1 3977/3985/1 8558/8566/1 +f 8568/8576/1 8567/8575/1 3978/3986/1 3977/3985/1 +f 8570/8578/1 3973/3981/1 3976/3984/1 8571/8579/1 +f 8575/8583/1 8580/8588/1 3973/3981/1 8570/8578/1 +f 8580/8588/1 8579/8587/1 3974/3982/1 3973/3981/1 +f 8582/8590/1 3969/3977/1 3972/3980/1 8583/8591/1 +f 8587/8595/1 8592/8600/1 3969/3977/1 8582/8590/1 +f 8592/8600/1 8591/8599/1 3970/3978/1 3969/3977/1 +f 8594/8602/1 3965/3973/1 3968/3976/1 8595/8603/1 +f 8599/8607/1 8604/8612/1 3965/3973/1 8594/8602/1 +f 8604/8612/1 8603/8611/1 3966/3974/1 3965/3973/1 +f 8606/8614/1 3961/3969/1 3964/3972/1 8607/8615/1 +f 8611/8619/1 8616/8624/1 3961/3969/1 8606/8614/1 +f 8616/8624/1 8615/8623/1 3962/3970/1 3961/3969/1 +f 8618/8626/1 3957/3965/1 3960/3968/1 8619/8627/1 +f 8623/8631/1 8628/8636/1 3957/3965/1 8618/8626/1 +f 8628/8636/1 8627/8635/1 3958/3966/1 3957/3965/1 +f 8630/8638/1 3953/3961/1 3956/3964/1 8631/8639/1 +f 8635/8643/1 8640/8648/1 3953/3961/1 8630/8638/1 +f 8640/8648/1 8639/8647/1 3954/3962/1 3953/3961/1 +f 8642/8650/1 3949/3957/1 3952/3960/1 8643/8651/1 +f 8647/8655/1 8652/8660/1 3949/3957/1 8642/8650/1 +f 8652/8660/1 8651/8659/1 3950/3958/1 3949/3957/1 +f 8654/8662/1 3945/3953/1 3948/3956/1 8655/8663/1 +f 8659/8667/1 8664/8672/1 3945/3953/1 8654/8662/1 +f 8664/8672/1 8663/8671/1 3946/3954/1 3945/3953/1 +f 8666/8674/1 3941/3949/1 3944/3952/1 8667/8675/1 +f 8671/8679/1 8676/8684/1 3941/3949/1 8666/8674/1 +f 8676/8684/1 8675/8683/1 3942/3950/1 3941/3949/1 +f 8678/8686/1 3937/3945/1 3940/3948/1 8679/8687/1 +f 8683/8691/1 8688/8696/1 3937/3945/1 8678/8686/1 +f 8688/8696/1 8687/8695/1 3938/3946/1 3937/3945/1 +f 8690/8698/1 3933/3941/1 3936/3944/1 8691/8699/1 +f 8695/8703/1 8700/8708/1 3933/3941/1 8690/8698/1 +f 8700/8708/1 8699/8707/1 3934/3942/1 3933/3941/1 +f 8702/8710/1 3929/3937/1 3932/3940/1 8703/8711/1 +f 8707/8715/1 8712/8720/1 3929/3937/1 8702/8710/1 +f 8712/8720/1 8711/8719/1 3930/3938/1 3929/3937/1 +f 8714/8722/1 3925/3933/1 3928/3936/1 8715/8723/1 +f 8719/8727/1 8724/8732/1 3925/3933/1 8714/8722/1 +f 8724/8732/1 8723/8731/1 3926/3934/1 3925/3933/1 +f 8726/8734/1 3921/3929/1 3924/3932/1 8727/8735/1 +f 8731/8739/1 8736/8744/1 3921/3929/1 8726/8734/1 +f 8736/8744/1 8735/8743/1 3922/3930/1 3921/3929/1 +f 8738/8746/1 3917/3925/1 3920/3928/1 8739/8747/1 +f 8743/8751/1 8748/8756/1 3917/3925/1 8738/8746/1 +f 8748/8756/1 8747/8755/1 3918/3926/1 3917/3925/1 +f 8750/8758/1 3913/3921/1 3916/3924/1 8751/8759/1 +f 8755/8763/1 8760/8768/1 3913/3921/1 8750/8758/1 +f 8760/8768/1 8759/8767/1 3914/3922/1 3913/3921/1 +f 8762/8770/1 3909/3917/1 3912/3920/1 8763/8771/1 +f 8767/8775/1 8772/8780/1 3909/3917/1 8762/8770/1 +f 8772/8780/1 8771/8779/1 3910/3918/1 3909/3917/1 +f 8774/8782/1 3905/3913/1 3908/3916/1 8775/8783/1 +f 8779/8787/1 8784/8792/1 3905/3913/1 8774/8782/1 +f 8784/8792/1 8783/8791/1 3906/3914/1 3905/3913/1 +f 8786/8794/1 3901/3909/1 3904/3912/1 8787/8795/1 +f 8791/8799/1 8796/8804/1 3901/3909/1 8786/8794/1 +f 8796/8804/1 8795/8803/1 3902/3910/1 3901/3909/1 +f 8798/8806/1 3897/3905/1 3900/3908/1 8799/8807/1 +f 8803/8811/1 8808/8816/1 3897/3905/1 8798/8806/1 +f 8808/8816/1 8807/8815/1 3898/3906/1 3897/3905/1 +f 8810/8818/1 3893/3901/1 3896/3904/1 8811/8819/1 +f 8815/8823/1 8820/8828/1 3893/3901/1 8810/8818/1 +f 8820/8828/1 8819/8827/1 3894/3902/1 3893/3901/1 +f 8822/8830/1 3889/3897/1 3892/3900/1 8823/8831/1 +f 8827/8835/1 8832/8840/1 3889/3897/1 8822/8830/1 +f 8832/8840/1 8831/8839/1 3890/3898/1 3889/3897/1 +f 8834/8842/1 3885/3893/1 3888/3896/1 8835/8843/1 +f 8839/8847/1 8844/8852/1 3885/3893/1 8834/8842/1 +f 8844/8852/1 8843/8851/1 3886/3894/1 3885/3893/1 +f 8846/8854/1 3881/3889/1 3884/3892/1 8847/8855/1 +f 8851/8859/1 8856/8864/1 3881/3889/1 8846/8854/1 +f 8856/8864/1 8855/8863/1 3882/3890/1 3881/3889/1 +f 8858/8866/1 3877/3885/1 3880/3888/1 8859/8867/1 +f 8863/8871/1 8868/8876/1 3877/3885/1 8858/8866/1 +f 8868/8876/1 8867/8875/1 3878/3886/1 3877/3885/1 +f 8870/8878/1 3873/3881/1 3876/3884/1 8871/8879/1 +f 8875/8883/1 8880/8888/1 3873/3881/1 8870/8878/1 +f 8880/8888/1 8879/8887/1 3874/3882/1 3873/3881/1 +f 8882/8890/1 3869/3877/1 3872/3880/1 8883/8891/1 +f 8887/8895/1 8892/8900/1 3869/3877/1 8882/8890/1 +f 8892/8900/1 8891/8899/1 3870/3878/1 3869/3877/1 +f 8894/8902/1 3865/3873/1 3868/3876/1 8895/8903/1 +f 8899/8907/1 8904/8912/1 3865/3873/1 8894/8902/1 +f 8904/8912/1 8903/8911/1 3866/3874/1 3865/3873/1 +f 8906/8914/1 3861/3869/1 3864/3872/1 8907/8915/1 +f 8911/8919/1 8916/8924/1 3861/3869/1 8906/8914/1 +f 8916/8924/1 8915/8923/1 3862/3870/1 3861/3869/1 +f 8918/8926/1 3857/3865/1 3860/3868/1 8919/8927/1 +f 8923/8931/1 8928/8936/1 3857/3865/1 8918/8926/1 +f 8928/8936/1 8927/8935/1 3858/3866/1 3857/3865/1 +f 8930/8938/1 3853/3861/1 3856/3864/1 8931/8939/1 +f 8935/8943/1 8940/8948/1 3853/3861/1 8930/8938/1 +f 8940/8948/1 8939/8947/1 3854/3862/1 3853/3861/1 +f 8942/8950/1 3849/3857/1 3852/3860/1 8943/8951/1 +f 8947/8955/1 8952/8960/1 3849/3857/1 8942/8950/1 +f 8952/8960/1 8951/8959/1 3850/3858/1 3849/3857/1 +f 8954/8962/1 3845/3853/1 3848/3856/1 8955/8963/1 +f 8959/8967/1 8964/8972/1 3845/3853/1 8954/8962/1 +f 8964/8972/1 8963/8971/1 3846/3854/1 3845/3853/1 +f 8966/8974/1 3841/3849/1 3844/3852/1 8967/8975/1 +f 8971/8979/1 8976/8984/1 3841/3849/1 8966/8974/1 +f 8976/8984/1 8975/8983/1 3842/3850/1 3841/3849/1 +f 8978/8986/1 3837/3845/1 3840/3848/1 8979/8987/1 +f 8983/8991/1 8988/8996/1 3837/3845/1 8978/8986/1 +f 8988/8996/1 8987/8995/1 3838/3846/1 3837/3845/1 +f 8990/8998/1 3833/3841/1 3836/3844/1 8991/8999/1 +f 8995/9003/1 9000/9008/1 3833/3841/1 8990/8998/1 +f 9000/9008/1 8999/9007/1 3834/3842/1 3833/3841/1 +f 9002/9010/1 3829/3837/1 3832/3840/1 9003/9011/1 +f 9007/9015/1 9012/9020/1 3829/3837/1 9002/9010/1 +f 9012/9020/1 9011/9019/1 3830/3838/1 3829/3837/1 +f 9014/9022/1 3825/3833/1 3828/3836/1 9015/9023/1 +f 9019/9027/1 9024/9032/1 3825/3833/1 9014/9022/1 +f 9024/9032/1 9023/9031/1 3826/3834/1 3825/3833/1 +f 9026/9034/1 3821/3829/1 3824/3832/1 9027/9035/1 +f 9031/9039/1 9036/9044/1 3821/3829/1 9026/9034/1 +f 9036/9044/1 9035/9043/1 3822/3830/1 3821/3829/1 +f 9038/9046/1 3817/3825/1 3820/3828/1 9039/9047/1 +f 9043/9051/1 9048/9056/1 3817/3825/1 9038/9046/1 +f 9048/9056/1 9047/9055/1 3818/3826/1 3817/3825/1 +f 9050/9058/1 3813/3821/1 3816/3824/1 9051/9059/1 +f 9055/9063/1 9060/9068/1 3813/3821/1 9050/9058/1 +f 9060/9068/1 9059/9067/1 3814/3822/1 3813/3821/1 +f 9062/9070/1 3809/3817/1 3812/3820/1 9063/9071/1 +f 9067/9075/1 9072/9080/1 3809/3817/1 9062/9070/1 +f 9072/9080/1 9071/9079/1 3810/3818/1 3809/3817/1 +f 9074/9082/1 3805/3813/1 3808/3816/1 9075/9083/1 +f 9079/9087/1 9084/9092/1 3805/3813/1 9074/9082/1 +f 9084/9092/1 9083/9091/1 3806/3814/1 3805/3813/1 +f 9086/9094/1 3801/3809/1 3804/3812/1 9087/9095/1 +f 9091/9099/1 9096/9104/1 3801/3809/1 9086/9094/1 +f 9096/9104/1 9095/9103/1 3802/3810/1 3801/3809/1 +f 9098/9106/1 3797/3805/1 3800/3808/1 9099/9107/1 +f 9103/9111/1 9108/9116/1 3797/3805/1 9098/9106/1 +f 9108/9116/1 9107/9115/1 3798/3806/1 3797/3805/1 +f 9110/9118/1 3793/3801/1 3796/3804/1 9111/9119/1 +f 9115/9123/1 9120/9128/1 3793/3801/1 9110/9118/1 +f 9120/9128/1 9119/9127/1 3794/3802/1 3793/3801/1 +f 9122/9130/1 3789/3797/1 3792/3800/1 9123/9131/1 +f 9127/9135/1 9132/9140/1 3789/3797/1 9122/9130/1 +f 9132/9140/1 9131/9139/1 3790/3798/1 3789/3797/1 +f 9134/9142/1 3785/3793/1 3788/3796/1 9135/9143/1 +f 9139/9147/1 9144/9152/1 3785/3793/1 9134/9142/1 +f 9144/9152/1 9143/9151/1 3786/3794/1 3785/3793/1 +f 9146/9154/1 3781/3789/1 3784/3792/1 9147/9155/1 +f 9151/9159/1 9156/9164/1 3781/3789/1 9146/9154/1 +f 9156/9164/1 9155/9163/1 3782/3790/1 3781/3789/1 +f 9158/9166/1 3777/3785/1 3780/3788/1 9159/9167/1 +f 9163/9171/1 9168/9176/1 3777/3785/1 9158/9166/1 +f 9168/9176/1 9167/9175/1 3778/3786/1 3777/3785/1 +f 9170/9178/1 3773/3781/1 3776/3784/1 9171/9179/1 +f 9175/9183/1 9180/9188/1 3773/3781/1 9170/9178/1 +f 9180/9188/1 9179/9187/1 3774/3782/1 3773/3781/1 +f 9182/9190/1 3769/3777/1 3772/3780/1 9183/9191/1 +f 9187/9195/1 9192/9200/1 3769/3777/1 9182/9190/1 +f 9192/9200/1 9191/9199/1 3770/3778/1 3769/3777/1 +f 9194/9202/1 3765/3773/1 3768/3776/1 9195/9203/1 +f 9199/9207/1 9204/9212/1 3765/3773/1 9194/9202/1 +f 9204/9212/1 9203/9211/1 3766/3774/1 3765/3773/1 +f 9206/9214/1 3761/3769/1 3764/3772/1 9207/9215/1 +f 9211/9219/1 9216/9224/1 3761/3769/1 9206/9214/1 +f 9216/9224/1 9215/9223/1 3762/3770/1 3761/3769/1 +f 9218/9226/1 3757/3765/1 3760/3768/1 9219/9227/1 +f 9223/9231/1 9228/9236/1 3757/3765/1 9218/9226/1 +f 9228/9236/1 9227/9235/1 3758/3766/1 3757/3765/1 +f 9230/9238/1 3753/3761/1 3756/3764/1 9231/9239/1 +f 9235/9243/1 9240/9248/1 3753/3761/1 9230/9238/1 +f 9240/9248/1 9239/9247/1 3754/3762/1 3753/3761/1 +f 9242/9250/1 3749/3757/1 3752/3760/1 9243/9251/1 +f 9247/9255/1 9252/9260/1 3749/3757/1 9242/9250/1 +f 9252/9260/1 9251/9259/1 3750/3758/1 3749/3757/1 +f 9254/9262/1 3745/3753/1 3748/3756/1 9255/9263/1 +f 9259/9267/1 9264/9272/1 3745/3753/1 9254/9262/1 +f 9264/9272/1 9263/9271/1 3746/3754/1 3745/3753/1 +f 9266/9274/1 3741/3749/1 3744/3752/1 9267/9275/1 +f 9271/9279/1 9276/9284/1 3741/3749/1 9266/9274/1 +f 9276/9284/1 9275/9283/1 3742/3750/1 3741/3749/1 +f 9278/9286/1 3737/3745/1 3740/3748/1 9279/9287/1 +f 9283/9291/1 9288/9296/1 3737/3745/1 9278/9286/1 +f 9288/9296/1 9287/9295/1 3738/3746/1 3737/3745/1 +f 9290/9298/1 3733/3741/1 3736/3744/1 9291/9299/1 +f 9295/9303/1 9300/9308/1 3733/3741/1 9290/9298/1 +f 9300/9308/1 9299/9307/1 3734/3742/1 3733/3741/1 +f 9302/9310/1 3729/3737/1 3732/3740/1 9303/9311/1 +f 9307/9315/1 9312/9320/1 3729/3737/1 9302/9310/1 +f 9312/9320/1 9311/9319/1 3730/3738/1 3729/3737/1 +f 9314/9322/1 3725/3733/1 3728/3736/1 9315/9323/1 +f 9319/9327/1 9324/9332/1 3725/3733/1 9314/9322/1 +f 9324/9332/1 9323/9331/1 3726/3734/1 3725/3733/1 +f 9326/9334/1 3721/3729/1 3724/3732/1 9327/9335/1 +f 9331/9339/1 9336/9344/1 3721/3729/1 9326/9334/1 +f 9336/9344/1 9335/9343/1 3722/3730/1 3721/3729/1 +f 9338/9346/1 3717/3725/1 3720/3728/1 9339/9347/1 +f 9343/9351/1 9348/9356/1 3717/3725/1 9338/9346/1 +f 9348/9356/1 9347/9355/1 3718/3726/1 3717/3725/1 +f 9350/9358/1 3713/3721/1 3716/3724/1 9351/9359/1 +f 9355/9363/1 9360/9368/1 3713/3721/1 9350/9358/1 +f 9360/9368/1 9359/9367/1 3714/3722/1 3713/3721/1 +f 9362/9370/1 3709/3717/1 3712/3720/1 9363/9371/1 +f 9367/9375/1 9372/9380/1 3709/3717/1 9362/9370/1 +f 9372/9380/1 9371/9379/1 3710/3718/1 3709/3717/1 +f 9374/9382/1 3705/3713/1 3708/3716/1 9375/9383/1 +f 9379/9387/1 9384/9392/1 3705/3713/1 9374/9382/1 +f 9384/9392/1 9383/9391/1 3706/3714/1 3705/3713/1 +f 9386/9394/1 3701/3709/1 3704/3712/1 9387/9395/1 +f 9391/9399/1 9396/9404/1 3701/3709/1 9386/9394/1 +f 9396/9404/1 9395/9403/1 3702/3710/1 3701/3709/1 +f 9398/9406/1 3697/3705/1 3700/3708/1 9399/9407/1 +f 9403/9411/1 9408/9416/1 3697/3705/1 9398/9406/1 +f 9408/9416/1 9407/9415/1 3698/3706/1 3697/3705/1 +f 9410/9418/1 3693/3701/1 3696/3704/1 9411/9419/1 +f 9415/9423/1 9420/9428/1 3693/3701/1 9410/9418/1 +f 9420/9428/1 9419/9427/1 3694/3702/1 3693/3701/1 +f 9422/9430/1 3689/3697/1 3692/3700/1 9423/9431/1 +f 9427/9435/1 9432/9440/1 3689/3697/1 9422/9430/1 +f 9432/9440/1 9431/9439/1 3690/3698/1 3689/3697/1 +f 9434/9442/1 3685/3693/1 3688/3696/1 9435/9443/1 +f 9439/9447/1 9444/9452/1 3685/3693/1 9434/9442/1 +f 9444/9452/1 9443/9451/1 3686/3694/1 3685/3693/1 +f 9446/9454/1 3681/3689/1 3684/3692/1 9447/9455/1 +f 9451/9459/1 9456/9464/1 3681/3689/1 9446/9454/1 +f 9456/9464/1 9455/9463/1 3682/3690/1 3681/3689/1 +f 9458/9466/1 3677/3685/1 3680/3688/1 9459/9467/1 +f 9463/9471/1 9468/9476/1 3677/3685/1 9458/9466/1 +f 9468/9476/1 9467/9475/1 3678/3686/1 3677/3685/1 +f 9470/9478/1 3673/3681/1 3676/3684/1 9471/9479/1 +f 9475/9483/1 9480/9488/1 3673/3681/1 9470/9478/1 +f 9480/9488/1 9479/9487/1 3674/3682/1 3673/3681/1 +f 9482/9490/1 3669/3677/1 3672/3680/1 9483/9491/1 +f 9487/9495/1 9492/9500/1 3669/3677/1 9482/9490/1 +f 9492/9500/1 9491/9499/1 3670/3678/1 3669/3677/1 +f 9494/9502/1 3665/3673/1 3668/3676/1 9495/9503/1 +f 9499/9507/1 9504/9512/1 3665/3673/1 9494/9502/1 +f 9504/9512/1 9503/9511/1 3666/3674/1 3665/3673/1 +f 9506/9514/1 3661/3669/1 3664/3672/1 9507/9515/1 +f 9511/9519/1 9516/9524/1 3661/3669/1 9506/9514/1 +f 9516/9524/1 9515/9523/1 3662/3670/1 3661/3669/1 +f 9518/9526/1 3657/3665/1 3660/3668/1 9519/9527/1 +f 9523/9531/1 9528/9536/1 3657/3665/1 9518/9526/1 +f 9528/9536/1 9527/9535/1 3658/3666/1 3657/3665/1 +f 9530/9538/1 3653/3661/1 3656/3664/1 9531/9539/1 +f 9535/9543/1 9540/9548/1 3653/3661/1 9530/9538/1 +f 9540/9548/1 9539/9547/1 3654/3662/1 3653/3661/1 +f 9542/9550/1 3649/3657/1 3652/3660/1 9543/9551/1 +f 9547/9555/1 9552/9560/1 3649/3657/1 9542/9550/1 +f 9552/9560/1 9551/9559/1 3650/3658/1 3649/3657/1 +f 9554/9562/1 3645/3653/1 3648/3656/1 9555/9563/1 +f 9559/9567/1 9564/9572/1 3645/3653/1 9554/9562/1 +f 9564/9572/1 9563/9571/1 3646/3654/1 3645/3653/1 +f 9566/9574/1 3641/3649/1 3644/3652/1 9567/9575/1 +f 9571/9579/1 9576/9584/1 3641/3649/1 9566/9574/1 +f 9576/9584/1 9575/9583/1 3642/3650/1 3641/3649/1 +f 9578/9586/1 3637/3645/1 3640/3648/1 9579/9587/1 +f 9583/9591/1 9588/9596/1 3637/3645/1 9578/9586/1 +f 9588/9596/1 9587/9595/1 3638/3646/1 3637/3645/1 +f 9590/9598/1 3633/3641/1 3636/3644/1 9591/9599/1 +f 9595/9603/1 9600/9608/1 3633/3641/1 9590/9598/1 +f 9600/9608/1 9599/9607/1 3634/3642/1 3633/3641/1 +f 9602/9610/1 3629/3637/1 3632/3640/1 9603/9611/1 +f 9607/9615/1 9612/9620/1 3629/3637/1 9602/9610/1 +f 9612/9620/1 9611/9619/1 3630/3638/1 3629/3637/1 +f 9614/9622/1 3625/3633/1 3628/3636/1 9615/9623/1 +f 9619/9627/1 9624/9632/1 3625/3633/1 9614/9622/1 +f 9624/9632/1 9623/9631/1 3626/3634/1 3625/3633/1 +f 9626/9634/1 3621/3629/1 3624/3632/1 9627/9635/1 +f 9631/9639/1 9636/9644/1 3621/3629/1 9626/9634/1 +f 9636/9644/1 9635/9643/1 3622/3630/1 3621/3629/1 +f 9638/9646/1 3617/3625/1 3620/3628/1 9639/9647/1 +f 9643/9651/1 9648/9656/1 3617/3625/1 9638/9646/1 +f 9648/9656/1 9647/9655/1 3618/3626/1 3617/3625/1 +f 9650/9658/1 3613/3621/1 3616/3624/1 9651/9659/1 +f 9655/9663/1 9660/9668/1 3613/3621/1 9650/9658/1 +f 9660/9668/1 9659/9667/1 3614/3622/1 3613/3621/1 +f 9662/9670/1 3609/3617/1 3612/3620/1 9663/9671/1 +f 9667/9675/1 9672/9680/1 3609/3617/1 9662/9670/1 +f 9672/9680/1 9671/9679/1 3610/3618/1 3609/3617/1 +f 9674/9682/1 3605/3613/1 3608/3616/1 9675/9683/1 +f 9679/9687/1 9684/9692/1 3605/3613/1 9674/9682/1 +f 9684/9692/1 9683/9691/1 3606/3614/1 3605/3613/1 +f 9686/9694/1 3601/3609/1 3604/3612/1 9687/9695/1 +f 9691/9699/1 9696/9704/1 3601/3609/1 9686/9694/1 +f 9696/9704/1 9695/9703/1 3602/3610/1 3601/3609/1 +f 9698/9706/1 3597/3605/1 3600/3608/1 9699/9707/1 +f 9703/9711/1 9708/9716/1 3597/3605/1 9698/9706/1 +f 9708/9716/1 9707/9715/1 3598/3606/1 3597/3605/1 +f 9710/9718/1 3593/3601/1 3596/3604/1 9711/9719/1 +f 9715/9723/1 9720/9728/1 3593/3601/1 9710/9718/1 +f 9720/9728/1 9719/9727/1 3594/3602/1 3593/3601/1 +f 9722/9730/1 3589/3597/1 3592/3600/1 9723/9731/1 +f 9727/9735/1 9732/9740/1 3589/3597/1 9722/9730/1 +f 9732/9740/1 9731/9739/1 3590/3598/1 3589/3597/1 +f 9734/9742/1 3585/3593/1 3588/3596/1 9735/9743/1 +f 9739/9747/1 9744/9752/1 3585/3593/1 9734/9742/1 +f 9744/9752/1 9743/9751/1 3586/3594/1 3585/3593/1 +f 9746/9754/1 3581/3589/1 3584/3592/1 9747/9755/1 +f 9751/9759/1 9756/9764/1 3581/3589/1 9746/9754/1 +f 9756/9764/1 9755/9763/1 3582/3590/1 3581/3589/1 +f 9758/9766/1 3577/3585/1 3580/3588/1 9759/9767/1 +f 9763/9771/1 9768/9776/1 3577/3585/1 9758/9766/1 +f 9768/9776/1 9767/9775/1 3578/3586/1 3577/3585/1 +f 9770/9778/1 3573/3581/1 3576/3584/1 9771/9779/1 +f 9775/9783/1 9780/9788/1 3573/3581/1 9770/9778/1 +f 9780/9788/1 9779/9787/1 3574/3582/1 3573/3581/1 +f 9782/9790/1 3569/3577/1 3572/3580/1 9783/9791/1 +f 9787/9795/1 9792/9800/1 3569/3577/1 9782/9790/1 +f 9792/9800/1 9791/9799/1 3570/3578/1 3569/3577/1 +f 9794/9802/1 3565/3573/1 3568/3576/1 9795/9803/1 +f 9799/9807/1 9804/9812/1 3565/3573/1 9794/9802/1 +f 9804/9812/1 9803/9811/1 3566/3574/1 3565/3573/1 +f 9806/9814/1 3561/3569/1 3564/3572/1 9807/9815/1 +f 9811/9819/1 9816/9824/1 3561/3569/1 9806/9814/1 +f 9816/9824/1 9815/9823/1 3562/3570/1 3561/3569/1 +f 9818/9826/1 3557/3565/1 3560/3568/1 9819/9827/1 +f 9823/9831/1 9828/9836/1 3557/3565/1 9818/9826/1 +f 9828/9836/1 9827/9835/1 3558/3566/1 3557/3565/1 +f 9830/9838/1 3553/3561/1 3556/3564/1 9831/9839/1 +f 9835/9843/1 9840/9848/1 3553/3561/1 9830/9838/1 +f 9840/9848/1 9839/9847/1 3554/3562/1 3553/3561/1 +f 9842/9850/1 3549/3557/1 3552/3560/1 9843/9851/1 +f 9847/9855/1 9852/9860/1 3549/3557/1 9842/9850/1 +f 9852/9860/1 9851/9859/1 3550/3558/1 3549/3557/1 +f 9854/9862/1 3545/3553/1 3548/3556/1 9855/9863/1 +f 9859/9867/1 9864/9872/1 3545/3553/1 9854/9862/1 +f 9864/9872/1 9863/9871/1 3546/3554/1 3545/3553/1 +f 9866/9874/1 3541/3549/1 3544/3552/1 9867/9875/1 +f 9871/9879/1 9876/9884/1 3541/3549/1 9866/9874/1 +f 9876/9884/1 9875/9883/1 3542/3550/1 3541/3549/1 +f 9878/9886/1 3537/3545/1 3540/3548/1 9879/9887/1 +f 9883/9891/1 9888/9896/1 3537/3545/1 9878/9886/1 +f 9888/9896/1 9887/9895/1 3538/3546/1 3537/3545/1 +f 9890/9898/1 3533/3541/1 3536/3544/1 9891/9899/1 +f 9895/9903/1 9900/9908/1 3533/3541/1 9890/9898/1 +f 9900/9908/1 9899/9907/1 3534/3542/1 3533/3541/1 +f 9902/9910/1 3529/3537/1 3532/3540/1 9903/9911/1 +f 9907/9915/1 9912/9920/1 3529/3537/1 9902/9910/1 +f 9912/9920/1 9911/9919/1 3530/3538/1 3529/3537/1 +f 9914/9922/1 3525/3533/1 3528/3536/1 9915/9923/1 +f 9919/9927/1 9924/9932/1 3525/3533/1 9914/9922/1 +f 9924/9932/1 9923/9931/1 3526/3534/1 3525/3533/1 +f 9926/9934/1 3521/3529/1 3524/3532/1 9927/9935/1 +f 9931/9939/1 9936/9944/1 3521/3529/1 9926/9934/1 +f 9936/9944/1 9935/9943/1 3522/3530/1 3521/3529/1 +f 9938/9946/1 3517/3525/1 3520/3528/1 9939/9947/1 +f 9943/9951/1 9948/9956/1 3517/3525/1 9938/9946/1 +f 9948/9956/1 9947/9955/1 3518/3526/1 3517/3525/1 +f 9950/9958/1 3513/3521/1 3516/3524/1 9951/9959/1 +f 9955/9963/1 9960/9968/1 3513/3521/1 9950/9958/1 +f 9960/9968/1 9959/9967/1 3514/3522/1 3513/3521/1 +f 9962/9970/1 3509/3517/1 3512/3520/1 9963/9971/1 +f 9967/9975/1 9972/9980/1 3509/3517/1 9962/9970/1 +f 9972/9980/1 9971/9979/1 3510/3518/1 3509/3517/1 +f 9974/9982/1 3505/3513/1 3508/3516/1 9975/9983/1 +f 9979/9987/1 9984/9992/1 3505/3513/1 9974/9982/1 +f 9984/9992/1 9983/9991/1 3506/3514/1 3505/3513/1 +f 9986/9994/1 3501/3509/1 3504/3512/1 9987/9995/1 +f 9991/9999/1 9996/10004/1 3501/3509/1 9986/9994/1 +f 9996/10004/1 9995/10003/1 3502/3510/1 3501/3509/1 +f 9998/10006/1 3497/3505/1 3500/3508/1 9999/10007/1 +f 10003/10011/1 10008/10016/1 3497/3505/1 9998/10006/1 +f 10008/10016/1 10007/10015/1 3498/3506/1 3497/3505/1 +f 10010/10018/1 3493/3501/1 3496/3504/1 10011/10019/1 +f 10015/10023/1 10020/10028/1 3493/3501/1 10010/10018/1 +f 10020/10028/1 10019/10027/1 3494/3502/1 3493/3501/1 +f 10022/10030/1 3489/3497/1 3492/3500/1 10023/10031/1 +f 10027/10035/1 10032/10040/1 3489/3497/1 10022/10030/1 +f 10032/10040/1 10031/10039/1 3490/3498/1 3489/3497/1 +f 10034/10042/1 3485/3493/1 3488/3496/1 10035/10043/1 +f 10039/10047/1 10044/10052/1 3485/3493/1 10034/10042/1 +f 10044/10052/1 10043/10051/1 3486/3494/1 3485/3493/1 +f 10046/10054/1 3481/3489/1 3484/3492/1 10047/10055/1 +f 10051/10059/1 10056/10064/1 3481/3489/1 10046/10054/1 +f 10056/10064/1 10055/10063/1 3482/3490/1 3481/3489/1 +f 10058/10066/1 3477/3485/1 3480/3488/1 10059/10067/1 +f 10063/10071/1 10068/10076/1 3477/3485/1 10058/10066/1 +f 10068/10076/1 10067/10075/1 3478/3486/1 3477/3485/1 +f 10070/10078/1 3473/3481/1 3476/3484/1 10071/10079/1 +f 10075/10083/1 10080/10088/1 3473/3481/1 10070/10078/1 +f 10080/10088/1 10079/10087/1 3474/3482/1 3473/3481/1 +f 10082/10090/1 3469/3477/1 3472/3480/1 10083/10091/1 +f 10087/10095/1 10092/10100/1 3469/3477/1 10082/10090/1 +f 10092/10100/1 10091/10099/1 3470/3478/1 3469/3477/1 +f 10094/10102/1 3465/3473/1 3468/3476/1 10095/10103/1 +f 10099/10107/1 10104/10112/1 3465/3473/1 10094/10102/1 +f 10104/10112/1 10103/10111/1 3466/3474/1 3465/3473/1 +f 10106/10114/1 3461/3469/1 3464/3472/1 10107/10115/1 +f 10111/10119/1 10116/10124/1 3461/3469/1 10106/10114/1 +f 10116/10124/1 10115/10123/1 3462/3470/1 3461/3469/1 +f 10118/10126/1 3457/3465/1 3460/3468/1 10119/10127/1 +f 10123/10131/1 10128/10136/1 3457/3465/1 10118/10126/1 +f 10128/10136/1 10127/10135/1 3458/3466/1 3457/3465/1 +f 10130/10138/1 3453/3461/1 3456/3464/1 10131/10139/1 +f 10135/10143/1 10140/10148/1 3453/3461/1 10130/10138/1 +f 10140/10148/1 10139/10147/1 3454/3462/1 3453/3461/1 +f 10142/10150/1 3449/3457/1 3452/3460/1 10143/10151/1 +f 10147/10155/1 10152/10160/1 3449/3457/1 10142/10150/1 +f 10152/10160/1 10151/10159/1 3450/3458/1 3449/3457/1 +f 10154/10162/1 3445/3453/1 3448/3456/1 10155/10163/1 +f 10159/10167/1 10164/10172/1 3445/3453/1 10154/10162/1 +f 10164/10172/1 10163/10171/1 3446/3454/1 3445/3453/1 +f 10166/10174/1 3441/3449/1 3444/3452/1 10167/10175/1 +f 10171/10179/1 10176/10184/1 3441/3449/1 10166/10174/1 +f 10176/10184/1 10175/10183/1 3442/3450/1 3441/3449/1 +f 10178/10186/1 3437/3445/1 3440/3448/1 10179/10187/1 +f 10183/10191/1 10188/10196/1 3437/3445/1 10178/10186/1 +f 10188/10196/1 10187/10195/1 3438/3446/1 3437/3445/1 +f 10190/10198/1 3433/3441/1 3436/3444/1 10191/10199/1 +f 10195/10203/1 10200/10208/1 3433/3441/1 10190/10198/1 +f 10200/10208/1 10199/10207/1 3434/3442/1 3433/3441/1 +f 10202/10210/1 3429/3437/1 3432/3440/1 10203/10211/1 +f 10207/10215/1 10212/10220/1 3429/3437/1 10202/10210/1 +f 10212/10220/1 10211/10219/1 3430/3438/1 3429/3437/1 +f 10214/10222/1 3425/3433/1 3428/3436/1 10215/10223/1 +f 10219/10227/1 10224/10232/1 3425/3433/1 10214/10222/1 +f 10224/10232/1 10223/10231/1 3426/3434/1 3425/3433/1 +f 10226/10234/1 3421/3429/1 3424/3432/1 10227/10235/1 +f 10231/10239/1 10236/10244/1 3421/3429/1 10226/10234/1 +f 10236/10244/1 10235/10243/1 3422/3430/1 3421/3429/1 +f 10238/10246/1 3417/3425/1 3420/3428/1 10239/10247/1 +f 10243/10251/1 10248/10256/1 3417/3425/1 10238/10246/1 +f 10248/10256/1 10247/10255/1 3418/3426/1 3417/3425/1 +f 10250/10258/1 3413/3421/1 3416/3424/1 10251/10259/1 +f 10255/10263/1 10260/10268/1 3413/3421/1 10250/10258/1 +f 10260/10268/1 10259/10267/1 3414/3422/1 3413/3421/1 +f 10262/10270/1 3409/3417/1 3412/3420/1 10263/10271/1 +f 10267/10275/1 10272/10280/1 3409/3417/1 10262/10270/1 +f 10272/10280/1 10271/10279/1 3410/3418/1 3409/3417/1 +f 10274/10282/1 3405/3413/1 3408/3416/1 10275/10283/1 +f 10279/10287/1 10284/10292/1 3405/3413/1 10274/10282/1 +f 10284/10292/1 10283/10291/1 3406/3414/1 3405/3413/1 +f 10286/10294/1 3401/3409/1 3404/3412/1 10287/10295/1 +f 10291/10299/1 10296/10304/1 3401/3409/1 10286/10294/1 +f 10296/10304/1 10295/10303/1 3402/3410/1 3401/3409/1 +f 10298/10306/1 3397/3405/1 3400/3408/1 10299/10307/1 +f 10303/10311/1 10308/10316/1 3397/3405/1 10298/10306/1 +f 10308/10316/1 10307/10315/1 3398/3406/1 3397/3405/1 +f 10310/10318/1 3393/3401/1 3396/3404/1 10311/10319/1 +f 10315/10323/1 10320/10328/1 3393/3401/1 10310/10318/1 +f 10320/10328/1 10319/10327/1 3394/3402/1 3393/3401/1 +f 10322/10330/1 3389/3397/1 3392/3400/1 10323/10331/1 +f 10327/10335/1 10332/10340/1 3389/3397/1 10322/10330/1 +f 10332/10340/1 10331/10339/1 3390/3398/1 3389/3397/1 +f 10334/10342/1 3385/3393/1 3388/3396/1 10335/10343/1 +f 10339/10347/1 10344/10352/1 3385/3393/1 10334/10342/1 +f 10344/10352/1 10343/10351/1 3386/3394/1 3385/3393/1 +f 10346/10354/1 3381/3389/1 3384/3392/1 10347/10355/1 +f 10351/10359/1 10356/10364/1 3381/3389/1 10346/10354/1 +f 10356/10364/1 10355/10363/1 3382/3390/1 3381/3389/1 +f 10358/10366/1 3377/3385/1 3380/3388/1 10359/10367/1 +f 10363/10371/1 10368/10376/1 3377/3385/1 10358/10366/1 +f 10368/10376/1 10367/10375/1 3378/3386/1 3377/3385/1 +f 10370/10378/1 3373/3381/1 3376/3384/1 10371/10379/1 +f 10375/10383/1 10380/10388/1 3373/3381/1 10370/10378/1 +f 10380/10388/1 10379/10387/1 3374/3382/1 3373/3381/1 +f 10382/10390/1 3369/3377/1 3372/3380/1 10383/10391/1 +f 10387/10395/1 10392/10400/1 3369/3377/1 10382/10390/1 +f 10392/10400/1 10391/10399/1 3370/3378/1 3369/3377/1 +f 10394/10402/1 3365/3373/1 3368/3376/1 10395/10403/1 +f 10399/10407/1 10404/10412/1 3365/3373/1 10394/10402/1 +f 10404/10412/1 10403/10411/1 3366/3374/1 3365/3373/1 +f 10406/10414/1 3361/3369/1 3364/3372/1 10407/10415/1 +f 10411/10419/1 10416/10424/1 3361/3369/1 10406/10414/1 +f 10416/10424/1 10415/10423/1 3362/3370/1 3361/3369/1 +f 10418/10426/1 3357/3365/1 3360/3368/1 10419/10427/1 +f 10423/10431/1 10428/10436/1 3357/3365/1 10418/10426/1 +f 10428/10436/1 10427/10435/1 3358/3366/1 3357/3365/1 +f 10430/10438/1 3353/3361/1 3356/3364/1 10431/10439/1 +f 10435/10443/1 10440/10448/1 3353/3361/1 10430/10438/1 +f 10440/10448/1 10439/10447/1 3354/3362/1 3353/3361/1 +f 10442/10450/1 3349/3357/1 3352/3360/1 10443/10451/1 +f 10447/10455/1 10452/10460/1 3349/3357/1 10442/10450/1 +f 10452/10460/1 10451/10459/1 3350/3358/1 3349/3357/1 +f 10454/10462/1 3345/3353/1 3348/3356/1 10455/10463/1 +f 10459/10467/1 10464/10472/1 3345/3353/1 10454/10462/1 +f 10464/10472/1 10463/10471/1 3346/3354/1 3345/3353/1 +f 10466/10474/1 3341/3349/1 3344/3352/1 10467/10475/1 +f 10471/10479/1 10476/10484/1 3341/3349/1 10466/10474/1 +f 10476/10484/1 10475/10483/1 3342/3350/1 3341/3349/1 +f 10478/10486/1 3337/3345/1 3340/3348/1 10479/10487/1 +f 10483/10491/1 10488/10496/1 3337/3345/1 10478/10486/1 +f 10488/10496/1 10487/10495/1 3338/3346/1 3337/3345/1 +f 10490/10498/1 3333/3341/1 3336/3344/1 10491/10499/1 +f 10495/10503/1 10500/10508/1 3333/3341/1 10490/10498/1 +f 10500/10508/1 10499/10507/1 3334/3342/1 3333/3341/1 +f 10502/10510/1 3329/3337/1 3332/3340/1 10503/10511/1 +f 10507/10515/1 10512/10520/1 3329/3337/1 10502/10510/1 +f 10512/10520/1 10511/10519/1 3330/3338/1 3329/3337/1 +f 10514/10522/1 3325/3333/1 3328/3336/1 10515/10523/1 +f 10519/10527/1 10524/10532/1 3325/3333/1 10514/10522/1 +f 10524/10532/1 10523/10531/1 3326/3334/1 3325/3333/1 +f 10526/10534/1 3321/3329/1 3324/3332/1 10527/10535/1 +f 10531/10539/1 10536/10544/1 3321/3329/1 10526/10534/1 +f 10536/10544/1 10535/10543/1 3322/3330/1 3321/3329/1 +f 10538/10546/1 3317/3325/1 3320/3328/1 10539/10547/1 +f 10543/10551/1 10548/10556/1 3317/3325/1 10538/10546/1 +f 10548/10556/1 10547/10555/1 3318/3326/1 3317/3325/1 +f 10550/10558/1 3313/3321/1 3316/3324/1 10551/10559/1 +f 10555/10563/1 10560/10568/1 3313/3321/1 10550/10558/1 +f 10560/10568/1 10559/10567/1 3314/3322/1 3313/3321/1 +f 10562/10570/1 3309/3317/1 3312/3320/1 10563/10571/1 +f 10567/10575/1 10572/10580/1 3309/3317/1 10562/10570/1 +f 10572/10580/1 10571/10579/1 3310/3318/1 3309/3317/1 +f 10574/10582/1 3305/3313/1 3308/3316/1 10575/10583/1 +f 10579/10587/1 10584/10592/1 3305/3313/1 10574/10582/1 +f 10584/10592/1 10583/10591/1 3306/3314/1 3305/3313/1 +f 10586/10594/1 3301/3309/1 3304/3312/1 10587/10595/1 +f 10591/10599/1 10596/10604/1 3301/3309/1 10586/10594/1 +f 10596/10604/1 10595/10603/1 3302/3310/1 3301/3309/1 +f 10598/10606/1 3297/3305/1 3300/3308/1 10599/10607/1 +f 10603/10611/1 10608/10616/1 3297/3305/1 10598/10606/1 +f 10608/10616/1 10607/10615/1 3298/3306/1 3297/3305/1 +f 10610/10618/1 3293/3301/1 3296/3304/1 10611/10619/1 +f 10615/10623/1 10620/10628/1 3293/3301/1 10610/10618/1 +f 10620/10628/1 10619/10627/1 3294/3302/1 3293/3301/1 +f 10622/10630/1 3289/3297/1 3292/3300/1 10623/10631/1 +f 10627/10635/1 10632/10640/1 3289/3297/1 10622/10630/1 +f 10632/10640/1 10631/10639/1 3290/3298/1 3289/3297/1 +f 10634/10642/1 3285/3293/1 3288/3296/1 10635/10643/1 +f 10639/10647/1 10644/10652/1 3285/3293/1 10634/10642/1 +f 10644/10652/1 10643/10651/1 3286/3294/1 3285/3293/1 +f 10646/10654/1 3281/3289/1 3284/3292/1 10647/10655/1 +f 10651/10659/1 10656/10664/1 3281/3289/1 10646/10654/1 +f 10656/10664/1 10655/10663/1 3282/3290/1 3281/3289/1 +f 10658/10666/1 3277/3285/1 3280/3288/1 10659/10667/1 +f 10663/10671/1 10668/10676/1 3277/3285/1 10658/10666/1 +f 10668/10676/1 10667/10675/1 3278/3286/1 3277/3285/1 +f 10670/10678/1 3273/3281/1 3276/3284/1 10671/10679/1 +f 10675/10683/1 10680/10688/1 3273/3281/1 10670/10678/1 +f 10680/10688/1 10679/10687/1 3274/3282/1 3273/3281/1 +f 10682/10690/1 3269/3277/1 3272/3280/1 10683/10691/1 +f 10687/10695/1 10692/10700/1 3269/3277/1 10682/10690/1 +f 10692/10700/1 10691/10699/1 3270/3278/1 3269/3277/1 +f 10694/10702/1 3265/3273/1 3268/3276/1 10695/10703/1 +f 10699/10707/1 10704/10712/1 3265/3273/1 10694/10702/1 +f 10704/10712/1 10703/10711/1 3266/3274/1 3265/3273/1 +f 10706/10714/1 3261/3269/1 3264/3272/1 10707/10715/1 +f 10711/10719/1 10716/10724/1 3261/3269/1 10706/10714/1 +f 10716/10724/1 10715/10723/1 3262/3270/1 3261/3269/1 +f 10718/10726/1 3257/3265/1 3260/3268/1 10719/10727/1 +f 10723/10731/1 10728/10736/1 3257/3265/1 10718/10726/1 +f 10728/10736/1 10727/10735/1 3258/3266/1 3257/3265/1 +f 10730/10738/1 3253/3261/1 3256/3264/1 10731/10739/1 +f 10735/10743/1 10740/10748/1 3253/3261/1 10730/10738/1 +f 10740/10748/1 10739/10747/1 3254/3262/1 3253/3261/1 +f 10742/10750/1 3249/3257/1 3252/3260/1 10743/10751/1 +f 10747/10755/1 10752/10760/1 3249/3257/1 10742/10750/1 +f 10752/10760/1 10751/10759/1 3250/3258/1 3249/3257/1 +f 10754/10762/1 3245/3253/1 3248/3256/1 10755/10763/1 +f 10759/10767/1 10764/10772/1 3245/3253/1 10754/10762/1 +f 10764/10772/1 10763/10771/1 3246/3254/1 3245/3253/1 +f 10766/10774/1 3241/3249/1 3244/3252/1 10767/10775/1 +f 10771/10779/1 10776/10784/1 3241/3249/1 10766/10774/1 +f 10776/10784/1 10775/10783/1 3242/3250/1 3241/3249/1 +f 10778/10786/1 3237/3245/1 3240/3248/1 10779/10787/1 +f 10783/10791/1 10788/10796/1 3237/3245/1 10778/10786/1 +f 10788/10796/1 10787/10795/1 3238/3246/1 3237/3245/1 +f 10790/10798/1 3233/3241/1 3236/3244/1 10791/10799/1 +f 10795/10803/1 10800/10808/1 3233/3241/1 10790/10798/1 +f 10800/10808/1 10799/10807/1 3234/3242/1 3233/3241/1 +f 10802/10810/1 3229/3237/1 3232/3240/1 10803/10811/1 +f 10807/10815/1 10812/10820/1 3229/3237/1 10802/10810/1 +f 10812/10820/1 10811/10819/1 3230/3238/1 3229/3237/1 +f 10814/10822/1 3225/3233/1 3228/3236/1 10815/10823/1 +f 10819/10827/1 10824/10832/1 3225/3233/1 10814/10822/1 +f 10824/10832/1 10823/10831/1 3226/3234/1 3225/3233/1 +f 10826/10834/1 3221/3229/1 3224/3232/1 10827/10835/1 +f 10831/10839/1 10836/10844/1 3221/3229/1 10826/10834/1 +f 10836/10844/1 10835/10843/1 3222/3230/1 3221/3229/1 +f 10838/10846/1 3217/3225/1 3220/3228/1 10839/10847/1 +f 10843/10851/1 10848/10856/1 3217/3225/1 10838/10846/1 +f 10848/10856/1 10847/10855/1 3218/3226/1 3217/3225/1 +f 10850/10858/1 3213/3221/1 3216/3224/1 10851/10859/1 +f 10855/10863/1 10860/10868/1 3213/3221/1 10850/10858/1 +f 10860/10868/1 10859/10867/1 3214/3222/1 3213/3221/1 +f 10862/10870/1 3209/3217/1 3212/3220/1 10863/10871/1 +f 10867/10875/1 10872/10880/1 3209/3217/1 10862/10870/1 +f 10872/10880/1 10871/10879/1 3210/3218/1 3209/3217/1 +f 10874/10882/1 3205/3213/1 3208/3216/1 10875/10883/1 +f 10879/10887/1 10884/10892/1 3205/3213/1 10874/10882/1 +f 10884/10892/1 10883/10891/1 3206/3214/1 3205/3213/1 +f 10886/10894/1 3201/3209/1 3204/3212/1 10887/10895/1 +f 10891/10899/1 10896/10904/1 3201/3209/1 10886/10894/1 +f 10896/10904/1 10895/10903/1 3202/3210/1 3201/3209/1 +f 10898/10906/1 3197/3205/1 3200/3208/1 10899/10907/1 +f 10903/10911/1 10908/10916/1 3197/3205/1 10898/10906/1 +f 10908/10916/1 10907/10915/1 3198/3206/1 3197/3205/1 +f 10910/10918/1 3193/3201/1 3196/3204/1 10911/10919/1 +f 10915/10923/1 10920/10928/1 3193/3201/1 10910/10918/1 +f 10920/10928/1 10919/10927/1 3194/3202/1 3193/3201/1 +f 10922/10930/1 3189/3197/1 3192/3200/1 10923/10931/1 +f 10927/10935/1 10932/10940/1 3189/3197/1 10922/10930/1 +f 10932/10940/1 10931/10939/1 3190/3198/1 3189/3197/1 +f 10934/10942/1 3185/3193/1 3188/3196/1 10935/10943/1 +f 10939/10947/1 10944/10952/1 3185/3193/1 10934/10942/1 +f 10944/10952/1 10943/10951/1 3186/3194/1 3185/3193/1 +f 10946/10954/1 3181/3189/1 3184/3192/1 10947/10955/1 +f 10951/10959/1 10956/10964/1 3181/3189/1 10946/10954/1 +f 10956/10964/1 10955/10963/1 3182/3190/1 3181/3189/1 +f 10958/10966/1 3177/3185/1 3180/3188/1 10959/10967/1 +f 10963/10971/1 10968/10976/1 3177/3185/1 10958/10966/1 +f 10968/10976/1 10967/10975/1 3178/3186/1 3177/3185/1 +f 10970/10978/1 3173/3181/1 3176/3184/1 10971/10979/1 +f 10975/10983/1 10980/10988/1 3173/3181/1 10970/10978/1 +f 10980/10988/1 10979/10987/1 3174/3182/1 3173/3181/1 +f 10982/10990/1 3169/3177/1 3172/3180/1 10983/10991/1 +f 10987/10995/1 10992/11000/1 3169/3177/1 10982/10990/1 +f 10992/11000/1 10991/10999/1 3170/3178/1 3169/3177/1 +f 10994/11002/1 3165/3173/1 3168/3176/1 10995/11003/1 +f 10999/11007/1 11004/11012/1 3165/3173/1 10994/11002/1 +f 11004/11012/1 11003/11011/1 3166/3174/1 3165/3173/1 +f 11006/11014/1 3161/3169/1 3164/3172/1 11007/11015/1 +f 11011/11019/1 11016/11024/1 3161/3169/1 11006/11014/1 +f 11016/11024/1 11015/11023/1 3162/3170/1 3161/3169/1 +f 11018/11026/1 3157/3165/1 3160/3168/1 11019/11027/1 +f 11023/11031/1 11028/11036/1 3157/3165/1 11018/11026/1 +f 11028/11036/1 11027/11035/1 3158/3166/1 3157/3165/1 +f 11030/11038/1 3153/3161/1 3156/3164/1 11031/11039/1 +f 11035/11043/1 11040/11048/1 3153/3161/1 11030/11038/1 +f 11040/11048/1 11039/11047/1 3154/3162/1 3153/3161/1 +f 11042/11050/1 3149/3157/1 3152/3160/1 11043/11051/1 +f 11047/11055/1 11052/11060/1 3149/3157/1 11042/11050/1 +f 11052/11060/1 11051/11059/1 3150/3158/1 3149/3157/1 +f 11054/11062/1 3145/3153/1 3148/3156/1 11055/11063/1 +f 11059/11067/1 11064/11072/1 3145/3153/1 11054/11062/1 +f 11064/11072/1 11063/11071/1 3146/3154/1 3145/3153/1 +f 11066/11074/1 3141/3149/1 3144/3152/1 11067/11075/1 +f 11071/11079/1 11076/11084/1 3141/3149/1 11066/11074/1 +f 11076/11084/1 11075/11083/1 3142/3150/1 3141/3149/1 +f 11078/11086/1 3137/3145/1 3140/3148/1 11079/11087/1 +f 11083/11091/1 11088/11096/1 3137/3145/1 11078/11086/1 +f 11088/11096/1 11087/11095/1 3138/3146/1 3137/3145/1 +f 11090/11098/1 3133/3141/1 3136/3144/1 11091/11099/1 +f 11095/11103/1 11100/11108/1 3133/3141/1 11090/11098/1 +f 11100/11108/1 11099/11107/1 3134/3142/1 3133/3141/1 +f 11102/11110/1 3129/3137/1 3132/3140/1 11103/11111/1 +f 11107/11115/1 11112/11120/1 3129/3137/1 11102/11110/1 +f 11112/11120/1 11111/11119/1 3130/3138/1 3129/3137/1 +f 11114/11122/1 3125/3133/1 3128/3136/1 11115/11123/1 +f 11119/11127/1 11124/11132/1 3125/3133/1 11114/11122/1 +f 11124/11132/1 11123/11131/1 3126/3134/1 3125/3133/1 +f 11126/11134/1 3121/3129/1 3124/3132/1 11127/11135/1 +f 11131/11139/1 11136/11144/1 3121/3129/1 11126/11134/1 +f 11136/11144/1 11135/11143/1 3122/3130/1 3121/3129/1 +f 11138/11146/1 3117/3125/1 3120/3128/1 11139/11147/1 +f 11143/11151/1 11148/11156/1 3117/3125/1 11138/11146/1 +f 11148/11156/1 11147/11155/1 3118/3126/1 3117/3125/1 +f 11150/11158/1 3113/3121/1 3116/3124/1 11151/11159/1 +f 11155/11163/1 11160/11168/1 3113/3121/1 11150/11158/1 +f 11160/11168/1 11159/11167/1 3114/3122/1 3113/3121/1 +f 11162/11170/1 3109/3117/1 3112/3120/1 11163/11171/1 +f 11167/11175/1 11172/11180/1 3109/3117/1 11162/11170/1 +f 11172/11180/1 11171/11179/1 3110/3118/1 3109/3117/1 +f 11174/11182/1 3105/3113/1 3108/3116/1 11175/11183/1 +f 11179/11187/1 11184/11192/1 3105/3113/1 11174/11182/1 +f 11184/11192/1 11183/11191/1 3106/3114/1 3105/3113/1 +f 11186/11194/1 3101/3109/1 3104/3112/1 11187/11195/1 +f 11191/11199/1 11196/11204/1 3101/3109/1 11186/11194/1 +f 11196/11204/1 11195/11203/1 3102/3110/1 3101/3109/1 +f 11198/11206/1 3097/3105/1 3100/3108/1 11199/11207/1 +f 11203/11211/1 11208/11216/1 3097/3105/1 11198/11206/1 +f 11208/11216/1 11207/11215/1 3098/3106/1 3097/3105/1 +f 11210/11218/1 3093/3101/1 3096/3104/1 11211/11219/1 +f 11215/11223/1 11220/11228/1 3093/3101/1 11210/11218/1 +f 11220/11228/1 11219/11227/1 3094/3102/1 3093/3101/1 +f 11222/11230/1 3089/3097/1 3092/3100/1 11223/11231/1 +f 11227/11235/1 11232/11240/1 3089/3097/1 11222/11230/1 +f 11232/11240/1 11231/11239/1 3090/3098/1 3089/3097/1 +f 11234/11242/1 3085/3093/1 3088/3096/1 11235/11243/1 +f 11239/11247/1 11244/11252/1 3085/3093/1 11234/11242/1 +f 11244/11252/1 11243/11251/1 3086/3094/1 3085/3093/1 +f 11246/11254/1 3081/3089/1 3084/3092/1 11247/11255/1 +f 11251/11259/1 11256/11264/1 3081/3089/1 11246/11254/1 +f 11256/11264/1 11255/11263/1 3082/3090/1 3081/3089/1 +f 11258/11266/1 3077/3085/1 3080/3088/1 11259/11267/1 +f 11263/11271/1 11268/11276/1 3077/3085/1 11258/11266/1 +f 11268/11276/1 11267/11275/1 3078/3086/1 3077/3085/1 +f 11270/11278/1 3073/3081/1 3076/3084/1 11271/11279/1 +f 11275/11283/1 11280/11288/1 3073/3081/1 11270/11278/1 +f 11280/11288/1 11279/11287/1 3074/3082/1 3073/3081/1 +f 11282/11290/1 3069/3077/1 3072/3080/1 11283/11291/1 +f 11287/11295/1 11292/11300/1 3069/3077/1 11282/11290/1 +f 11292/11300/1 11291/11299/1 3070/3078/1 3069/3077/1 +f 11294/11302/1 3065/3073/1 3068/3076/1 11295/11303/1 +f 11299/11307/1 11304/11312/1 3065/3073/1 11294/11302/1 +f 11304/11312/1 11303/11311/1 3066/3074/1 3065/3073/1 +f 11306/11314/1 3061/3069/1 3064/3072/1 11307/11315/1 +f 11311/11319/1 11316/11324/1 3061/3069/1 11306/11314/1 +f 11316/11324/1 11315/11323/1 3062/3070/1 3061/3069/1 +f 11318/11326/1 3057/3065/1 3060/3068/1 11319/11327/1 +f 11323/11331/1 11328/11336/1 3057/3065/1 11318/11326/1 +f 11328/11336/1 11327/11335/1 3058/3066/1 3057/3065/1 +f 11330/11338/1 3053/3061/1 3056/3064/1 11331/11339/1 +f 11335/11343/1 11340/11348/1 3053/3061/1 11330/11338/1 +f 11340/11348/1 11339/11347/1 3054/3062/1 3053/3061/1 +f 11342/11350/1 3049/3057/1 3052/3060/1 11343/11351/1 +f 11347/11355/1 11352/11360/1 3049/3057/1 11342/11350/1 +f 11352/11360/1 11351/11359/1 3050/3058/1 3049/3057/1 +f 11354/11362/1 3045/3053/1 3048/3056/1 11355/11363/1 +f 11359/11367/1 11364/11372/1 3045/3053/1 11354/11362/1 +f 11364/11372/1 11363/11371/1 3046/3054/1 3045/3053/1 +f 11366/11374/1 3041/3049/1 3044/3052/1 11367/11375/1 +f 11371/11379/1 11376/11384/1 3041/3049/1 11366/11374/1 +f 11376/11384/1 11375/11383/1 3042/3050/1 3041/3049/1 +f 11378/11386/1 3037/3045/1 3040/3048/1 11379/11387/1 +f 11383/11391/1 11388/11396/1 3037/3045/1 11378/11386/1 +f 11388/11396/1 11387/11395/1 3038/3046/1 3037/3045/1 +f 11390/11398/1 3033/3041/1 3036/3044/1 11391/11399/1 +f 11395/11403/1 11400/11408/1 3033/3041/1 11390/11398/1 +f 11400/11408/1 11399/11407/1 3034/3042/1 3033/3041/1 +f 11402/11410/1 3029/3037/1 3032/3040/1 11403/11411/1 +f 11407/11415/1 11412/11420/1 3029/3037/1 11402/11410/1 +f 11412/11420/1 11411/11419/1 3030/3038/1 3029/3037/1 +f 11414/11422/1 3025/3033/1 3028/3036/1 11415/11423/1 +f 11419/11427/1 11424/11432/1 3025/3033/1 11414/11422/1 +f 11424/11432/1 11423/11431/1 3026/3034/1 3025/3033/1 +f 11426/11434/1 3021/3029/1 3024/3032/1 11427/11435/1 +f 11431/11439/1 11436/11444/1 3021/3029/1 11426/11434/1 +f 11436/11444/1 11435/11443/1 3022/3030/1 3021/3029/1 +f 11438/11446/1 3017/3025/1 3020/3028/1 11439/11447/1 +f 11443/11451/1 11448/11456/1 3017/3025/1 11438/11446/1 +f 11448/11456/1 11447/11455/1 3018/3026/1 3017/3025/1 +f 11450/11458/1 3013/3021/1 3016/3024/1 11451/11459/1 +f 11455/11463/1 11460/11468/1 3013/3021/1 11450/11458/1 +f 11460/11468/1 11459/11467/1 3014/3022/1 3013/3021/1 +f 11462/11470/1 3009/3017/1 3012/3020/1 11463/11471/1 +f 11467/11475/1 11472/11480/1 3009/3017/1 11462/11470/1 +f 11472/11480/1 11471/11479/1 3010/3018/1 3009/3017/1 +f 11474/11482/1 3005/3013/1 3008/3016/1 11475/11483/1 +f 11479/11487/1 11484/11492/1 3005/3013/1 11474/11482/1 +f 11484/11492/1 11483/11491/1 3006/3014/1 3005/3013/1 +f 11486/11494/1 3001/3009/1 3004/3012/1 11487/11495/1 +f 11491/11499/1 11496/11504/1 3001/3009/1 11486/11494/1 +f 11496/11504/1 11495/11503/1 3002/3010/1 3001/3009/1 +f 11498/11506/1 2997/3005/1 3000/3008/1 11499/11507/1 +f 11503/11511/1 11508/11516/1 2997/3005/1 11498/11506/1 +f 11508/11516/1 11507/11515/1 2998/3006/1 2997/3005/1 +f 11510/11518/1 2993/3001/1 2996/3004/1 11511/11519/1 +f 11515/11523/1 11520/11528/1 2993/3001/1 11510/11518/1 +f 11520/11528/1 11519/11527/1 2994/3002/1 2993/3001/1 +f 11522/11530/1 2989/2997/1 2992/3000/1 11523/11531/1 +f 11527/11535/1 11532/11540/1 2989/2997/1 11522/11530/1 +f 11532/11540/1 11531/11539/1 2990/2998/1 2989/2997/1 +f 11534/11542/1 2985/2993/1 2988/2996/1 11535/11543/1 +f 11539/11547/1 11544/11552/1 2985/2993/1 11534/11542/1 +f 11544/11552/1 11543/11551/1 2986/2994/1 2985/2993/1 +f 11546/11554/1 2981/2989/1 2984/2992/1 11547/11555/1 +f 11551/11559/1 11556/11564/1 2981/2989/1 11546/11554/1 +f 11556/11564/1 11555/11563/1 2982/2990/1 2981/2989/1 +f 11558/11566/1 2977/2985/1 2980/2988/1 11559/11567/1 +f 11563/11571/1 11568/11576/1 2977/2985/1 11558/11566/1 +f 11568/11576/1 11567/11575/1 2978/2986/1 2977/2985/1 +f 11570/11578/1 2973/2981/1 2976/2984/1 11571/11579/1 +f 11575/11583/1 11580/11588/1 2973/2981/1 11570/11578/1 +f 11580/11588/1 11579/11587/1 2974/2982/1 2973/2981/1 +f 11582/11590/1 2969/2977/1 2972/2980/1 11583/11591/1 +f 11587/11595/1 11592/11600/1 2969/2977/1 11582/11590/1 +f 11592/11600/1 11591/11599/1 2970/2978/1 2969/2977/1 +f 11594/11602/1 2965/2973/1 2968/2976/1 11595/11603/1 +f 11599/11607/1 11604/11612/1 2965/2973/1 11594/11602/1 +f 11604/11612/1 11603/11611/1 2966/2974/1 2965/2973/1 +f 11606/11614/1 2961/2969/1 2964/2972/1 11607/11615/1 +f 11611/11619/1 11616/11624/1 2961/2969/1 11606/11614/1 +f 11616/11624/1 11615/11623/1 2962/2970/1 2961/2969/1 +f 11618/11626/1 2957/2965/1 2960/2968/1 11619/11627/1 +f 11623/11631/1 11628/11636/1 2957/2965/1 11618/11626/1 +f 11628/11636/1 11627/11635/1 2958/2966/1 2957/2965/1 +f 11630/11638/1 2953/2961/1 2956/2964/1 11631/11639/1 +f 11635/11643/1 11640/11648/1 2953/2961/1 11630/11638/1 +f 11640/11648/1 11639/11647/1 2954/2962/1 2953/2961/1 +f 11642/11650/1 2949/2957/1 2952/2960/1 11643/11651/1 +f 11647/11655/1 11652/11660/1 2949/2957/1 11642/11650/1 +f 11652/11660/1 11651/11659/1 2950/2958/1 2949/2957/1 +f 11654/11662/1 2945/2953/1 2948/2956/1 11655/11663/1 +f 11659/11667/1 11664/11672/1 2945/2953/1 11654/11662/1 +f 11664/11672/1 11663/11671/1 2946/2954/1 2945/2953/1 +f 11666/11674/1 2941/2949/1 2944/2952/1 11667/11675/1 +f 11671/11679/1 11676/11684/1 2941/2949/1 11666/11674/1 +f 11676/11684/1 11675/11683/1 2942/2950/1 2941/2949/1 +f 11678/11686/1 2937/2945/1 2940/2948/1 11679/11687/1 +f 11683/11691/1 11688/11696/1 2937/2945/1 11678/11686/1 +f 11688/11696/1 11687/11695/1 2938/2946/1 2937/2945/1 +f 11690/11698/1 2933/2941/1 2936/2944/1 11691/11699/1 +f 11695/11703/1 11700/11708/1 2933/2941/1 11690/11698/1 +f 11700/11708/1 11699/11707/1 2934/2942/1 2933/2941/1 +f 11702/11710/1 2929/2937/1 2932/2940/1 11703/11711/1 +f 11707/11715/1 11712/11720/1 2929/2937/1 11702/11710/1 +f 11712/11720/1 11711/11719/1 2930/2938/1 2929/2937/1 +f 11714/11722/1 2925/2933/1 2928/2936/1 11715/11723/1 +f 11719/11727/1 11724/11732/1 2925/2933/1 11714/11722/1 +f 11724/11732/1 11723/11731/1 2926/2934/1 2925/2933/1 +f 11726/11734/1 2921/2929/1 2924/2932/1 11727/11735/1 +f 11731/11739/1 11736/11744/1 2921/2929/1 11726/11734/1 +f 11736/11744/1 11735/11743/1 2922/2930/1 2921/2929/1 +f 11738/11746/1 2917/2925/1 2920/2928/1 11739/11747/1 +f 11743/11751/1 11748/11756/1 2917/2925/1 11738/11746/1 +f 11748/11756/1 11747/11755/1 2918/2926/1 2917/2925/1 +f 11750/11758/1 2913/2921/1 2916/2924/1 11751/11759/1 +f 11755/11763/1 11760/11768/1 2913/2921/1 11750/11758/1 +f 11760/11768/1 11759/11767/1 2914/2922/1 2913/2921/1 +f 11762/11770/1 2909/2917/1 2912/2920/1 11763/11771/1 +f 11767/11775/1 11772/11780/1 2909/2917/1 11762/11770/1 +f 11772/11780/1 11771/11779/1 2910/2918/1 2909/2917/1 +f 11774/11782/1 2905/2913/1 2908/2916/1 11775/11783/1 +f 11779/11787/1 11784/11792/1 2905/2913/1 11774/11782/1 +f 11784/11792/1 11783/11791/1 2906/2914/1 2905/2913/1 +f 11786/11794/1 2901/2909/1 2904/2912/1 11787/11795/1 +f 11791/11799/1 11796/11804/1 2901/2909/1 11786/11794/1 +f 11796/11804/1 11795/11803/1 2902/2910/1 2901/2909/1 +f 11798/11806/1 2897/2905/1 2900/2908/1 11799/11807/1 +f 11803/11811/1 11808/11816/1 2897/2905/1 11798/11806/1 +f 11808/11816/1 11807/11815/1 2898/2906/1 2897/2905/1 +f 11810/11818/1 2893/2901/1 2896/2904/1 11811/11819/1 +f 11815/11823/1 11820/11828/1 2893/2901/1 11810/11818/1 +f 11820/11828/1 11819/11827/1 2894/2902/1 2893/2901/1 +f 11822/11830/1 2889/2897/1 2892/2900/1 11823/11831/1 +f 11827/11835/1 11832/11840/1 2889/2897/1 11822/11830/1 +f 11832/11840/1 11831/11839/1 2890/2898/1 2889/2897/1 +f 11834/11842/1 2885/2893/1 2888/2896/1 11835/11843/1 +f 11839/11847/1 11844/11852/1 2885/2893/1 11834/11842/1 +f 11844/11852/1 11843/11851/1 2886/2894/1 2885/2893/1 +f 11846/11854/1 2881/2889/1 2884/2892/1 11847/11855/1 +f 11851/11859/1 11856/11864/1 2881/2889/1 11846/11854/1 +f 11856/11864/1 11855/11863/1 2882/2890/1 2881/2889/1 +f 11858/11866/1 2877/2885/1 2880/2888/1 11859/11867/1 +f 11863/11871/1 11868/11876/1 2877/2885/1 11858/11866/1 +f 11868/11876/1 11867/11875/1 2878/2886/1 2877/2885/1 +f 11870/11878/1 2873/2881/1 2876/2884/1 11871/11879/1 +f 11875/11883/1 11880/11888/1 2873/2881/1 11870/11878/1 +f 11880/11888/1 11879/11887/1 2874/2882/1 2873/2881/1 +f 11882/11890/1 2869/2877/1 2872/2880/1 11883/11891/1 +f 11887/11895/1 11892/11900/1 2869/2877/1 11882/11890/1 +f 11892/11900/1 11891/11899/1 2870/2878/1 2869/2877/1 +f 11894/11902/1 2865/2873/1 2868/2876/1 11895/11903/1 +f 11899/11907/1 11904/11912/1 2865/2873/1 11894/11902/1 +f 11904/11912/1 11903/11911/1 2866/2874/1 2865/2873/1 +f 11906/11914/1 2861/2869/1 2864/2872/1 11907/11915/1 +f 11911/11919/1 11916/11924/1 2861/2869/1 11906/11914/1 +f 11916/11924/1 11915/11923/1 2862/2870/1 2861/2869/1 +f 11918/11926/1 2857/2865/1 2860/2868/1 11919/11927/1 +f 11923/11931/1 11928/11936/1 2857/2865/1 11918/11926/1 +f 11928/11936/1 11927/11935/1 2858/2866/1 2857/2865/1 +f 11930/11938/1 2853/2861/1 2856/2864/1 11931/11939/1 +f 11935/11943/1 11940/11948/1 2853/2861/1 11930/11938/1 +f 11940/11948/1 11939/11947/1 2854/2862/1 2853/2861/1 +f 11942/11950/1 2849/2857/1 2852/2860/1 11943/11951/1 +f 11947/11955/1 11952/11960/1 2849/2857/1 11942/11950/1 +f 11952/11960/1 11951/11959/1 2850/2858/1 2849/2857/1 +f 11954/11962/1 2845/2853/1 2848/2856/1 11955/11963/1 +f 11959/11967/1 11964/11972/1 2845/2853/1 11954/11962/1 +f 11964/11972/1 11963/11971/1 2846/2854/1 2845/2853/1 +f 11966/11974/1 2841/2849/1 2844/2852/1 11967/11975/1 +f 11971/11979/1 11976/11984/1 2841/2849/1 11966/11974/1 +f 11976/11984/1 11975/11983/1 2842/2850/1 2841/2849/1 +f 11978/11986/1 2837/2845/1 2840/2848/1 11979/11987/1 +f 11983/11991/1 11988/11996/1 2837/2845/1 11978/11986/1 +f 11988/11996/1 11987/11995/1 2838/2846/1 2837/2845/1 +f 11990/11998/1 2833/2841/1 2836/2844/1 11991/11999/1 +f 11995/12003/1 12000/12008/1 2833/2841/1 11990/11998/1 +f 12000/12008/1 11999/12007/1 2834/2842/1 2833/2841/1 +f 12002/12010/1 2829/2837/1 2832/2840/1 12003/12011/1 +f 12007/12015/1 12012/12020/1 2829/2837/1 12002/12010/1 +f 12012/12020/1 12011/12019/1 2830/2838/1 2829/2837/1 +f 12014/12022/1 2825/2833/1 2828/2836/1 12015/12023/1 +f 12019/12027/1 12024/12032/1 2825/2833/1 12014/12022/1 +f 12024/12032/1 12023/12031/1 2826/2834/1 2825/2833/1 +f 12026/12034/1 2821/2829/1 2824/2832/1 12027/12035/1 +f 12031/12039/1 12036/12044/1 2821/2829/1 12026/12034/1 +f 12036/12044/1 12035/12043/1 2822/2830/1 2821/2829/1 +f 12038/12046/1 2817/2825/1 2820/2828/1 12039/12047/1 +f 12043/12051/1 12048/12056/1 2817/2825/1 12038/12046/1 +f 12048/12056/1 12047/12055/1 2818/2826/1 2817/2825/1 +f 12050/12058/1 2813/2821/1 2816/2824/1 12051/12059/1 +f 12055/12063/1 12060/12068/1 2813/2821/1 12050/12058/1 +f 12060/12068/1 12059/12067/1 2814/2822/1 2813/2821/1 +f 12062/12070/1 2809/2817/1 2812/2820/1 12063/12071/1 +f 12067/12075/1 12072/12080/1 2809/2817/1 12062/12070/1 +f 12072/12080/1 12071/12079/1 2810/2818/1 2809/2817/1 +f 12074/12082/1 2805/2813/1 2808/2816/1 12075/12083/1 +f 12079/12087/1 12084/12092/1 2805/2813/1 12074/12082/1 +f 12084/12092/1 12083/12091/1 2806/2814/1 2805/2813/1 +f 12086/12094/1 2801/2809/1 2804/2812/1 12087/12095/1 +f 12091/12099/1 12096/12104/1 2801/2809/1 12086/12094/1 +f 12096/12104/1 12095/12103/1 2802/2810/1 2801/2809/1 +f 12098/12106/1 2797/2805/1 2800/2808/1 12099/12107/1 +f 12103/12111/1 12108/12116/1 2797/2805/1 12098/12106/1 +f 12108/12116/1 12107/12115/1 2798/2806/1 2797/2805/1 +f 12110/12118/1 2793/2801/1 2796/2804/1 12111/12119/1 +f 12115/12123/1 12120/12128/1 2793/2801/1 12110/12118/1 +f 12120/12128/1 12119/12127/1 2794/2802/1 2793/2801/1 +f 12122/12130/1 2789/2797/1 2792/2800/1 12123/12131/1 +f 12127/12135/1 12132/12140/1 2789/2797/1 12122/12130/1 +f 12132/12140/1 12131/12139/1 2790/2798/1 2789/2797/1 +f 12134/12142/1 2785/2793/1 2788/2796/1 12135/12143/1 +f 12139/12147/1 12144/12152/1 2785/2793/1 12134/12142/1 +f 12144/12152/1 12143/12151/1 2786/2794/1 2785/2793/1 +f 12146/12154/1 2781/2789/1 2784/2792/1 12147/12155/1 +f 12151/12159/1 12156/12164/1 2781/2789/1 12146/12154/1 +f 12156/12164/1 12155/12163/1 2782/2790/1 2781/2789/1 +f 12158/12166/1 2777/2785/1 2780/2788/1 12159/12167/1 +f 12163/12171/1 12168/12176/1 2777/2785/1 12158/12166/1 +f 12168/12176/1 12167/12175/1 2778/2786/1 2777/2785/1 +f 12170/12178/1 2773/2781/1 2776/2784/1 12171/12179/1 +f 12175/12183/1 12180/12188/1 2773/2781/1 12170/12178/1 +f 12180/12188/1 12179/12187/1 2774/2782/1 2773/2781/1 +f 12182/12190/1 2769/2777/1 2772/2780/1 12183/12191/1 +f 12187/12195/1 12192/12200/1 2769/2777/1 12182/12190/1 +f 12192/12200/1 12191/12199/1 2770/2778/1 2769/2777/1 +f 12194/12202/1 2765/2773/1 2768/2776/1 12195/12203/1 +f 12199/12207/1 12204/12212/1 2765/2773/1 12194/12202/1 +f 12204/12212/1 12203/12211/1 2766/2774/1 2765/2773/1 +f 12206/12214/1 2761/2769/1 2764/2772/1 12207/12215/1 +f 12211/12219/1 12216/12224/1 2761/2769/1 12206/12214/1 +f 12216/12224/1 12215/12223/1 2762/2770/1 2761/2769/1 +f 12218/12226/1 2757/2765/1 2760/2768/1 12219/12227/1 +f 12223/12231/1 12228/12236/1 2757/2765/1 12218/12226/1 +f 12228/12236/1 12227/12235/1 2758/2766/1 2757/2765/1 +f 12230/12238/1 2753/2761/1 2756/2764/1 12231/12239/1 +f 12235/12243/1 12240/12248/1 2753/2761/1 12230/12238/1 +f 12240/12248/1 12239/12247/1 2754/2762/1 2753/2761/1 +f 12242/12250/1 2749/2757/1 2752/2760/1 12243/12251/1 +f 12247/12255/1 12252/12260/1 2749/2757/1 12242/12250/1 +f 12252/12260/1 12251/12259/1 2750/2758/1 2749/2757/1 +f 12254/12262/1 2745/2753/1 2748/2756/1 12255/12263/1 +f 12259/12267/1 12264/12272/1 2745/2753/1 12254/12262/1 +f 12264/12272/1 12263/12271/1 2746/2754/1 2745/2753/1 +f 12266/12274/1 2741/2749/1 2744/2752/1 12267/12275/1 +f 12271/12279/1 12276/12284/1 2741/2749/1 12266/12274/1 +f 12276/12284/1 12275/12283/1 2742/2750/1 2741/2749/1 +f 12278/12286/1 2737/2745/1 2740/2748/1 12279/12287/1 +f 12283/12291/1 12288/12296/1 2737/2745/1 12278/12286/1 +f 12288/12296/1 12287/12295/1 2738/2746/1 2737/2745/1 +f 12290/12298/1 2733/2741/1 2736/2744/1 12291/12299/1 +f 12295/12303/1 12300/12308/1 2733/2741/1 12290/12298/1 +f 12300/12308/1 12299/12307/1 2734/2742/1 2733/2741/1 +f 12302/12310/1 2729/2737/1 2732/2740/1 12303/12311/1 +f 12307/12315/1 12312/12320/1 2729/2737/1 12302/12310/1 +f 12312/12320/1 12311/12319/1 2730/2738/1 2729/2737/1 +f 12314/12322/1 2725/2733/1 2728/2736/1 12315/12323/1 +f 12319/12327/1 12324/12332/1 2725/2733/1 12314/12322/1 +f 12324/12332/1 12323/12331/1 2726/2734/1 2725/2733/1 +f 12326/12334/1 2721/2729/1 2724/2732/1 12327/12335/1 +f 12331/12339/1 12336/12344/1 2721/2729/1 12326/12334/1 +f 12336/12344/1 12335/12343/1 2722/2730/1 2721/2729/1 +f 12338/12346/1 2717/2725/1 2720/2728/1 12339/12347/1 +f 12343/12351/1 12348/12356/1 2717/2725/1 12338/12346/1 +f 12348/12356/1 12347/12355/1 2718/2726/1 2717/2725/1 +f 12350/12358/1 2713/2721/1 2716/2724/1 12351/12359/1 +f 12355/12363/1 12360/12368/1 2713/2721/1 12350/12358/1 +f 12360/12368/1 12359/12367/1 2714/2722/1 2713/2721/1 +f 12362/12370/1 2709/2717/1 2712/2720/1 12363/12371/1 +f 12367/12375/1 12372/12380/1 2709/2717/1 12362/12370/1 +f 12372/12380/1 12371/12379/1 2710/2718/1 2709/2717/1 +f 12374/12382/1 2705/2713/1 2708/2716/1 12375/12383/1 +f 12379/12387/1 12384/12392/1 2705/2713/1 12374/12382/1 +f 12384/12392/1 12383/12391/1 2706/2714/1 2705/2713/1 +f 12386/12394/1 2701/2709/1 2704/2712/1 12387/12395/1 +f 12391/12399/1 12396/12404/1 2701/2709/1 12386/12394/1 +f 12396/12404/1 12395/12403/1 2702/2710/1 2701/2709/1 +f 12398/12406/1 2697/2705/1 2700/2708/1 12399/12407/1 +f 12403/12411/1 12408/12416/1 2697/2705/1 12398/12406/1 +f 12408/12416/1 12407/12415/1 2698/2706/1 2697/2705/1 +f 12410/12418/1 2693/2701/1 2696/2704/1 12411/12419/1 +f 12415/12423/1 12420/12428/1 2693/2701/1 12410/12418/1 +f 12420/12428/1 12419/12427/1 2694/2702/1 2693/2701/1 +f 12422/12430/1 2689/2697/1 2692/2700/1 12423/12431/1 +f 12427/12435/1 12432/12440/1 2689/2697/1 12422/12430/1 +f 12432/12440/1 12431/12439/1 2690/2698/1 2689/2697/1 +f 12434/12442/1 2685/2693/1 2688/2696/1 12435/12443/1 +f 12439/12447/1 12444/12452/1 2685/2693/1 12434/12442/1 +f 12444/12452/1 12443/12451/1 2686/2694/1 2685/2693/1 +f 12446/12454/1 2681/2689/1 2684/2692/1 12447/12455/1 +f 12451/12459/1 12456/12464/1 2681/2689/1 12446/12454/1 +f 12456/12464/1 12455/12463/1 2682/2690/1 2681/2689/1 +f 12458/12466/1 2677/2685/1 2680/2688/1 12459/12467/1 +f 12463/12471/1 12468/12476/1 2677/2685/1 12458/12466/1 +f 12468/12476/1 12467/12475/1 2678/2686/1 2677/2685/1 +f 12470/12478/1 2673/2681/1 2676/2684/1 12471/12479/1 +f 12475/12483/1 12480/12488/1 2673/2681/1 12470/12478/1 +f 12480/12488/1 12479/12487/1 2674/2682/1 2673/2681/1 +f 12482/12490/1 2669/2677/1 2672/2680/1 12483/12491/1 +f 12487/12495/1 12492/12500/1 2669/2677/1 12482/12490/1 +f 12492/12500/1 12491/12499/1 2670/2678/1 2669/2677/1 +f 12494/12502/1 2665/2673/1 2668/2676/1 12495/12503/1 +f 12499/12507/1 12504/12512/1 2665/2673/1 12494/12502/1 +f 12504/12512/1 12503/12511/1 2666/2674/1 2665/2673/1 +f 12506/12514/1 2661/2669/1 2664/2672/1 12507/12515/1 +f 12511/12519/1 12516/12524/1 2661/2669/1 12506/12514/1 +f 12516/12524/1 12515/12523/1 2662/2670/1 2661/2669/1 +f 12518/12526/1 2657/2665/1 2660/2668/1 12519/12527/1 +f 12523/12531/1 12528/12536/1 2657/2665/1 12518/12526/1 +f 12528/12536/1 12527/12535/1 2658/2666/1 2657/2665/1 +f 12530/12538/1 2653/2661/1 2656/2664/1 12531/12539/1 +f 12535/12543/1 12540/12548/1 2653/2661/1 12530/12538/1 +f 12540/12548/1 12539/12547/1 2654/2662/1 2653/2661/1 +f 12542/12550/1 2649/2657/1 2652/2660/1 12543/12551/1 +f 12547/12555/1 12552/12560/1 2649/2657/1 12542/12550/1 +f 12552/12560/1 12551/12559/1 2650/2658/1 2649/2657/1 +f 12554/12562/1 2645/2653/1 2648/2656/1 12555/12563/1 +f 12559/12567/1 12564/12572/1 2645/2653/1 12554/12562/1 +f 12564/12572/1 12563/12571/1 2646/2654/1 2645/2653/1 +f 12566/12574/1 2641/2649/1 2644/2652/1 12567/12575/1 +f 12571/12579/1 12576/12584/1 2641/2649/1 12566/12574/1 +f 12576/12584/1 12575/12583/1 2642/2650/1 2641/2649/1 +f 12578/12586/1 2637/2645/1 2640/2648/1 12579/12587/1 +f 12583/12591/1 12588/12596/1 2637/2645/1 12578/12586/1 +f 12588/12596/1 12587/12595/1 2638/2646/1 2637/2645/1 +f 12590/12598/1 2633/2641/1 2636/2644/1 12591/12599/1 +f 12595/12603/1 12600/12608/1 2633/2641/1 12590/12598/1 +f 12600/12608/1 12599/12607/1 2634/2642/1 2633/2641/1 +f 12602/12610/1 2629/2637/1 2632/2640/1 12603/12611/1 +f 12607/12615/1 12612/12620/1 2629/2637/1 12602/12610/1 +f 12612/12620/1 12611/12619/1 2630/2638/1 2629/2637/1 +f 12614/12622/1 2625/2633/1 2628/2636/1 12615/12623/1 +f 12619/12627/1 12624/12632/1 2625/2633/1 12614/12622/1 +f 12624/12632/1 12623/12631/1 2626/2634/1 2625/2633/1 +f 12626/12634/1 2621/2629/1 2624/2632/1 12627/12635/1 +f 12631/12639/1 12636/12644/1 2621/2629/1 12626/12634/1 +f 12636/12644/1 12635/12643/1 2622/2630/1 2621/2629/1 +f 12638/12646/1 2617/2625/1 2620/2628/1 12639/12647/1 +f 12643/12651/1 12648/12656/1 2617/2625/1 12638/12646/1 +f 12648/12656/1 12647/12655/1 2618/2626/1 2617/2625/1 +f 12650/12658/1 2613/2621/1 2616/2624/1 12651/12659/1 +f 12655/12663/1 12660/12668/1 2613/2621/1 12650/12658/1 +f 12660/12668/1 12659/12667/1 2614/2622/1 2613/2621/1 +f 12662/12670/1 2609/2617/1 2612/2620/1 12663/12671/1 +f 12667/12675/1 12672/12680/1 2609/2617/1 12662/12670/1 +f 12672/12680/1 12671/12679/1 2610/2618/1 2609/2617/1 +f 12674/12682/1 2605/2613/1 2608/2616/1 12675/12683/1 +f 12679/12687/1 12684/12692/1 2605/2613/1 12674/12682/1 +f 12684/12692/1 12683/12691/1 2606/2614/1 2605/2613/1 +f 12686/12694/1 2601/2609/1 2604/2612/1 12687/12695/1 +f 12691/12699/1 12696/12704/1 2601/2609/1 12686/12694/1 +f 12696/12704/1 12695/12703/1 2602/2610/1 2601/2609/1 +f 12698/12706/1 2597/2605/1 2600/2608/1 12699/12707/1 +f 12703/12711/1 12708/12716/1 2597/2605/1 12698/12706/1 +f 12708/12716/1 12707/12715/1 2598/2606/1 2597/2605/1 +f 12710/12718/1 2593/2601/1 2596/2604/1 12711/12719/1 +f 12715/12723/1 12720/12728/1 2593/2601/1 12710/12718/1 +f 12720/12728/1 12719/12727/1 2594/2602/1 2593/2601/1 +f 12722/12730/1 2589/2597/1 2592/2600/1 12723/12731/1 +f 12727/12735/1 12732/12740/1 2589/2597/1 12722/12730/1 +f 12732/12740/1 12731/12739/1 2590/2598/1 2589/2597/1 +f 12734/12742/1 2585/2593/1 2588/2596/1 12735/12743/1 +f 12739/12747/1 12744/12752/1 2585/2593/1 12734/12742/1 +f 12744/12752/1 12743/12751/1 2586/2594/1 2585/2593/1 +f 12746/12754/1 2581/2589/1 2584/2592/1 12747/12755/1 +f 12751/12759/1 12756/12764/1 2581/2589/1 12746/12754/1 +f 12756/12764/1 12755/12763/1 2582/2590/1 2581/2589/1 +f 12758/12766/1 2577/2585/1 2580/2588/1 12759/12767/1 +f 12763/12771/1 12768/12776/1 2577/2585/1 12758/12766/1 +f 12768/12776/1 12767/12775/1 2578/2586/1 2577/2585/1 +f 12770/12778/1 2573/2581/1 2576/2584/1 12771/12779/1 +f 12775/12783/1 12780/12788/1 2573/2581/1 12770/12778/1 +f 12780/12788/1 12779/12787/1 2574/2582/1 2573/2581/1 +f 12782/12790/1 2569/2577/1 2572/2580/1 12783/12791/1 +f 12787/12795/1 12792/12800/1 2569/2577/1 12782/12790/1 +f 12792/12800/1 12791/12799/1 2570/2578/1 2569/2577/1 +f 12794/12802/1 2565/2573/1 2568/2576/1 12795/12803/1 +f 12799/12807/1 12804/12812/1 2565/2573/1 12794/12802/1 +f 12804/12812/1 12803/12811/1 2566/2574/1 2565/2573/1 +f 12806/12814/1 2561/2569/1 2564/2572/1 12807/12815/1 +f 12811/12819/1 12816/12824/1 2561/2569/1 12806/12814/1 +f 12816/12824/1 12815/12823/1 2562/2570/1 2561/2569/1 +f 12818/12826/1 2557/2565/1 2560/2568/1 12819/12827/1 +f 12823/12831/1 12828/12836/1 2557/2565/1 12818/12826/1 +f 12828/12836/1 12827/12835/1 2558/2566/1 2557/2565/1 +f 12830/12838/1 2553/2561/1 2556/2564/1 12831/12839/1 +f 12835/12843/1 12840/12848/1 2553/2561/1 12830/12838/1 +f 12840/12848/1 12839/12847/1 2554/2562/1 2553/2561/1 +f 12842/12850/1 2549/2557/1 2552/2560/1 12843/12851/1 +f 12847/12855/1 12852/12860/1 2549/2557/1 12842/12850/1 +f 12852/12860/1 12851/12859/1 2550/2558/1 2549/2557/1 +f 12854/12862/1 2545/2553/1 2548/2556/1 12855/12863/1 +f 12859/12867/1 12864/12872/1 2545/2553/1 12854/12862/1 +f 12864/12872/1 12863/12871/1 2546/2554/1 2545/2553/1 +f 12866/12874/1 2541/2549/1 2544/2552/1 12867/12875/1 +f 12871/12879/1 12876/12884/1 2541/2549/1 12866/12874/1 +f 12876/12884/1 12875/12883/1 2542/2550/1 2541/2549/1 +f 12878/12886/1 2537/2545/1 2540/2548/1 12879/12887/1 +f 12883/12891/1 12888/12896/1 2537/2545/1 12878/12886/1 +f 12888/12896/1 12887/12895/1 2538/2546/1 2537/2545/1 +f 12890/12898/1 2533/2541/1 2536/2544/1 12891/12899/1 +f 12895/12903/1 12900/12908/1 2533/2541/1 12890/12898/1 +f 12900/12908/1 12899/12907/1 2534/2542/1 2533/2541/1 +f 12902/12910/1 2529/2537/1 2532/2540/1 12903/12911/1 +f 12907/12915/1 12912/12920/1 2529/2537/1 12902/12910/1 +f 12912/12920/1 12911/12919/1 2530/2538/1 2529/2537/1 +f 12914/12922/1 2525/2533/1 2528/2536/1 12915/12923/1 +f 12919/12927/1 12924/12932/1 2525/2533/1 12914/12922/1 +f 12924/12932/1 12923/12931/1 2526/2534/1 2525/2533/1 +f 12926/12934/1 2521/2529/1 2524/2532/1 12927/12935/1 +f 12931/12939/1 12936/12944/1 2521/2529/1 12926/12934/1 +f 12936/12944/1 12935/12943/1 2522/2530/1 2521/2529/1 +f 12938/12946/1 2517/2525/1 2520/2528/1 12939/12947/1 +f 12943/12951/1 12948/12956/1 2517/2525/1 12938/12946/1 +f 12948/12956/1 12947/12955/1 2518/2526/1 2517/2525/1 +f 12950/12958/1 2513/2521/1 2516/2524/1 12951/12959/1 +f 12955/12963/1 12960/12968/1 2513/2521/1 12950/12958/1 +f 12960/12968/1 12959/12967/1 2514/2522/1 2513/2521/1 +f 12962/12970/1 2509/2517/1 2512/2520/1 12963/12971/1 +f 12967/12975/1 12972/12980/1 2509/2517/1 12962/12970/1 +f 12972/12980/1 12971/12979/1 2510/2518/1 2509/2517/1 +f 12974/12982/1 2505/2513/1 2508/2516/1 12975/12983/1 +f 12979/12987/1 12984/12992/1 2505/2513/1 12974/12982/1 +f 12984/12992/1 12983/12991/1 2506/2514/1 2505/2513/1 +f 12986/12994/1 2501/2509/1 2504/2512/1 12987/12995/1 +f 12991/12999/1 12996/13004/1 2501/2509/1 12986/12994/1 +f 12996/13004/1 12995/13003/1 2502/2510/1 2501/2509/1 +f 12998/13006/1 2497/2505/1 2500/2508/1 12999/13007/1 +f 13003/13011/1 13008/13016/1 2497/2505/1 12998/13006/1 +f 13008/13016/1 13007/13015/1 2498/2506/1 2497/2505/1 +f 13010/13018/1 2493/2501/1 2496/2504/1 13011/13019/1 +f 13015/13023/1 13020/13028/1 2493/2501/1 13010/13018/1 +f 13020/13028/1 13019/13027/1 2494/2502/1 2493/2501/1 +f 13022/13030/1 2489/2497/1 2492/2500/1 13023/13031/1 +f 13027/13035/1 13032/13040/1 2489/2497/1 13022/13030/1 +f 13032/13040/1 13031/13039/1 2490/2498/1 2489/2497/1 +f 13034/13042/1 2485/2493/1 2488/2496/1 13035/13043/1 +f 13039/13047/1 13044/13052/1 2485/2493/1 13034/13042/1 +f 13044/13052/1 13043/13051/1 2486/2494/1 2485/2493/1 +f 13046/13054/1 2481/2489/1 2484/2492/1 13047/13055/1 +f 13051/13059/1 13056/13064/1 2481/2489/1 13046/13054/1 +f 13056/13064/1 13055/13063/1 2482/2490/1 2481/2489/1 +f 13058/13066/1 2477/2485/1 2480/2488/1 13059/13067/1 +f 13063/13071/1 13068/13076/1 2477/2485/1 13058/13066/1 +f 13068/13076/1 13067/13075/1 2478/2486/1 2477/2485/1 +f 13070/13078/1 2473/2481/1 2476/2484/1 13071/13079/1 +f 13075/13083/1 13080/13088/1 2473/2481/1 13070/13078/1 +f 13080/13088/1 13079/13087/1 2474/2482/1 2473/2481/1 +f 13082/13090/1 2469/2477/1 2472/2480/1 13083/13091/1 +f 13087/13095/1 13092/13100/1 2469/2477/1 13082/13090/1 +f 13092/13100/1 13091/13099/1 2470/2478/1 2469/2477/1 +f 13094/13102/1 2465/2473/1 2468/2476/1 13095/13103/1 +f 13099/13107/1 13104/13112/1 2465/2473/1 13094/13102/1 +f 13104/13112/1 13103/13111/1 2466/2474/1 2465/2473/1 +f 13106/13114/1 2461/2469/1 2464/2472/1 13107/13115/1 +f 13111/13119/1 13116/13124/1 2461/2469/1 13106/13114/1 +f 13116/13124/1 13115/13123/1 2462/2470/1 2461/2469/1 +f 13118/13126/1 2457/2465/1 2460/2468/1 13119/13127/1 +f 13123/13131/1 13128/13136/1 2457/2465/1 13118/13126/1 +f 13128/13136/1 13127/13135/1 2458/2466/1 2457/2465/1 +f 13130/13138/1 2453/2461/1 2456/2464/1 13131/13139/1 +f 13135/13143/1 13140/13148/1 2453/2461/1 13130/13138/1 +f 13140/13148/1 13139/13147/1 2454/2462/1 2453/2461/1 +f 13142/13150/1 2449/2457/1 2452/2460/1 13143/13151/1 +f 13147/13155/1 13152/13160/1 2449/2457/1 13142/13150/1 +f 13152/13160/1 13151/13159/1 2450/2458/1 2449/2457/1 +f 13154/13162/1 2445/2453/1 2448/2456/1 13155/13163/1 +f 13159/13167/1 13164/13172/1 2445/2453/1 13154/13162/1 +f 13164/13172/1 13163/13171/1 2446/2454/1 2445/2453/1 +f 13166/13174/1 2441/2449/1 2444/2452/1 13167/13175/1 +f 13171/13179/1 13176/13184/1 2441/2449/1 13166/13174/1 +f 13176/13184/1 13175/13183/1 2442/2450/1 2441/2449/1 +f 13178/13186/1 2437/2445/1 2440/2448/1 13179/13187/1 +f 13183/13191/1 13188/13196/1 2437/2445/1 13178/13186/1 +f 13188/13196/1 13187/13195/1 2438/2446/1 2437/2445/1 +f 13190/13198/1 2433/2441/1 2436/2444/1 13191/13199/1 +f 13195/13203/1 13200/13208/1 2433/2441/1 13190/13198/1 +f 13200/13208/1 13199/13207/1 2434/2442/1 2433/2441/1 +f 13202/13210/1 2429/2437/1 2432/2440/1 13203/13211/1 +f 13207/13215/1 13212/13220/1 2429/2437/1 13202/13210/1 +f 13212/13220/1 13211/13219/1 2430/2438/1 2429/2437/1 +f 13214/13222/1 2425/2433/1 2428/2436/1 13215/13223/1 +f 13219/13227/1 13224/13232/1 2425/2433/1 13214/13222/1 +f 13224/13232/1 13223/13231/1 2426/2434/1 2425/2433/1 +f 13226/13234/1 2421/2429/1 2424/2432/1 13227/13235/1 +f 13231/13239/1 13236/13244/1 2421/2429/1 13226/13234/1 +f 13236/13244/1 13235/13243/1 2422/2430/1 2421/2429/1 +f 13238/13246/1 2417/2425/1 2420/2428/1 13239/13247/1 +f 13243/13251/1 13248/13256/1 2417/2425/1 13238/13246/1 +f 13248/13256/1 13247/13255/1 2418/2426/1 2417/2425/1 +f 13250/13258/1 2413/2421/1 2416/2424/1 13251/13259/1 +f 13255/13263/1 13260/13268/1 2413/2421/1 13250/13258/1 +f 13260/13268/1 13259/13267/1 2414/2422/1 2413/2421/1 +f 13262/13270/1 2409/2417/1 2412/2420/1 13263/13271/1 +f 13267/13275/1 13272/13280/1 2409/2417/1 13262/13270/1 +f 13272/13280/1 13271/13279/1 2410/2418/1 2409/2417/1 +f 13274/13282/1 2405/2413/1 2408/2416/1 13275/13283/1 +f 13279/13287/1 13284/13292/1 2405/2413/1 13274/13282/1 +f 13284/13292/1 13283/13291/1 2406/2414/1 2405/2413/1 +f 13286/13294/1 2401/2409/1 2404/2412/1 13287/13295/1 +f 13291/13299/1 13296/13304/1 2401/2409/1 13286/13294/1 +f 13296/13304/1 13295/13303/1 2402/2410/1 2401/2409/1 +f 13298/13306/1 2397/2405/1 2400/2408/1 13299/13307/1 +f 13303/13311/1 13308/13316/1 2397/2405/1 13298/13306/1 +f 13308/13316/1 13307/13315/1 2398/2406/1 2397/2405/1 +f 13310/13318/1 2393/2401/1 2396/2404/1 13311/13319/1 +f 13315/13323/1 13320/13328/1 2393/2401/1 13310/13318/1 +f 13320/13328/1 13319/13327/1 2394/2402/1 2393/2401/1 +f 13322/13330/1 2389/2397/1 2392/2400/1 13323/13331/1 +f 13327/13335/1 13332/13340/1 2389/2397/1 13322/13330/1 +f 13332/13340/1 13331/13339/1 2390/2398/1 2389/2397/1 +f 13334/13342/1 2385/2393/1 2388/2396/1 13335/13343/1 +f 13339/13347/1 13344/13352/1 2385/2393/1 13334/13342/1 +f 13344/13352/1 13343/13351/1 2386/2394/1 2385/2393/1 +f 13346/13354/1 2381/2389/1 2384/2392/1 13347/13355/1 +f 13351/13359/1 13356/13364/1 2381/2389/1 13346/13354/1 +f 13356/13364/1 13355/13363/1 2382/2390/1 2381/2389/1 +f 13358/13366/1 2377/2385/1 2380/2388/1 13359/13367/1 +f 13363/13371/1 13368/13376/1 2377/2385/1 13358/13366/1 +f 13368/13376/1 13367/13375/1 2378/2386/1 2377/2385/1 +f 13370/13378/1 2373/2381/1 2376/2384/1 13371/13379/1 +f 13375/13383/1 13380/13388/1 2373/2381/1 13370/13378/1 +f 13380/13388/1 13379/13387/1 2374/2382/1 2373/2381/1 +f 13382/13390/1 2369/2377/1 2372/2380/1 13383/13391/1 +f 13387/13395/1 13392/13400/1 2369/2377/1 13382/13390/1 +f 13392/13400/1 13391/13399/1 2370/2378/1 2369/2377/1 +f 13394/13402/1 2365/2373/1 2368/2376/1 13395/13403/1 +f 13399/13407/1 13404/13412/1 2365/2373/1 13394/13402/1 +f 13404/13412/1 13403/13411/1 2366/2374/1 2365/2373/1 +f 13406/13414/1 2361/2369/1 2364/2372/1 13407/13415/1 +f 13411/13419/1 13416/13424/1 2361/2369/1 13406/13414/1 +f 13416/13424/1 13415/13423/1 2362/2370/1 2361/2369/1 +f 13418/13426/1 2357/2365/1 2360/2368/1 13419/13427/1 +f 13423/13431/1 13428/13436/1 2357/2365/1 13418/13426/1 +f 13428/13436/1 13427/13435/1 2358/2366/1 2357/2365/1 +f 13430/13438/1 2353/2361/1 2356/2364/1 13431/13439/1 +f 13435/13443/1 13440/13448/1 2353/2361/1 13430/13438/1 +f 13440/13448/1 13439/13447/1 2354/2362/1 2353/2361/1 +f 13442/13450/1 2349/2357/1 2352/2360/1 13443/13451/1 +f 13447/13455/1 13452/13460/1 2349/2357/1 13442/13450/1 +f 13452/13460/1 13451/13459/1 2350/2358/1 2349/2357/1 +f 13454/13462/1 2345/2353/1 2348/2356/1 13455/13463/1 +f 13459/13467/1 13464/13472/1 2345/2353/1 13454/13462/1 +f 13464/13472/1 13463/13471/1 2346/2354/1 2345/2353/1 +f 13466/13474/1 2341/2349/1 2344/2352/1 13467/13475/1 +f 13471/13479/1 13476/13484/1 2341/2349/1 13466/13474/1 +f 13476/13484/1 13475/13483/1 2342/2350/1 2341/2349/1 +f 13478/13486/1 2337/2345/1 2340/2348/1 13479/13487/1 +f 13483/13491/1 13488/13496/1 2337/2345/1 13478/13486/1 +f 13488/13496/1 13487/13495/1 2338/2346/1 2337/2345/1 +f 13490/13498/1 2333/2341/1 2336/2344/1 13491/13499/1 +f 13495/13503/1 13500/13508/1 2333/2341/1 13490/13498/1 +f 13500/13508/1 13499/13507/1 2334/2342/1 2333/2341/1 +f 13502/13510/1 2329/2337/1 2332/2340/1 13503/13511/1 +f 13507/13515/1 13512/13520/1 2329/2337/1 13502/13510/1 +f 13512/13520/1 13511/13519/1 2330/2338/1 2329/2337/1 +f 13514/13522/1 2325/2333/1 2328/2336/1 13515/13523/1 +f 13519/13527/1 13524/13532/1 2325/2333/1 13514/13522/1 +f 13524/13532/1 13523/13531/1 2326/2334/1 2325/2333/1 +f 13526/13534/1 2321/2329/1 2324/2332/1 13527/13535/1 +f 13531/13539/1 13536/13544/1 2321/2329/1 13526/13534/1 +f 13536/13544/1 13535/13543/1 2322/2330/1 2321/2329/1 +f 13538/13546/1 2317/2325/1 2320/2328/1 13539/13547/1 +f 13543/13551/1 13548/13556/1 2317/2325/1 13538/13546/1 +f 13548/13556/1 13547/13555/1 2318/2326/1 2317/2325/1 +f 13550/13558/1 2313/2321/1 2316/2324/1 13551/13559/1 +f 13555/13563/1 13560/13568/1 2313/2321/1 13550/13558/1 +f 13560/13568/1 13559/13567/1 2314/2322/1 2313/2321/1 +f 13562/13570/1 2309/2317/1 2312/2320/1 13563/13571/1 +f 13567/13575/1 13572/13580/1 2309/2317/1 13562/13570/1 +f 13572/13580/1 13571/13579/1 2310/2318/1 2309/2317/1 +f 13574/13582/1 2305/2313/1 2308/2316/1 13575/13583/1 +f 13579/13587/1 13584/13592/1 2305/2313/1 13574/13582/1 +f 13584/13592/1 13583/13591/1 2306/2314/1 2305/2313/1 +f 13586/13594/1 2301/2309/1 2304/2312/1 13587/13595/1 +f 13591/13599/1 13596/13604/1 2301/2309/1 13586/13594/1 +f 13596/13604/1 13595/13603/1 2302/2310/1 2301/2309/1 +f 13598/13606/1 2297/2305/1 2300/2308/1 13599/13607/1 +f 13603/13611/1 13608/13616/1 2297/2305/1 13598/13606/1 +f 13608/13616/1 13607/13615/1 2298/2306/1 2297/2305/1 +f 13610/13618/1 2293/2301/1 2296/2304/1 13611/13619/1 +f 13615/13623/1 13620/13628/1 2293/2301/1 13610/13618/1 +f 13620/13628/1 13619/13627/1 2294/2302/1 2293/2301/1 +f 13622/13630/1 2289/2297/1 2292/2300/1 13623/13631/1 +f 13627/13635/1 13632/13640/1 2289/2297/1 13622/13630/1 +f 13632/13640/1 13631/13639/1 2290/2298/1 2289/2297/1 +f 13634/13642/1 2285/2293/1 2288/2296/1 13635/13643/1 +f 13639/13647/1 13644/13652/1 2285/2293/1 13634/13642/1 +f 13644/13652/1 13643/13651/1 2286/2294/1 2285/2293/1 +f 13646/13654/1 2281/2289/1 2284/2292/1 13647/13655/1 +f 13651/13659/1 13656/13664/1 2281/2289/1 13646/13654/1 +f 13656/13664/1 13655/13663/1 2282/2290/1 2281/2289/1 +f 13658/13666/1 2277/2285/1 2280/2288/1 13659/13667/1 +f 13663/13671/1 13668/13676/1 2277/2285/1 13658/13666/1 +f 13668/13676/1 13667/13675/1 2278/2286/1 2277/2285/1 +f 13670/13678/1 2273/2281/1 2276/2284/1 13671/13679/1 +f 13675/13683/1 13680/13688/1 2273/2281/1 13670/13678/1 +f 13680/13688/1 13679/13687/1 2274/2282/1 2273/2281/1 +f 13682/13690/1 2269/2277/1 2272/2280/1 13683/13691/1 +f 13687/13695/1 13692/13700/1 2269/2277/1 13682/13690/1 +f 13692/13700/1 13691/13699/1 2270/2278/1 2269/2277/1 +f 13694/13702/1 2265/2273/1 2268/2276/1 13695/13703/1 +f 13699/13707/1 13704/13712/1 2265/2273/1 13694/13702/1 +f 13704/13712/1 13703/13711/1 2266/2274/1 2265/2273/1 +f 13706/13714/1 2261/2269/1 2264/2272/1 13707/13715/1 +f 13711/13719/1 13716/13724/1 2261/2269/1 13706/13714/1 +f 13716/13724/1 13715/13723/1 2262/2270/1 2261/2269/1 +f 13718/13726/1 2257/2265/1 2260/2268/1 13719/13727/1 +f 13723/13731/1 13728/13736/1 2257/2265/1 13718/13726/1 +f 13728/13736/1 13727/13735/1 2258/2266/1 2257/2265/1 +f 13730/13738/1 2253/2261/1 2256/2264/1 13731/13739/1 +f 13735/13743/1 13740/13748/1 2253/2261/1 13730/13738/1 +f 13740/13748/1 13739/13747/1 2254/2262/1 2253/2261/1 +f 13742/13750/1 2249/2257/1 2252/2260/1 13743/13751/1 +f 13747/13755/1 13752/13760/1 2249/2257/1 13742/13750/1 +f 13752/13760/1 13751/13759/1 2250/2258/1 2249/2257/1 +f 13754/13762/1 2245/2253/1 2248/2256/1 13755/13763/1 +f 13759/13767/1 13764/13772/1 2245/2253/1 13754/13762/1 +f 13764/13772/1 13763/13771/1 2246/2254/1 2245/2253/1 +f 13766/13774/1 2241/2249/1 2244/2252/1 13767/13775/1 +f 13771/13779/1 13776/13784/1 2241/2249/1 13766/13774/1 +f 13776/13784/1 13775/13783/1 2242/2250/1 2241/2249/1 +f 13778/13786/1 2237/2245/1 2240/2248/1 13779/13787/1 +f 13783/13791/1 13788/13796/1 2237/2245/1 13778/13786/1 +f 13788/13796/1 13787/13795/1 2238/2246/1 2237/2245/1 +f 13790/13798/1 2233/2241/1 2236/2244/1 13791/13799/1 +f 13795/13803/1 13800/13808/1 2233/2241/1 13790/13798/1 +f 13800/13808/1 13799/13807/1 2234/2242/1 2233/2241/1 +f 13802/13810/1 2229/2237/1 2232/2240/1 13803/13811/1 +f 13807/13815/1 13812/13820/1 2229/2237/1 13802/13810/1 +f 13812/13820/1 13811/13819/1 2230/2238/1 2229/2237/1 +f 13814/13822/1 2225/2233/1 2228/2236/1 13815/13823/1 +f 13819/13827/1 13824/13832/1 2225/2233/1 13814/13822/1 +f 13824/13832/1 13823/13831/1 2226/2234/1 2225/2233/1 +f 13826/13834/1 2221/2229/1 2224/2232/1 13827/13835/1 +f 13831/13839/1 13836/13844/1 2221/2229/1 13826/13834/1 +f 13836/13844/1 13835/13843/1 2222/2230/1 2221/2229/1 +f 13838/13846/1 2217/2225/1 2220/2228/1 13839/13847/1 +f 13843/13851/1 13848/13856/1 2217/2225/1 13838/13846/1 +f 13848/13856/1 13847/13855/1 2218/2226/1 2217/2225/1 +f 13850/13858/1 2213/2221/1 2216/2224/1 13851/13859/1 +f 13855/13863/1 13860/13868/1 2213/2221/1 13850/13858/1 +f 13860/13868/1 13859/13867/1 2214/2222/1 2213/2221/1 +f 13862/13870/1 2209/2217/1 2212/2220/1 13863/13871/1 +f 13867/13875/1 13872/13880/1 2209/2217/1 13862/13870/1 +f 13872/13880/1 13871/13879/1 2210/2218/1 2209/2217/1 +f 13874/13882/1 2205/2213/1 2208/2216/1 13875/13883/1 +f 13879/13887/1 13884/13892/1 2205/2213/1 13874/13882/1 +f 13884/13892/1 13883/13891/1 2206/2214/1 2205/2213/1 +f 13886/13894/1 2201/2209/1 2204/2212/1 13887/13895/1 +f 13891/13899/1 13896/13904/1 2201/2209/1 13886/13894/1 +f 13896/13904/1 13895/13903/1 2202/2210/1 2201/2209/1 +f 13898/13906/1 2197/2205/1 2200/2208/1 13899/13907/1 +f 13903/13911/1 13908/13916/1 2197/2205/1 13898/13906/1 +f 13908/13916/1 13907/13915/1 2198/2206/1 2197/2205/1 +f 13910/13918/1 2193/2201/1 2196/2204/1 13911/13919/1 +f 13915/13923/1 13920/13928/1 2193/2201/1 13910/13918/1 +f 13920/13928/1 13919/13927/1 2194/2202/1 2193/2201/1 +f 13922/13930/1 2189/2197/1 2192/2200/1 13923/13931/1 +f 13927/13935/1 13932/13940/1 2189/2197/1 13922/13930/1 +f 13932/13940/1 13931/13939/1 2190/2198/1 2189/2197/1 +f 13934/13942/1 2185/2193/1 2188/2196/1 13935/13943/1 +f 13939/13947/1 13944/13952/1 2185/2193/1 13934/13942/1 +f 13944/13952/1 13943/13951/1 2186/2194/1 2185/2193/1 +f 13946/13954/1 2181/2189/1 2184/2192/1 13947/13955/1 +f 13951/13959/1 13956/13964/1 2181/2189/1 13946/13954/1 +f 13956/13964/1 13955/13963/1 2182/2190/1 2181/2189/1 +f 13958/13966/1 2177/2185/1 2180/2188/1 13959/13967/1 +f 13963/13971/1 13968/13976/1 2177/2185/1 13958/13966/1 +f 13968/13976/1 13967/13975/1 2178/2186/1 2177/2185/1 +f 13970/13978/1 2173/2181/1 2176/2184/1 13971/13979/1 +f 13975/13983/1 13980/13988/1 2173/2181/1 13970/13978/1 +f 13980/13988/1 13979/13987/1 2174/2182/1 2173/2181/1 +f 13982/13990/1 2169/2177/1 2172/2180/1 13983/13991/1 +f 13987/13995/1 13992/14000/1 2169/2177/1 13982/13990/1 +f 13992/14000/1 13991/13999/1 2170/2178/1 2169/2177/1 +f 13994/14002/1 2165/2173/1 2168/2176/1 13995/14003/1 +f 13999/14007/1 14004/14012/1 2165/2173/1 13994/14002/1 +f 14004/14012/1 14003/14011/1 2166/2174/1 2165/2173/1 +f 14006/14014/1 2161/2169/1 2164/2172/1 14007/14015/1 +f 14011/14019/1 14016/14024/1 2161/2169/1 14006/14014/1 +f 14016/14024/1 14015/14023/1 2162/2170/1 2161/2169/1 +f 14018/14026/1 2157/2165/1 2160/2168/1 14019/14027/1 +f 14023/14031/1 14028/14036/1 2157/2165/1 14018/14026/1 +f 14028/14036/1 14027/14035/1 2158/2166/1 2157/2165/1 +f 14030/14038/1 2153/2161/1 2156/2164/1 14031/14039/1 +f 14035/14043/1 14040/14048/1 2153/2161/1 14030/14038/1 +f 14040/14048/1 14039/14047/1 2154/2162/1 2153/2161/1 +f 14042/14050/1 2149/2157/1 2152/2160/1 14043/14051/1 +f 14047/14055/1 14052/14060/1 2149/2157/1 14042/14050/1 +f 14052/14060/1 14051/14059/1 2150/2158/1 2149/2157/1 +f 14054/14062/1 2145/2153/1 2148/2156/1 14055/14063/1 +f 14059/14067/1 14064/14072/1 2145/2153/1 14054/14062/1 +f 14064/14072/1 14063/14071/1 2146/2154/1 2145/2153/1 +f 14066/14074/1 2141/2149/1 2144/2152/1 14067/14075/1 +f 14071/14079/1 14076/14084/1 2141/2149/1 14066/14074/1 +f 14076/14084/1 14075/14083/1 2142/2150/1 2141/2149/1 +f 14078/14086/1 2137/2145/1 2140/2148/1 14079/14087/1 +f 14083/14091/1 14088/14096/1 2137/2145/1 14078/14086/1 +f 14088/14096/1 14087/14095/1 2138/2146/1 2137/2145/1 +f 14090/14098/1 2133/2141/1 2136/2144/1 14091/14099/1 +f 14095/14103/1 14100/14108/1 2133/2141/1 14090/14098/1 +f 14100/14108/1 14099/14107/1 2134/2142/1 2133/2141/1 +f 14102/14110/1 2129/2137/1 2132/2140/1 14103/14111/1 +f 14107/14115/1 14112/14120/1 2129/2137/1 14102/14110/1 +f 14112/14120/1 14111/14119/1 2130/2138/1 2129/2137/1 +f 14114/14122/1 2125/2133/1 2128/2136/1 14115/14123/1 +f 14119/14127/1 14124/14132/1 2125/2133/1 14114/14122/1 +f 14124/14132/1 14123/14131/1 2126/2134/1 2125/2133/1 +f 14126/14134/1 2121/2129/1 2124/2132/1 14127/14135/1 +f 14131/14139/1 14136/14144/1 2121/2129/1 14126/14134/1 +f 14136/14144/1 14135/14143/1 2122/2130/1 2121/2129/1 +f 14138/14146/1 2117/2125/1 2120/2128/1 14139/14147/1 +f 14143/14151/1 14148/14156/1 2117/2125/1 14138/14146/1 +f 14148/14156/1 14147/14155/1 2118/2126/1 2117/2125/1 +f 14150/14158/1 2113/2121/1 2116/2124/1 14151/14159/1 +f 14155/14163/1 14160/14168/1 2113/2121/1 14150/14158/1 +f 14160/14168/1 14159/14167/1 2114/2122/1 2113/2121/1 +f 14162/14170/1 2109/2117/1 2112/2120/1 14163/14171/1 +f 14167/14175/1 14172/14180/1 2109/2117/1 14162/14170/1 +f 14172/14180/1 14171/14179/1 2110/2118/1 2109/2117/1 +f 14174/14182/1 2105/2113/1 2108/2116/1 14175/14183/1 +f 14179/14187/1 14184/14192/1 2105/2113/1 14174/14182/1 +f 14184/14192/1 14183/14191/1 2106/2114/1 2105/2113/1 +f 14186/14194/1 2101/2109/1 2104/2112/1 14187/14195/1 +f 14191/14199/1 14196/14204/1 2101/2109/1 14186/14194/1 +f 14196/14204/1 14195/14203/1 2102/2110/1 2101/2109/1 +f 14198/14206/1 2097/2105/1 2100/2108/1 14199/14207/1 +f 14203/14211/1 14208/14216/1 2097/2105/1 14198/14206/1 +f 14208/14216/1 14207/14215/1 2098/2106/1 2097/2105/1 +f 14210/14218/1 2093/2101/1 2096/2104/1 14211/14219/1 +f 14215/14223/1 14220/14228/1 2093/2101/1 14210/14218/1 +f 14220/14228/1 14219/14227/1 2094/2102/1 2093/2101/1 +f 14222/14230/1 2089/2097/1 2092/2100/1 14223/14231/1 +f 14227/14235/1 14232/14240/1 2089/2097/1 14222/14230/1 +f 14232/14240/1 14231/14239/1 2090/2098/1 2089/2097/1 +f 14234/14242/1 2085/2093/1 2088/2096/1 14235/14243/1 +f 14239/14247/1 14244/14252/1 2085/2093/1 14234/14242/1 +f 14244/14252/1 14243/14251/1 2086/2094/1 2085/2093/1 +f 14246/14254/1 2081/2089/1 2084/2092/1 14247/14255/1 +f 14251/14259/1 14256/14264/1 2081/2089/1 14246/14254/1 +f 14256/14264/1 14255/14263/1 2082/2090/1 2081/2089/1 +f 14258/14266/1 2077/2085/1 2080/2088/1 14259/14267/1 +f 14263/14271/1 14268/14276/1 2077/2085/1 14258/14266/1 +f 14268/14276/1 14267/14275/1 2078/2086/1 2077/2085/1 +f 14270/14278/1 2073/2081/1 2076/2084/1 14271/14279/1 +f 14275/14283/1 14280/14288/1 2073/2081/1 14270/14278/1 +f 14280/14288/1 14279/14287/1 2074/2082/1 2073/2081/1 +f 14282/14290/1 2069/2077/1 2072/2080/1 14283/14291/1 +f 14287/14295/1 14292/14300/1 2069/2077/1 14282/14290/1 +f 14292/14300/1 14291/14299/1 2070/2078/1 2069/2077/1 +f 14294/14302/1 2065/2073/1 2068/2076/1 14295/14303/1 +f 14299/14307/1 14304/14312/1 2065/2073/1 14294/14302/1 +f 14304/14312/1 14303/14311/1 2066/2074/1 2065/2073/1 +f 14306/14314/1 2061/2069/1 2064/2072/1 14307/14315/1 +f 14311/14319/1 14316/14324/1 2061/2069/1 14306/14314/1 +f 14316/14324/1 14315/14323/1 2062/2070/1 2061/2069/1 +f 14318/14326/1 2057/2065/1 2060/2068/1 14319/14327/1 +f 14323/14331/1 14328/14336/1 2057/2065/1 14318/14326/1 +f 14328/14336/1 14327/14335/1 2058/2066/1 2057/2065/1 +f 14330/14338/1 2053/2061/1 2056/2064/1 14331/14339/1 +f 14335/14343/1 14340/14348/1 2053/2061/1 14330/14338/1 +f 14340/14348/1 14339/14347/1 2054/2062/1 2053/2061/1 +f 14342/14350/1 2049/2057/1 2052/2060/1 14343/14351/1 +f 14347/14355/1 14352/14360/1 2049/2057/1 14342/14350/1 +f 14352/14360/1 14351/14359/1 2050/2058/1 2049/2057/1 +f 14354/14362/1 2045/2053/1 2048/2056/1 14355/14363/1 +f 14359/14367/1 14364/14372/1 2045/2053/1 14354/14362/1 +f 14364/14372/1 14363/14371/1 2046/2054/1 2045/2053/1 +f 14366/14374/1 2041/2049/1 2044/2052/1 14367/14375/1 +f 14371/14379/1 14376/14384/1 2041/2049/1 14366/14374/1 +f 14376/14384/1 14375/14383/1 2042/2050/1 2041/2049/1 +f 14378/14386/1 2037/2045/1 2040/2048/1 14379/14387/1 +f 14383/14391/1 14388/14396/1 2037/2045/1 14378/14386/1 +f 14388/14396/1 14387/14395/1 2038/2046/1 2037/2045/1 +f 14390/14398/1 2033/2041/1 2036/2044/1 14391/14399/1 +f 14395/14403/1 14400/14408/1 2033/2041/1 14390/14398/1 +f 14400/14408/1 14399/14407/1 2034/2042/1 2033/2041/1 +f 14402/14410/1 2029/2037/1 2032/2040/1 14403/14411/1 +f 14407/14415/1 14412/14420/1 2029/2037/1 14402/14410/1 +f 14412/14420/1 14411/14419/1 2030/2038/1 2029/2037/1 +f 14414/14422/1 2025/2033/1 2028/2036/1 14415/14423/1 +f 14419/14427/1 14424/14432/1 2025/2033/1 14414/14422/1 +f 14424/14432/1 14423/14431/1 2026/2034/1 2025/2033/1 +f 14426/14434/1 2021/2029/1 2024/2032/1 14427/14435/1 +f 14431/14439/1 14436/14444/1 2021/2029/1 14426/14434/1 +f 14436/14444/1 14435/14443/1 2022/2030/1 2021/2029/1 +f 14438/14446/1 2017/2025/1 2020/2028/1 14439/14447/1 +f 14443/14451/1 14448/14456/1 2017/2025/1 14438/14446/1 +f 14448/14456/1 14447/14455/1 2018/2026/1 2017/2025/1 +f 14450/14458/1 2013/2021/1 2016/2024/1 14451/14459/1 +f 14455/14463/1 14460/14468/1 2013/2021/1 14450/14458/1 +f 14460/14468/1 14459/14467/1 2014/2022/1 2013/2021/1 +f 14462/14470/1 2009/2017/1 2012/2020/1 14463/14471/1 +f 14467/14475/1 14472/14480/1 2009/2017/1 14462/14470/1 +f 14472/14480/1 14471/14479/1 2010/2018/1 2009/2017/1 +f 14474/14482/1 2005/2013/1 2008/2016/1 14475/14483/1 +f 14479/14487/1 14484/14492/1 2005/2013/1 14474/14482/1 +f 14484/14492/1 14483/14491/1 2006/2014/1 2005/2013/1 +f 14486/14494/1 2001/2009/1 2004/2012/1 14487/14495/1 +f 14491/14499/1 14496/14504/1 2001/2009/1 14486/14494/1 +f 14496/14504/1 14495/14503/1 2002/2010/1 2001/2009/1 +f 14498/14506/1 1997/2005/1 2000/2008/1 14499/14507/1 +f 14503/14511/1 14508/14516/1 1997/2005/1 14498/14506/1 +f 14508/14516/1 14507/14515/1 1998/2006/1 1997/2005/1 +f 14510/14518/1 1993/2001/1 1996/2004/1 14511/14519/1 +f 14515/14523/1 14520/14528/1 1993/2001/1 14510/14518/1 +f 14520/14528/1 14519/14527/1 1994/2002/1 1993/2001/1 +f 14522/14530/1 1989/1997/1 1992/2000/1 14523/14531/1 +f 14527/14535/1 14532/14540/1 1989/1997/1 14522/14530/1 +f 14532/14540/1 14531/14539/1 1990/1998/1 1989/1997/1 +f 14534/14542/1 1985/1993/1 1988/1996/1 14535/14543/1 +f 14539/14547/1 14544/14552/1 1985/1993/1 14534/14542/1 +f 14544/14552/1 14543/14551/1 1986/1994/1 1985/1993/1 +f 14546/14554/1 1981/1989/1 1984/1992/1 14547/14555/1 +f 14551/14559/1 14556/14564/1 1981/1989/1 14546/14554/1 +f 14556/14564/1 14555/14563/1 1982/1990/1 1981/1989/1 +f 14558/14566/1 1977/1985/1 1980/1988/1 14559/14567/1 +f 14563/14571/1 14568/14576/1 1977/1985/1 14558/14566/1 +f 14568/14576/1 14567/14575/1 1978/1986/1 1977/1985/1 +f 14570/14578/1 1973/1981/1 1976/1984/1 14571/14579/1 +f 14575/14583/1 14580/14588/1 1973/1981/1 14570/14578/1 +f 14580/14588/1 14579/14587/1 1974/1982/1 1973/1981/1 +f 14582/14590/1 1969/1977/1 1972/1980/1 14583/14591/1 +f 14587/14595/1 14592/14600/1 1969/1977/1 14582/14590/1 +f 14592/14600/1 14591/14599/1 1970/1978/1 1969/1977/1 +f 14594/14602/1 1965/1973/1 1968/1976/1 14595/14603/1 +f 14599/14607/1 14604/14612/1 1965/1973/1 14594/14602/1 +f 14604/14612/1 14603/14611/1 1966/1974/1 1965/1973/1 +f 14606/14614/1 1961/1969/1 1964/1972/1 14607/14615/1 +f 14611/14619/1 14616/14624/1 1961/1969/1 14606/14614/1 +f 14616/14624/1 14615/14623/1 1962/1970/1 1961/1969/1 +f 14618/14626/1 1957/1965/1 1960/1968/1 14619/14627/1 +f 14623/14631/1 14628/14636/1 1957/1965/1 14618/14626/1 +f 14628/14636/1 14627/14635/1 1958/1966/1 1957/1965/1 +f 14630/14638/1 1953/1961/1 1956/1964/1 14631/14639/1 +f 14635/14643/1 14640/14648/1 1953/1961/1 14630/14638/1 +f 14640/14648/1 14639/14647/1 1954/1962/1 1953/1961/1 +f 14642/14650/1 1949/1957/1 1952/1960/1 14643/14651/1 +f 14647/14655/1 14652/14660/1 1949/1957/1 14642/14650/1 +f 14652/14660/1 14651/14659/1 1950/1958/1 1949/1957/1 +f 14654/14662/1 1945/1953/1 1948/1956/1 14655/14663/1 +f 14659/14667/1 14664/14672/1 1945/1953/1 14654/14662/1 +f 14664/14672/1 14663/14671/1 1946/1954/1 1945/1953/1 +f 14666/14674/1 1941/1949/1 1944/1952/1 14667/14675/1 +f 14671/14679/1 14676/14684/1 1941/1949/1 14666/14674/1 +f 14676/14684/1 14675/14683/1 1942/1950/1 1941/1949/1 +f 14678/14686/1 1937/1945/1 1940/1948/1 14679/14687/1 +f 14683/14691/1 14688/14696/1 1937/1945/1 14678/14686/1 +f 14688/14696/1 14687/14695/1 1938/1946/1 1937/1945/1 +f 14690/14698/1 1933/1941/1 1936/1944/1 14691/14699/1 +f 14695/14703/1 14700/14708/1 1933/1941/1 14690/14698/1 +f 14700/14708/1 14699/14707/1 1934/1942/1 1933/1941/1 +f 14702/14710/1 1929/1937/1 1932/1940/1 14703/14711/1 +f 14707/14715/1 14712/14720/1 1929/1937/1 14702/14710/1 +f 14712/14720/1 14711/14719/1 1930/1938/1 1929/1937/1 +f 14714/14722/1 1925/1933/1 1928/1936/1 14715/14723/1 +f 14719/14727/1 14724/14732/1 1925/1933/1 14714/14722/1 +f 14724/14732/1 14723/14731/1 1926/1934/1 1925/1933/1 +f 14726/14734/1 1921/1929/1 1924/1932/1 14727/14735/1 +f 14731/14739/1 14736/14744/1 1921/1929/1 14726/14734/1 +f 14736/14744/1 14735/14743/1 1922/1930/1 1921/1929/1 +f 14738/14746/1 1917/1925/1 1920/1928/1 14739/14747/1 +f 14743/14751/1 14748/14756/1 1917/1925/1 14738/14746/1 +f 14748/14756/1 14747/14755/1 1918/1926/1 1917/1925/1 +f 14750/14758/1 1913/1921/1 1916/1924/1 14751/14759/1 +f 14755/14763/1 14760/14768/1 1913/1921/1 14750/14758/1 +f 14760/14768/1 14759/14767/1 1914/1922/1 1913/1921/1 +f 14762/14770/1 1909/1917/1 1912/1920/1 14763/14771/1 +f 14767/14775/1 14772/14780/1 1909/1917/1 14762/14770/1 +f 14772/14780/1 14771/14779/1 1910/1918/1 1909/1917/1 +f 14774/14782/1 1905/1913/1 1908/1916/1 14775/14783/1 +f 14779/14787/1 14784/14792/1 1905/1913/1 14774/14782/1 +f 14784/14792/1 14783/14791/1 1906/1914/1 1905/1913/1 +f 14786/14794/1 1901/1909/1 1904/1912/1 14787/14795/1 +f 14791/14799/1 14796/14804/1 1901/1909/1 14786/14794/1 +f 14796/14804/1 14795/14803/1 1902/1910/1 1901/1909/1 +f 14798/14806/1 1897/1905/1 1900/1908/1 14799/14807/1 +f 14803/14811/1 14808/14816/1 1897/1905/1 14798/14806/1 +f 14808/14816/1 14807/14815/1 1898/1906/1 1897/1905/1 +f 14810/14818/1 1893/1901/1 1896/1904/1 14811/14819/1 +f 14815/14823/1 14820/14828/1 1893/1901/1 14810/14818/1 +f 14820/14828/1 14819/14827/1 1894/1902/1 1893/1901/1 +f 14822/14830/1 1889/1897/1 1892/1900/1 14823/14831/1 +f 14827/14835/1 14832/14840/1 1889/1897/1 14822/14830/1 +f 14832/14840/1 14831/14839/1 1890/1898/1 1889/1897/1 +f 14834/14842/1 1885/1893/1 1888/1896/1 14835/14843/1 +f 14839/14847/1 14844/14852/1 1885/1893/1 14834/14842/1 +f 14844/14852/1 14843/14851/1 1886/1894/1 1885/1893/1 +f 14846/14854/1 1881/1889/1 1884/1892/1 14847/14855/1 +f 14851/14859/1 14856/14864/1 1881/1889/1 14846/14854/1 +f 14856/14864/1 14855/14863/1 1882/1890/1 1881/1889/1 +f 14858/14866/1 1877/1885/1 1880/1888/1 14859/14867/1 +f 14863/14871/1 14868/14876/1 1877/1885/1 14858/14866/1 +f 14868/14876/1 14867/14875/1 1878/1886/1 1877/1885/1 +f 14870/14878/1 1873/1881/1 1876/1884/1 14871/14879/1 +f 14875/14883/1 14880/14888/1 1873/1881/1 14870/14878/1 +f 14880/14888/1 14879/14887/1 1874/1882/1 1873/1881/1 +f 14882/14890/1 1869/1877/1 1872/1880/1 14883/14891/1 +f 14887/14895/1 14892/14900/1 1869/1877/1 14882/14890/1 +f 14892/14900/1 14891/14899/1 1870/1878/1 1869/1877/1 +f 14894/14902/1 1865/1873/1 1868/1876/1 14895/14903/1 +f 14899/14907/1 14904/14912/1 1865/1873/1 14894/14902/1 +f 14904/14912/1 14903/14911/1 1866/1874/1 1865/1873/1 +f 14906/14914/1 1861/1869/1 1864/1872/1 14907/14915/1 +f 14911/14919/1 14916/14924/1 1861/1869/1 14906/14914/1 +f 14916/14924/1 14915/14923/1 1862/1870/1 1861/1869/1 +f 14918/14926/1 1857/1865/1 1860/1868/1 14919/14927/1 +f 14923/14931/1 14928/14936/1 1857/1865/1 14918/14926/1 +f 14928/14936/1 14927/14935/1 1858/1866/1 1857/1865/1 +f 14930/14938/1 1853/1861/1 1856/1864/1 14931/14939/1 +f 14935/14943/1 14940/14948/1 1853/1861/1 14930/14938/1 +f 14940/14948/1 14939/14947/1 1854/1862/1 1853/1861/1 +f 14942/14950/1 1849/1857/1 1852/1860/1 14943/14951/1 +f 14947/14955/1 14952/14960/1 1849/1857/1 14942/14950/1 +f 14952/14960/1 14951/14959/1 1850/1858/1 1849/1857/1 +f 14954/14962/1 1845/1853/1 1848/1856/1 14955/14963/1 +f 14959/14967/1 14964/14972/1 1845/1853/1 14954/14962/1 +f 14964/14972/1 14963/14971/1 1846/1854/1 1845/1853/1 +f 14966/14974/1 1841/1849/1 1844/1852/1 14967/14975/1 +f 14971/14979/1 14976/14984/1 1841/1849/1 14966/14974/1 +f 14976/14984/1 14975/14983/1 1842/1850/1 1841/1849/1 +f 14978/14986/1 1837/1845/1 1840/1848/1 14979/14987/1 +f 14983/14991/1 14988/14996/1 1837/1845/1 14978/14986/1 +f 14988/14996/1 14987/14995/1 1838/1846/1 1837/1845/1 +f 14990/14998/1 1833/1841/1 1836/1844/1 14991/14999/1 +f 14995/15003/1 15000/15008/1 1833/1841/1 14990/14998/1 +f 15000/15008/1 14999/15007/1 1834/1842/1 1833/1841/1 +f 15002/15010/1 1829/1837/1 1832/1840/1 15003/15011/1 +f 15007/15015/1 15012/15020/1 1829/1837/1 15002/15010/1 +f 15012/15020/1 15011/15019/1 1830/1838/1 1829/1837/1 +f 15014/15022/1 1825/1833/1 1828/1836/1 15015/15023/1 +f 15019/15027/1 15024/15032/1 1825/1833/1 15014/15022/1 +f 15024/15032/1 15023/15031/1 1826/1834/1 1825/1833/1 +f 15026/15034/1 1821/1829/1 1824/1832/1 15027/15035/1 +f 15031/15039/1 15036/15044/1 1821/1829/1 15026/15034/1 +f 15036/15044/1 15035/15043/1 1822/1830/1 1821/1829/1 +f 15038/15046/1 1817/1825/1 1820/1828/1 15039/15047/1 +f 15043/15051/1 15048/15056/1 1817/1825/1 15038/15046/1 +f 15048/15056/1 15047/15055/1 1818/1826/1 1817/1825/1 +f 15050/15058/1 1813/1821/1 1816/1824/1 15051/15059/1 +f 15055/15063/1 15060/15068/1 1813/1821/1 15050/15058/1 +f 15060/15068/1 15059/15067/1 1814/1822/1 1813/1821/1 +f 15062/15070/1 1809/1817/1 1812/1820/1 15063/15071/1 +f 15067/15075/1 15072/15080/1 1809/1817/1 15062/15070/1 +f 15072/15080/1 15071/15079/1 1810/1818/1 1809/1817/1 +f 15074/15082/1 1805/1813/1 1808/1816/1 15075/15083/1 +f 15079/15087/1 15084/15092/1 1805/1813/1 15074/15082/1 +f 15084/15092/1 15083/15091/1 1806/1814/1 1805/1813/1 +f 15086/15094/1 1801/1809/1 1804/1812/1 15087/15095/1 +f 15091/15099/1 15096/15104/1 1801/1809/1 15086/15094/1 +f 15096/15104/1 15095/15103/1 1802/1810/1 1801/1809/1 +f 15098/15106/1 1797/1805/1 1800/1808/1 15099/15107/1 +f 15103/15111/1 15108/15116/1 1797/1805/1 15098/15106/1 +f 15108/15116/1 15107/15115/1 1798/1806/1 1797/1805/1 +f 15110/15118/1 1793/1801/1 1796/1804/1 15111/15119/1 +f 15115/15123/1 15120/15128/1 1793/1801/1 15110/15118/1 +f 15120/15128/1 15119/15127/1 1794/1802/1 1793/1801/1 +f 15122/15130/1 1789/1797/1 1792/1800/1 15123/15131/1 +f 15127/15135/1 15132/15140/1 1789/1797/1 15122/15130/1 +f 15132/15140/1 15131/15139/1 1790/1798/1 1789/1797/1 +f 15134/15142/1 1785/1793/1 1788/1796/1 15135/15143/1 +f 15139/15147/1 15144/15152/1 1785/1793/1 15134/15142/1 +f 15144/15152/1 15143/15151/1 1786/1794/1 1785/1793/1 +f 15146/15154/1 1781/1789/1 1784/1792/1 15147/15155/1 +f 15151/15159/1 15156/15164/1 1781/1789/1 15146/15154/1 +f 15156/15164/1 15155/15163/1 1782/1790/1 1781/1789/1 +f 15158/15166/1 1777/1785/1 1780/1788/1 15159/15167/1 +f 15163/15171/1 15168/15176/1 1777/1785/1 15158/15166/1 +f 15168/15176/1 15167/15175/1 1778/1786/1 1777/1785/1 +f 15170/15178/1 1773/1781/1 1776/1784/1 15171/15179/1 +f 15175/15183/1 15180/15188/1 1773/1781/1 15170/15178/1 +f 15180/15188/1 15179/15187/1 1774/1782/1 1773/1781/1 +f 15182/15190/1 1769/1777/1 1772/1780/1 15183/15191/1 +f 15187/15195/1 15192/15200/1 1769/1777/1 15182/15190/1 +f 15192/15200/1 15191/15199/1 1770/1778/1 1769/1777/1 +f 15194/15202/1 1765/1773/1 1768/1776/1 15195/15203/1 +f 15199/15207/1 15204/15212/1 1765/1773/1 15194/15202/1 +f 15204/15212/1 15203/15211/1 1766/1774/1 1765/1773/1 +f 15206/15214/1 1761/1769/1 1764/1772/1 15207/15215/1 +f 15211/15219/1 15216/15224/1 1761/1769/1 15206/15214/1 +f 15216/15224/1 15215/15223/1 1762/1770/1 1761/1769/1 +f 15218/15226/1 1757/1765/1 1760/1768/1 15219/15227/1 +f 15223/15231/1 15228/15236/1 1757/1765/1 15218/15226/1 +f 15228/15236/1 15227/15235/1 1758/1766/1 1757/1765/1 +f 15230/15238/1 1753/1761/1 1756/1764/1 15231/15239/1 +f 15235/15243/1 15240/15248/1 1753/1761/1 15230/15238/1 +f 15240/15248/1 15239/15247/1 1754/1762/1 1753/1761/1 +f 15242/15250/1 1749/1757/1 1752/1760/1 15243/15251/1 +f 15247/15255/1 15252/15260/1 1749/1757/1 15242/15250/1 +f 15252/15260/1 15251/15259/1 1750/1758/1 1749/1757/1 +f 15254/15262/1 1745/1753/1 1748/1756/1 15255/15263/1 +f 15259/15267/1 15264/15272/1 1745/1753/1 15254/15262/1 +f 15264/15272/1 15263/15271/1 1746/1754/1 1745/1753/1 +f 15266/15274/1 1741/1749/1 1744/1752/1 15267/15275/1 +f 15271/15279/1 15276/15284/1 1741/1749/1 15266/15274/1 +f 15276/15284/1 15275/15283/1 1742/1750/1 1741/1749/1 +f 15278/15286/1 1737/1745/1 1740/1748/1 15279/15287/1 +f 15283/15291/1 15288/15296/1 1737/1745/1 15278/15286/1 +f 15288/15296/1 15287/15295/1 1738/1746/1 1737/1745/1 +f 15290/15298/1 1733/1741/1 1736/1744/1 15291/15299/1 +f 15295/15303/1 15300/15308/1 1733/1741/1 15290/15298/1 +f 15300/15308/1 15299/15307/1 1734/1742/1 1733/1741/1 +f 15302/15310/1 1729/1737/1 1732/1740/1 15303/15311/1 +f 15307/15315/1 15312/15320/1 1729/1737/1 15302/15310/1 +f 15312/15320/1 15311/15319/1 1730/1738/1 1729/1737/1 +f 15314/15322/1 1725/1733/1 1728/1736/1 15315/15323/1 +f 15319/15327/1 15324/15332/1 1725/1733/1 15314/15322/1 +f 15324/15332/1 15323/15331/1 1726/1734/1 1725/1733/1 +f 15326/15334/1 1721/1729/1 1724/1732/1 15327/15335/1 +f 15331/15339/1 15336/15344/1 1721/1729/1 15326/15334/1 +f 15336/15344/1 15335/15343/1 1722/1730/1 1721/1729/1 +f 15338/15346/1 1717/1725/1 1720/1728/1 15339/15347/1 +f 15343/15351/1 15348/15356/1 1717/1725/1 15338/15346/1 +f 15348/15356/1 15347/15355/1 1718/1726/1 1717/1725/1 +f 15350/15358/1 1713/1721/1 1716/1724/1 15351/15359/1 +f 15355/15363/1 15360/15368/1 1713/1721/1 15350/15358/1 +f 15360/15368/1 15359/15367/1 1714/1722/1 1713/1721/1 +f 15362/15370/1 1709/1717/1 1712/1720/1 15363/15371/1 +f 15367/15375/1 15372/15380/1 1709/1717/1 15362/15370/1 +f 15372/15380/1 15371/15379/1 1710/1718/1 1709/1717/1 +f 15374/15382/1 1705/1713/1 1708/1716/1 15375/15383/1 +f 15379/15387/1 15384/15392/1 1705/1713/1 15374/15382/1 +f 15384/15392/1 15383/15391/1 1706/1714/1 1705/1713/1 +f 15386/15394/1 1701/1709/1 1704/1712/1 15387/15395/1 +f 15391/15399/1 15396/15404/1 1701/1709/1 15386/15394/1 +f 15396/15404/1 15395/15403/1 1702/1710/1 1701/1709/1 +f 15398/15406/1 1697/1705/1 1700/1708/1 15399/15407/1 +f 15403/15411/1 15408/15416/1 1697/1705/1 15398/15406/1 +f 15408/15416/1 15407/15415/1 1698/1706/1 1697/1705/1 +f 15410/15418/1 1693/1701/1 1696/1704/1 15411/15419/1 +f 15415/15423/1 15420/15428/1 1693/1701/1 15410/15418/1 +f 15420/15428/1 15419/15427/1 1694/1702/1 1693/1701/1 +f 15422/15430/1 1689/1697/1 1692/1700/1 15423/15431/1 +f 15427/15435/1 15432/15440/1 1689/1697/1 15422/15430/1 +f 15432/15440/1 15431/15439/1 1690/1698/1 1689/1697/1 +f 15434/15442/1 1685/1693/1 1688/1696/1 15435/15443/1 +f 15439/15447/1 15444/15452/1 1685/1693/1 15434/15442/1 +f 15444/15452/1 15443/15451/1 1686/1694/1 1685/1693/1 +f 15446/15454/1 1681/1689/1 1684/1692/1 15447/15455/1 +f 15451/15459/1 15456/15464/1 1681/1689/1 15446/15454/1 +f 15456/15464/1 15455/15463/1 1682/1690/1 1681/1689/1 +f 15458/15466/1 1677/1685/1 1680/1688/1 15459/15467/1 +f 15463/15471/1 15468/15476/1 1677/1685/1 15458/15466/1 +f 15468/15476/1 15467/15475/1 1678/1686/1 1677/1685/1 +f 15470/15478/1 1673/1681/1 1676/1684/1 15471/15479/1 +f 15475/15483/1 15480/15488/1 1673/1681/1 15470/15478/1 +f 15480/15488/1 15479/15487/1 1674/1682/1 1673/1681/1 +f 15482/15490/1 1669/1677/1 1672/1680/1 15483/15491/1 +f 15487/15495/1 15492/15500/1 1669/1677/1 15482/15490/1 +f 15492/15500/1 15491/15499/1 1670/1678/1 1669/1677/1 +f 15494/15502/1 1665/1673/1 1668/1676/1 15495/15503/1 +f 15499/15507/1 15504/15512/1 1665/1673/1 15494/15502/1 +f 15504/15512/1 15503/15511/1 1666/1674/1 1665/1673/1 +f 15506/15514/1 1661/1669/1 1664/1672/1 15507/15515/1 +f 15511/15519/1 15516/15524/1 1661/1669/1 15506/15514/1 +f 15516/15524/1 15515/15523/1 1662/1670/1 1661/1669/1 +f 15518/15526/1 1657/1665/1 1660/1668/1 15519/15527/1 +f 15523/15531/1 15528/15536/1 1657/1665/1 15518/15526/1 +f 15528/15536/1 15527/15535/1 1658/1666/1 1657/1665/1 +f 15530/15538/1 1653/1661/1 1656/1664/1 15531/15539/1 +f 15535/15543/1 15540/15548/1 1653/1661/1 15530/15538/1 +f 15540/15548/1 15539/15547/1 1654/1662/1 1653/1661/1 +f 15542/15550/1 1649/1657/1 1652/1660/1 15543/15551/1 +f 15547/15555/1 15552/15560/1 1649/1657/1 15542/15550/1 +f 15552/15560/1 15551/15559/1 1650/1658/1 1649/1657/1 +f 15554/15562/1 1645/1653/1 1648/1656/1 15555/15563/1 +f 15559/15567/1 15564/15572/1 1645/1653/1 15554/15562/1 +f 15564/15572/1 15563/15571/1 1646/1654/1 1645/1653/1 +f 15566/15574/1 1641/1649/1 1644/1652/1 15567/15575/1 +f 15571/15579/1 15576/15584/1 1641/1649/1 15566/15574/1 +f 15576/15584/1 15575/15583/1 1642/1650/1 1641/1649/1 +f 15578/15586/1 1637/1645/1 1640/1648/1 15579/15587/1 +f 15583/15591/1 15588/15596/1 1637/1645/1 15578/15586/1 +f 15588/15596/1 15587/15595/1 1638/1646/1 1637/1645/1 +f 15590/15598/1 1633/1641/1 1636/1644/1 15591/15599/1 +f 15595/15603/1 15600/15608/1 1633/1641/1 15590/15598/1 +f 15600/15608/1 15599/15607/1 1634/1642/1 1633/1641/1 +f 15602/15610/1 1629/1637/1 1632/1640/1 15603/15611/1 +f 15607/15615/1 15612/15620/1 1629/1637/1 15602/15610/1 +f 15612/15620/1 15611/15619/1 1630/1638/1 1629/1637/1 +f 15614/15622/1 1625/1633/1 1628/1636/1 15615/15623/1 +f 15619/15627/1 15624/15632/1 1625/1633/1 15614/15622/1 +f 15624/15632/1 15623/15631/1 1626/1634/1 1625/1633/1 +f 15626/15634/1 1621/1629/1 1624/1632/1 15627/15635/1 +f 15631/15639/1 15636/15644/1 1621/1629/1 15626/15634/1 +f 15636/15644/1 15635/15643/1 1622/1630/1 1621/1629/1 +f 15638/15646/1 1617/1625/1 1620/1628/1 15639/15647/1 +f 15643/15651/1 15648/15656/1 1617/1625/1 15638/15646/1 +f 15648/15656/1 15647/15655/1 1618/1626/1 1617/1625/1 +f 15650/15658/1 1613/1621/1 1616/1624/1 15651/15659/1 +f 15655/15663/1 15660/15668/1 1613/1621/1 15650/15658/1 +f 15660/15668/1 15659/15667/1 1614/1622/1 1613/1621/1 +f 15662/15670/1 1609/1617/1 1612/1620/1 15663/15671/1 +f 15667/15675/1 15672/15680/1 1609/1617/1 15662/15670/1 +f 15672/15680/1 15671/15679/1 1610/1618/1 1609/1617/1 +f 15674/15682/1 1605/1613/1 1608/1616/1 15675/15683/1 +f 15679/15687/1 15684/15692/1 1605/1613/1 15674/15682/1 +f 15684/15692/1 15683/15691/1 1606/1614/1 1605/1613/1 +f 15686/15694/1 1601/1609/1 1604/1612/1 15687/15695/1 +f 15691/15699/1 15696/15704/1 1601/1609/1 15686/15694/1 +f 15696/15704/1 15695/15703/1 1602/1610/1 1601/1609/1 +f 15698/15706/1 1597/1605/1 1600/1608/1 15699/15707/1 +f 15703/15711/1 15708/15716/1 1597/1605/1 15698/15706/1 +f 15708/15716/1 15707/15715/1 1598/1606/1 1597/1605/1 +f 15710/15718/1 1593/1601/1 1596/1604/1 15711/15719/1 +f 15715/15723/1 15720/15728/1 1593/1601/1 15710/15718/1 +f 15720/15728/1 15719/15727/1 1594/1602/1 1593/1601/1 +f 15722/15730/1 1589/1597/1 1592/1600/1 15723/15731/1 +f 15727/15735/1 15732/15740/1 1589/1597/1 15722/15730/1 +f 15732/15740/1 15731/15739/1 1590/1598/1 1589/1597/1 +f 15734/15742/1 1585/1593/1 1588/1596/1 15735/15743/1 +f 15739/15747/1 15744/15752/1 1585/1593/1 15734/15742/1 +f 15744/15752/1 15743/15751/1 1586/1594/1 1585/1593/1 +f 15746/15754/1 1581/1589/1 1584/1592/1 15747/15755/1 +f 15751/15759/1 15756/15764/1 1581/1589/1 15746/15754/1 +f 15756/15764/1 15755/15763/1 1582/1590/1 1581/1589/1 +f 15758/15766/1 1577/1585/1 1580/1588/1 15759/15767/1 +f 15763/15771/1 15768/15776/1 1577/1585/1 15758/15766/1 +f 15768/15776/1 15767/15775/1 1578/1586/1 1577/1585/1 +f 15770/15778/1 1573/1581/1 1576/1584/1 15771/15779/1 +f 15775/15783/1 15780/15788/1 1573/1581/1 15770/15778/1 +f 15780/15788/1 15779/15787/1 1574/1582/1 1573/1581/1 +f 15782/15790/1 1569/1577/1 1572/1580/1 15783/15791/1 +f 15787/15795/1 15792/15800/1 1569/1577/1 15782/15790/1 +f 15792/15800/1 15791/15799/1 1570/1578/1 1569/1577/1 +f 15794/15802/1 1565/1573/1 1568/1576/1 15795/15803/1 +f 15799/15807/1 15804/15812/1 1565/1573/1 15794/15802/1 +f 15804/15812/1 15803/15811/1 1566/1574/1 1565/1573/1 +f 15806/15814/1 1561/1569/1 1564/1572/1 15807/15815/1 +f 15811/15819/1 15816/15824/1 1561/1569/1 15806/15814/1 +f 15816/15824/1 15815/15823/1 1562/1570/1 1561/1569/1 +f 15818/15826/1 1557/1565/1 1560/1568/1 15819/15827/1 +f 15823/15831/1 15828/15836/1 1557/1565/1 15818/15826/1 +f 15828/15836/1 15827/15835/1 1558/1566/1 1557/1565/1 +f 15830/15838/1 1553/1561/1 1556/1564/1 15831/15839/1 +f 15835/15843/1 15840/15848/1 1553/1561/1 15830/15838/1 +f 15840/15848/1 15839/15847/1 1554/1562/1 1553/1561/1 +f 15842/15850/1 1549/1557/1 1552/1560/1 15843/15851/1 +f 15847/15855/1 15852/15860/1 1549/1557/1 15842/15850/1 +f 15852/15860/1 15851/15859/1 1550/1558/1 1549/1557/1 +f 15854/15862/1 1545/1553/1 1548/1556/1 15855/15863/1 +f 15859/15867/1 15864/15872/1 1545/1553/1 15854/15862/1 +f 15864/15872/1 15863/15871/1 1546/1554/1 1545/1553/1 +f 15866/15874/1 1541/1549/1 1544/1552/1 15867/15875/1 +f 15871/15879/1 15876/15884/1 1541/1549/1 15866/15874/1 +f 15876/15884/1 15875/15883/1 1542/1550/1 1541/1549/1 +f 15878/15886/1 1537/1545/1 1540/1548/1 15879/15887/1 +f 15883/15891/1 15888/15896/1 1537/1545/1 15878/15886/1 +f 15888/15896/1 15887/15895/1 1538/1546/1 1537/1545/1 +f 15890/15898/1 1533/1541/1 1536/1544/1 15891/15899/1 +f 15895/15903/1 15900/15908/1 1533/1541/1 15890/15898/1 +f 15900/15908/1 15899/15907/1 1534/1542/1 1533/1541/1 +f 15902/15910/1 1529/1537/1 1532/1540/1 15903/15911/1 +f 15907/15915/1 15912/15920/1 1529/1537/1 15902/15910/1 +f 15912/15920/1 15911/15919/1 1530/1538/1 1529/1537/1 +f 15914/15922/1 1525/1533/1 1528/1536/1 15915/15923/1 +f 15919/15927/1 15924/15932/1 1525/1533/1 15914/15922/1 +f 15924/15932/1 15923/15931/1 1526/1534/1 1525/1533/1 +f 15926/15934/1 1521/1529/1 1524/1532/1 15927/15935/1 +f 15931/15939/1 15936/15944/1 1521/1529/1 15926/15934/1 +f 15936/15944/1 15935/15943/1 1522/1530/1 1521/1529/1 +f 15938/15946/1 1517/1525/1 1520/1528/1 15939/15947/1 +f 15943/15951/1 15948/15956/1 1517/1525/1 15938/15946/1 +f 15948/15956/1 15947/15955/1 1518/1526/1 1517/1525/1 +f 15950/15958/1 1513/1521/1 1516/1524/1 15951/15959/1 +f 15955/15963/1 15960/15968/1 1513/1521/1 15950/15958/1 +f 15960/15968/1 15959/15967/1 1514/1522/1 1513/1521/1 +f 15962/15970/1 1509/1517/1 1512/1520/1 15963/15971/1 +f 15967/15975/1 15972/15980/1 1509/1517/1 15962/15970/1 +f 15972/15980/1 15971/15979/1 1510/1518/1 1509/1517/1 +f 15974/15982/1 1505/1513/1 1508/1516/1 15975/15983/1 +f 15979/15987/1 15984/15992/1 1505/1513/1 15974/15982/1 +f 15984/15992/1 15983/15991/1 1506/1514/1 1505/1513/1 +f 15986/15994/1 1501/1509/1 1504/1512/1 15987/15995/1 +f 15991/15999/1 15996/16004/1 1501/1509/1 15986/15994/1 +f 15996/16004/1 15995/16003/1 1502/1510/1 1501/1509/1 +f 15998/16006/1 1497/1505/1 1500/1508/1 15999/16007/1 +f 16003/16011/1 16008/16016/1 1497/1505/1 15998/16006/1 +f 16008/16016/1 16007/16015/1 1498/1506/1 1497/1505/1 +f 16010/16018/1 1493/1501/1 1496/1504/1 16011/16019/1 +f 16015/16023/1 16020/16028/1 1493/1501/1 16010/16018/1 +f 16020/16028/1 16019/16027/1 1494/1502/1 1493/1501/1 +f 16022/16030/1 1489/1497/1 1492/1500/1 16023/16031/1 +f 16027/16035/1 16032/16040/1 1489/1497/1 16022/16030/1 +f 16032/16040/1 16031/16039/1 1490/1498/1 1489/1497/1 +f 16034/16042/1 1485/1493/1 1488/1496/1 16035/16043/1 +f 16039/16047/1 16044/16052/1 1485/1493/1 16034/16042/1 +f 16044/16052/1 16043/16051/1 1486/1494/1 1485/1493/1 +f 16046/16054/1 1481/1489/1 1484/1492/1 16047/16055/1 +f 16051/16059/1 16056/16064/1 1481/1489/1 16046/16054/1 +f 16056/16064/1 16055/16063/1 1482/1490/1 1481/1489/1 +f 16058/16066/1 1477/1485/1 1480/1488/1 16059/16067/1 +f 16063/16071/1 16068/16076/1 1477/1485/1 16058/16066/1 +f 16068/16076/1 16067/16075/1 1478/1486/1 1477/1485/1 +f 16070/16078/1 1473/1481/1 1476/1484/1 16071/16079/1 +f 16075/16083/1 16080/16088/1 1473/1481/1 16070/16078/1 +f 16080/16088/1 16079/16087/1 1474/1482/1 1473/1481/1 +f 16082/16090/1 1469/1477/1 1472/1480/1 16083/16091/1 +f 16087/16095/1 16092/16100/1 1469/1477/1 16082/16090/1 +f 16092/16100/1 16091/16099/1 1470/1478/1 1469/1477/1 +f 16094/16102/1 1465/1473/1 1468/1476/1 16095/16103/1 +f 16099/16107/1 16104/16112/1 1465/1473/1 16094/16102/1 +f 16104/16112/1 16103/16111/1 1466/1474/1 1465/1473/1 +f 16106/16114/1 1461/1469/1 1464/1472/1 16107/16115/1 +f 16111/16119/1 16116/16124/1 1461/1469/1 16106/16114/1 +f 16116/16124/1 16115/16123/1 1462/1470/1 1461/1469/1 +f 16118/16126/1 1457/1465/1 1460/1468/1 16119/16127/1 +f 16123/16131/1 16128/16136/1 1457/1465/1 16118/16126/1 +f 16128/16136/1 16127/16135/1 1458/1466/1 1457/1465/1 +f 16130/16138/1 1453/1461/1 1456/1464/1 16131/16139/1 +f 16135/16143/1 16140/16148/1 1453/1461/1 16130/16138/1 +f 16140/16148/1 16139/16147/1 1454/1462/1 1453/1461/1 +f 16142/16150/1 1449/1457/1 1452/1460/1 16143/16151/1 +f 16147/16155/1 16152/16160/1 1449/1457/1 16142/16150/1 +f 16152/16160/1 16151/16159/1 1450/1458/1 1449/1457/1 +f 16154/16162/1 1445/1453/1 1448/1456/1 16155/16163/1 +f 16159/16167/1 16164/16172/1 1445/1453/1 16154/16162/1 +f 16164/16172/1 16163/16171/1 1446/1454/1 1445/1453/1 +f 16166/16174/1 1441/1449/1 1444/1452/1 16167/16175/1 +f 16171/16179/1 16176/16184/1 1441/1449/1 16166/16174/1 +f 16176/16184/1 16175/16183/1 1442/1450/1 1441/1449/1 +f 16178/16186/1 1437/1445/1 1440/1448/1 16179/16187/1 +f 16183/16191/1 16188/16196/1 1437/1445/1 16178/16186/1 +f 16188/16196/1 16187/16195/1 1438/1446/1 1437/1445/1 +f 16190/16198/1 1433/1441/1 1436/1444/1 16191/16199/1 +f 16195/16203/1 16200/16208/1 1433/1441/1 16190/16198/1 +f 16200/16208/1 16199/16207/1 1434/1442/1 1433/1441/1 +f 16202/16210/1 1429/1437/1 1432/1440/1 16203/16211/1 +f 16207/16215/1 16212/16220/1 1429/1437/1 16202/16210/1 +f 16212/16220/1 16211/16219/1 1430/1438/1 1429/1437/1 +f 16214/16222/1 1425/1433/1 1428/1436/1 16215/16223/1 +f 16219/16227/1 16224/16232/1 1425/1433/1 16214/16222/1 +f 16224/16232/1 16223/16231/1 1426/1434/1 1425/1433/1 +f 16226/16234/1 1421/1429/1 1424/1432/1 16227/16235/1 +f 16231/16239/1 16236/16244/1 1421/1429/1 16226/16234/1 +f 16236/16244/1 16235/16243/1 1422/1430/1 1421/1429/1 +f 16238/16246/1 1417/1425/1 1420/1428/1 16239/16247/1 +f 16243/16251/1 16248/16256/1 1417/1425/1 16238/16246/1 +f 16248/16256/1 16247/16255/1 1418/1426/1 1417/1425/1 +f 16250/16258/1 1413/1421/1 1416/1424/1 16251/16259/1 +f 16255/16263/1 16260/16268/1 1413/1421/1 16250/16258/1 +f 16260/16268/1 16259/16267/1 1414/1422/1 1413/1421/1 +f 16262/16270/1 1409/1417/1 1412/1420/1 16263/16271/1 +f 16267/16275/1 16272/16280/1 1409/1417/1 16262/16270/1 +f 16272/16280/1 16271/16279/1 1410/1418/1 1409/1417/1 +f 16274/16282/1 1405/1413/1 1408/1416/1 16275/16283/1 +f 16279/16287/1 16284/16292/1 1405/1413/1 16274/16282/1 +f 16284/16292/1 16283/16291/1 1406/1414/1 1405/1413/1 +f 16286/16294/1 1401/1409/1 1404/1412/1 16287/16295/1 +f 16291/16299/1 16296/16304/1 1401/1409/1 16286/16294/1 +f 16296/16304/1 16295/16303/1 1402/1410/1 1401/1409/1 +f 16298/16306/1 1397/1405/1 1400/1408/1 16299/16307/1 +f 16303/16311/1 16308/16316/1 1397/1405/1 16298/16306/1 +f 16308/16316/1 16307/16315/1 1398/1406/1 1397/1405/1 +f 16310/16318/1 1393/1401/1 1396/1404/1 16311/16319/1 +f 16315/16323/1 16320/16328/1 1393/1401/1 16310/16318/1 +f 16320/16328/1 16319/16327/1 1394/1402/1 1393/1401/1 +f 16322/16330/1 1389/1397/1 1392/1400/1 16323/16331/1 +f 16327/16335/1 16332/16340/1 1389/1397/1 16322/16330/1 +f 16332/16340/1 16331/16339/1 1390/1398/1 1389/1397/1 +f 16334/16342/1 1385/1393/1 1388/1396/1 16335/16343/1 +f 16339/16347/1 16344/16352/1 1385/1393/1 16334/16342/1 +f 16344/16352/1 16343/16351/1 1386/1394/1 1385/1393/1 +f 16346/16354/1 1381/1389/1 1384/1392/1 16347/16355/1 +f 16351/16359/1 16356/16364/1 1381/1389/1 16346/16354/1 +f 16356/16364/1 16355/16363/1 1382/1390/1 1381/1389/1 +f 16358/16366/1 1377/1385/1 1380/1388/1 16359/16367/1 +f 16363/16371/1 16368/16376/1 1377/1385/1 16358/16366/1 +f 16368/16376/1 16367/16375/1 1378/1386/1 1377/1385/1 +f 16370/16378/1 1373/1381/1 1376/1384/1 16371/16379/1 +f 16375/16383/1 16380/16388/1 1373/1381/1 16370/16378/1 +f 16380/16388/1 16379/16387/1 1374/1382/1 1373/1381/1 +f 16382/16390/1 1369/1377/1 1372/1380/1 16383/16391/1 +f 16387/16395/1 16392/16400/1 1369/1377/1 16382/16390/1 +f 16392/16400/1 16391/16399/1 1370/1378/1 1369/1377/1 +f 16394/16402/1 1365/1373/1 1368/1376/1 16395/16403/1 +f 16399/16407/1 16404/16412/1 1365/1373/1 16394/16402/1 +f 16404/16412/1 16403/16411/1 1366/1374/1 1365/1373/1 +f 16406/16414/1 1361/1369/1 1364/1372/1 16407/16415/1 +f 16411/16419/1 16416/16424/1 1361/1369/1 16406/16414/1 +f 16416/16424/1 16415/16423/1 1362/1370/1 1361/1369/1 +f 16418/16426/1 1357/1365/1 1360/1368/1 16419/16427/1 +f 16423/16431/1 16428/16436/1 1357/1365/1 16418/16426/1 +f 16428/16436/1 16427/16435/1 1358/1366/1 1357/1365/1 +f 16430/16438/1 1353/1361/1 1356/1364/1 16431/16439/1 +f 16435/16443/1 16440/16448/1 1353/1361/1 16430/16438/1 +f 16440/16448/1 16439/16447/1 1354/1362/1 1353/1361/1 +f 16442/16450/1 1349/1357/1 1352/1360/1 16443/16451/1 +f 16447/16455/1 16452/16460/1 1349/1357/1 16442/16450/1 +f 16452/16460/1 16451/16459/1 1350/1358/1 1349/1357/1 +f 16454/16462/1 1345/1353/1 1348/1356/1 16455/16463/1 +f 16459/16467/1 16464/16472/1 1345/1353/1 16454/16462/1 +f 16464/16472/1 16463/16471/1 1346/1354/1 1345/1353/1 +f 16466/16474/1 1341/1349/1 1344/1352/1 16467/16475/1 +f 16471/16479/1 16476/16484/1 1341/1349/1 16466/16474/1 +f 16476/16484/1 16475/16483/1 1342/1350/1 1341/1349/1 +f 16478/16486/1 1337/1345/1 1340/1348/1 16479/16487/1 +f 16483/16491/1 16488/16496/1 1337/1345/1 16478/16486/1 +f 16488/16496/1 16487/16495/1 1338/1346/1 1337/1345/1 +f 16490/16498/1 1333/1341/1 1336/1344/1 16491/16499/1 +f 16495/16503/1 16500/16508/1 1333/1341/1 16490/16498/1 +f 16500/16508/1 16499/16507/1 1334/1342/1 1333/1341/1 +f 16502/16510/1 1329/1337/1 1332/1340/1 16503/16511/1 +f 16507/16515/1 16512/16520/1 1329/1337/1 16502/16510/1 +f 16512/16520/1 16511/16519/1 1330/1338/1 1329/1337/1 +f 16514/16522/1 1325/1333/1 1328/1336/1 16515/16523/1 +f 16519/16527/1 16524/16532/1 1325/1333/1 16514/16522/1 +f 16524/16532/1 16523/16531/1 1326/1334/1 1325/1333/1 +f 16526/16534/1 1321/1329/1 1324/1332/1 16527/16535/1 +f 16531/16539/1 16536/16544/1 1321/1329/1 16526/16534/1 +f 16536/16544/1 16535/16543/1 1322/1330/1 1321/1329/1 +f 16538/16546/1 1317/1325/1 1320/1328/1 16539/16547/1 +f 16543/16551/1 16548/16556/1 1317/1325/1 16538/16546/1 +f 16548/16556/1 16547/16555/1 1318/1326/1 1317/1325/1 +f 16550/16558/1 1313/1321/1 1316/1324/1 16551/16559/1 +f 16555/16563/1 16560/16568/1 1313/1321/1 16550/16558/1 +f 16560/16568/1 16559/16567/1 1314/1322/1 1313/1321/1 +f 16562/16570/1 1309/1317/1 1312/1320/1 16563/16571/1 +f 16567/16575/1 16572/16580/1 1309/1317/1 16562/16570/1 +f 16572/16580/1 16571/16579/1 1310/1318/1 1309/1317/1 +f 16574/16582/1 1305/1313/1 1308/1316/1 16575/16583/1 +f 16579/16587/1 16584/16592/1 1305/1313/1 16574/16582/1 +f 16584/16592/1 16583/16591/1 1306/1314/1 1305/1313/1 +f 16586/16594/1 1301/1309/1 1304/1312/1 16587/16595/1 +f 16591/16599/1 16596/16604/1 1301/1309/1 16586/16594/1 +f 16596/16604/1 16595/16603/1 1302/1310/1 1301/1309/1 +f 16598/16606/1 1297/1305/1 1300/1308/1 16599/16607/1 +f 16603/16611/1 16608/16616/1 1297/1305/1 16598/16606/1 +f 16608/16616/1 16607/16615/1 1298/1306/1 1297/1305/1 +f 16610/16618/1 1293/1301/1 1296/1304/1 16611/16619/1 +f 16615/16623/1 16620/16628/1 1293/1301/1 16610/16618/1 +f 16620/16628/1 16619/16627/1 1294/1302/1 1293/1301/1 +f 16622/16630/1 1289/1297/1 1292/1300/1 16623/16631/1 +f 16627/16635/1 16632/16640/1 1289/1297/1 16622/16630/1 +f 16632/16640/1 16631/16639/1 1290/1298/1 1289/1297/1 +f 16634/16642/1 1285/1293/1 1288/1296/1 16635/16643/1 +f 16639/16647/1 16644/16652/1 1285/1293/1 16634/16642/1 +f 16644/16652/1 16643/16651/1 1286/1294/1 1285/1293/1 +f 16646/16654/1 1281/1289/1 1284/1292/1 16647/16655/1 +f 16651/16659/1 16656/16664/1 1281/1289/1 16646/16654/1 +f 16656/16664/1 16655/16663/1 1282/1290/1 1281/1289/1 +f 16658/16666/1 1277/1285/1 1280/1288/1 16659/16667/1 +f 16663/16671/1 16668/16676/1 1277/1285/1 16658/16666/1 +f 16668/16676/1 16667/16675/1 1278/1286/1 1277/1285/1 +f 16670/16678/1 1273/1281/1 1276/1284/1 16671/16679/1 +f 16675/16683/1 16680/16688/1 1273/1281/1 16670/16678/1 +f 16680/16688/1 16679/16687/1 1274/1282/1 1273/1281/1 +f 16682/16690/1 1269/1277/1 1272/1280/1 16683/16691/1 +f 16687/16695/1 16692/16700/1 1269/1277/1 16682/16690/1 +f 16692/16700/1 16691/16699/1 1270/1278/1 1269/1277/1 +f 16694/16702/1 1265/1273/1 1268/1276/1 16695/16703/1 +f 16699/16707/1 16704/16712/1 1265/1273/1 16694/16702/1 +f 16704/16712/1 16703/16711/1 1266/1274/1 1265/1273/1 +f 16706/16714/1 1261/1269/1 1264/1272/1 16707/16715/1 +f 16711/16719/1 16716/16724/1 1261/1269/1 16706/16714/1 +f 16716/16724/1 16715/16723/1 1262/1270/1 1261/1269/1 +f 16718/16726/1 1257/1265/1 1260/1268/1 16719/16727/1 +f 16723/16731/1 16728/16736/1 1257/1265/1 16718/16726/1 +f 16728/16736/1 16727/16735/1 1258/1266/1 1257/1265/1 +f 16730/16738/1 1253/1261/1 1256/1264/1 16731/16739/1 +f 16735/16743/1 16740/16748/1 1253/1261/1 16730/16738/1 +f 16740/16748/1 16739/16747/1 1254/1262/1 1253/1261/1 +f 16742/16750/1 1249/1257/1 1252/1260/1 16743/16751/1 +f 16747/16755/1 16752/16760/1 1249/1257/1 16742/16750/1 +f 16752/16760/1 16751/16759/1 1250/1258/1 1249/1257/1 +f 16754/16762/1 1245/1253/1 1248/1256/1 16755/16763/1 +f 16759/16767/1 16764/16772/1 1245/1253/1 16754/16762/1 +f 16764/16772/1 16763/16771/1 1246/1254/1 1245/1253/1 +f 16766/16774/1 1241/1249/1 1244/1252/1 16767/16775/1 +f 16771/16779/1 16776/16784/1 1241/1249/1 16766/16774/1 +f 16776/16784/1 16775/16783/1 1242/1250/1 1241/1249/1 +f 16778/16786/1 1237/1245/1 1240/1248/1 16779/16787/1 +f 16783/16791/1 16788/16796/1 1237/1245/1 16778/16786/1 +f 16788/16796/1 16787/16795/1 1238/1246/1 1237/1245/1 +f 16790/16798/1 1233/1241/1 1236/1244/1 16791/16799/1 +f 16795/16803/1 16800/16808/1 1233/1241/1 16790/16798/1 +f 16800/16808/1 16799/16807/1 1234/1242/1 1233/1241/1 +f 16802/16810/1 1229/1237/1 1232/1240/1 16803/16811/1 +f 16807/16815/1 16812/16820/1 1229/1237/1 16802/16810/1 +f 16812/16820/1 16811/16819/1 1230/1238/1 1229/1237/1 +f 16814/16822/1 1225/1233/1 1228/1236/1 16815/16823/1 +f 16819/16827/1 16824/16832/1 1225/1233/1 16814/16822/1 +f 16824/16832/1 16823/16831/1 1226/1234/1 1225/1233/1 +f 16826/16834/1 1221/1229/1 1224/1232/1 16827/16835/1 +f 16831/16839/1 16836/16844/1 1221/1229/1 16826/16834/1 +f 16836/16844/1 16835/16843/1 1222/1230/1 1221/1229/1 +f 16838/16846/1 1217/1225/1 1220/1228/1 16839/16847/1 +f 16843/16851/1 16848/16856/1 1217/1225/1 16838/16846/1 +f 16848/16856/1 16847/16855/1 1218/1226/1 1217/1225/1 +f 16850/16858/1 1213/1221/1 1216/1224/1 16851/16859/1 +f 16855/16863/1 16860/16868/1 1213/1221/1 16850/16858/1 +f 16860/16868/1 16859/16867/1 1214/1222/1 1213/1221/1 +f 16862/16870/1 1209/1217/1 1212/1220/1 16863/16871/1 +f 16867/16875/1 16872/16880/1 1209/1217/1 16862/16870/1 +f 16872/16880/1 16871/16879/1 1210/1218/1 1209/1217/1 +f 16874/16882/1 1205/1213/1 1208/1216/1 16875/16883/1 +f 16879/16887/1 16884/16892/1 1205/1213/1 16874/16882/1 +f 16884/16892/1 16883/16891/1 1206/1214/1 1205/1213/1 +f 16886/16894/1 1201/1209/1 1204/1212/1 16887/16895/1 +f 16891/16899/1 16896/16904/1 1201/1209/1 16886/16894/1 +f 16896/16904/1 16895/16903/1 1202/1210/1 1201/1209/1 +f 16898/16906/1 1197/1205/1 1200/1208/1 16899/16907/1 +f 16903/16911/1 16908/16916/1 1197/1205/1 16898/16906/1 +f 16908/16916/1 16907/16915/1 1198/1206/1 1197/1205/1 +f 16910/16918/1 1193/1201/1 1196/1204/1 16911/16919/1 +f 16915/16923/1 16920/16928/1 1193/1201/1 16910/16918/1 +f 16920/16928/1 16919/16927/1 1194/1202/1 1193/1201/1 +f 16922/16930/1 1189/1197/1 1192/1200/1 16923/16931/1 +f 16927/16935/1 16932/16940/1 1189/1197/1 16922/16930/1 +f 16932/16940/1 16931/16939/1 1190/1198/1 1189/1197/1 +f 16934/16942/1 1185/1193/1 1188/1196/1 16935/16943/1 +f 16939/16947/1 16944/16952/1 1185/1193/1 16934/16942/1 +f 16944/16952/1 16943/16951/1 1186/1194/1 1185/1193/1 +f 16946/16954/1 1181/1189/1 1184/1192/1 16947/16955/1 +f 16951/16959/1 16956/16964/1 1181/1189/1 16946/16954/1 +f 16956/16964/1 16955/16963/1 1182/1190/1 1181/1189/1 +f 16958/16966/1 1177/1185/1 1180/1188/1 16959/16967/1 +f 16963/16971/1 16968/16976/1 1177/1185/1 16958/16966/1 +f 16968/16976/1 16967/16975/1 1178/1186/1 1177/1185/1 +f 16970/16978/1 1173/1181/1 1176/1184/1 16971/16979/1 +f 16975/16983/1 16980/16988/1 1173/1181/1 16970/16978/1 +f 16980/16988/1 16979/16987/1 1174/1182/1 1173/1181/1 +f 16982/16990/1 1169/1177/1 1172/1180/1 16983/16991/1 +f 16987/16995/1 16992/17000/1 1169/1177/1 16982/16990/1 +f 16992/17000/1 16991/16999/1 1170/1178/1 1169/1177/1 +f 16994/17002/1 1165/1173/1 1168/1176/1 16995/17003/1 +f 16999/17007/1 17004/17012/1 1165/1173/1 16994/17002/1 +f 17004/17012/1 17003/17011/1 1166/1174/1 1165/1173/1 +f 17006/17014/1 1161/1169/1 1164/1172/1 17007/17015/1 +f 17011/17019/1 17016/17024/1 1161/1169/1 17006/17014/1 +f 17016/17024/1 17015/17023/1 1162/1170/1 1161/1169/1 +f 17018/17026/1 1157/1165/1 1160/1168/1 17019/17027/1 +f 17023/17031/1 17028/17036/1 1157/1165/1 17018/17026/1 +f 17028/17036/1 17027/17035/1 1158/1166/1 1157/1165/1 +f 17030/17038/1 1153/1161/1 1156/1164/1 17031/17039/1 +f 17035/17043/1 17040/17048/1 1153/1161/1 17030/17038/1 +f 17040/17048/1 17039/17047/1 1154/1162/1 1153/1161/1 +f 17042/17050/1 1149/1157/1 1152/1160/1 17043/17051/1 +f 17047/17055/1 17052/17060/1 1149/1157/1 17042/17050/1 +f 17052/17060/1 17051/17059/1 1150/1158/1 1149/1157/1 +f 17054/17062/1 1145/1153/1 1148/1156/1 17055/17063/1 +f 17059/17067/1 17064/17072/1 1145/1153/1 17054/17062/1 +f 17064/17072/1 17063/17071/1 1146/1154/1 1145/1153/1 +f 17066/17074/1 1141/1149/1 1144/1152/1 17067/17075/1 +f 17071/17079/1 17076/17084/1 1141/1149/1 17066/17074/1 +f 17076/17084/1 17075/17083/1 1142/1150/1 1141/1149/1 +f 17078/17086/1 1137/1145/1 1140/1148/1 17079/17087/1 +f 17083/17091/1 17088/17096/1 1137/1145/1 17078/17086/1 +f 17088/17096/1 17087/17095/1 1138/1146/1 1137/1145/1 +f 17090/17098/1 1133/1141/1 1136/1144/1 17091/17099/1 +f 17095/17103/1 17100/17108/1 1133/1141/1 17090/17098/1 +f 17100/17108/1 17099/17107/1 1134/1142/1 1133/1141/1 +f 17102/17110/1 1129/1137/1 1132/1140/1 17103/17111/1 +f 17107/17115/1 17112/17120/1 1129/1137/1 17102/17110/1 +f 17112/17120/1 17111/17119/1 1130/1138/1 1129/1137/1 +f 17114/17122/1 1125/1133/1 1128/1136/1 17115/17123/1 +f 17119/17127/1 17124/17132/1 1125/1133/1 17114/17122/1 +f 17124/17132/1 17123/17131/1 1126/1134/1 1125/1133/1 +f 17126/17134/1 1121/1129/1 1124/1132/1 17127/17135/1 +f 17131/17139/1 17136/17144/1 1121/1129/1 17126/17134/1 +f 17136/17144/1 17135/17143/1 1122/1130/1 1121/1129/1 +f 17138/17146/1 1117/1125/1 1120/1128/1 17139/17147/1 +f 17143/17151/1 17148/17156/1 1117/1125/1 17138/17146/1 +f 17148/17156/1 17147/17155/1 1118/1126/1 1117/1125/1 +f 17150/17158/1 1113/1121/1 1116/1124/1 17151/17159/1 +f 17155/17163/1 17160/17168/1 1113/1121/1 17150/17158/1 +f 17160/17168/1 17159/17167/1 1114/1122/1 1113/1121/1 +f 17162/17170/1 1109/1117/1 1112/1120/1 17163/17171/1 +f 17167/17175/1 17172/17180/1 1109/1117/1 17162/17170/1 +f 17172/17180/1 17171/17179/1 1110/1118/1 1109/1117/1 +f 17174/17182/1 1105/1113/1 1108/1116/1 17175/17183/1 +f 17179/17187/1 17184/17192/1 1105/1113/1 17174/17182/1 +f 17184/17192/1 17183/17191/1 1106/1114/1 1105/1113/1 +f 17186/17194/1 1101/1109/1 1104/1112/1 17187/17195/1 +f 17191/17199/1 17196/17204/1 1101/1109/1 17186/17194/1 +f 17196/17204/1 17195/17203/1 1102/1110/1 1101/1109/1 +f 17198/17206/1 1097/1105/1 1100/1108/1 17199/17207/1 +f 17203/17211/1 17208/17216/1 1097/1105/1 17198/17206/1 +f 17208/17216/1 17207/17215/1 1098/1106/1 1097/1105/1 +f 17210/17218/1 1093/1101/1 1096/1104/1 17211/17219/1 +f 17215/17223/1 17220/17228/1 1093/1101/1 17210/17218/1 +f 17220/17228/1 17219/17227/1 1094/1102/1 1093/1101/1 +f 17222/17230/1 1089/1097/1 1092/1100/1 17223/17231/1 +f 17227/17235/1 17232/17240/1 1089/1097/1 17222/17230/1 +f 17232/17240/1 17231/17239/1 1090/1098/1 1089/1097/1 +f 17234/17242/1 1085/1093/1 1088/1096/1 17235/17243/1 +f 17239/17247/1 17244/17252/1 1085/1093/1 17234/17242/1 +f 17244/17252/1 17243/17251/1 1086/1094/1 1085/1093/1 +f 17246/17254/1 1081/1089/1 1084/1092/1 17247/17255/1 +f 17251/17259/1 17256/17264/1 1081/1089/1 17246/17254/1 +f 17256/17264/1 17255/17263/1 1082/1090/1 1081/1089/1 +f 17258/17266/1 1077/1085/1 1080/1088/1 17259/17267/1 +f 17263/17271/1 17268/17276/1 1077/1085/1 17258/17266/1 +f 17268/17276/1 17267/17275/1 1078/1086/1 1077/1085/1 +f 17270/17278/1 1073/1081/1 1076/1084/1 17271/17279/1 +f 17275/17283/1 17280/17288/1 1073/1081/1 17270/17278/1 +f 17280/17288/1 17279/17287/1 1074/1082/1 1073/1081/1 +f 17282/17290/1 1069/1077/1 1072/1080/1 17283/17291/1 +f 17287/17295/1 17292/17300/1 1069/1077/1 17282/17290/1 +f 17292/17300/1 17291/17299/1 1070/1078/1 1069/1077/1 +f 17294/17302/1 1065/1073/1 1068/1076/1 17295/17303/1 +f 17299/17307/1 17304/17312/1 1065/1073/1 17294/17302/1 +f 17304/17312/1 17303/17311/1 1066/1074/1 1065/1073/1 +f 17306/17314/1 1061/1069/1 1064/1072/1 17307/17315/1 +f 17311/17319/1 17316/17324/1 1061/1069/1 17306/17314/1 +f 17316/17324/1 17315/17323/1 1062/1070/1 1061/1069/1 +f 17318/17326/1 1057/1065/1 1060/1068/1 17319/17327/1 +f 17323/17331/1 17328/17336/1 1057/1065/1 17318/17326/1 +f 17328/17336/1 17327/17335/1 1058/1066/1 1057/1065/1 +f 17330/17338/1 1053/1061/1 1056/1064/1 17331/17339/1 +f 17335/17343/1 17340/17348/1 1053/1061/1 17330/17338/1 +f 17340/17348/1 17339/17347/1 1054/1062/1 1053/1061/1 +f 17342/17350/1 1049/1057/1 1052/1060/1 17343/17351/1 +f 17347/17355/1 17352/17360/1 1049/1057/1 17342/17350/1 +f 17352/17360/1 17351/17359/1 1050/1058/1 1049/1057/1 +f 17354/17362/1 1045/1053/1 1048/1056/1 17355/17363/1 +f 17359/17367/1 17364/17372/1 1045/1053/1 17354/17362/1 +f 17364/17372/1 17363/17371/1 1046/1054/1 1045/1053/1 +f 17366/17374/1 1041/1049/1 1044/1052/1 17367/17375/1 +f 17371/17379/1 17376/17384/1 1041/1049/1 17366/17374/1 +f 17376/17384/1 17375/17383/1 1042/1050/1 1041/1049/1 +f 17378/17386/1 1037/1045/1 1040/1048/1 17379/17387/1 +f 17383/17391/1 17388/17396/1 1037/1045/1 17378/17386/1 +f 17388/17396/1 17387/17395/1 1038/1046/1 1037/1045/1 +f 17390/17398/1 1033/1041/1 1036/1044/1 17391/17399/1 +f 17395/17403/1 17400/17408/1 1033/1041/1 17390/17398/1 +f 17400/17408/1 17399/17407/1 1034/1042/1 1033/1041/1 +f 17402/17410/1 1029/1037/1 1032/1040/1 17403/17411/1 +f 17407/17415/1 17412/17420/1 1029/1037/1 17402/17410/1 +f 17412/17420/1 17411/17419/1 1030/1038/1 1029/1037/1 diff --git a/examples/qt3d/advancedcustommaterial/qml.qrc b/examples/qt3d/advancedcustommaterial/qml.qrc new file mode 100644 index 000000000..a15e444cd --- /dev/null +++ b/examples/qt3d/advancedcustommaterial/qml.qrc @@ -0,0 +1,8 @@ + + + main.qml + SceneRoot.qml + Water.qml + WaterMaterial.qml + + diff --git a/examples/qt3d/advancedcustommaterial/shaders.qrc b/examples/qt3d/advancedcustommaterial/shaders.qrc new file mode 100644 index 000000000..1fcce7ae3 --- /dev/null +++ b/examples/qt3d/advancedcustommaterial/shaders.qrc @@ -0,0 +1,8 @@ + + + shaders/gl3/water.frag + shaders/gl3/water.vert + shaders/es2/water.frag + shaders/es2/water.vert + + diff --git a/examples/qt3d/advancedcustommaterial/shaders/es2/water.frag b/examples/qt3d/advancedcustommaterial/shaders/es2/water.frag new file mode 100644 index 000000000..ea54a87f1 --- /dev/null +++ b/examples/qt3d/advancedcustommaterial/shaders/es2/water.frag @@ -0,0 +1,72 @@ +#define FP highp + +varying FP vec3 worldPosition; +varying FP vec2 texCoord; +varying FP vec2 waveTexCoord; +varying FP vec2 movtexCoord; +varying FP vec2 multexCoord; +varying FP vec2 skyTexCoord; + +varying FP vec3 vpos; + +varying FP mat3 tangentMatrix; +varying FP vec3 color; + +uniform FP sampler2D diffuseTexture; +uniform FP sampler2D specularTexture; +uniform FP sampler2D normalTexture; +uniform FP sampler2D waveTexture; +uniform FP sampler2D skyTexture; +uniform FP sampler2D foamTexture; + +uniform FP float offsetx; +uniform FP float offsety; +uniform FP float specularity; +uniform FP float waveStrenght; +uniform FP vec3 ka; +uniform FP vec3 specularColor; +uniform FP float shininess; +uniform FP float normalAmount; +uniform FP vec3 eyePosition; + +#pragma include light.inc.frag + +void main() +{ + // Move waveTexCoords + FP vec2 waveMovCoord = waveTexCoord; + waveMovCoord.x += offsetx; + waveMovCoord.y -= offsety; + FP vec4 wave = texture2D(waveTexture, waveMovCoord); + + //Wiggle the newCoord by r and b colors of waveTexture + FP vec2 newCoord = texCoord; + newCoord.x += wave.r * waveStrenght; + newCoord.y -= wave.b * waveStrenght; + + // Sample the textures at the interpolated texCoords + // Use default texCoord for diffuse (it does not move on x or y, so it can be used as "ground under the water"). + FP vec4 diffuseTextureColor = texture2D(diffuseTexture, texCoord); + // 2 Animated Layers of specularTexture mixed with the newCoord + FP vec4 specularTextureColor = texture2D( specularTexture, multexCoord+newCoord) + (texture2D( specularTexture, movtexCoord+newCoord )); + // 2 Animated Layers of normalTexture mixed with the newCoord + FP vec3 normal = normalAmount * texture2D( normalTexture, movtexCoord+newCoord ).rgb - vec3( 1.0 )+(normalAmount * texture2D( normalTexture, multexCoord+newCoord ).rgb - vec3( 1.0 )); + // Animated skyTexture layer + FP vec4 skycolor = texture2D(skyTexture, skyTexCoord); + skycolor = skycolor * 0.4; + //Animated foamTexture layer + FP vec4 foamTextureColor = texture2D(foamTexture, texCoord); + + // Calculate the lighting model, keeping the specular component separate + FP vec3 diffuseColor, specularColor; + adsModelNormalMapped(worldPosition, normal, eyePosition, shininess, tangentMatrix, diffuseColor, specularColor); + + // Combine final fragment color + FP vec4 outputColor = vec4(((skycolor.rgb + ka + diffuseTextureColor.rgb * (diffuseColor))+(specularColor * specularTextureColor.a*specularity)), vpos.y ); + + + outputColor += (foamTextureColor.rgba*vpos.y); + + gl_FragColor = vec4(outputColor.rgb,1.0); +} + diff --git a/examples/qt3d/advancedcustommaterial/shaders/es2/water.vert b/examples/qt3d/advancedcustommaterial/shaders/es2/water.vert new file mode 100644 index 000000000..1a7d46a46 --- /dev/null +++ b/examples/qt3d/advancedcustommaterial/shaders/es2/water.vert @@ -0,0 +1,88 @@ +#define FP highp + +attribute FP vec3 vertexPosition; +attribute FP vec3 vertexNormal; +attribute FP vec2 vertexTexCoord; +attribute FP vec4 vertexTangent; + +varying FP vec3 worldPosition; +varying FP vec2 texCoord; +varying FP vec2 movtexCoord; +varying FP vec2 multexCoord; +varying FP vec2 waveTexCoord; +varying FP vec2 skyTexCoord; +varying FP mat3 tangentMatrix; +varying FP vec3 vpos; + +uniform FP mat4 modelMatrix; +uniform FP mat3 modelNormalMatrix; +uniform FP mat4 mvp; + +uniform FP float offsetx; +uniform FP float offsety; +uniform FP float vertYpos; +uniform FP float texCoordScale; +uniform FP float waveheight; +uniform FP float waveRandom; + + +void main() +{ + // Scale texture coordinates for for fragment shader + texCoord = vertexTexCoord * texCoordScale; + movtexCoord = vertexTexCoord * texCoordScale; + multexCoord = vertexTexCoord * (texCoordScale*0.5); + waveTexCoord = vertexTexCoord * (texCoordScale * 6.0); + skyTexCoord = vertexTexCoord * (texCoordScale * 0.2); + + // Add Animated x and y Offset to SKY, MOV and MUL texCoords + movtexCoord = vec2(texCoord.x+offsetx,texCoord.y+offsety); + multexCoord = vec2(texCoord.x-offsetx,texCoord.y+offsety); + skyTexCoord = vec2(texCoord.x-(offsetx/2.0),texCoord.y-(offsety/2.0)); + + // Transform position, normal, and tangent to world coords + worldPosition = vec3(modelMatrix * vec4(vertexPosition, 1.0)); + FP vec3 normal = normalize(modelNormalMatrix * vertexNormal); + FP vec3 tangent = normalize(vec3(modelMatrix * vec4(vertexTangent.xyz, 0.0))); + + // Make the tangent truly orthogonal to the normal by using Gram-Schmidt. + // This allows to build the tangentMatrix below by simply transposing the + // tangent -> world space matrix (which would now be orthogonal) + tangent = normalize(tangent - dot(tangent, normal) * normal); + + // Calculate binormal vector. No "real" need to renormalize it, + // as built by crossing two normal vectors. + // To orient the binormal correctly, use the fourth coordinate of the tangent, + // which is +1 for a right hand system, and -1 for a left hand system. + FP vec3 binormal = cross(normal, tangent) * vertexTangent.w; + + // Construct matrix to transform from eye coords to tangent space + tangentMatrix = mat3( + tangent.x, binormal.x, normal.x, + tangent.y, binormal.y, normal.y, + tangent.z, binormal.z, normal.z); + + // Calculate animated vertex positions + + FP float sinPos = (vertexPosition.z)+(vertexPosition.x); + FP float sinPos2 = (vertexPosition.y/2.0)+(vertexPosition.z); + FP vec3 vertMod = vec3(vertexPosition.x,vertexPosition.y,vertexPosition.z); + + vertMod = vec3(vertMod.x+=sin(vertYpos*2.2-sinPos2)*waveheight, + vertMod.y=sin(vertYpos*2.2+sinPos)*waveheight, + vertMod.z-=sin(vertYpos*2.2-cos(sinPos2))*waveheight); + + FP vec3 vertModCom = vec3(vertMod.x+=cos(vertYpos*2.2-cos(sinPos2))*waveheight, + vertMod.y=sin(vertYpos*2.2+cos(sinPos))*waveheight, + vertMod.z-=cos(vertYpos*2.2-cos(sinPos))*waveheight); + + + // Add wave animation only to vertices above world pos.y zero + if(vertexPosition.y < 0.0){vertModCom = vertexPosition;} + else{vertModCom = vertModCom;} + + vpos = vertModCom; + + // Calculate vertex position in clip coordinates + gl_Position = mvp * vec4(vertModCom, 1.0); +} diff --git a/examples/qt3d/advancedcustommaterial/shaders/gl3/water.frag b/examples/qt3d/advancedcustommaterial/shaders/gl3/water.frag new file mode 100644 index 000000000..ae40bdf37 --- /dev/null +++ b/examples/qt3d/advancedcustommaterial/shaders/gl3/water.frag @@ -0,0 +1,74 @@ +#version 150 core + +in vec3 worldPosition; +in vec2 texCoord; +in vec2 waveTexCoord; +in vec2 movtexCoord; +in vec2 multexCoord; +in vec2 skyTexCoord; + +in vec3 vpos; + +in mat3 tangentMatrix; +in vec3 color; + +uniform sampler2D diffuseTexture; +uniform sampler2D specularTexture; +uniform sampler2D normalTexture; +uniform sampler2D waveTexture; +uniform sampler2D skyTexture; +uniform sampler2D foamTexture; + +uniform float offsetx; +uniform float offsety; +uniform float specularity; +uniform float waveStrenght; +uniform vec3 ka; +uniform vec3 specularColor; +uniform float shininess; +uniform float normalAmount; +uniform vec3 eyePosition; + +out vec4 fragColor; + +#pragma include light.inc.frag + +void main() +{ + // Move waveTexCoords + vec2 waveMovCoord = waveTexCoord; + waveMovCoord.x += offsetx; + waveMovCoord.y -= offsety; + vec4 wave = texture2D(waveTexture, waveMovCoord); + + //Wiggle the newCoord by r and b colors of waveTexture + vec2 newCoord = texCoord; + newCoord.x += wave.r * waveStrenght; + newCoord.y -= wave.b * waveStrenght; + + // Sample the textures at the interpolated texCoords + // Use default texCoord for diffuse (it does not move on x or y, so it can be used as "ground under the water"). + vec4 diffuseTextureColor = texture(diffuseTexture, texCoord); + // 2 Animated Layers of specularTexture mixed with the newCoord + vec4 specularTextureColor = texture( specularTexture, multexCoord+newCoord) + (texture( specularTexture, movtexCoord+newCoord )); + // 2 Animated Layers of normalTexture mixed with the newCoord + vec3 normal = normalAmount * texture( normalTexture, movtexCoord+newCoord ).rgb - vec3( 1.0 )+(normalAmount * texture( normalTexture, multexCoord+newCoord ).rgb - vec3( 1.0 )); + // Animated skyTexture layer + vec4 skycolor = texture(skyTexture, skyTexCoord); + skycolor = skycolor * 0.4; + //Animated foamTexture layer + vec4 foamTextureColor = texture(foamTexture, texCoord); + + // Calculate the lighting model, keeping the specular component separate + vec3 diffuseColor, specularColor; + adsModelNormalMapped(worldPosition, normal, eyePosition, shininess, tangentMatrix, diffuseColor, specularColor); + + // Combine final fragment color + vec4 outputColor = vec4(((skycolor.rgb + ka + diffuseTextureColor.rgb * (diffuseColor))+(specularColor * specularTextureColor.a*specularity)), vpos.y ); + + + outputColor += (foamTextureColor.rgba*vpos.y); + + fragColor = vec4(outputColor.rgb,1.0); +} + diff --git a/examples/qt3d/advancedcustommaterial/shaders/gl3/water.vert b/examples/qt3d/advancedcustommaterial/shaders/gl3/water.vert new file mode 100644 index 000000000..a4ddcf62b --- /dev/null +++ b/examples/qt3d/advancedcustommaterial/shaders/gl3/water.vert @@ -0,0 +1,88 @@ +#version 150 core + +in vec3 vertexPosition; +in vec3 vertexNormal; +in vec2 vertexTexCoord; +in vec4 vertexTangent; + +out vec3 worldPosition; +out vec2 texCoord; +out vec2 movtexCoord; +out vec2 multexCoord; +out vec2 waveTexCoord; +out vec2 skyTexCoord; +out mat3 tangentMatrix; +out vec3 vpos; + +uniform mat4 modelMatrix; +uniform mat3 modelNormalMatrix; +uniform mat4 mvp; + +uniform float offsetx; +uniform float offsety; +uniform float vertYpos; +uniform float texCoordScale; +uniform float waveheight; +uniform float waveRandom; + + +void main() +{ + // Scale texture coordinates for for fragment shader + texCoord = vertexTexCoord * texCoordScale; + movtexCoord = vertexTexCoord * texCoordScale; + multexCoord = vertexTexCoord * (texCoordScale*0.5); + waveTexCoord = vertexTexCoord * (texCoordScale * 6); + skyTexCoord = vertexTexCoord * (texCoordScale * 0.2); + + // Add Animated x and y Offset to SKY, MOV and MUL texCoords + movtexCoord = vec2(texCoord.x+offsetx,texCoord.y+offsety); + multexCoord = vec2(texCoord.x-offsetx,texCoord.y+offsety); + skyTexCoord = vec2(texCoord.x-(offsetx/2),texCoord.y-(offsety/2)); + + // Transform position, normal, and tangent to world coords + worldPosition = vec3(modelMatrix * vec4(vertexPosition, 1.0)); + vec3 normal = normalize(modelNormalMatrix * vertexNormal); + vec3 tangent = normalize(vec3(modelMatrix * vec4(vertexTangent.xyz, 0.0))); + + // Make the tangent truly orthogonal to the normal by using Gram-Schmidt. + // This allows to build the tangentMatrix below by simply transposing the + // tangent -> world space matrix (which would now be orthogonal) + tangent = normalize(tangent - dot(tangent, normal) * normal); + + // Calculate binormal vector. No "real" need to renormalize it, + // as built by crossing two normal vectors. + // To orient the binormal correctly, use the fourth coordinate of the tangent, + // which is +1 for a right hand system, and -1 for a left hand system. + vec3 binormal = cross(normal, tangent) * vertexTangent.w; + + // Construct matrix to transform from eye coords to tangent space + tangentMatrix = mat3( + tangent.x, binormal.x, normal.x, + tangent.y, binormal.y, normal.y, + tangent.z, binormal.z, normal.z); + + // Calculate animated vertex positions + + float sinPos = (vertexPosition.z)+(vertexPosition.x); + float sinPos2 = (vertexPosition.y/2)+(vertexPosition.z); + vec3 vertMod = vec3(vertexPosition.x,vertexPosition.y,vertexPosition.z); + + vertMod = vec3(vertMod.x+=sin(vertYpos*2.2-sinPos2)*waveheight, + vertMod.y=sin(vertYpos*2.2+sinPos)*waveheight, + vertMod.z-=sin(vertYpos*2.2-cos(sinPos2))*waveheight); + + vec3 vertModCom = vec3(vertMod.x+=cos(vertYpos*2.2-cos(sinPos2))*waveheight, + vertMod.y=sin(vertYpos*2.2+cos(sinPos))*waveheight, + vertMod.z-=cos(vertYpos*2.2-cos(sinPos))*waveheight); + + + // Add wave animation only to vertices above world pos.y zero + if(vertexPosition.y < 0.0){vertModCom = vertexPosition;} + else{vertModCom = vertModCom;} + + vpos = vertModCom; + + // Calculate vertex position in clip coordinates + gl_Position = mvp * vec4(vertModCom, 1.0); +} diff --git a/examples/qt3d/advancedcustommaterial/textures.qrc b/examples/qt3d/advancedcustommaterial/textures.qrc new file mode 100644 index 000000000..b5a3a20d0 --- /dev/null +++ b/examples/qt3d/advancedcustommaterial/textures.qrc @@ -0,0 +1,10 @@ + + + textures/sky.jpg + textures/WaterNormal.jpg + textures/WaterSpecular.jpg + textures/Waterwave.jpg + textures/foam.jpg + textures/WaterDiffuse.jpg + + diff --git a/examples/qt3d/advancedcustommaterial/textures/WaterDiffuse.jpg b/examples/qt3d/advancedcustommaterial/textures/WaterDiffuse.jpg new file mode 100644 index 000000000..70b41d89f Binary files /dev/null and b/examples/qt3d/advancedcustommaterial/textures/WaterDiffuse.jpg differ diff --git a/examples/qt3d/advancedcustommaterial/textures/WaterNormal.jpg b/examples/qt3d/advancedcustommaterial/textures/WaterNormal.jpg new file mode 100644 index 000000000..884934a28 Binary files /dev/null and b/examples/qt3d/advancedcustommaterial/textures/WaterNormal.jpg differ diff --git a/examples/qt3d/advancedcustommaterial/textures/WaterSpecular.jpg b/examples/qt3d/advancedcustommaterial/textures/WaterSpecular.jpg new file mode 100644 index 000000000..a9bd82312 Binary files /dev/null and b/examples/qt3d/advancedcustommaterial/textures/WaterSpecular.jpg differ diff --git a/examples/qt3d/advancedcustommaterial/textures/Waterwave.jpg b/examples/qt3d/advancedcustommaterial/textures/Waterwave.jpg new file mode 100644 index 000000000..15e3419d5 Binary files /dev/null and b/examples/qt3d/advancedcustommaterial/textures/Waterwave.jpg differ diff --git a/examples/qt3d/advancedcustommaterial/textures/foam.jpg b/examples/qt3d/advancedcustommaterial/textures/foam.jpg new file mode 100644 index 000000000..b2100a8d7 Binary files /dev/null and b/examples/qt3d/advancedcustommaterial/textures/foam.jpg differ diff --git a/examples/qt3d/advancedcustommaterial/textures/sky.jpg b/examples/qt3d/advancedcustommaterial/textures/sky.jpg new file mode 100644 index 000000000..0f5765239 Binary files /dev/null and b/examples/qt3d/advancedcustommaterial/textures/sky.jpg differ diff --git a/examples/qt3d/qt3d.pro b/examples/qt3d/qt3d.pro index e145ac990..51c65e64a 100644 --- a/examples/qt3d/qt3d.pro +++ b/examples/qt3d/qt3d.pro @@ -17,7 +17,8 @@ SUBDIRS += \ lights \ compute-particles \ 3d-text \ - qardboard + qardboard \ + advancedcustommaterial qtHaveModule(multimedia): SUBDIRS += audio-visualizer-qml -- cgit v1.2.3 From 0bb720013d93c34d589c352a53405d8110fa57fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Mon, 6 Feb 2017 15:46:49 +0200 Subject: Add simple custom material example Change-Id: Ia1a706888ca3bb1eedcac34903afe7da0c168462 Reviewed-by: Sean Harmer --- examples/qt3d/qt3d.pro | 3 +- examples/qt3d/simplecustommaterial/PlaneModel.qml | 76 +++++++++++++ examples/qt3d/simplecustommaterial/SceneRoot.qml | 79 ++++++++++++++ .../qt3d/simplecustommaterial/SimpleMaterial.qml | 119 +++++++++++++++++++++ examples/qt3d/simplecustommaterial/main.cpp | 66 ++++++++++++ examples/qt3d/simplecustommaterial/main.qml | 85 +++++++++++++++ examples/qt3d/simplecustommaterial/models.qrc | 5 + examples/qt3d/simplecustommaterial/qml.qrc | 8 ++ examples/qt3d/simplecustommaterial/shaders.qrc | 8 ++ .../shaders/es2/simpleColor.frag | 10 ++ .../shaders/es2/simpleColor.vert | 15 +++ .../shaders/gl3/simpleColor.frag | 11 ++ .../shaders/gl3/simpleColor.vert | 15 +++ .../simplecustommaterial/simplecustommaterial.pro | 14 +++ examples/qt3d/simplecustommaterial/textures.qrc | 8 ++ 15 files changed, 521 insertions(+), 1 deletion(-) create mode 100644 examples/qt3d/simplecustommaterial/PlaneModel.qml create mode 100644 examples/qt3d/simplecustommaterial/SceneRoot.qml create mode 100644 examples/qt3d/simplecustommaterial/SimpleMaterial.qml create mode 100644 examples/qt3d/simplecustommaterial/main.cpp create mode 100644 examples/qt3d/simplecustommaterial/main.qml create mode 100644 examples/qt3d/simplecustommaterial/models.qrc create mode 100644 examples/qt3d/simplecustommaterial/qml.qrc create mode 100644 examples/qt3d/simplecustommaterial/shaders.qrc create mode 100644 examples/qt3d/simplecustommaterial/shaders/es2/simpleColor.frag create mode 100644 examples/qt3d/simplecustommaterial/shaders/es2/simpleColor.vert create mode 100644 examples/qt3d/simplecustommaterial/shaders/gl3/simpleColor.frag create mode 100644 examples/qt3d/simplecustommaterial/shaders/gl3/simpleColor.vert create mode 100644 examples/qt3d/simplecustommaterial/simplecustommaterial.pro create mode 100644 examples/qt3d/simplecustommaterial/textures.qrc diff --git a/examples/qt3d/qt3d.pro b/examples/qt3d/qt3d.pro index 51c65e64a..a64624352 100644 --- a/examples/qt3d/qt3d.pro +++ b/examples/qt3d/qt3d.pro @@ -18,7 +18,8 @@ SUBDIRS += \ compute-particles \ 3d-text \ qardboard \ - advancedcustommaterial + advancedcustommaterial \ + simplecustommaterial qtHaveModule(multimedia): SUBDIRS += audio-visualizer-qml diff --git a/examples/qt3d/simplecustommaterial/PlaneModel.qml b/examples/qt3d/simplecustommaterial/PlaneModel.qml new file mode 100644 index 000000000..b5271fe0c --- /dev/null +++ b/examples/qt3d/simplecustommaterial/PlaneModel.qml @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import Qt3D.Core 2.0 +import Qt3D.Render 2.0 +import Qt3D.Extras 2.0 + +Entity { + id: root + + components: [transform, mesh, material] + + SimpleMaterial { + id: material + maincolor: "red" + } + + Transform { + id: transform + rotationX: 45 + } + + PlaneMesh { + id: mesh + width: 1.0 + height: 1.0 + meshResolution: Qt.size(2, 2) + } +} diff --git a/examples/qt3d/simplecustommaterial/SceneRoot.qml b/examples/qt3d/simplecustommaterial/SceneRoot.qml new file mode 100644 index 000000000..93b2681c6 --- /dev/null +++ b/examples/qt3d/simplecustommaterial/SceneRoot.qml @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import Qt3D.Core 2.0 +import Qt3D.Render 2.0 +import Qt3D.Extras 2.0 + +Entity { + id: sceneRoot + + Camera { + id: camera + projectionType: CameraLens.PerspectiveProjection + fieldOfView: 45 + nearPlane: 0.1 + farPlane: 1000.0 + position: Qt.vector3d(0.0, 0.0, 2.0) + upVector: Qt.vector3d(0.0, 1.0, 0.0) + viewCenter: Qt.vector3d(0.0, 0.0, 0.0) + } + + components: [ + RenderSettings { + activeFrameGraph: ForwardRenderer { + id: renderer + clearColor: "#2d2d2d" + camera: camera + } + } + ] + PlaneModel { } +} diff --git a/examples/qt3d/simplecustommaterial/SimpleMaterial.qml b/examples/qt3d/simplecustommaterial/SimpleMaterial.qml new file mode 100644 index 000000000..0ad045e25 --- /dev/null +++ b/examples/qt3d/simplecustommaterial/SimpleMaterial.qml @@ -0,0 +1,119 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import Qt3D.Core 2.0 +import Qt3D.Render 2.0 + +Material { + id: root + + property color maincolor: Qt.rgba(0.0, 0.0, 0.0, 1.0) + + parameters: [ + Parameter { + name: "maincolor" + value: Qt.vector3d(root.maincolor.r, root.maincolor.g, root.maincolor.b) + } + ] + + effect: Effect { + + property string vertex: "qrc:/shaders/gl3/simpleColor.vert" + property string fragment: "qrc:/shaders/gl3/simpleColor.frag" + property string vertexES: "qrc:/shaders/es2/simpleColor.vert" + property string fragmentES: "qrc:/shaders/es2/simpleColor.frag" + + FilterKey { + id: forward + name: "renderingStyle" + value: "forward" + } + ShaderProgram { + id: gl3Shader + vertexShaderCode: loadSource(parent.vertex) + fragmentShaderCode: loadSource(parent.fragment) + } + ShaderProgram { + id: es2Shader + vertexShaderCode: loadSource(parent.vertexES) + fragmentShaderCode: loadSource(parent.fragmentES) + } + techniques: [ + // OpenGL 3.1 + Technique { + filterKeys: [forward] + graphicsApiFilter { + api: GraphicsApiFilter.OpenGL + profile: GraphicsApiFilter.CoreProfile + majorVersion: 3 + minorVersion: 1 + } + renderPasses: RenderPass { + shaderProgram: gl3Shader + } + }, + // ES 2.0 + Technique { + filterKeys: [forward] + graphicsApiFilter { + api: GraphicsApiFilter.OpenGLES + profile: GraphicsApiFilter.CoreProfile + majorVersion: 2 + minorVersion: 0 + } + renderPasses: RenderPass { + shaderProgram: es2Shader + } + } + ] + } +} + + diff --git a/examples/qt3d/simplecustommaterial/main.cpp b/examples/qt3d/simplecustommaterial/main.cpp new file mode 100644 index 000000000..392fe50ee --- /dev/null +++ b/examples/qt3d/simplecustommaterial/main.cpp @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include + +int main(int argc, char **argv) +{ + QGuiApplication app(argc, argv); + + QQuickView view; + + view.resize(1024, 1024); + view.setResizeMode(QQuickView::SizeRootObjectToView); + view.setSource(QUrl("qrc:/main.qml")); + view.show(); + + return app.exec(); +} diff --git a/examples/qt3d/simplecustommaterial/main.qml b/examples/qt3d/simplecustommaterial/main.qml new file mode 100644 index 000000000..2c1e95930 --- /dev/null +++ b/examples/qt3d/simplecustommaterial/main.qml @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import QtQuick.Scene3D 2.0 +import Qt3D.Render 2.0 + +Item { + + Rectangle { + id: scene + property bool colorChange: true + anchors.fill: parent + color: "White" + + transform: Rotation { + id: sceneRotation + axis.x: 1 + axis.y: 0 + axis.z: 0 + origin.x: scene.width / 2 + origin.y: scene.height / 2 + } + + Scene3D { + id: scene3d + anchors.fill: parent + anchors.margins: 10 + focus: true + aspects: ["input", "logic"] + cameraAspectRatioMode: Scene3D.AutomaticAspectRatio + + SceneRoot { + id: root + } + } + } +} diff --git a/examples/qt3d/simplecustommaterial/models.qrc b/examples/qt3d/simplecustommaterial/models.qrc new file mode 100644 index 000000000..eb6f06cac --- /dev/null +++ b/examples/qt3d/simplecustommaterial/models.qrc @@ -0,0 +1,5 @@ + + + waterPlane.obj + + diff --git a/examples/qt3d/simplecustommaterial/qml.qrc b/examples/qt3d/simplecustommaterial/qml.qrc new file mode 100644 index 000000000..016c93e42 --- /dev/null +++ b/examples/qt3d/simplecustommaterial/qml.qrc @@ -0,0 +1,8 @@ + + + main.qml + SceneRoot.qml + SimpleMaterial.qml + PlaneModel.qml + + diff --git a/examples/qt3d/simplecustommaterial/shaders.qrc b/examples/qt3d/simplecustommaterial/shaders.qrc new file mode 100644 index 000000000..9881e224a --- /dev/null +++ b/examples/qt3d/simplecustommaterial/shaders.qrc @@ -0,0 +1,8 @@ + + + shaders/gl3/simpleColor.frag + shaders/gl3/simpleColor.vert + shaders/es2/simpleColor.frag + shaders/es2/simpleColor.vert + + diff --git a/examples/qt3d/simplecustommaterial/shaders/es2/simpleColor.frag b/examples/qt3d/simplecustommaterial/shaders/es2/simpleColor.frag new file mode 100644 index 000000000..d18c01699 --- /dev/null +++ b/examples/qt3d/simplecustommaterial/shaders/es2/simpleColor.frag @@ -0,0 +1,10 @@ +#define FP highp + +uniform FP vec3 maincolor; + +void main() +{ + //output color from material + gl_FragColor = vec4(maincolor,1.0); +} + diff --git a/examples/qt3d/simplecustommaterial/shaders/es2/simpleColor.vert b/examples/qt3d/simplecustommaterial/shaders/es2/simpleColor.vert new file mode 100644 index 000000000..24934948c --- /dev/null +++ b/examples/qt3d/simplecustommaterial/shaders/es2/simpleColor.vert @@ -0,0 +1,15 @@ +#define FP highp + +attribute FP vec3 vertexPosition; +varying FP vec3 worldPosition; +uniform FP mat4 modelMatrix; +uniform FP mat4 mvp; + +void main() +{ + // Transform position, normal, and tangent to world coords + worldPosition = vec3(modelMatrix * vec4(vertexPosition, 1.0)); + + // Calculate vertex position in clip coordinates + gl_Position = mvp * vec4(worldPosition, 1.0); +} diff --git a/examples/qt3d/simplecustommaterial/shaders/gl3/simpleColor.frag b/examples/qt3d/simplecustommaterial/shaders/gl3/simpleColor.frag new file mode 100644 index 000000000..c899052d9 --- /dev/null +++ b/examples/qt3d/simplecustommaterial/shaders/gl3/simpleColor.frag @@ -0,0 +1,11 @@ +#version 150 core + +uniform vec3 maincolor; +out vec4 fragColor; + +void main() +{ + //output color from material + fragColor = vec4(maincolor,1.0); +} + diff --git a/examples/qt3d/simplecustommaterial/shaders/gl3/simpleColor.vert b/examples/qt3d/simplecustommaterial/shaders/gl3/simpleColor.vert new file mode 100644 index 000000000..b29c69d7d --- /dev/null +++ b/examples/qt3d/simplecustommaterial/shaders/gl3/simpleColor.vert @@ -0,0 +1,15 @@ +#version 150 core + +in vec3 vertexPosition; +out vec3 worldPosition; +uniform mat4 modelMatrix; +uniform mat4 mvp; + +void main() +{ + // Transform position, normal, and tangent to world coords + worldPosition = vec3(modelMatrix * vec4(vertexPosition, 1.0)); + + // Calculate vertex position in clip coordinates + gl_Position = mvp * vec4(worldPosition, 1.0); +} diff --git a/examples/qt3d/simplecustommaterial/simplecustommaterial.pro b/examples/qt3d/simplecustommaterial/simplecustommaterial.pro new file mode 100644 index 000000000..856eaaadf --- /dev/null +++ b/examples/qt3d/simplecustommaterial/simplecustommaterial.pro @@ -0,0 +1,14 @@ +TEMPLATE = app + +!include( ../examples.pri ) { + error( "Couldn't find the examples.pri file!" ) +} + +QT += qml quick +CONFIG += c++11 + +SOURCES += main.cpp + +RESOURCES += qml.qrc \ + shaders.qrc + diff --git a/examples/qt3d/simplecustommaterial/textures.qrc b/examples/qt3d/simplecustommaterial/textures.qrc new file mode 100644 index 000000000..1267d21c9 --- /dev/null +++ b/examples/qt3d/simplecustommaterial/textures.qrc @@ -0,0 +1,8 @@ + + + WaterDiffuse.png + WaterNormal.jpg + WaterSpecular.jpg + Waterwave.jpg + + -- cgit v1.2.3 From 154c3a9b44082a176a9700b5086a7bc758155a25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Fri, 20 Jan 2017 14:27:08 +0200 Subject: Move scene2d to own module and implement conditional plugin loading MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add quick3dscene2d module - Add importsscene2d qml module - Modify RenderAspect to load plugins conditionally - change autotests to match the module change Change-Id: If6596472acbd9a377561b2bfd2094a0585c781ac Reviewed-by: Antti Määttä --- src/plugins/renderplugins/scene2d/scene2d.pro | 4 +- .../renderplugins/scene2d/scene2dplugin.cpp | 2 +- .../imports/render/qt3dquick3drenderplugin.cpp | 4 - src/quick3d/imports/scene2d/importsscene2d.pro | 19 + src/quick3d/imports/scene2d/qmldir | 3 + .../imports/scene2d/qtquickscene2dplugin.cpp | 56 ++ src/quick3d/imports/scene2d/qtquickscene2dplugin.h | 62 ++ .../quick3drender/qt3dquickrender_logging.cpp | 49 -- .../quick3drender/qt3dquickrender_logging_p.h | 65 -- src/quick3d/quick3drender/quick3drender.pro | 7 +- src/quick3d/quick3drender/scene2d/qscene2d.cpp | 697 --------------------- src/quick3d/quick3drender/scene2d/qscene2d.h | 117 ---- src/quick3d/quick3drender/scene2d/qscene2d_p.h | 219 ------- src/quick3d/quick3drender/scene2d/scene2d.cpp | 372 ----------- src/quick3d/quick3drender/scene2d/scene2d.pri | 10 - src/quick3d/quick3drender/scene2d/scene2d_p.h | 127 ---- src/quick3d/quick3dscene2d/items/items.pri | 10 + src/quick3d/quick3dscene2d/items/qscene2d.cpp | 697 +++++++++++++++++++++ src/quick3d/quick3dscene2d/items/qscene2d.h | 117 ++++ src/quick3d/quick3dscene2d/items/qscene2d_p.h | 219 +++++++ src/quick3d/quick3dscene2d/items/scene2d.cpp | 372 +++++++++++ src/quick3d/quick3dscene2d/items/scene2d.pri | 10 + src/quick3d/quick3dscene2d/items/scene2d_p.h | 127 ++++ .../quick3dscene2d/qt3dquickscene2d_global.cpp | 58 ++ .../quick3dscene2d/qt3dquickscene2d_global.h | 56 ++ .../quick3dscene2d/qt3dquickscene2d_global_p.h | 88 +++ .../quick3dscene2d/qt3dquickscene2d_logging.cpp | 49 ++ .../quick3dscene2d/qt3dquickscene2d_logging_p.h | 65 ++ .../quick3dscene2d/qt3dquickscene2dnodefactory.cpp | 89 +++ .../quick3dscene2d/qt3dquickscene2dnodefactory_p.h | 89 +++ src/quick3d/quick3dscene2d/quick3dscene2d.pro | 31 + src/render/frontend/qrenderaspect.cpp | 38 +- src/render/frontend/qrenderaspect_p.h | 10 +- src/src.pro | 12 +- sync.profile | 1 + tests/auto/render/qscene2d/qscene2d.pro | 2 +- tests/auto/render/qscene2d/tst_qscene2d.cpp | 2 +- tests/auto/render/scene2d/scene2d.pro | 2 +- tests/auto/render/scene2d/tst_scene2d.cpp | 2 +- tests/manual/render-qml-to-texture-qml/main.qml | 1 + .../render-qml-to-texture-qml.pro | 2 +- tests/manual/render-qml-to-texture/main.cpp | 2 +- .../render-qml-to-texture.pro | 2 +- tests/manual/video-texture-qml/main.qml | 1 + 44 files changed, 2282 insertions(+), 1685 deletions(-) create mode 100644 src/quick3d/imports/scene2d/importsscene2d.pro create mode 100644 src/quick3d/imports/scene2d/qmldir create mode 100644 src/quick3d/imports/scene2d/qtquickscene2dplugin.cpp create mode 100644 src/quick3d/imports/scene2d/qtquickscene2dplugin.h delete mode 100644 src/quick3d/quick3drender/qt3dquickrender_logging.cpp delete mode 100644 src/quick3d/quick3drender/qt3dquickrender_logging_p.h delete mode 100644 src/quick3d/quick3drender/scene2d/qscene2d.cpp delete mode 100644 src/quick3d/quick3drender/scene2d/qscene2d.h delete mode 100644 src/quick3d/quick3drender/scene2d/qscene2d_p.h delete mode 100644 src/quick3d/quick3drender/scene2d/scene2d.cpp delete mode 100644 src/quick3d/quick3drender/scene2d/scene2d.pri delete mode 100644 src/quick3d/quick3drender/scene2d/scene2d_p.h create mode 100644 src/quick3d/quick3dscene2d/items/items.pri create mode 100644 src/quick3d/quick3dscene2d/items/qscene2d.cpp create mode 100644 src/quick3d/quick3dscene2d/items/qscene2d.h create mode 100644 src/quick3d/quick3dscene2d/items/qscene2d_p.h create mode 100644 src/quick3d/quick3dscene2d/items/scene2d.cpp create mode 100644 src/quick3d/quick3dscene2d/items/scene2d.pri create mode 100644 src/quick3d/quick3dscene2d/items/scene2d_p.h create mode 100644 src/quick3d/quick3dscene2d/qt3dquickscene2d_global.cpp create mode 100644 src/quick3d/quick3dscene2d/qt3dquickscene2d_global.h create mode 100644 src/quick3d/quick3dscene2d/qt3dquickscene2d_global_p.h create mode 100644 src/quick3d/quick3dscene2d/qt3dquickscene2d_logging.cpp create mode 100644 src/quick3d/quick3dscene2d/qt3dquickscene2d_logging_p.h create mode 100644 src/quick3d/quick3dscene2d/qt3dquickscene2dnodefactory.cpp create mode 100644 src/quick3d/quick3dscene2d/qt3dquickscene2dnodefactory_p.h create mode 100644 src/quick3d/quick3dscene2d/quick3dscene2d.pro diff --git a/src/plugins/renderplugins/scene2d/scene2d.pro b/src/plugins/renderplugins/scene2d/scene2d.pro index dbf9c3e36..4f7ae6ea9 100644 --- a/src/plugins/renderplugins/scene2d/scene2d.pro +++ b/src/plugins/renderplugins/scene2d/scene2d.pro @@ -1,17 +1,15 @@ TARGET = scene2d -QT += core-private 3dcore 3dcore-private 3drender 3drender-private 3dextras 3dquickrender 3dquickrender-private +QT += core-private 3dcore 3dcore-private 3drender 3drender-private 3dextras 3dquickscene2d 3dquickscene2d-private # Qt3D is free of Q_FOREACH - make sure it stays that way: DEFINES += QT_NO_FOREACH HEADERS += \ scene2dplugin.h -# scene2dnode_p.h SOURCES += \ main.cpp \ scene2dplugin.cpp -# scene2dnode.cpp DISTFILES += \ scene2dplugin.json diff --git a/src/plugins/renderplugins/scene2d/scene2dplugin.cpp b/src/plugins/renderplugins/scene2d/scene2dplugin.cpp index 5621858ea..83e002473 100644 --- a/src/plugins/renderplugins/scene2d/scene2dplugin.cpp +++ b/src/plugins/renderplugins/scene2d/scene2dplugin.cpp @@ -40,7 +40,7 @@ #include "scene2dplugin.h" #include -#include +#include QT_BEGIN_NAMESPACE diff --git a/src/quick3d/imports/render/qt3dquick3drenderplugin.cpp b/src/quick3d/imports/render/qt3dquick3drenderplugin.cpp index f162e3d2b..b151d1b39 100644 --- a/src/quick3d/imports/render/qt3dquick3drenderplugin.cpp +++ b/src/quick3d/imports/render/qt3dquick3drenderplugin.cpp @@ -109,7 +109,6 @@ #include #include -#include #include #include #include @@ -285,9 +284,6 @@ void Qt3DQuick3DRenderPlugin::registerTypes(const char *uri) qmlRegisterType(uri, 2, 0, "SeamlessCubemap"); qmlRegisterType(uri, 2, 0, "StencilOperation"); qmlRegisterType(uri, 2, 0, "StencilMask"); - - // Scene2D - Qt3DRender::Quick::registerType("QScene2D", "Qt3D.Render/Scene2D", uri, 2, 9, "Scene2D"); } QT_END_NAMESPACE diff --git a/src/quick3d/imports/scene2d/importsscene2d.pro b/src/quick3d/imports/scene2d/importsscene2d.pro new file mode 100644 index 000000000..13ccf7818 --- /dev/null +++ b/src/quick3d/imports/scene2d/importsscene2d.pro @@ -0,0 +1,19 @@ +CXX_MODULE = qml +TARGET = qtquickscene2dplugin +TARGETPATH = QtQuick/Scene2D +IMPORT_VERSION = 2.0 + +QT += qml quick 3dcore 3drender 3drender-private 3dinput 3dlogic 3dquickscene2d + +# Qt3D is free of Q_FOREACH - make sure it stays that way: +DEFINES += QT_NO_FOREACH + +HEADERS += \ + qtquickscene2dplugin.h \ + +SOURCES += \ + qtquickscene2dplugin.cpp \ + +OTHER_FILES += qmldir + +load(qml_plugin) diff --git a/src/quick3d/imports/scene2d/qmldir b/src/quick3d/imports/scene2d/qmldir new file mode 100644 index 000000000..2e807f1e6 --- /dev/null +++ b/src/quick3d/imports/scene2d/qmldir @@ -0,0 +1,3 @@ +module QtQuick.Scene2D +plugin qtquickscene2dplugin +classname QtQuickScene2DPlugin diff --git a/src/quick3d/imports/scene2d/qtquickscene2dplugin.cpp b/src/quick3d/imports/scene2d/qtquickscene2dplugin.cpp new file mode 100644 index 000000000..44ca596d3 --- /dev/null +++ b/src/quick3d/imports/scene2d/qtquickscene2dplugin.cpp @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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 "qtquickscene2dplugin.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +static void initScene2dPlugin() +{ + Qt3DRender::QRenderAspectPrivate::configurePlugin("scene2d"); +} + +Q_COREAPP_STARTUP_FUNCTION(initScene2dPlugin) + +void QtQuickScene2DPlugin::registerTypes(const char *uri) +{ + qmlRegisterType(uri, 2, 9, "Scene2D"); +} + +QT_END_NAMESPACE diff --git a/src/quick3d/imports/scene2d/qtquickscene2dplugin.h b/src/quick3d/imports/scene2d/qtquickscene2dplugin.h new file mode 100644 index 000000000..c9318673f --- /dev/null +++ b/src/quick3d/imports/scene2d/qtquickscene2dplugin.h @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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$ +** +****************************************************************************/ + +#ifndef QTQUICKSCENE2DPLUGIN_H +#define QTQUICKSCENE2DPLUGIN_H + +#include + +static void initResources() +{ +#ifdef QT_STATIC + Q_INIT_RESOURCE(qmake_QtQuick_Scene2D); +#endif +} + +QT_BEGIN_NAMESPACE + +class QtQuickScene2DPlugin : public QQmlExtensionPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) +public: + QtQuickScene2DPlugin(QObject *parent = 0) : QQmlExtensionPlugin(parent) { initResources(); } + void registerTypes(const char *uri) Q_DECL_OVERRIDE; +}; + +QT_END_NAMESPACE + +#endif // QTQUICKSCENE2DPLUGIN_H diff --git a/src/quick3d/quick3drender/qt3dquickrender_logging.cpp b/src/quick3d/quick3drender/qt3dquickrender_logging.cpp deleted file mode 100644 index b9e5d2e08..000000000 --- a/src/quick3d/quick3drender/qt3dquickrender_logging.cpp +++ /dev/null @@ -1,49 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 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 "qt3dquickrender_logging_p.h" - -QT_BEGIN_NAMESPACE - -namespace Qt3DRender { -namespace Quick { - -Q_LOGGING_CATEGORY(Scene2D, "Qt3D.Scene2D") - -} // Quick -} // Qt3DRender - -QT_END_NAMESPACE diff --git a/src/quick3d/quick3drender/qt3dquickrender_logging_p.h b/src/quick3d/quick3drender/qt3dquickrender_logging_p.h deleted file mode 100644 index c34abfdd3..000000000 --- a/src/quick3d/quick3drender/qt3dquickrender_logging_p.h +++ /dev/null @@ -1,65 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 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$ -** -****************************************************************************/ - -#ifndef QT3DQUICKRENDER_LOGGING_P_H -#define QT3DQUICKRENDER_LOGGING_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include - -QT_BEGIN_NAMESPACE - -namespace Qt3DRender { -namespace Quick { - -Q_DECLARE_LOGGING_CATEGORY(Scene2D) - -} // Quick -} // Qt3DRender - -QT_END_NAMESPACE - -#endif // QT3DQUICKRENDER_LOGGING_P_H diff --git a/src/quick3d/quick3drender/quick3drender.pro b/src/quick3d/quick3drender/quick3drender.pro index b1b904e12..88d7a9556 100644 --- a/src/quick3d/quick3drender/quick3drender.pro +++ b/src/quick3d/quick3drender/quick3drender.pro @@ -14,19 +14,16 @@ gcov { SOURCES += \ qt3dquickrender_global.cpp \ - qt3dquickrendernodefactory.cpp \ - qt3dquickrender_logging.cpp + qt3dquickrendernodefactory.cpp HEADERS += \ qt3dquickrendernodefactory_p.h \ qt3dquickrender_global_p.h \ - qt3dquickrender_global.h \ - qt3dquickrender_logging_p.h + qt3dquickrender_global.h # otherwise mingw headers do not declare common functions like ::strcasecmp win32-g++*:QMAKE_CXXFLAGS_CXX11 = -std=gnu++0x include(./items/items.pri) -include(./scene2d/scene2d.pri) load(qt_module) diff --git a/src/quick3d/quick3drender/scene2d/qscene2d.cpp b/src/quick3d/quick3drender/scene2d/qscene2d.cpp deleted file mode 100644 index fa46cd3d2..000000000 --- a/src/quick3d/quick3drender/scene2d/qscene2d.cpp +++ /dev/null @@ -1,697 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 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 "qscene2d.h" -#include "qscene2d_p.h" -#include "scene2d_p.h" - -#include - -#include - -QT_BEGIN_NAMESPACE - -using namespace Qt3DCore; - -namespace Qt3DRender { - -namespace Quick { - -/*! - \class Qt3DRender::QScene2D - \inmodule Qt3DRender - - \brief This class enables rendering qml into a texture, which then can be - used as a part of 3D scene. - - The component uses QQuickRenderControl to render the given QML source into an - offscreen surface, which is attached to a texture provided by the user. This allows the - component to directly render into the texture without intermediate copy and the user to - freely specify how the texture is used in the 3D scene. - - \since 5.9 -*/ - -/*! - \qmltype Scene2D - \inqmlmodule Qt3D.Render - \since - \ingroup - \instantiates Qt3DRender::QScene2D - \brief Scene2D - */ - -/*! - \enum QScene2D::RenderPolicy - - This enum type describes types of render policies available. - \value Continuous The Scene2D is rendering continuously. This is the default render policy. - \value SingleShot The Scene2D renders to the texture only once after which the resources - allocated for rendering are released. -*/ - -/*! - \qmlproperty RenderTargetOutput Qt3D.Render::Scene2D::output - Holds the RenderTargetOutput, which specifies where the Scene2D is rendering to. - */ - -/*! - \qmlproperty QUrl Qt3D.Render::Scene2D::source - Holds the qml source url. - */ - -/*! - \qmlproperty enumeration Qt3D.Render::Scene2D::renderPolicy - Holds the render policy of this Scene2D. - */ - -/*! - \qmlproperty bool Qt3D.Render::Scene2D::loaded - Holds whether the source has been loaded. - */ - -class RenderControl : public QQuickRenderControl -{ -public: - RenderControl(QWindow *w) : m_window(w) { } - QWindow *renderWindow(QPoint *offset) Q_DECL_OVERRIDE; - -private: - QWindow *m_window; -}; - -QWindow *RenderControl::renderWindow(QPoint *offset) -{ - if (offset) - *offset = QPoint(0, 0); - return m_window; -} - -/*! - \internal - Constructs object shared by the front-end and back-end to synchronize the rendering. - */ -Scene2DSharedObject::Scene2DSharedObject(Scene2DManager *manager) - : m_quit(false) - , m_requestSync(false) - , m_prepared(false) - , m_initialized(false) - , m_renderControl(nullptr) - , m_quickWindow(nullptr) - , m_renderManager(manager) - , m_surface(nullptr) - , m_renderObject(nullptr) - , m_disallowed(false) -{ -} - -Scene2DSharedObject::~Scene2DSharedObject() -{ -} - -void Scene2DSharedObject::cleanup() -{ - delete m_renderControl; - delete m_quickWindow; - delete m_surface; - m_renderControl = nullptr; - m_quickWindow = nullptr; - m_surface = nullptr; - m_initialized = false; -} - -bool Scene2DSharedObject::canRender() const -{ - return m_initialized && m_prepared && !m_disallowed; -} - -bool Scene2DSharedObject::isInitialized() const -{ - return m_initialized; -} - -void Scene2DSharedObject::disallowRender() -{ - m_disallowed = true; -} - -void Scene2DSharedObject::setInitialized() -{ - m_initialized = true; -} - -bool Scene2DSharedObject::isPrepared() const -{ - return m_prepared; -} - -void Scene2DSharedObject::setPrepared() -{ - m_prepared = true; -} - -// not protected, call only from main thread -bool Scene2DSharedObject::isQuit() const -{ - Q_ASSERT(QThread::currentThread() == QCoreApplication::instance()->thread()); - return m_quit; -} - -// not protected, call only from main thread -void Scene2DSharedObject::requestQuit() -{ - Q_ASSERT(QThread::currentThread() == QCoreApplication::instance()->thread()); - m_quit = true; - QCoreApplication::postEvent(m_renderObject, new QEvent(QUIT)); -} - -bool Scene2DSharedObject::isSyncRequested() const -{ - return m_requestSync; -} - -void Scene2DSharedObject::requestRender(bool sync) -{ - m_requestSync = sync; - QCoreApplication::postEvent(m_renderObject, new QEvent(RENDER)); -} - -void Scene2DSharedObject::wait() -{ - m_cond.wait(&m_mutex); -} - -void Scene2DSharedObject::wake() -{ - m_cond.wakeOne(); -} - -void Scene2DSharedObject::clearSyncRequest() -{ - m_requestSync = false; -} - -/*! - \internal - Constructs qml render manager. - */ -Scene2DManager::Scene2DManager(QScene2DPrivate *priv) - : m_priv(priv) - , m_qmlEngine(nullptr) - , m_qmlComponent(nullptr) - , m_rootItem(nullptr) - , m_source(nullptr) - , m_requested(false) - , m_initialized(false) - , m_renderSyncRequested(false) - , m_sharedObject(new Scene2DSharedObject(this)) - , m_renderPolicy(QScene2D::Continuous) - , m_backendInitialized(false) - , m_noSourceMode(false) - , m_item(nullptr) - , m_ownEngine(false) -{ - m_sharedObject->m_surface = new QOffscreenSurface; - m_sharedObject->m_surface->setFormat(QSurfaceFormat::defaultFormat()); - m_sharedObject->m_surface->create(); - - // Create render control - m_sharedObject->m_renderControl = new RenderControl(nullptr); - - // Create window to render the QML with - m_sharedObject->m_quickWindow = new QQuickWindow(m_sharedObject->m_renderControl); - m_sharedObject->m_quickWindow->setClearBeforeRendering(false); - - connect(m_sharedObject->m_renderControl, &QQuickRenderControl::renderRequested, - this, &Scene2DManager::requestRender); - connect(m_sharedObject->m_renderControl, &QQuickRenderControl::sceneChanged, - this, &Scene2DManager::requestRenderSync); -} - -Scene2DManager::~Scene2DManager() -{ - m_sharedObject = nullptr; -} - -void Scene2DManager::requestRender() -{ - // Don't request render until the backend is initialized. - if (m_sharedObject->canRender()) { - if (!m_requested) { - m_requested = true; - QCoreApplication::postEvent(this, new QEvent(RENDER)); - } - } -} - -void Scene2DManager::requestRenderSync() -{ - // Don't request render until the backed is initialized. - if (m_sharedObject->canRender()) { - if (!m_requested) { - m_requested = true; - QCoreApplication::postEvent(this, new QEvent(RENDERSYNC)); - } - } else { - m_renderSyncRequested = true; - } -} - -void Scene2DManager::startIfInitialized() -{ - if (!m_initialized && m_backendInitialized) { - if (m_source.isValid() && !m_noSourceMode) { - // Create a QML engine. - if (!m_qmlEngine) { - m_qmlEngine = new QQmlEngine; - if (!m_qmlEngine->incubationController()) { - m_qmlEngine->setIncubationController(m_sharedObject->m_quickWindow - ->incubationController()); - } - } - - // create component - m_ownEngine = true; - m_qmlComponent = new QQmlComponent(m_qmlEngine, m_source); - if (m_qmlComponent->isLoading()) { - connect(m_qmlComponent, &QQmlComponent::statusChanged, - this, &Scene2DManager::run); - } else { - run(); - } - } else if (m_item != nullptr) { - m_rootItem = m_item; - - // Associate root item with the window. - m_rootItem->setParentItem(m_sharedObject->m_quickWindow->contentItem()); - - // Update window size. - updateSizes(); - - m_initialized = true; - m_sharedObject->setInitialized(); - } - } -} - -void Scene2DManager::stopAndClean() -{ - if (m_sharedObject->isInitialized()) { - QMutexLocker lock(&m_sharedObject->m_mutex); - m_sharedObject->requestQuit(); - m_sharedObject->wait(); - m_sharedObject->cleanup(); - if (m_ownEngine) { - QObject::disconnect(m_connection); - delete m_qmlEngine; - } - delete m_qmlComponent; - m_qmlEngine = nullptr; - m_qmlComponent = nullptr; - } -} - -void Scene2DManager::run() -{ - disconnect(m_qmlComponent, &QQmlComponent::statusChanged, this, &Scene2DManager::run); - - if (m_qmlComponent->isError()) { - QList errorList = m_qmlComponent->errors(); - for (const QQmlError &error: errorList) - qWarning() << error.url() << error.line() << error; - return; - } - - QObject *rootObject = m_qmlComponent->create(); - if (m_qmlComponent->isError()) { - QList errorList = m_qmlComponent->errors(); - for (const QQmlError &error: errorList) - qWarning() << error.url() << error.line() << error; - return; - } - - m_rootItem = qobject_cast(rootObject); - if (!m_rootItem) { - qWarning("QScene2D: Root item is not a QQuickItem."); - delete rootObject; - return; - } - - // The root item is ready. Associate it with the window. - m_rootItem->setParentItem(m_sharedObject->m_quickWindow->contentItem()); - - // Update window size. - updateSizes(); - - m_initialized = true; - m_sharedObject->setInitialized(); - - emit onLoadedChanged(); -} - -void Scene2DManager::updateSizes() -{ - const int width = m_rootItem->width(); - const int height = m_rootItem->height(); - if (width == 0 || height == 0) { - qWarning() << "QScene2D: Root item size not set."; - return; - } - m_sharedObject->m_quickWindow->setGeometry(0, 0, width, height); -} - -void Scene2DManager::setSource(const QUrl &url) -{ - m_source = url; - startIfInitialized(); -} - -void Scene2DManager::setItem(QQuickItem *item) -{ - m_noSourceMode = true; - m_item = item; - startIfInitialized(); -} - -bool Scene2DManager::event(QEvent *e) -{ - switch (e->type()) { - - case RENDER: { - // just render request, don't need to call sync in render thread - QMutexLocker lock(&m_sharedObject->m_mutex); - m_sharedObject->requestRender(false); - m_requested = false; - return true; - } - - case RENDERSYNC: { - // sync and render request, main and render threads must be synchronized - if (!m_sharedObject->isQuit()) - doRenderSync(); - m_requested = false; - return true; - } - - case PREPARE: { - m_sharedObject->m_renderControl->prepareThread(m_sharedObject->m_renderThread); - m_sharedObject->setPrepared(); - - if (m_renderSyncRequested) { - if (!m_requested) { - m_requested = true; - QCoreApplication::postEvent(this, new QEvent(RENDERSYNC)); - } - m_renderSyncRequested = false; - } - return true; - } - - case INITIALIZED: { - // backend is initialized, start the qml - m_backendInitialized = true; - startIfInitialized(); - return true; - } - - case RENDERED: { - // render is done, excellent, now clean anything not needed anymore. - stopAndClean(); - return true; - } - - default: - break; - } - return QObject::event(e); -} - -bool Scene2DManager::forwardEvent(QEvent *event) -{ - switch (event->type()) { - - case QEvent::MouseMove: - case QEvent::MouseButtonDblClick: - case QEvent::MouseButtonPress: - case QEvent::MouseButtonRelease: { - QMouseEvent* me = static_cast(event); - QPointF pos = me->localPos(); - pos = QPointF(pos.x() * m_rootItem->width(), pos.y() * m_rootItem->height()); - QMouseEvent nme = QMouseEvent(me->type(), pos, pos, pos, me->button(), me->buttons(), - me->modifiers(), Qt::MouseEventSynthesizedByApplication); - QCoreApplication::sendEvent(m_sharedObject->m_quickWindow, &nme); - } break; - - case QEvent::KeyPress: - case QEvent::KeyRelease: { - QCoreApplication::sendEvent(m_sharedObject->m_quickWindow, event); - } break; - - default: - break; - } - return false; -} - -void Scene2DManager::doRenderSync() -{ - QMutexLocker lock(&m_sharedObject->m_mutex); - - m_sharedObject->requestRender(true); - m_sharedObject->m_renderControl->polishItems(); - - // begin waiting render thread - m_sharedObject->wait(); - m_requested = false; -} - -void Scene2DManager::cleanup() -{ - stopAndClean(); -} - -void Scene2DManager::setEngine(QQmlEngine *engine) -{ - m_qmlEngine = engine; - m_ownEngine = false; - if (engine) { - m_connection = QObject::connect(engine, &QObject::destroyed, - this, &Scene2DManager::engineDestroyed); - } -} - -void Scene2DManager::engineDestroyed() -{ - QObject::disconnect(m_connection); - m_qmlEngine = nullptr; - m_ownEngine = false; -} - - -QScene2DPrivate::QScene2DPrivate() - : Qt3DCore::QNodePrivate() - , m_renderManager(new Scene2DManager(this)) - , m_output(nullptr) -{ -} - -QScene2DPrivate::~QScene2DPrivate() -{ - m_renderManager->cleanup(); - delete m_renderManager; -} - - -/*! - The constructor creates a new QScene2D instance with the specified \a parent. - */ -QScene2D::QScene2D(Qt3DCore::QNode *parent) - : Qt3DCore::QNode(*new QScene2DPrivate, parent) -{ - Q_D(QScene2D); - connect(d->m_renderManager, &Scene2DManager::onLoadedChanged, - this, &QScene2D::sourceLoaded); -} - -QScene2D::QScene2D(QQmlEngine *engine, Qt3DCore::QNode *parent) - : Qt3DCore::QNode(*new QScene2DPrivate, parent) -{ - Q_D(QScene2D); - connect(d->m_renderManager, &Scene2DManager::onLoadedChanged, - this, &QScene2D::sourceLoaded); - d->m_renderManager->setEngine(engine); -} - -QScene2D::~QScene2D() -{ -} - -bool QScene2D::loaded() const -{ - Q_D(const QScene2D); - return d->m_renderManager->m_initialized; -} - -/*! - \property QScene2D::source - \brief Specifies the url for the qml. - - This property specifies the url to the qml being rendered to the texture. - The source must specify QQuickItem as a root. The item must specify width - and height. The rendered qml is scaled to the texture size. - The property can not be changed after the rendering has been initialized. - */ -QUrl QScene2D::source() const -{ - Q_D(const QScene2D); - return d->m_renderManager->m_source; -} - -void QScene2D::setSource(const QUrl &url) -{ - Q_D(QScene2D); - if (d->m_renderManager->m_initialized) { - qWarning() << "Unable to set source after initialization."; - return; - } - if (d->m_renderManager->m_source != url) { - d->m_renderManager->setSource(url); - emit sourceChanged(url); - } -} - -QQuickItem* QScene2D::item() const -{ - Q_D(const QScene2D); - return d->m_renderManager->m_item; -} - -void QScene2D::setItem(QQuickItem *item) -{ - Q_D(QScene2D); - if (d->m_renderManager->m_initialized) { - qWarning() << "Unable to set item after initialization."; - return; - } - if (d->m_renderManager->m_item != item) { - d->m_renderManager->setItem(item); - emit itemChanged(item); - } -} - -/*! - \property QScene2D::renderPolicy - - Holds the render policy of this Scene2D. - */ -QScene2D::RenderPolicy QScene2D::renderPolicy() const -{ - Q_D(const QScene2D); - return d->m_renderManager->m_renderPolicy; -} - -void QScene2D::setRenderPolicy(QScene2D::RenderPolicy renderPolicy) -{ - Q_D(const QScene2D); - if (d->m_renderManager->m_renderPolicy != renderPolicy) { - d->m_renderManager->m_renderPolicy = renderPolicy; - emit renderPolicyChanged(renderPolicy); - } -} - -/*! - \property QScene2D::output - Holds the QRenderTargetOutput, which specifies where the QScene2D is - rendering to. - */ -Qt3DRender::QRenderTargetOutput *QScene2D::output() const -{ - Q_D(const QScene2D); - return d->m_output; -} - -void QScene2D::setOutput(Qt3DRender::QRenderTargetOutput *output) -{ - Q_D(QScene2D); - if (d->m_output != output) { - if (d->m_output) - d->unregisterDestructionHelper(d->m_output); - d->m_output = output; - if (output) - d->registerDestructionHelper(output, &QScene2D::setOutput, d->m_output); - emit outputChanged(output); - } -} - -Qt3DCore::QNodeCreatedChangeBasePtr QScene2D::createNodeCreationChange() const -{ - auto creationChange = Qt3DCore::QNodeCreatedChangePtr::create(this); - auto &data = creationChange->data; - Q_D(const QScene2D); - data.renderPolicy = d->m_renderManager->m_renderPolicy; - data.sharedObject = d->m_renderManager->m_sharedObject; - data.output = d->m_output ? d->m_output->id() : Qt3DCore::QNodeId(); - return creationChange; -} - -bool QScene2D::event(QEvent *event) -{ - Q_D(QScene2D); - d->m_renderManager->forwardEvent(event); - return true; -} - -/*! - Returns the qml engine used by the QScene2D. - */ -QQmlEngine *QScene2D::engine() const -{ - Q_D(const QScene2D); - return d->m_renderManager->m_qmlEngine; -} - -/*! - \internal - */ -void QScene2D::sourceLoaded() -{ - emit loadedChanged(true); -} - -} // namespace Quick -} // namespace Qt3DRender - -QT_END_NAMESPACE diff --git a/src/quick3d/quick3drender/scene2d/qscene2d.h b/src/quick3d/quick3drender/scene2d/qscene2d.h deleted file mode 100644 index 0a7e943d6..000000000 --- a/src/quick3d/quick3drender/scene2d/qscene2d.h +++ /dev/null @@ -1,117 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 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$ -** -****************************************************************************/ - -#ifndef QT3DRENDER_QUICK3DRENDER_QSCENE2D_H -#define QT3DRENDER_QUICK3DRENDER_QSCENE2D_H - -#include -#include - -#include -#include - -#include - -#include - -QT_BEGIN_NAMESPACE - -namespace Qt3DRender { - -namespace Quick { - -class QScene2DPrivate; - -class QT3DQUICKRENDERSHARED_EXPORT QScene2D : public Qt3DCore::QNode -{ - Q_OBJECT - - Q_PROPERTY(Qt3DRender::QRenderTargetOutput *output READ output WRITE setOutput NOTIFY outputChanged) - Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged) - Q_PROPERTY(QScene2D::RenderPolicy renderPolicy READ renderPolicy WRITE setRenderPolicy NOTIFY renderPolicyChanged) - Q_PROPERTY(bool loaded READ loaded NOTIFY loadedChanged) - Q_PROPERTY(QQuickItem *item READ item WRITE setItem NOTIFY itemChanged) - - Q_CLASSINFO("DefaultProperty", "item") - -public: - - enum RenderPolicy { - Continuous, - SingleShot - }; - Q_ENUM(RenderPolicy) - - explicit QScene2D(Qt3DCore::QNode *parent = nullptr); - QScene2D(QQmlEngine *engine, Qt3DCore::QNode *parent = nullptr); - ~QScene2D(); - - Qt3DRender::QRenderTargetOutput *output() const; - QUrl source() const; - bool loaded() const; - QScene2D::RenderPolicy renderPolicy() const; - QQuickItem *item() const; - QQmlEngine *engine() const; - bool event(QEvent *event) Q_DECL_OVERRIDE; - -public Q_SLOTS: - void setOutput(Qt3DRender::QRenderTargetOutput *output); - void setSource(const QUrl &url); - void setRenderPolicy(QScene2D::RenderPolicy policy); - void setItem(QQuickItem *item); - -Q_SIGNALS: - void outputChanged(Qt3DRender::QRenderTargetOutput *output); - void sourceChanged(const QUrl &url); - void loadedChanged(bool loaded); - void renderPolicyChanged(QScene2D::RenderPolicy policy); - void itemChanged(QQuickItem *item); - -protected: - Q_DECLARE_PRIVATE(QScene2D) - -private: - Qt3DCore::QNodeCreatedChangeBasePtr createNodeCreationChange() const Q_DECL_OVERRIDE; - - void sourceLoaded(); -}; - -} // namespace Quick -} // namespace Qt3DRender - -QT_END_NAMESPACE - -#endif // QT3DRENDER_QUICK3DRENDER_QSCENE2D_H diff --git a/src/quick3d/quick3drender/scene2d/qscene2d_p.h b/src/quick3d/quick3drender/scene2d/qscene2d_p.h deleted file mode 100644 index 34b54b231..000000000 --- a/src/quick3d/quick3drender/scene2d/qscene2d_p.h +++ /dev/null @@ -1,219 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 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$ -** -****************************************************************************/ - -#ifndef QT3DRENDER_QUICK3DRENDER_QSCENE2D_P_H -#define QT3DRENDER_QUICK3DRENDER_QSCENE2D_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of other Qt classes. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -QT_BEGIN_NAMESPACE - -namespace Qt3DRender { - -namespace Quick { - -class QScene2D; -class Scene2DManager; - -// render thread -> render thread -static const QEvent::Type INITIALIZE = QEvent::Type(QEvent::User + 1); - -// main thread -> main thread, render thread -static const QEvent::Type RENDER = QEvent::Type(QEvent::User + 2); - -// main thread -> main thread -static const QEvent::Type RENDERSYNC = QEvent::Type(QEvent::User + 3); - -// render thread -> main thread -static const QEvent::Type PREPARE = QEvent::Type(QEvent::User + 4); -static const QEvent::Type INITIALIZED = QEvent::Type(QEvent::User + 5); -static const QEvent::Type RENDERED = QEvent::Type(QEvent::User + 6); - -// main thread -> render thread -static const QEvent::Type QUIT = QEvent::Type(QEvent::User + 7); - -class Q_AUTOTEST_EXPORT Scene2DSharedObject -{ -public: - Scene2DSharedObject(Scene2DManager *manager); - ~Scene2DSharedObject(); - - QQuickRenderControl *m_renderControl; - QQuickWindow *m_quickWindow; - Scene2DManager *m_renderManager; - QOffscreenSurface *m_surface; - - QThread *m_renderThread; - QObject *m_renderObject; - - QWaitCondition m_cond; - QMutex m_mutex; - - bool isInitialized() const; - void setInitialized(); - - void requestQuit(); - bool isQuit() const; - - void requestRender(bool sync); - - bool isSyncRequested() const; - void clearSyncRequest(); - - void wait(); - void wake(); - - bool isPrepared() const; - void setPrepared(); - - void disallowRender(); - bool canRender() const; - - void cleanup(); - -private: - - bool m_disallowed; - bool m_quit; - bool m_requestSync; - bool m_requestRender; - bool m_prepared; - bool m_initialized; -}; - -typedef QSharedPointer Scene2DSharedObjectPtr; - -class Q_AUTOTEST_EXPORT QScene2DPrivate : public Qt3DCore::QNodePrivate -{ -public: - Q_DECLARE_PUBLIC(QScene2D) - - QScene2DPrivate(); - ~QScene2DPrivate(); - - Scene2DManager *m_renderManager; - QMetaObject::Connection m_textureDestroyedConnection; - Qt3DRender::QRenderTargetOutput *m_output; -}; - -struct QScene2DData -{ - QScene2D::RenderPolicy renderPolicy; - Scene2DSharedObjectPtr sharedObject; - Qt3DCore::QNodeId output; -}; - -class Scene2DManager : public QObject -{ - Q_OBJECT -public: - Scene2DManager(QScene2DPrivate *priv); - ~Scene2DManager(); - - QQmlEngine *m_qmlEngine; - QQmlComponent *m_qmlComponent; - QQuickItem *m_rootItem; - QQuickItem *m_item; - - QScene2DPrivate *m_priv; - QSharedPointer m_sharedObject; - - QUrl m_source; - Qt3DCore::QNodeId m_id; - QMetaObject::Connection m_connection; - QScene2D::RenderPolicy m_renderPolicy; - - bool m_requested; - bool m_initialized; - bool m_renderSyncRequested; - bool m_backendInitialized; - bool m_noSourceMode; - bool m_ownEngine; - - void requestRender(); - void requestRenderSync(); - void doRenderSync(); - void startIfInitialized(); - void stopAndClean(); - void run(); - void updateSizes(); - - void setSource(const QUrl &url); - void setItem(QQuickItem *item); - - bool event(QEvent *e) Q_DECL_OVERRIDE; - bool forwardEvent(QEvent *event); - - Q_SIGNAL void onLoadedChanged(); - - void cleanup(); - void setEngine(QQmlEngine *engine); - void engineDestroyed(); -}; - -} // namespace Quick -} // namespace Qt3DRender - -QT_END_NAMESPACE - -Q_DECLARE_METATYPE(Qt3DRender::Quick::Scene2DSharedObjectPtr) - -#endif // QT3DRENDER_QUICK3DRENDER_QSCENE2D_P_H diff --git a/src/quick3d/quick3drender/scene2d/scene2d.cpp b/src/quick3d/quick3drender/scene2d/scene2d.cpp deleted file mode 100644 index 9317dc2c5..000000000 --- a/src/quick3d/quick3drender/scene2d/scene2d.cpp +++ /dev/null @@ -1,372 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 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 -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE - -#ifndef GL_DEPTH24_STENCIL8 -#define GL_DEPTH24_STENCIL8 0x88F0 -#endif - -using namespace Qt3DRender::Quick; - -namespace Qt3DRender { - -namespace Render { - -namespace Quick { - -Q_GLOBAL_STATIC(QThread, renderThread) -Q_GLOBAL_STATIC(QAtomicInt, renderThreadClientCount) - -#ifndef GL_DEPTH24_STENCIL8 -#define GL_DEPTH24_STENCIL8 0x88F0 -#endif - -RenderQmlEventHandler::RenderQmlEventHandler(Scene2D *node) - : QObject() - , m_node(node) -{ -} - -// Event handler for the RenderQmlToTexture::renderThread -bool RenderQmlEventHandler::event(QEvent *e) -{ - switch (e->type()) { - - case RENDER: { - m_node->render(); - return true; - } - - case INITIALIZE: { - m_node->initializeRender(); - return true; - } - - case QUIT: { - m_node->cleanup(); - return true; - } - - default: - break; - } - return QObject::event(e); -} - -Scene2D::Scene2D() - : m_context(nullptr) - , m_shareContext(nullptr) - , m_renderThread(nullptr) - , m_sharedObject(nullptr) - , m_fbo(0) - , m_rbo(0) - , m_initialized(false) - , m_renderInitialized(false) - , m_renderPolicy(Qt3DRender::Quick::QScene2D::Continuous) -{ - renderThreadClientCount->fetchAndAddAcquire(1); -} - -Scene2D::~Scene2D() -{ - // this gets called from aspect thread. Wait for the render thread then delete it. - // TODO: render thread deletion -// if (m_renderThread) { -// m_renderThread->wait(1000); -// delete m_renderThread; -// } -} - -void Scene2D::setOutput(Qt3DCore::QNodeId outputId) -{ - m_outputId = outputId; -} - -void Scene2D::initializeSharedObject() -{ - if (!m_initialized) { - - renderThread->setObjectName(QStringLiteral("Scene2D::renderThread")); - m_renderThread = renderThread; - m_sharedObject->m_renderThread = m_renderThread; - - // Create event handler for the render thread - m_sharedObject->m_renderObject = new RenderQmlEventHandler(this); - m_sharedObject->m_renderObject->moveToThread(m_sharedObject->m_renderThread); - if (!m_sharedObject->m_renderThread->isRunning()) - m_sharedObject->m_renderThread->start(); - - // Notify main thread we have been initialized - if (m_sharedObject->m_renderManager) - QCoreApplication::postEvent(m_sharedObject->m_renderManager, new QEvent(INITIALIZED)); - - // Initialize render thread - QCoreApplication::postEvent(m_sharedObject->m_renderObject, new QEvent(INITIALIZE)); - - m_initialized = true; - } -} - -void Scene2D::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) -{ - const auto typedChange = qSharedPointerCast>(change); - const auto &data = typedChange->data; - m_renderPolicy = data.renderPolicy; - setSharedObject(data.sharedObject); - setOutput(data.output); -} - -void Scene2D::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) -{ - if (e->type() == Qt3DCore::PropertyUpdated) { - Qt3DCore::QPropertyUpdatedChangePtr propertyChange - = qSharedPointerCast(e); - if (propertyChange->propertyName() == QByteArrayLiteral("renderPolicy")) { - m_renderPolicy = propertyChange->value().value(); - } else if (propertyChange->propertyName() == QByteArrayLiteral("output")) { - Qt3DCore::QNodeId outputId = propertyChange->value().value(); - setOutput(outputId); - } else if (propertyChange->propertyName() == QByteArrayLiteral("sharedObject")) { - const Scene2DSharedObjectPtr sharedObject - = propertyChange->value().value(); - setSharedObject(sharedObject); - } - } - BackendNode::sceneChangeEvent(e); -} - -void Scene2D::setSharedObject(Qt3DRender::Quick::Scene2DSharedObjectPtr sharedObject) -{ - m_sharedObject = sharedObject; - if (!m_initialized) - initializeSharedObject(); -} - -void Scene2D::initializeRender() -{ - if (!m_renderInitialized && m_sharedObject.data() != nullptr) { - m_shareContext = renderer()->shareContext(); - if (!m_shareContext){ - qCDebug(Qt3DRender::Quick::Scene2D) << Q_FUNC_INFO << "Renderer not initialized."; - QCoreApplication::postEvent(m_sharedObject->m_renderObject, new QEvent(INITIALIZE)); - return; - } - m_context = new QOpenGLContext(); -#ifdef Q_OS_MACOS - m_context->setFormat(m_shareContext->format()); -#else - QSurfaceFormat format; - format.setDepthBufferSize(24); - format.setStencilBufferSize(8); - m_context->setFormat(format); -#endif - m_context->setShareContext(m_shareContext); - m_context->create(); - - m_context->makeCurrent(m_sharedObject->m_surface); - m_sharedObject->m_renderControl->initialize(m_context); - m_context->doneCurrent(); - - QCoreApplication::postEvent(m_sharedObject->m_renderManager, new QEvent(PREPARE)); - m_renderInitialized = true; - } -} - -bool Scene2D::updateFbo(QOpenGLTexture *texture) -{ - QOpenGLFunctions *gl = m_context->functions(); - if (m_fbo == 0) { - gl->glGenFramebuffers(1, &m_fbo); - gl->glGenRenderbuffers(1, &m_rbo); - } - // TODO: Add another codepath when GL_DEPTH24_STENCIL8 is not supported - gl->glBindRenderbuffer(GL_RENDERBUFFER, m_rbo); - gl->glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, - m_textureSize.width(), m_textureSize.height()); - gl->glBindRenderbuffer(GL_RENDERBUFFER, 0); - - gl->glBindFramebuffer(GL_FRAMEBUFFER, m_fbo); - gl->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - GL_TEXTURE_2D, texture->textureId(), 0); - gl->glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_rbo); - GLenum status = gl->glCheckFramebufferStatus(GL_FRAMEBUFFER); - gl->glBindFramebuffer(GL_FRAMEBUFFER, 0); - - if (status != GL_FRAMEBUFFER_COMPLETE) - return false; - return true; -} - -void Scene2D::syncRenderControl() -{ - if (m_sharedObject->isSyncRequested()) { - - m_sharedObject->clearSyncRequest(); - - m_sharedObject->m_renderControl->sync(); - - // gui thread can now continue - m_sharedObject->wake(); - } -} - -void Scene2D::render() -{ - if (m_initialized && m_renderInitialized && m_sharedObject.data() != nullptr) { - - QMutexLocker lock(&m_sharedObject->m_mutex); - - QOpenGLTexture *texture = nullptr; - const Qt3DRender::Render::Attachment *attachmentData = nullptr; - QMutex *textureLock = nullptr; - - m_context->makeCurrent(m_sharedObject->m_surface); - - if (resourceAccessor()->accessResource(m_outputId, (void**)&attachmentData, nullptr)) { - if (!resourceAccessor()->accessResource(attachmentData->m_textureUuid, - (void**)&texture, &textureLock)) { - // Need to call sync even if the texture is not in use - syncRenderControl(); - m_context->doneCurrent(); - qCDebug(Qt3DRender::Quick::Scene2D) << Q_FUNC_INFO << "Texture not in use."; - QCoreApplication::postEvent(m_sharedObject->m_renderObject, new QEvent(RENDER)); - return; - } - textureLock->lock(); - const QSize textureSize = QSize(texture->width(), texture->height()); - if (m_attachmentData.m_textureUuid != attachmentData->m_textureUuid - || m_attachmentData.m_point != attachmentData->m_point - || m_attachmentData.m_face != attachmentData->m_face - || m_attachmentData.m_layer != attachmentData->m_layer - || m_attachmentData.m_mipLevel != attachmentData->m_mipLevel - || m_textureSize != textureSize) { - m_textureSize = textureSize; - m_attachmentData = *attachmentData; - if (!updateFbo(texture)) { - // Need to call sync even if the fbo is not usable - syncRenderControl(); - textureLock->unlock(); - m_context->doneCurrent(); - qCWarning(Qt3DRender::Quick::Scene2D) << Q_FUNC_INFO << "Fbo not initialized."; - return; - } - } - } - - if (m_fbo != m_sharedObject->m_quickWindow->renderTargetId()) - m_sharedObject->m_quickWindow->setRenderTarget(m_fbo, m_textureSize); - - // Call disallow rendering while mutex is locked - if (m_renderPolicy == QScene2D::SingleShot) - m_sharedObject->disallowRender(); - - // Sync - if (m_sharedObject->isSyncRequested()) { - - m_sharedObject->clearSyncRequest(); - - m_sharedObject->m_renderControl->sync(); - } - - // Render - m_sharedObject->m_renderControl->render(); - - // Tell main thread we are done so it can begin cleanup if this is final frame - if (m_renderPolicy == QScene2D::SingleShot) - QCoreApplication::postEvent(m_sharedObject->m_renderManager, new QEvent(RENDERED)); - - m_sharedObject->m_quickWindow->resetOpenGLState(); - m_context->functions()->glFlush(); - if (texture->isAutoMipMapGenerationEnabled()) - texture->generateMipMaps(); - textureLock->unlock(); - m_context->doneCurrent(); - - // gui thread can now continue - m_sharedObject->wake(); - } -} - -// this function gets called while the main thread is waiting -void Scene2D::cleanup() -{ - if (m_renderInitialized && m_initialized) { - m_context->makeCurrent(m_sharedObject->m_surface); - m_sharedObject->m_renderControl->invalidate(); - m_context->functions()->glDeleteFramebuffers(1, &m_fbo); - m_context->functions()->glDeleteRenderbuffers(1, &m_rbo); - m_context->doneCurrent(); - m_renderInitialized = false; - } - if (m_initialized) { - delete m_sharedObject->m_renderObject; - m_sharedObject->m_renderObject = nullptr; - delete m_context; - m_context = nullptr; - m_initialized = false; - } - if (m_sharedObject) { - // wake up the main thread - m_sharedObject->wake(); - m_sharedObject = nullptr; - } - - renderThreadClientCount->fetchAndSubAcquire(1); - if (renderThreadClientCount->load() == 0) - renderThread->quit(); -} - -} // namespace Quick -} // namespace Render -} // namespace Qt3DRender - -QT_END_NAMESPACE diff --git a/src/quick3d/quick3drender/scene2d/scene2d.pri b/src/quick3d/quick3drender/scene2d/scene2d.pri deleted file mode 100644 index 4635c43e1..000000000 --- a/src/quick3d/quick3drender/scene2d/scene2d.pri +++ /dev/null @@ -1,10 +0,0 @@ -HEADERS += \ - $$PWD/qscene2d.h \ - $$PWD/qscene2d_p.h \ - $$PWD/scene2d_p.h - -SOURCES += \ - $$PWD/qscene2d.cpp \ - $$PWD/scene2d.cpp - -INCLUDEPATH += $$PWD diff --git a/src/quick3d/quick3drender/scene2d/scene2d_p.h b/src/quick3d/quick3drender/scene2d/scene2d_p.h deleted file mode 100644 index 3a8ccf531..000000000 --- a/src/quick3d/quick3drender/scene2d/scene2d_p.h +++ /dev/null @@ -1,127 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 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$ -** -****************************************************************************/ - -#ifndef QT3DRENDER_RENDER_QUICK_SCENE2D_P_H -#define QT3DRENDER_RENDER_QUICK_SCENE2D_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of other Qt classes. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include -#include - -#include -#include - -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE - -namespace Qt3DRender { - -namespace Render { - -class GraphicsContext; - -namespace Quick { - -class Scene2D; - -class RenderQmlEventHandler : public QObject -{ - Q_OBJECT -public: - RenderQmlEventHandler(Scene2D *node); - bool event(QEvent *e) Q_DECL_OVERRIDE; - -private: - Scene2D *m_node; -}; - -class QT3DQUICKRENDERSHARED_EXPORT Scene2D : public Qt3DRender::Render::BackendNode -{ -public: - Scene2D(); - ~Scene2D(); - - void render(); - void initializeRender(); - void setSharedObject(Qt3DRender::Quick::Scene2DSharedObjectPtr sharedObject); - void cleanup(); - void setOutput(Qt3DCore::QNodeId outputId); - void initializeSharedObject(); - - void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_OVERRIDE; - void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_OVERRIDE; - - bool updateFbo(QOpenGLTexture *texture); - void syncRenderControl(); - - QOpenGLContext *m_context; - QOpenGLContext *m_shareContext; - QThread *m_renderThread; - Qt3DCore::QNodeId m_outputId; - QSharedPointer m_sharedObject; - Qt3DCore::QNodeId m_peerId; - Qt3DRender::Render::Attachment m_attachmentData; - - GLuint m_fbo; - GLuint m_rbo; - QSize m_textureSize; - - bool m_initialized; - bool m_renderInitialized; - Qt3DRender::Quick::QScene2D::RenderPolicy m_renderPolicy; -}; - -} // Quick -} // Render -} // Qt3DRender - -QT_END_NAMESPACE - -#endif // QT3DRENDER_RENDER_QUICK_SCENE2D_P_H diff --git a/src/quick3d/quick3dscene2d/items/items.pri b/src/quick3d/quick3dscene2d/items/items.pri new file mode 100644 index 000000000..7a9a641f8 --- /dev/null +++ b/src/quick3d/quick3dscene2d/items/items.pri @@ -0,0 +1,10 @@ +HEADERS += \ + $$PWD/scene2d_p.h \ + $$PWD/qscene2d_p.h \ + $$PWD/qscene2d.h + +SOURCES += \ + $$PWD/qscene2d.cpp \ + $$PWD/scene2d.cpp + +INCLUDEPATH += $$PWD diff --git a/src/quick3d/quick3dscene2d/items/qscene2d.cpp b/src/quick3d/quick3dscene2d/items/qscene2d.cpp new file mode 100644 index 000000000..fa46cd3d2 --- /dev/null +++ b/src/quick3d/quick3dscene2d/items/qscene2d.cpp @@ -0,0 +1,697 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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 "qscene2d.h" +#include "qscene2d_p.h" +#include "scene2d_p.h" + +#include + +#include + +QT_BEGIN_NAMESPACE + +using namespace Qt3DCore; + +namespace Qt3DRender { + +namespace Quick { + +/*! + \class Qt3DRender::QScene2D + \inmodule Qt3DRender + + \brief This class enables rendering qml into a texture, which then can be + used as a part of 3D scene. + + The component uses QQuickRenderControl to render the given QML source into an + offscreen surface, which is attached to a texture provided by the user. This allows the + component to directly render into the texture without intermediate copy and the user to + freely specify how the texture is used in the 3D scene. + + \since 5.9 +*/ + +/*! + \qmltype Scene2D + \inqmlmodule Qt3D.Render + \since + \ingroup + \instantiates Qt3DRender::QScene2D + \brief Scene2D + */ + +/*! + \enum QScene2D::RenderPolicy + + This enum type describes types of render policies available. + \value Continuous The Scene2D is rendering continuously. This is the default render policy. + \value SingleShot The Scene2D renders to the texture only once after which the resources + allocated for rendering are released. +*/ + +/*! + \qmlproperty RenderTargetOutput Qt3D.Render::Scene2D::output + Holds the RenderTargetOutput, which specifies where the Scene2D is rendering to. + */ + +/*! + \qmlproperty QUrl Qt3D.Render::Scene2D::source + Holds the qml source url. + */ + +/*! + \qmlproperty enumeration Qt3D.Render::Scene2D::renderPolicy + Holds the render policy of this Scene2D. + */ + +/*! + \qmlproperty bool Qt3D.Render::Scene2D::loaded + Holds whether the source has been loaded. + */ + +class RenderControl : public QQuickRenderControl +{ +public: + RenderControl(QWindow *w) : m_window(w) { } + QWindow *renderWindow(QPoint *offset) Q_DECL_OVERRIDE; + +private: + QWindow *m_window; +}; + +QWindow *RenderControl::renderWindow(QPoint *offset) +{ + if (offset) + *offset = QPoint(0, 0); + return m_window; +} + +/*! + \internal + Constructs object shared by the front-end and back-end to synchronize the rendering. + */ +Scene2DSharedObject::Scene2DSharedObject(Scene2DManager *manager) + : m_quit(false) + , m_requestSync(false) + , m_prepared(false) + , m_initialized(false) + , m_renderControl(nullptr) + , m_quickWindow(nullptr) + , m_renderManager(manager) + , m_surface(nullptr) + , m_renderObject(nullptr) + , m_disallowed(false) +{ +} + +Scene2DSharedObject::~Scene2DSharedObject() +{ +} + +void Scene2DSharedObject::cleanup() +{ + delete m_renderControl; + delete m_quickWindow; + delete m_surface; + m_renderControl = nullptr; + m_quickWindow = nullptr; + m_surface = nullptr; + m_initialized = false; +} + +bool Scene2DSharedObject::canRender() const +{ + return m_initialized && m_prepared && !m_disallowed; +} + +bool Scene2DSharedObject::isInitialized() const +{ + return m_initialized; +} + +void Scene2DSharedObject::disallowRender() +{ + m_disallowed = true; +} + +void Scene2DSharedObject::setInitialized() +{ + m_initialized = true; +} + +bool Scene2DSharedObject::isPrepared() const +{ + return m_prepared; +} + +void Scene2DSharedObject::setPrepared() +{ + m_prepared = true; +} + +// not protected, call only from main thread +bool Scene2DSharedObject::isQuit() const +{ + Q_ASSERT(QThread::currentThread() == QCoreApplication::instance()->thread()); + return m_quit; +} + +// not protected, call only from main thread +void Scene2DSharedObject::requestQuit() +{ + Q_ASSERT(QThread::currentThread() == QCoreApplication::instance()->thread()); + m_quit = true; + QCoreApplication::postEvent(m_renderObject, new QEvent(QUIT)); +} + +bool Scene2DSharedObject::isSyncRequested() const +{ + return m_requestSync; +} + +void Scene2DSharedObject::requestRender(bool sync) +{ + m_requestSync = sync; + QCoreApplication::postEvent(m_renderObject, new QEvent(RENDER)); +} + +void Scene2DSharedObject::wait() +{ + m_cond.wait(&m_mutex); +} + +void Scene2DSharedObject::wake() +{ + m_cond.wakeOne(); +} + +void Scene2DSharedObject::clearSyncRequest() +{ + m_requestSync = false; +} + +/*! + \internal + Constructs qml render manager. + */ +Scene2DManager::Scene2DManager(QScene2DPrivate *priv) + : m_priv(priv) + , m_qmlEngine(nullptr) + , m_qmlComponent(nullptr) + , m_rootItem(nullptr) + , m_source(nullptr) + , m_requested(false) + , m_initialized(false) + , m_renderSyncRequested(false) + , m_sharedObject(new Scene2DSharedObject(this)) + , m_renderPolicy(QScene2D::Continuous) + , m_backendInitialized(false) + , m_noSourceMode(false) + , m_item(nullptr) + , m_ownEngine(false) +{ + m_sharedObject->m_surface = new QOffscreenSurface; + m_sharedObject->m_surface->setFormat(QSurfaceFormat::defaultFormat()); + m_sharedObject->m_surface->create(); + + // Create render control + m_sharedObject->m_renderControl = new RenderControl(nullptr); + + // Create window to render the QML with + m_sharedObject->m_quickWindow = new QQuickWindow(m_sharedObject->m_renderControl); + m_sharedObject->m_quickWindow->setClearBeforeRendering(false); + + connect(m_sharedObject->m_renderControl, &QQuickRenderControl::renderRequested, + this, &Scene2DManager::requestRender); + connect(m_sharedObject->m_renderControl, &QQuickRenderControl::sceneChanged, + this, &Scene2DManager::requestRenderSync); +} + +Scene2DManager::~Scene2DManager() +{ + m_sharedObject = nullptr; +} + +void Scene2DManager::requestRender() +{ + // Don't request render until the backend is initialized. + if (m_sharedObject->canRender()) { + if (!m_requested) { + m_requested = true; + QCoreApplication::postEvent(this, new QEvent(RENDER)); + } + } +} + +void Scene2DManager::requestRenderSync() +{ + // Don't request render until the backed is initialized. + if (m_sharedObject->canRender()) { + if (!m_requested) { + m_requested = true; + QCoreApplication::postEvent(this, new QEvent(RENDERSYNC)); + } + } else { + m_renderSyncRequested = true; + } +} + +void Scene2DManager::startIfInitialized() +{ + if (!m_initialized && m_backendInitialized) { + if (m_source.isValid() && !m_noSourceMode) { + // Create a QML engine. + if (!m_qmlEngine) { + m_qmlEngine = new QQmlEngine; + if (!m_qmlEngine->incubationController()) { + m_qmlEngine->setIncubationController(m_sharedObject->m_quickWindow + ->incubationController()); + } + } + + // create component + m_ownEngine = true; + m_qmlComponent = new QQmlComponent(m_qmlEngine, m_source); + if (m_qmlComponent->isLoading()) { + connect(m_qmlComponent, &QQmlComponent::statusChanged, + this, &Scene2DManager::run); + } else { + run(); + } + } else if (m_item != nullptr) { + m_rootItem = m_item; + + // Associate root item with the window. + m_rootItem->setParentItem(m_sharedObject->m_quickWindow->contentItem()); + + // Update window size. + updateSizes(); + + m_initialized = true; + m_sharedObject->setInitialized(); + } + } +} + +void Scene2DManager::stopAndClean() +{ + if (m_sharedObject->isInitialized()) { + QMutexLocker lock(&m_sharedObject->m_mutex); + m_sharedObject->requestQuit(); + m_sharedObject->wait(); + m_sharedObject->cleanup(); + if (m_ownEngine) { + QObject::disconnect(m_connection); + delete m_qmlEngine; + } + delete m_qmlComponent; + m_qmlEngine = nullptr; + m_qmlComponent = nullptr; + } +} + +void Scene2DManager::run() +{ + disconnect(m_qmlComponent, &QQmlComponent::statusChanged, this, &Scene2DManager::run); + + if (m_qmlComponent->isError()) { + QList errorList = m_qmlComponent->errors(); + for (const QQmlError &error: errorList) + qWarning() << error.url() << error.line() << error; + return; + } + + QObject *rootObject = m_qmlComponent->create(); + if (m_qmlComponent->isError()) { + QList errorList = m_qmlComponent->errors(); + for (const QQmlError &error: errorList) + qWarning() << error.url() << error.line() << error; + return; + } + + m_rootItem = qobject_cast(rootObject); + if (!m_rootItem) { + qWarning("QScene2D: Root item is not a QQuickItem."); + delete rootObject; + return; + } + + // The root item is ready. Associate it with the window. + m_rootItem->setParentItem(m_sharedObject->m_quickWindow->contentItem()); + + // Update window size. + updateSizes(); + + m_initialized = true; + m_sharedObject->setInitialized(); + + emit onLoadedChanged(); +} + +void Scene2DManager::updateSizes() +{ + const int width = m_rootItem->width(); + const int height = m_rootItem->height(); + if (width == 0 || height == 0) { + qWarning() << "QScene2D: Root item size not set."; + return; + } + m_sharedObject->m_quickWindow->setGeometry(0, 0, width, height); +} + +void Scene2DManager::setSource(const QUrl &url) +{ + m_source = url; + startIfInitialized(); +} + +void Scene2DManager::setItem(QQuickItem *item) +{ + m_noSourceMode = true; + m_item = item; + startIfInitialized(); +} + +bool Scene2DManager::event(QEvent *e) +{ + switch (e->type()) { + + case RENDER: { + // just render request, don't need to call sync in render thread + QMutexLocker lock(&m_sharedObject->m_mutex); + m_sharedObject->requestRender(false); + m_requested = false; + return true; + } + + case RENDERSYNC: { + // sync and render request, main and render threads must be synchronized + if (!m_sharedObject->isQuit()) + doRenderSync(); + m_requested = false; + return true; + } + + case PREPARE: { + m_sharedObject->m_renderControl->prepareThread(m_sharedObject->m_renderThread); + m_sharedObject->setPrepared(); + + if (m_renderSyncRequested) { + if (!m_requested) { + m_requested = true; + QCoreApplication::postEvent(this, new QEvent(RENDERSYNC)); + } + m_renderSyncRequested = false; + } + return true; + } + + case INITIALIZED: { + // backend is initialized, start the qml + m_backendInitialized = true; + startIfInitialized(); + return true; + } + + case RENDERED: { + // render is done, excellent, now clean anything not needed anymore. + stopAndClean(); + return true; + } + + default: + break; + } + return QObject::event(e); +} + +bool Scene2DManager::forwardEvent(QEvent *event) +{ + switch (event->type()) { + + case QEvent::MouseMove: + case QEvent::MouseButtonDblClick: + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: { + QMouseEvent* me = static_cast(event); + QPointF pos = me->localPos(); + pos = QPointF(pos.x() * m_rootItem->width(), pos.y() * m_rootItem->height()); + QMouseEvent nme = QMouseEvent(me->type(), pos, pos, pos, me->button(), me->buttons(), + me->modifiers(), Qt::MouseEventSynthesizedByApplication); + QCoreApplication::sendEvent(m_sharedObject->m_quickWindow, &nme); + } break; + + case QEvent::KeyPress: + case QEvent::KeyRelease: { + QCoreApplication::sendEvent(m_sharedObject->m_quickWindow, event); + } break; + + default: + break; + } + return false; +} + +void Scene2DManager::doRenderSync() +{ + QMutexLocker lock(&m_sharedObject->m_mutex); + + m_sharedObject->requestRender(true); + m_sharedObject->m_renderControl->polishItems(); + + // begin waiting render thread + m_sharedObject->wait(); + m_requested = false; +} + +void Scene2DManager::cleanup() +{ + stopAndClean(); +} + +void Scene2DManager::setEngine(QQmlEngine *engine) +{ + m_qmlEngine = engine; + m_ownEngine = false; + if (engine) { + m_connection = QObject::connect(engine, &QObject::destroyed, + this, &Scene2DManager::engineDestroyed); + } +} + +void Scene2DManager::engineDestroyed() +{ + QObject::disconnect(m_connection); + m_qmlEngine = nullptr; + m_ownEngine = false; +} + + +QScene2DPrivate::QScene2DPrivate() + : Qt3DCore::QNodePrivate() + , m_renderManager(new Scene2DManager(this)) + , m_output(nullptr) +{ +} + +QScene2DPrivate::~QScene2DPrivate() +{ + m_renderManager->cleanup(); + delete m_renderManager; +} + + +/*! + The constructor creates a new QScene2D instance with the specified \a parent. + */ +QScene2D::QScene2D(Qt3DCore::QNode *parent) + : Qt3DCore::QNode(*new QScene2DPrivate, parent) +{ + Q_D(QScene2D); + connect(d->m_renderManager, &Scene2DManager::onLoadedChanged, + this, &QScene2D::sourceLoaded); +} + +QScene2D::QScene2D(QQmlEngine *engine, Qt3DCore::QNode *parent) + : Qt3DCore::QNode(*new QScene2DPrivate, parent) +{ + Q_D(QScene2D); + connect(d->m_renderManager, &Scene2DManager::onLoadedChanged, + this, &QScene2D::sourceLoaded); + d->m_renderManager->setEngine(engine); +} + +QScene2D::~QScene2D() +{ +} + +bool QScene2D::loaded() const +{ + Q_D(const QScene2D); + return d->m_renderManager->m_initialized; +} + +/*! + \property QScene2D::source + \brief Specifies the url for the qml. + + This property specifies the url to the qml being rendered to the texture. + The source must specify QQuickItem as a root. The item must specify width + and height. The rendered qml is scaled to the texture size. + The property can not be changed after the rendering has been initialized. + */ +QUrl QScene2D::source() const +{ + Q_D(const QScene2D); + return d->m_renderManager->m_source; +} + +void QScene2D::setSource(const QUrl &url) +{ + Q_D(QScene2D); + if (d->m_renderManager->m_initialized) { + qWarning() << "Unable to set source after initialization."; + return; + } + if (d->m_renderManager->m_source != url) { + d->m_renderManager->setSource(url); + emit sourceChanged(url); + } +} + +QQuickItem* QScene2D::item() const +{ + Q_D(const QScene2D); + return d->m_renderManager->m_item; +} + +void QScene2D::setItem(QQuickItem *item) +{ + Q_D(QScene2D); + if (d->m_renderManager->m_initialized) { + qWarning() << "Unable to set item after initialization."; + return; + } + if (d->m_renderManager->m_item != item) { + d->m_renderManager->setItem(item); + emit itemChanged(item); + } +} + +/*! + \property QScene2D::renderPolicy + + Holds the render policy of this Scene2D. + */ +QScene2D::RenderPolicy QScene2D::renderPolicy() const +{ + Q_D(const QScene2D); + return d->m_renderManager->m_renderPolicy; +} + +void QScene2D::setRenderPolicy(QScene2D::RenderPolicy renderPolicy) +{ + Q_D(const QScene2D); + if (d->m_renderManager->m_renderPolicy != renderPolicy) { + d->m_renderManager->m_renderPolicy = renderPolicy; + emit renderPolicyChanged(renderPolicy); + } +} + +/*! + \property QScene2D::output + Holds the QRenderTargetOutput, which specifies where the QScene2D is + rendering to. + */ +Qt3DRender::QRenderTargetOutput *QScene2D::output() const +{ + Q_D(const QScene2D); + return d->m_output; +} + +void QScene2D::setOutput(Qt3DRender::QRenderTargetOutput *output) +{ + Q_D(QScene2D); + if (d->m_output != output) { + if (d->m_output) + d->unregisterDestructionHelper(d->m_output); + d->m_output = output; + if (output) + d->registerDestructionHelper(output, &QScene2D::setOutput, d->m_output); + emit outputChanged(output); + } +} + +Qt3DCore::QNodeCreatedChangeBasePtr QScene2D::createNodeCreationChange() const +{ + auto creationChange = Qt3DCore::QNodeCreatedChangePtr::create(this); + auto &data = creationChange->data; + Q_D(const QScene2D); + data.renderPolicy = d->m_renderManager->m_renderPolicy; + data.sharedObject = d->m_renderManager->m_sharedObject; + data.output = d->m_output ? d->m_output->id() : Qt3DCore::QNodeId(); + return creationChange; +} + +bool QScene2D::event(QEvent *event) +{ + Q_D(QScene2D); + d->m_renderManager->forwardEvent(event); + return true; +} + +/*! + Returns the qml engine used by the QScene2D. + */ +QQmlEngine *QScene2D::engine() const +{ + Q_D(const QScene2D); + return d->m_renderManager->m_qmlEngine; +} + +/*! + \internal + */ +void QScene2D::sourceLoaded() +{ + emit loadedChanged(true); +} + +} // namespace Quick +} // namespace Qt3DRender + +QT_END_NAMESPACE diff --git a/src/quick3d/quick3dscene2d/items/qscene2d.h b/src/quick3d/quick3dscene2d/items/qscene2d.h new file mode 100644 index 000000000..c9bd9bea2 --- /dev/null +++ b/src/quick3d/quick3dscene2d/items/qscene2d.h @@ -0,0 +1,117 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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$ +** +****************************************************************************/ + +#ifndef QT3DRENDER_QUICK3DSCENE2D_QSCENE2D_H +#define QT3DRENDER_QUICK3DSCENE2D_QSCENE2D_H + +#include +#include + +#include +#include + +#include + +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +namespace Quick { + +class QScene2DPrivate; + +class QT3DQUICKSCENE2DSHARED_EXPORT QScene2D : public Qt3DCore::QNode +{ + Q_OBJECT + + Q_PROPERTY(Qt3DRender::QRenderTargetOutput *output READ output WRITE setOutput NOTIFY outputChanged) + Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged) + Q_PROPERTY(QScene2D::RenderPolicy renderPolicy READ renderPolicy WRITE setRenderPolicy NOTIFY renderPolicyChanged) + Q_PROPERTY(bool loaded READ loaded NOTIFY loadedChanged) + Q_PROPERTY(QQuickItem *item READ item WRITE setItem NOTIFY itemChanged) + + Q_CLASSINFO("DefaultProperty", "item") + +public: + + enum RenderPolicy { + Continuous, + SingleShot + }; + Q_ENUM(RenderPolicy) + + explicit QScene2D(Qt3DCore::QNode *parent = nullptr); + QScene2D(QQmlEngine *engine, Qt3DCore::QNode *parent = nullptr); + ~QScene2D(); + + Qt3DRender::QRenderTargetOutput *output() const; + QUrl source() const; + bool loaded() const; + QScene2D::RenderPolicy renderPolicy() const; + QQuickItem *item() const; + QQmlEngine *engine() const; + bool event(QEvent *event) Q_DECL_OVERRIDE; + +public Q_SLOTS: + void setOutput(Qt3DRender::QRenderTargetOutput *output); + void setSource(const QUrl &url); + void setRenderPolicy(QScene2D::RenderPolicy policy); + void setItem(QQuickItem *item); + +Q_SIGNALS: + void outputChanged(Qt3DRender::QRenderTargetOutput *output); + void sourceChanged(const QUrl &url); + void loadedChanged(bool loaded); + void renderPolicyChanged(QScene2D::RenderPolicy policy); + void itemChanged(QQuickItem *item); + +protected: + Q_DECLARE_PRIVATE(QScene2D) + +private: + Qt3DCore::QNodeCreatedChangeBasePtr createNodeCreationChange() const Q_DECL_OVERRIDE; + + void sourceLoaded(); +}; + +} // namespace Quick +} // namespace Qt3DRender + +QT_END_NAMESPACE + +#endif // QT3DRENDER_QUICK3DSCENE2D_QSCENE2D_H diff --git a/src/quick3d/quick3dscene2d/items/qscene2d_p.h b/src/quick3d/quick3dscene2d/items/qscene2d_p.h new file mode 100644 index 000000000..1aecbedd7 --- /dev/null +++ b/src/quick3d/quick3dscene2d/items/qscene2d_p.h @@ -0,0 +1,219 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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$ +** +****************************************************************************/ + +#ifndef QT3DRENDER_QUICK3DSCENE2D_QSCENE2D_P_H +#define QT3DRENDER_QUICK3DSCENE2D_QSCENE2D_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +namespace Quick { + +class QScene2D; +class Scene2DManager; + +// render thread -> render thread +static const QEvent::Type INITIALIZE = QEvent::Type(QEvent::User + 1); + +// main thread -> main thread, render thread +static const QEvent::Type RENDER = QEvent::Type(QEvent::User + 2); + +// main thread -> main thread +static const QEvent::Type RENDERSYNC = QEvent::Type(QEvent::User + 3); + +// render thread -> main thread +static const QEvent::Type PREPARE = QEvent::Type(QEvent::User + 4); +static const QEvent::Type INITIALIZED = QEvent::Type(QEvent::User + 5); +static const QEvent::Type RENDERED = QEvent::Type(QEvent::User + 6); + +// main thread -> render thread +static const QEvent::Type QUIT = QEvent::Type(QEvent::User + 7); + +class Q_AUTOTEST_EXPORT Scene2DSharedObject +{ +public: + Scene2DSharedObject(Scene2DManager *manager); + ~Scene2DSharedObject(); + + QQuickRenderControl *m_renderControl; + QQuickWindow *m_quickWindow; + Scene2DManager *m_renderManager; + QOffscreenSurface *m_surface; + + QThread *m_renderThread; + QObject *m_renderObject; + + QWaitCondition m_cond; + QMutex m_mutex; + + bool isInitialized() const; + void setInitialized(); + + void requestQuit(); + bool isQuit() const; + + void requestRender(bool sync); + + bool isSyncRequested() const; + void clearSyncRequest(); + + void wait(); + void wake(); + + bool isPrepared() const; + void setPrepared(); + + void disallowRender(); + bool canRender() const; + + void cleanup(); + +private: + + bool m_disallowed; + bool m_quit; + bool m_requestSync; + bool m_requestRender; + bool m_prepared; + bool m_initialized; +}; + +typedef QSharedPointer Scene2DSharedObjectPtr; + +class Q_AUTOTEST_EXPORT QScene2DPrivate : public Qt3DCore::QNodePrivate +{ +public: + Q_DECLARE_PUBLIC(QScene2D) + + QScene2DPrivate(); + ~QScene2DPrivate(); + + Scene2DManager *m_renderManager; + QMetaObject::Connection m_textureDestroyedConnection; + Qt3DRender::QRenderTargetOutput *m_output; +}; + +struct QScene2DData +{ + QScene2D::RenderPolicy renderPolicy; + Scene2DSharedObjectPtr sharedObject; + Qt3DCore::QNodeId output; +}; + +class Scene2DManager : public QObject +{ + Q_OBJECT +public: + Scene2DManager(QScene2DPrivate *priv); + ~Scene2DManager(); + + QQmlEngine *m_qmlEngine; + QQmlComponent *m_qmlComponent; + QQuickItem *m_rootItem; + QQuickItem *m_item; + + QScene2DPrivate *m_priv; + QSharedPointer m_sharedObject; + + QUrl m_source; + Qt3DCore::QNodeId m_id; + QMetaObject::Connection m_connection; + QScene2D::RenderPolicy m_renderPolicy; + + bool m_requested; + bool m_initialized; + bool m_renderSyncRequested; + bool m_backendInitialized; + bool m_noSourceMode; + bool m_ownEngine; + + void requestRender(); + void requestRenderSync(); + void doRenderSync(); + void startIfInitialized(); + void stopAndClean(); + void run(); + void updateSizes(); + + void setSource(const QUrl &url); + void setItem(QQuickItem *item); + + bool event(QEvent *e) Q_DECL_OVERRIDE; + bool forwardEvent(QEvent *event); + + Q_SIGNAL void onLoadedChanged(); + + void cleanup(); + void setEngine(QQmlEngine *engine); + void engineDestroyed(); +}; + +} // namespace Quick +} // namespace Qt3DRender + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(Qt3DRender::Quick::Scene2DSharedObjectPtr) + +#endif // QT3DRENDER_QUICK3DSCENE2D_QSCENE2D_P_H diff --git a/src/quick3d/quick3dscene2d/items/scene2d.cpp b/src/quick3d/quick3dscene2d/items/scene2d.cpp new file mode 100644 index 000000000..ef677bab8 --- /dev/null +++ b/src/quick3d/quick3dscene2d/items/scene2d.cpp @@ -0,0 +1,372 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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 +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +#ifndef GL_DEPTH24_STENCIL8 +#define GL_DEPTH24_STENCIL8 0x88F0 +#endif + +using namespace Qt3DRender::Quick; + +namespace Qt3DRender { + +namespace Render { + +namespace Quick { + +Q_GLOBAL_STATIC(QThread, renderThread) +Q_GLOBAL_STATIC(QAtomicInt, renderThreadClientCount) + +#ifndef GL_DEPTH24_STENCIL8 +#define GL_DEPTH24_STENCIL8 0x88F0 +#endif + +RenderQmlEventHandler::RenderQmlEventHandler(Scene2D *node) + : QObject() + , m_node(node) +{ +} + +// Event handler for the RenderQmlToTexture::renderThread +bool RenderQmlEventHandler::event(QEvent *e) +{ + switch (e->type()) { + + case RENDER: { + m_node->render(); + return true; + } + + case INITIALIZE: { + m_node->initializeRender(); + return true; + } + + case QUIT: { + m_node->cleanup(); + return true; + } + + default: + break; + } + return QObject::event(e); +} + +Scene2D::Scene2D() + : m_context(nullptr) + , m_shareContext(nullptr) + , m_renderThread(nullptr) + , m_sharedObject(nullptr) + , m_fbo(0) + , m_rbo(0) + , m_initialized(false) + , m_renderInitialized(false) + , m_renderPolicy(Qt3DRender::Quick::QScene2D::Continuous) +{ + renderThreadClientCount->fetchAndAddAcquire(1); +} + +Scene2D::~Scene2D() +{ + // this gets called from aspect thread. Wait for the render thread then delete it. + // TODO: render thread deletion +// if (m_renderThread) { +// m_renderThread->wait(1000); +// delete m_renderThread; +// } +} + +void Scene2D::setOutput(Qt3DCore::QNodeId outputId) +{ + m_outputId = outputId; +} + +void Scene2D::initializeSharedObject() +{ + if (!m_initialized) { + + renderThread->setObjectName(QStringLiteral("Scene2D::renderThread")); + m_renderThread = renderThread; + m_sharedObject->m_renderThread = m_renderThread; + + // Create event handler for the render thread + m_sharedObject->m_renderObject = new RenderQmlEventHandler(this); + m_sharedObject->m_renderObject->moveToThread(m_sharedObject->m_renderThread); + if (!m_sharedObject->m_renderThread->isRunning()) + m_sharedObject->m_renderThread->start(); + + // Notify main thread we have been initialized + if (m_sharedObject->m_renderManager) + QCoreApplication::postEvent(m_sharedObject->m_renderManager, new QEvent(INITIALIZED)); + + // Initialize render thread + QCoreApplication::postEvent(m_sharedObject->m_renderObject, new QEvent(INITIALIZE)); + + m_initialized = true; + } +} + +void Scene2D::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) +{ + const auto typedChange = qSharedPointerCast>(change); + const auto &data = typedChange->data; + m_renderPolicy = data.renderPolicy; + setSharedObject(data.sharedObject); + setOutput(data.output); +} + +void Scene2D::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) +{ + if (e->type() == Qt3DCore::PropertyUpdated) { + Qt3DCore::QPropertyUpdatedChangePtr propertyChange + = qSharedPointerCast(e); + if (propertyChange->propertyName() == QByteArrayLiteral("renderPolicy")) { + m_renderPolicy = propertyChange->value().value(); + } else if (propertyChange->propertyName() == QByteArrayLiteral("output")) { + Qt3DCore::QNodeId outputId = propertyChange->value().value(); + setOutput(outputId); + } else if (propertyChange->propertyName() == QByteArrayLiteral("sharedObject")) { + const Scene2DSharedObjectPtr sharedObject + = propertyChange->value().value(); + setSharedObject(sharedObject); + } + } + BackendNode::sceneChangeEvent(e); +} + +void Scene2D::setSharedObject(Qt3DRender::Quick::Scene2DSharedObjectPtr sharedObject) +{ + m_sharedObject = sharedObject; + if (!m_initialized) + initializeSharedObject(); +} + +void Scene2D::initializeRender() +{ + if (!m_renderInitialized && m_sharedObject.data() != nullptr) { + m_shareContext = renderer()->shareContext(); + if (!m_shareContext){ + qCDebug(Qt3DRender::Quick::Scene2D) << Q_FUNC_INFO << "Renderer not initialized."; + QCoreApplication::postEvent(m_sharedObject->m_renderObject, new QEvent(INITIALIZE)); + return; + } + m_context = new QOpenGLContext(); +#ifdef Q_OS_MACOS + m_context->setFormat(m_shareContext->format()); +#else + QSurfaceFormat format; + format.setDepthBufferSize(24); + format.setStencilBufferSize(8); + m_context->setFormat(format); +#endif + m_context->setShareContext(m_shareContext); + m_context->create(); + + m_context->makeCurrent(m_sharedObject->m_surface); + m_sharedObject->m_renderControl->initialize(m_context); + m_context->doneCurrent(); + + QCoreApplication::postEvent(m_sharedObject->m_renderManager, new QEvent(PREPARE)); + m_renderInitialized = true; + } +} + +bool Scene2D::updateFbo(QOpenGLTexture *texture) +{ + QOpenGLFunctions *gl = m_context->functions(); + if (m_fbo == 0) { + gl->glGenFramebuffers(1, &m_fbo); + gl->glGenRenderbuffers(1, &m_rbo); + } + // TODO: Add another codepath when GL_DEPTH24_STENCIL8 is not supported + gl->glBindRenderbuffer(GL_RENDERBUFFER, m_rbo); + gl->glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, + m_textureSize.width(), m_textureSize.height()); + gl->glBindRenderbuffer(GL_RENDERBUFFER, 0); + + gl->glBindFramebuffer(GL_FRAMEBUFFER, m_fbo); + gl->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, texture->textureId(), 0); + gl->glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_rbo); + GLenum status = gl->glCheckFramebufferStatus(GL_FRAMEBUFFER); + gl->glBindFramebuffer(GL_FRAMEBUFFER, 0); + + if (status != GL_FRAMEBUFFER_COMPLETE) + return false; + return true; +} + +void Scene2D::syncRenderControl() +{ + if (m_sharedObject->isSyncRequested()) { + + m_sharedObject->clearSyncRequest(); + + m_sharedObject->m_renderControl->sync(); + + // gui thread can now continue + m_sharedObject->wake(); + } +} + +void Scene2D::render() +{ + if (m_initialized && m_renderInitialized && m_sharedObject.data() != nullptr) { + + QMutexLocker lock(&m_sharedObject->m_mutex); + + QOpenGLTexture *texture = nullptr; + const Qt3DRender::Render::Attachment *attachmentData = nullptr; + QMutex *textureLock = nullptr; + + m_context->makeCurrent(m_sharedObject->m_surface); + + if (resourceAccessor()->accessResource(m_outputId, (void**)&attachmentData, nullptr)) { + if (!resourceAccessor()->accessResource(attachmentData->m_textureUuid, + (void**)&texture, &textureLock)) { + // Need to call sync even if the texture is not in use + syncRenderControl(); + m_context->doneCurrent(); + qCDebug(Qt3DRender::Quick::Scene2D) << Q_FUNC_INFO << "Texture not in use."; + QCoreApplication::postEvent(m_sharedObject->m_renderObject, new QEvent(RENDER)); + return; + } + textureLock->lock(); + const QSize textureSize = QSize(texture->width(), texture->height()); + if (m_attachmentData.m_textureUuid != attachmentData->m_textureUuid + || m_attachmentData.m_point != attachmentData->m_point + || m_attachmentData.m_face != attachmentData->m_face + || m_attachmentData.m_layer != attachmentData->m_layer + || m_attachmentData.m_mipLevel != attachmentData->m_mipLevel + || m_textureSize != textureSize) { + m_textureSize = textureSize; + m_attachmentData = *attachmentData; + if (!updateFbo(texture)) { + // Need to call sync even if the fbo is not usable + syncRenderControl(); + textureLock->unlock(); + m_context->doneCurrent(); + qCWarning(Qt3DRender::Quick::Scene2D) << Q_FUNC_INFO << "Fbo not initialized."; + return; + } + } + } + + if (m_fbo != m_sharedObject->m_quickWindow->renderTargetId()) + m_sharedObject->m_quickWindow->setRenderTarget(m_fbo, m_textureSize); + + // Call disallow rendering while mutex is locked + if (m_renderPolicy == QScene2D::SingleShot) + m_sharedObject->disallowRender(); + + // Sync + if (m_sharedObject->isSyncRequested()) { + + m_sharedObject->clearSyncRequest(); + + m_sharedObject->m_renderControl->sync(); + } + + // Render + m_sharedObject->m_renderControl->render(); + + // Tell main thread we are done so it can begin cleanup if this is final frame + if (m_renderPolicy == QScene2D::SingleShot) + QCoreApplication::postEvent(m_sharedObject->m_renderManager, new QEvent(RENDERED)); + + m_sharedObject->m_quickWindow->resetOpenGLState(); + m_context->functions()->glFlush(); + if (texture->isAutoMipMapGenerationEnabled()) + texture->generateMipMaps(); + textureLock->unlock(); + m_context->doneCurrent(); + + // gui thread can now continue + m_sharedObject->wake(); + } +} + +// this function gets called while the main thread is waiting +void Scene2D::cleanup() +{ + if (m_renderInitialized && m_initialized) { + m_context->makeCurrent(m_sharedObject->m_surface); + m_sharedObject->m_renderControl->invalidate(); + m_context->functions()->glDeleteFramebuffers(1, &m_fbo); + m_context->functions()->glDeleteRenderbuffers(1, &m_rbo); + m_context->doneCurrent(); + m_renderInitialized = false; + } + if (m_initialized) { + delete m_sharedObject->m_renderObject; + m_sharedObject->m_renderObject = nullptr; + delete m_context; + m_context = nullptr; + m_initialized = false; + } + if (m_sharedObject) { + // wake up the main thread + m_sharedObject->wake(); + m_sharedObject = nullptr; + } + + renderThreadClientCount->fetchAndSubAcquire(1); + if (renderThreadClientCount->load() == 0) + renderThread->quit(); +} + +} // namespace Quick +} // namespace Render +} // namespace Qt3DRender + +QT_END_NAMESPACE diff --git a/src/quick3d/quick3dscene2d/items/scene2d.pri b/src/quick3d/quick3dscene2d/items/scene2d.pri new file mode 100644 index 000000000..4635c43e1 --- /dev/null +++ b/src/quick3d/quick3dscene2d/items/scene2d.pri @@ -0,0 +1,10 @@ +HEADERS += \ + $$PWD/qscene2d.h \ + $$PWD/qscene2d_p.h \ + $$PWD/scene2d_p.h + +SOURCES += \ + $$PWD/qscene2d.cpp \ + $$PWD/scene2d.cpp + +INCLUDEPATH += $$PWD diff --git a/src/quick3d/quick3dscene2d/items/scene2d_p.h b/src/quick3d/quick3dscene2d/items/scene2d_p.h new file mode 100644 index 000000000..db32264c0 --- /dev/null +++ b/src/quick3d/quick3dscene2d/items/scene2d_p.h @@ -0,0 +1,127 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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$ +** +****************************************************************************/ + +#ifndef QT3DRENDER_RENDER_QUICK3DSCENE2D_SCENE2D_P_H +#define QT3DRENDER_RENDER_QUICK3DSCENE2D_SCENE2D_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include + +#include +#include + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +namespace Render { + +class GraphicsContext; + +namespace Quick { + +class Scene2D; + +class RenderQmlEventHandler : public QObject +{ + Q_OBJECT +public: + RenderQmlEventHandler(Scene2D *node); + bool event(QEvent *e) Q_DECL_OVERRIDE; + +private: + Scene2D *m_node; +}; + +class QT3DQUICKSCENE2DSHARED_EXPORT Scene2D : public Qt3DRender::Render::BackendNode +{ +public: + Scene2D(); + ~Scene2D(); + + void render(); + void initializeRender(); + void setSharedObject(Qt3DRender::Quick::Scene2DSharedObjectPtr sharedObject); + void cleanup(); + void setOutput(Qt3DCore::QNodeId outputId); + void initializeSharedObject(); + + void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_OVERRIDE; + void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_OVERRIDE; + + bool updateFbo(QOpenGLTexture *texture); + void syncRenderControl(); + + QOpenGLContext *m_context; + QOpenGLContext *m_shareContext; + QThread *m_renderThread; + Qt3DCore::QNodeId m_outputId; + QSharedPointer m_sharedObject; + Qt3DCore::QNodeId m_peerId; + Qt3DRender::Render::Attachment m_attachmentData; + + GLuint m_fbo; + GLuint m_rbo; + QSize m_textureSize; + + bool m_initialized; + bool m_renderInitialized; + Qt3DRender::Quick::QScene2D::RenderPolicy m_renderPolicy; +}; + +} // Quick +} // Render +} // Qt3DRender + +QT_END_NAMESPACE + +#endif // QT3DRENDER_RENDER_QUICK3DSCENE2D_SCENE2D_P_H diff --git a/src/quick3d/quick3dscene2d/qt3dquickscene2d_global.cpp b/src/quick3d/quick3dscene2d/qt3dquickscene2d_global.cpp new file mode 100644 index 000000000..da5698d52 --- /dev/null +++ b/src/quick3d/quick3dscene2d/qt3dquickscene2d_global.cpp @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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 "qt3dquickscene2d_global_p.h" +#include "qt3dquickscene2dnodefactory_p.h" + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { +namespace Quick { + +void Quick3DScene2D_initialize() +{ + Qt3DCore::QAbstractNodeFactory::registerNodeFactory(QuickScene2DNodeFactory::instance()); +} + +void Quick3DScene2D_registerType(const char *className, const char *quickName, int major, int minor) +{ + QuickScene2DNodeFactory::instance()->registerType(className, quickName, major, minor); +} + +} // namespace Quick +} // namespace Qt3DRender + +QT_END_NAMESPACE diff --git a/src/quick3d/quick3dscene2d/qt3dquickscene2d_global.h b/src/quick3d/quick3dscene2d/qt3dquickscene2d_global.h new file mode 100644 index 000000000..509a62024 --- /dev/null +++ b/src/quick3d/quick3dscene2d/qt3dquickscene2d_global.h @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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$ +** +****************************************************************************/ + +#ifndef QT3DQUICKSCENE2D_GLOBAL_H +#define QT3DQUICKSCENE2D_GLOBAL_H + +#include + +QT_BEGIN_NAMESPACE + +#if defined(QT_SHARED) || !defined(QT_STATIC) +# if defined(QT_BUILD_3DQUICKSCENE2D_LIB) +# define QT3DQUICKSCENE2DSHARED_EXPORT Q_DECL_EXPORT +# else +# define QT3DQUICKSCENE2DSHARED_EXPORT Q_DECL_IMPORT +# endif +#else +# define QT3DQUICKSCENE2DSHARED_EXPORT +#endif + +QT_END_NAMESPACE + +#endif // QT3DQUICKSCENE2D_GLOBAL_H diff --git a/src/quick3d/quick3dscene2d/qt3dquickscene2d_global_p.h b/src/quick3d/quick3dscene2d/qt3dquickscene2d_global_p.h new file mode 100644 index 000000000..e115e3d5e --- /dev/null +++ b/src/quick3d/quick3dscene2d/qt3dquickscene2d_global_p.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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$ +** +****************************************************************************/ + +#ifndef QT3DQUICKSCENE2D_GLOBAL_P_H +#define QT3DQUICKSCENE2D_GLOBAL_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include + +#define QT3DQUICKSCENE2DSHARED_PRIVATE_EXPORT QT3DQUICKSCENE2DSHARED_EXPORT + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +namespace Quick { + +QT3DQUICKSCENE2DSHARED_PRIVATE_EXPORT void Quick3DScene2D_initialize(); +QT3DQUICKSCENE2DSHARED_PRIVATE_EXPORT void Quick3DScene2D_registerType(const char *className, + const char *quickName, + int major, int minor); + +template void registerExtendedType(const char *className, const char *quickName, + const char *uri, int major, int minor, + const char *name) +{ + qmlRegisterExtendedType(uri, major, minor, name); + Quick3DScene2D_registerType(className, quickName, major, minor); +} + +template void registerType(const char *className, const char *quickName, + const char *uri, int major, int minor, const char *name) +{ + qmlRegisterType(uri, major, minor, name); + Quick3DScene2D_registerType(className, quickName, major, minor); +} + +} // Quick + +} // Qt3D + +QT_END_NAMESPACE + +#endif // QT3DQUICKSCENE2D_GLOBAL_P_H diff --git a/src/quick3d/quick3dscene2d/qt3dquickscene2d_logging.cpp b/src/quick3d/quick3dscene2d/qt3dquickscene2d_logging.cpp new file mode 100644 index 000000000..c9af316de --- /dev/null +++ b/src/quick3d/quick3dscene2d/qt3dquickscene2d_logging.cpp @@ -0,0 +1,49 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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 "qt3dquickscene2d_logging_p.h" + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { +namespace Quick { + +Q_LOGGING_CATEGORY(Scene2D, "Qt3D.Scene2D") + +} // Quick +} // Qt3DRender + +QT_END_NAMESPACE diff --git a/src/quick3d/quick3dscene2d/qt3dquickscene2d_logging_p.h b/src/quick3d/quick3dscene2d/qt3dquickscene2d_logging_p.h new file mode 100644 index 000000000..3120e9919 --- /dev/null +++ b/src/quick3d/quick3dscene2d/qt3dquickscene2d_logging_p.h @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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$ +** +****************************************************************************/ + +#ifndef QT3DQUICKSCENE2D_LOGGING_P_H +#define QT3DQUICKSCENE2D_LOGGING_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { +namespace Quick { + +Q_DECLARE_LOGGING_CATEGORY(Scene2D) + +} // Quick +} // Qt3DRender + +QT_END_NAMESPACE + +#endif // QT3DQUICKRENDER_LOGGING_P_H diff --git a/src/quick3d/quick3dscene2d/qt3dquickscene2dnodefactory.cpp b/src/quick3d/quick3dscene2d/qt3dquickscene2dnodefactory.cpp new file mode 100644 index 000000000..a796e74c0 --- /dev/null +++ b/src/quick3d/quick3dscene2d/qt3dquickscene2dnodefactory.cpp @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd and/or its subsidiary(-ies). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qt3dquickscene2dnodefactory_p.h" +#include + +#include + +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +Q_GLOBAL_STATIC(QuickScene2DNodeFactory, quick_scene2d_node_factory) + +static void initScene2dPlugin() +{ + Qt3DRender::QRenderAspectPrivate::configurePlugin("scene2d"); +} + +Q_COREAPP_STARTUP_FUNCTION(initScene2dPlugin) + +QuickScene2DNodeFactory *QuickScene2DNodeFactory::instance() +{ + return quick_scene2d_node_factory(); +} + +void QuickScene2DNodeFactory::registerType(const char *className, const char *quickName, + int major, int minor) +{ + m_types.insert(className, Type(quickName, major, minor)); +} + +Qt3DCore::QNode *QuickScene2DNodeFactory::createNode(const char *type) +{ + if (!m_types.contains(type)) + return nullptr; + + Type &typeInfo(m_types[type]); + + if (!typeInfo.resolved) { + typeInfo.resolved = true; + typeInfo.t = QQmlMetaType::qmlType(QString::fromLatin1(typeInfo.quickName), + typeInfo.version.first, typeInfo.version.second); + } + + return typeInfo.t ? qobject_cast(typeInfo.t->create()) : nullptr; +} + +} // namespace Qt3DRender + +QT_END_NAMESPACE diff --git a/src/quick3d/quick3dscene2d/qt3dquickscene2dnodefactory_p.h b/src/quick3d/quick3dscene2d/qt3dquickscene2dnodefactory_p.h new file mode 100644 index 000000000..b5eb82aa1 --- /dev/null +++ b/src/quick3d/quick3dscene2d/qt3dquickscene2dnodefactory_p.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd and/or its subsidiary(-ies). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QUICKSCENENODEFACTORY_H +#define QUICKSCENENODEFACTORY_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include + +QT_BEGIN_NAMESPACE + +class QQmlType; + +namespace Qt3DRender { + +class QuickScene2DNodeFactory : public Qt3DCore::QAbstractNodeFactory +{ +public: + Qt3DCore::QNode *createNode(const char *type) Q_DECL_OVERRIDE; + + void registerType(const char *className, const char *quickName, int major, int minor); + + static QuickScene2DNodeFactory *instance(); + +private: + struct Type { + Type() : t(nullptr), resolved(false) { } + Type(const char *quickName, int major, int minor) + : quickName(quickName), version(major, minor), t(nullptr), resolved(false) { } + QByteArray quickName; + QPair version; + QQmlType *t; + bool resolved; + }; + QHash m_types; +}; + +} // namespace Qt3DRender + +QT_END_NAMESPACE + +#endif // QUICKRENDERERNODEFACTORY_H diff --git a/src/quick3d/quick3dscene2d/quick3dscene2d.pro b/src/quick3d/quick3dscene2d/quick3dscene2d.pro new file mode 100644 index 000000000..7d2d59392 --- /dev/null +++ b/src/quick3d/quick3dscene2d/quick3dscene2d.pro @@ -0,0 +1,31 @@ +TARGET = Qt3DQuickScene2D +MODULE = 3dquickscene2d + +QT += core core-private qml qml-private 3dcore 3drender 3dquick 3dquick-private 3dcore-private 3drender-private +CONFIG -= precompile_header + +# Qt3D is free of Q_FOREACH - make sure it stays that way: +DEFINES += QT_NO_FOREACH + +gcov { + QMAKE_CXXFLAGS += -fprofile-arcs -ftest-coverage + QMAKE_LFLAGS += -fprofile-arcs -ftest-coverage +} + +SOURCES += \ + qt3dquickscene2d_global.cpp \ + qt3dquickscene2dnodefactory.cpp \ + qt3dquickscene2d_logging.cpp + +HEADERS += \ + qt3dquickscene2dnodefactory_p.h \ + qt3dquickscene2d_global_p.h \ + qt3dquickscene2d_global.h \ + qt3dquickscene2d_logging_p.h + +# otherwise mingw headers do not declare common functions like ::strcasecmp +win32-g++*:QMAKE_CXXFLAGS_CXX11 = -std=gnu++0x + +include(./items/items.pri) + +load(qt_module) diff --git a/src/render/frontend/qrenderaspect.cpp b/src/render/frontend/qrenderaspect.cpp index a1a65989f..73030138f 100644 --- a/src/render/frontend/qrenderaspect.cpp +++ b/src/render/frontend/qrenderaspect.cpp @@ -172,8 +172,8 @@ QRenderAspectPrivate::QRenderAspectPrivate(QRenderAspect::RenderType type) , m_renderType(type) , m_offscreenHelper(nullptr) { + m_instances.append(this); loadSceneParsers(); - loadRenderPlugins(); } /*! \internal */ @@ -185,6 +185,7 @@ QRenderAspectPrivate::~QRenderAspectPrivate() if (m_renderer != nullptr) qWarning() << Q_FUNC_INFO << "The renderer should have been deleted when reaching this point (this warning may be normal when running tests)"; delete m_nodeManagers; + m_instances.removeAll(this); } /*! \internal */ @@ -257,8 +258,8 @@ void QRenderAspectPrivate::registerBackendTypes() q->registerBackendType(QSharedPointer >::create(m_renderer)); // Plugins - for (Render::QRenderPlugin *plugin : qAsConst(m_renderPlugins)) - plugin->registerBackendTypes(q, m_renderer); + for (QString plugin : m_pluginConfig) + loadRenderPlugin(plugin); } /*! \internal */ @@ -570,13 +571,36 @@ void QRenderAspectPrivate::loadSceneParsers() } } -void QRenderAspectPrivate::loadRenderPlugins() +void QRenderAspectPrivate::loadRenderPlugin(const QString &pluginName) { + Q_Q(QRenderAspect); const QStringList keys = Render::QRenderPluginFactory::keys(); - for (const QString &key : keys) { - Render::QRenderPlugin *plugin = Render::QRenderPluginFactory::create(key, QStringList()); - if (plugin != nullptr) + if (!keys.contains(pluginName)) + return; + + if (m_pluginConfig.contains(pluginName) && !m_loadedPlugins.contains(pluginName)) { + Render::QRenderPlugin *plugin + = Render::QRenderPluginFactory::create(pluginName, QStringList()); + if (plugin != nullptr) { + m_loadedPlugins.append(pluginName); m_renderPlugins.append(plugin); + plugin->registerBackendTypes(q, m_renderer); + } + } +} + +QVector QRenderAspectPrivate::m_pluginConfig; +QMutex QRenderAspectPrivate::m_pluginLock; +QVector QRenderAspectPrivate::m_instances; + +void QRenderAspectPrivate::configurePlugin(const QString &plugin) +{ + QMutexLocker lock(&m_pluginLock); + if (!m_pluginConfig.contains(plugin)) { + m_pluginConfig.append(plugin); + + for (QRenderAspectPrivate *instance : m_instances) + instance->loadRenderPlugin(plugin); } } diff --git a/src/render/frontend/qrenderaspect_p.h b/src/render/frontend/qrenderaspect_p.h index 1fa0b26df..4f9983d32 100644 --- a/src/render/frontend/qrenderaspect_p.h +++ b/src/render/frontend/qrenderaspect_p.h @@ -55,6 +55,8 @@ #include #include +#include + QT_BEGIN_NAMESPACE class QSurface; @@ -84,7 +86,7 @@ public: void registerBackendTypes(); void unregisterBackendTypes(); void loadSceneParsers(); - void loadRenderPlugins(); + void loadRenderPlugin(const QString &pluginName); void renderInitialize(QOpenGLContext *context); void renderSynchronous(); void renderShutdown(); @@ -96,9 +98,15 @@ public: bool m_initialized; QList m_sceneImporter; + QVector m_loadedPlugins; QVector m_renderPlugins; QRenderAspect::RenderType m_renderType; Render::OffscreenSurfaceHelper *m_offscreenHelper; + + static QMutex m_pluginLock; + static QVector m_pluginConfig; + static QVector m_instances; + static void configurePlugin(const QString &plugin); }; } diff --git a/src/src.pro b/src/src.pro index a9b1a38f9..86a885e51 100644 --- a/src/src.pro +++ b/src/src.pro @@ -44,6 +44,10 @@ src_quick3d_extras.subdir = $$PWD/quick3d/quick3dextras src_quick3d_extras.target = sub-quick3d-extras src_quick3d_extras.depends = src_render src_logic src_input src_extras src_quick3d_core +src_quick3d_scene2d.subdir = $$PWD/quick3d/quick3dscene2d +src_quick3d_scene2d.target = sub-quick3d-scene2d +src_quick3d_scene2d.depends = src_render src_logic src_input src_quick3d_core + # Quick3D imports src_quick3d_core_imports.file = $$PWD/quick3d/imports/core/importscore.pro src_quick3d_core_imports.target = sub-quick3d-imports-core @@ -73,6 +77,10 @@ src_quick3d_imports_extras.file = $$PWD/quick3d/imports/extras/importsextras.pro src_quick3d_imports_extras.target = sub-quick3d-imports-extras src_quick3d_imports_extras.depends = src_extras src_quick3d_extras +src_quick3d_imports_scene2d.file = $$PWD/quick3d/imports/scene2d/importsscene2d.pro +src_quick3d_imports_scene2d.target = sub-quick3d-imports-scene2d +src_quick3d_imports_scene2d.depends = src_quick3d_scene2d + # Qt3D Scene Parser plugins src_plugins_sceneparsers.file = $$PWD/plugins/sceneparsers/sceneparsers.pro src_plugins_sceneparsers.target = sub-plugins-sceneparsers @@ -86,7 +94,7 @@ src_plugins_geometryloaders.depends = src_render src_extras # Qt3D Render plugins src_plugins_render.file = $$PWD/plugins/renderplugins/renderplugins.pro src_plugins_render.target = sub-plugins-render -src_plugins_render.depends = src_render src_extras src_quick3d_render +src_plugins_render.depends = src_render src_extras src_quick3d_render src_quick3d_scene2d SUBDIRS += \ src_core \ @@ -110,4 +118,6 @@ SUBDIRS += \ src_plugins_sceneparsers \ src_plugins_geometryloaders \ src_plugins_render \ + src_quick3d_scene2d \ + src_quick3d_imports_scene2d \ doc diff --git a/sync.profile b/sync.profile index 27b98417e..5382d7e88 100644 --- a/sync.profile +++ b/sync.profile @@ -10,6 +10,7 @@ "Qt3DLogic" => "$basedir/src/logic", "Qt3DExtras" => "$basedir/src/extras", "Qt3DQuickExtras" => "$basedir/src/quick3d/quick3dextras", + "Qt3DQuickScene2D" => "$basedir/src/quick3d/quick3dscene2d", ); %moduleheaders = ( # restrict the module headers to those found in relative path ); diff --git a/tests/auto/render/qscene2d/qscene2d.pro b/tests/auto/render/qscene2d/qscene2d.pro index b7458d1c2..b1d4d45a9 100644 --- a/tests/auto/render/qscene2d/qscene2d.pro +++ b/tests/auto/render/qscene2d/qscene2d.pro @@ -2,7 +2,7 @@ TEMPLATE = app TARGET = qscene2d -QT += 3dcore 3dcore-private 3drender 3drender-private testlib 3dquickrender 3dquickrender-private +QT += 3dcore 3dcore-private 3drender 3drender-private testlib 3dquickscene2d 3dquickscene2d-private CONFIG += testcase diff --git a/tests/auto/render/qscene2d/tst_qscene2d.cpp b/tests/auto/render/qscene2d/tst_qscene2d.cpp index 8d27945e4..f0ff2db1e 100644 --- a/tests/auto/render/qscene2d/tst_qscene2d.cpp +++ b/tests/auto/render/qscene2d/tst_qscene2d.cpp @@ -27,7 +27,7 @@ ****************************************************************************/ #include -#include +#include #include #include #include diff --git a/tests/auto/render/scene2d/scene2d.pro b/tests/auto/render/scene2d/scene2d.pro index 8685b0b5b..aacdea3e4 100644 --- a/tests/auto/render/scene2d/scene2d.pro +++ b/tests/auto/render/scene2d/scene2d.pro @@ -2,7 +2,7 @@ TEMPLATE = app TARGET = tst_scene2d -QT += 3dcore 3dcore-private 3drender 3drender-private testlib 3dquickrender 3dquickrender-private +QT += 3dcore 3dcore-private 3drender 3drender-private testlib 3dquickscene2d 3dquickscene2d-private CONFIG += testcase diff --git a/tests/auto/render/scene2d/tst_scene2d.cpp b/tests/auto/render/scene2d/tst_scene2d.cpp index 45ea85b42..b53318e7c 100644 --- a/tests/auto/render/scene2d/tst_scene2d.cpp +++ b/tests/auto/render/scene2d/tst_scene2d.cpp @@ -27,7 +27,7 @@ ****************************************************************************/ #include -#include +#include #include #include #include diff --git a/tests/manual/render-qml-to-texture-qml/main.qml b/tests/manual/render-qml-to-texture-qml/main.qml index 3f605a1a3..c793078d3 100644 --- a/tests/manual/render-qml-to-texture-qml/main.qml +++ b/tests/manual/render-qml-to-texture-qml/main.qml @@ -39,6 +39,7 @@ import Qt3D.Render 2.9 import Qt3D.Input 2.0 import QtQuick 2.0 as QQ2 import QtQuick.Scene3D 2.0 +import QtQuick.Scene2D 2.9 import QtQuick.Window 2.0 as QW2 import Qt3D.Extras 2.0 diff --git a/tests/manual/render-qml-to-texture-qml/render-qml-to-texture-qml.pro b/tests/manual/render-qml-to-texture-qml/render-qml-to-texture-qml.pro index 8155840d3..23729957c 100644 --- a/tests/manual/render-qml-to-texture-qml/render-qml-to-texture-qml.pro +++ b/tests/manual/render-qml-to-texture-qml/render-qml-to-texture-qml.pro @@ -6,7 +6,7 @@ error( "Couldn't find the render-qml-to-texture.pri file!") } -QT += 3dextras 3dcore 3drender 3dinput 3dquick qml quick 3dquickrender +QT += 3dextras 3dcore 3drender 3dinput 3dquick qml quick SOURCES += main.cpp diff --git a/tests/manual/render-qml-to-texture/main.cpp b/tests/manual/render-qml-to-texture/main.cpp index 79c0dbca2..a2fc6ed09 100644 --- a/tests/manual/render-qml-to-texture/main.cpp +++ b/tests/manual/render-qml-to-texture/main.cpp @@ -49,7 +49,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/tests/manual/render-qml-to-texture/render-qml-to-texture.pro b/tests/manual/render-qml-to-texture/render-qml-to-texture.pro index e98e62654..45c213803 100644 --- a/tests/manual/render-qml-to-texture/render-qml-to-texture.pro +++ b/tests/manual/render-qml-to-texture/render-qml-to-texture.pro @@ -2,7 +2,7 @@ error( "Couldn't find the manual.pri file!" ) } -QT += 3dextras 3dcore 3drender 3dinput 3dquick qml quick 3dquickrender +QT += 3dextras 3dcore 3drender 3dinput 3dquick qml quick 3dquickrender 3dquickscene2d SOURCES += main.cpp \ planematerial.cpp diff --git a/tests/manual/video-texture-qml/main.qml b/tests/manual/video-texture-qml/main.qml index 418ec06c4..6a8dff3d5 100644 --- a/tests/manual/video-texture-qml/main.qml +++ b/tests/manual/video-texture-qml/main.qml @@ -38,6 +38,7 @@ import Qt3D.Core 2.0 import Qt3D.Render 2.9 import Qt3D.Input 2.0 import QtQuick 2.2 as QQ2 +import QtQuick.Scene2D 2.9 import QtQuick.Window 2.0 as QW2 import Qt3D.Extras 2.0 import QtMultimedia 5.6 as QMM -- cgit v1.2.3 From dbd24a90610a3a229781edf7c1eb0962b8fb0b20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Wed, 1 Feb 2017 14:27:59 +0200 Subject: Split scene2d implementation to multiple files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I7926898be5409334ec46b59eec76678c613b0d87 Reviewed-by: Tomi Korpipää Reviewed-by: Kevin Ottens --- src/quick3d/quick3dscene2d/items/items.pri | 8 +- src/quick3d/quick3dscene2d/items/qscene2d.cpp | 420 +-------------------- src/quick3d/quick3dscene2d/items/qscene2d_p.h | 113 +----- src/quick3d/quick3dscene2d/items/scene2d.cpp | 1 + src/quick3d/quick3dscene2d/items/scene2d_p.h | 3 - .../quick3dscene2d/items/scene2dmanager.cpp | 368 ++++++++++++++++++ .../quick3dscene2d/items/scene2dmanager_p.h | 124 ++++++ .../quick3dscene2d/items/scene2dsharedobject.cpp | 161 ++++++++ .../quick3dscene2d/items/scene2dsharedobject_p.h | 131 +++++++ 9 files changed, 793 insertions(+), 536 deletions(-) create mode 100644 src/quick3d/quick3dscene2d/items/scene2dmanager.cpp create mode 100644 src/quick3d/quick3dscene2d/items/scene2dmanager_p.h create mode 100644 src/quick3d/quick3dscene2d/items/scene2dsharedobject.cpp create mode 100644 src/quick3d/quick3dscene2d/items/scene2dsharedobject_p.h diff --git a/src/quick3d/quick3dscene2d/items/items.pri b/src/quick3d/quick3dscene2d/items/items.pri index 7a9a641f8..5faa3f729 100644 --- a/src/quick3d/quick3dscene2d/items/items.pri +++ b/src/quick3d/quick3dscene2d/items/items.pri @@ -1,10 +1,14 @@ HEADERS += \ $$PWD/scene2d_p.h \ $$PWD/qscene2d_p.h \ - $$PWD/qscene2d.h + $$PWD/qscene2d.h \ + $$PWD/scene2dmanager_p.h \ + $$PWD/scene2dsharedobject_p.h SOURCES += \ $$PWD/qscene2d.cpp \ - $$PWD/scene2d.cpp + $$PWD/scene2d.cpp \ + $$PWD/scene2dmanager.cpp \ + $$PWD/scene2dsharedobject.cpp INCLUDEPATH += $$PWD diff --git a/src/quick3d/quick3dscene2d/items/qscene2d.cpp b/src/quick3d/quick3dscene2d/items/qscene2d.cpp index fa46cd3d2..e70855ce1 100644 --- a/src/quick3d/quick3dscene2d/items/qscene2d.cpp +++ b/src/quick3d/quick3dscene2d/items/qscene2d.cpp @@ -37,11 +37,10 @@ #include "qscene2d.h" #include "qscene2d_p.h" #include "scene2d_p.h" +#include "scene2dmanager_p.h" #include -#include - QT_BEGIN_NAMESPACE using namespace Qt3DCore; @@ -103,423 +102,6 @@ namespace Quick { Holds whether the source has been loaded. */ -class RenderControl : public QQuickRenderControl -{ -public: - RenderControl(QWindow *w) : m_window(w) { } - QWindow *renderWindow(QPoint *offset) Q_DECL_OVERRIDE; - -private: - QWindow *m_window; -}; - -QWindow *RenderControl::renderWindow(QPoint *offset) -{ - if (offset) - *offset = QPoint(0, 0); - return m_window; -} - -/*! - \internal - Constructs object shared by the front-end and back-end to synchronize the rendering. - */ -Scene2DSharedObject::Scene2DSharedObject(Scene2DManager *manager) - : m_quit(false) - , m_requestSync(false) - , m_prepared(false) - , m_initialized(false) - , m_renderControl(nullptr) - , m_quickWindow(nullptr) - , m_renderManager(manager) - , m_surface(nullptr) - , m_renderObject(nullptr) - , m_disallowed(false) -{ -} - -Scene2DSharedObject::~Scene2DSharedObject() -{ -} - -void Scene2DSharedObject::cleanup() -{ - delete m_renderControl; - delete m_quickWindow; - delete m_surface; - m_renderControl = nullptr; - m_quickWindow = nullptr; - m_surface = nullptr; - m_initialized = false; -} - -bool Scene2DSharedObject::canRender() const -{ - return m_initialized && m_prepared && !m_disallowed; -} - -bool Scene2DSharedObject::isInitialized() const -{ - return m_initialized; -} - -void Scene2DSharedObject::disallowRender() -{ - m_disallowed = true; -} - -void Scene2DSharedObject::setInitialized() -{ - m_initialized = true; -} - -bool Scene2DSharedObject::isPrepared() const -{ - return m_prepared; -} - -void Scene2DSharedObject::setPrepared() -{ - m_prepared = true; -} - -// not protected, call only from main thread -bool Scene2DSharedObject::isQuit() const -{ - Q_ASSERT(QThread::currentThread() == QCoreApplication::instance()->thread()); - return m_quit; -} - -// not protected, call only from main thread -void Scene2DSharedObject::requestQuit() -{ - Q_ASSERT(QThread::currentThread() == QCoreApplication::instance()->thread()); - m_quit = true; - QCoreApplication::postEvent(m_renderObject, new QEvent(QUIT)); -} - -bool Scene2DSharedObject::isSyncRequested() const -{ - return m_requestSync; -} - -void Scene2DSharedObject::requestRender(bool sync) -{ - m_requestSync = sync; - QCoreApplication::postEvent(m_renderObject, new QEvent(RENDER)); -} - -void Scene2DSharedObject::wait() -{ - m_cond.wait(&m_mutex); -} - -void Scene2DSharedObject::wake() -{ - m_cond.wakeOne(); -} - -void Scene2DSharedObject::clearSyncRequest() -{ - m_requestSync = false; -} - -/*! - \internal - Constructs qml render manager. - */ -Scene2DManager::Scene2DManager(QScene2DPrivate *priv) - : m_priv(priv) - , m_qmlEngine(nullptr) - , m_qmlComponent(nullptr) - , m_rootItem(nullptr) - , m_source(nullptr) - , m_requested(false) - , m_initialized(false) - , m_renderSyncRequested(false) - , m_sharedObject(new Scene2DSharedObject(this)) - , m_renderPolicy(QScene2D::Continuous) - , m_backendInitialized(false) - , m_noSourceMode(false) - , m_item(nullptr) - , m_ownEngine(false) -{ - m_sharedObject->m_surface = new QOffscreenSurface; - m_sharedObject->m_surface->setFormat(QSurfaceFormat::defaultFormat()); - m_sharedObject->m_surface->create(); - - // Create render control - m_sharedObject->m_renderControl = new RenderControl(nullptr); - - // Create window to render the QML with - m_sharedObject->m_quickWindow = new QQuickWindow(m_sharedObject->m_renderControl); - m_sharedObject->m_quickWindow->setClearBeforeRendering(false); - - connect(m_sharedObject->m_renderControl, &QQuickRenderControl::renderRequested, - this, &Scene2DManager::requestRender); - connect(m_sharedObject->m_renderControl, &QQuickRenderControl::sceneChanged, - this, &Scene2DManager::requestRenderSync); -} - -Scene2DManager::~Scene2DManager() -{ - m_sharedObject = nullptr; -} - -void Scene2DManager::requestRender() -{ - // Don't request render until the backend is initialized. - if (m_sharedObject->canRender()) { - if (!m_requested) { - m_requested = true; - QCoreApplication::postEvent(this, new QEvent(RENDER)); - } - } -} - -void Scene2DManager::requestRenderSync() -{ - // Don't request render until the backed is initialized. - if (m_sharedObject->canRender()) { - if (!m_requested) { - m_requested = true; - QCoreApplication::postEvent(this, new QEvent(RENDERSYNC)); - } - } else { - m_renderSyncRequested = true; - } -} - -void Scene2DManager::startIfInitialized() -{ - if (!m_initialized && m_backendInitialized) { - if (m_source.isValid() && !m_noSourceMode) { - // Create a QML engine. - if (!m_qmlEngine) { - m_qmlEngine = new QQmlEngine; - if (!m_qmlEngine->incubationController()) { - m_qmlEngine->setIncubationController(m_sharedObject->m_quickWindow - ->incubationController()); - } - } - - // create component - m_ownEngine = true; - m_qmlComponent = new QQmlComponent(m_qmlEngine, m_source); - if (m_qmlComponent->isLoading()) { - connect(m_qmlComponent, &QQmlComponent::statusChanged, - this, &Scene2DManager::run); - } else { - run(); - } - } else if (m_item != nullptr) { - m_rootItem = m_item; - - // Associate root item with the window. - m_rootItem->setParentItem(m_sharedObject->m_quickWindow->contentItem()); - - // Update window size. - updateSizes(); - - m_initialized = true; - m_sharedObject->setInitialized(); - } - } -} - -void Scene2DManager::stopAndClean() -{ - if (m_sharedObject->isInitialized()) { - QMutexLocker lock(&m_sharedObject->m_mutex); - m_sharedObject->requestQuit(); - m_sharedObject->wait(); - m_sharedObject->cleanup(); - if (m_ownEngine) { - QObject::disconnect(m_connection); - delete m_qmlEngine; - } - delete m_qmlComponent; - m_qmlEngine = nullptr; - m_qmlComponent = nullptr; - } -} - -void Scene2DManager::run() -{ - disconnect(m_qmlComponent, &QQmlComponent::statusChanged, this, &Scene2DManager::run); - - if (m_qmlComponent->isError()) { - QList errorList = m_qmlComponent->errors(); - for (const QQmlError &error: errorList) - qWarning() << error.url() << error.line() << error; - return; - } - - QObject *rootObject = m_qmlComponent->create(); - if (m_qmlComponent->isError()) { - QList errorList = m_qmlComponent->errors(); - for (const QQmlError &error: errorList) - qWarning() << error.url() << error.line() << error; - return; - } - - m_rootItem = qobject_cast(rootObject); - if (!m_rootItem) { - qWarning("QScene2D: Root item is not a QQuickItem."); - delete rootObject; - return; - } - - // The root item is ready. Associate it with the window. - m_rootItem->setParentItem(m_sharedObject->m_quickWindow->contentItem()); - - // Update window size. - updateSizes(); - - m_initialized = true; - m_sharedObject->setInitialized(); - - emit onLoadedChanged(); -} - -void Scene2DManager::updateSizes() -{ - const int width = m_rootItem->width(); - const int height = m_rootItem->height(); - if (width == 0 || height == 0) { - qWarning() << "QScene2D: Root item size not set."; - return; - } - m_sharedObject->m_quickWindow->setGeometry(0, 0, width, height); -} - -void Scene2DManager::setSource(const QUrl &url) -{ - m_source = url; - startIfInitialized(); -} - -void Scene2DManager::setItem(QQuickItem *item) -{ - m_noSourceMode = true; - m_item = item; - startIfInitialized(); -} - -bool Scene2DManager::event(QEvent *e) -{ - switch (e->type()) { - - case RENDER: { - // just render request, don't need to call sync in render thread - QMutexLocker lock(&m_sharedObject->m_mutex); - m_sharedObject->requestRender(false); - m_requested = false; - return true; - } - - case RENDERSYNC: { - // sync and render request, main and render threads must be synchronized - if (!m_sharedObject->isQuit()) - doRenderSync(); - m_requested = false; - return true; - } - - case PREPARE: { - m_sharedObject->m_renderControl->prepareThread(m_sharedObject->m_renderThread); - m_sharedObject->setPrepared(); - - if (m_renderSyncRequested) { - if (!m_requested) { - m_requested = true; - QCoreApplication::postEvent(this, new QEvent(RENDERSYNC)); - } - m_renderSyncRequested = false; - } - return true; - } - - case INITIALIZED: { - // backend is initialized, start the qml - m_backendInitialized = true; - startIfInitialized(); - return true; - } - - case RENDERED: { - // render is done, excellent, now clean anything not needed anymore. - stopAndClean(); - return true; - } - - default: - break; - } - return QObject::event(e); -} - -bool Scene2DManager::forwardEvent(QEvent *event) -{ - switch (event->type()) { - - case QEvent::MouseMove: - case QEvent::MouseButtonDblClick: - case QEvent::MouseButtonPress: - case QEvent::MouseButtonRelease: { - QMouseEvent* me = static_cast(event); - QPointF pos = me->localPos(); - pos = QPointF(pos.x() * m_rootItem->width(), pos.y() * m_rootItem->height()); - QMouseEvent nme = QMouseEvent(me->type(), pos, pos, pos, me->button(), me->buttons(), - me->modifiers(), Qt::MouseEventSynthesizedByApplication); - QCoreApplication::sendEvent(m_sharedObject->m_quickWindow, &nme); - } break; - - case QEvent::KeyPress: - case QEvent::KeyRelease: { - QCoreApplication::sendEvent(m_sharedObject->m_quickWindow, event); - } break; - - default: - break; - } - return false; -} - -void Scene2DManager::doRenderSync() -{ - QMutexLocker lock(&m_sharedObject->m_mutex); - - m_sharedObject->requestRender(true); - m_sharedObject->m_renderControl->polishItems(); - - // begin waiting render thread - m_sharedObject->wait(); - m_requested = false; -} - -void Scene2DManager::cleanup() -{ - stopAndClean(); -} - -void Scene2DManager::setEngine(QQmlEngine *engine) -{ - m_qmlEngine = engine; - m_ownEngine = false; - if (engine) { - m_connection = QObject::connect(engine, &QObject::destroyed, - this, &Scene2DManager::engineDestroyed); - } -} - -void Scene2DManager::engineDestroyed() -{ - QObject::disconnect(m_connection); - m_qmlEngine = nullptr; - m_ownEngine = false; -} - QScene2DPrivate::QScene2DPrivate() : Qt3DCore::QNodePrivate() diff --git a/src/quick3d/quick3dscene2d/items/qscene2d_p.h b/src/quick3d/quick3dscene2d/items/qscene2d_p.h index 1aecbedd7..4c9a6a842 100644 --- a/src/quick3d/quick3dscene2d/items/qscene2d_p.h +++ b/src/quick3d/quick3dscene2d/items/qscene2d_p.h @@ -48,21 +48,10 @@ // We mean it. // -#include -#include -#include -#include -#include -#include -#include -#include -#include - #include -#include -#include #include +#include QT_BEGIN_NAMESPACE @@ -90,56 +79,6 @@ static const QEvent::Type RENDERED = QEvent::Type(QEvent::User + 6); // main thread -> render thread static const QEvent::Type QUIT = QEvent::Type(QEvent::User + 7); -class Q_AUTOTEST_EXPORT Scene2DSharedObject -{ -public: - Scene2DSharedObject(Scene2DManager *manager); - ~Scene2DSharedObject(); - - QQuickRenderControl *m_renderControl; - QQuickWindow *m_quickWindow; - Scene2DManager *m_renderManager; - QOffscreenSurface *m_surface; - - QThread *m_renderThread; - QObject *m_renderObject; - - QWaitCondition m_cond; - QMutex m_mutex; - - bool isInitialized() const; - void setInitialized(); - - void requestQuit(); - bool isQuit() const; - - void requestRender(bool sync); - - bool isSyncRequested() const; - void clearSyncRequest(); - - void wait(); - void wake(); - - bool isPrepared() const; - void setPrepared(); - - void disallowRender(); - bool canRender() const; - - void cleanup(); - -private: - - bool m_disallowed; - bool m_quit; - bool m_requestSync; - bool m_requestRender; - bool m_prepared; - bool m_initialized; -}; - -typedef QSharedPointer Scene2DSharedObjectPtr; class Q_AUTOTEST_EXPORT QScene2DPrivate : public Qt3DCore::QNodePrivate { @@ -161,59 +100,9 @@ struct QScene2DData Qt3DCore::QNodeId output; }; -class Scene2DManager : public QObject -{ - Q_OBJECT -public: - Scene2DManager(QScene2DPrivate *priv); - ~Scene2DManager(); - - QQmlEngine *m_qmlEngine; - QQmlComponent *m_qmlComponent; - QQuickItem *m_rootItem; - QQuickItem *m_item; - - QScene2DPrivate *m_priv; - QSharedPointer m_sharedObject; - - QUrl m_source; - Qt3DCore::QNodeId m_id; - QMetaObject::Connection m_connection; - QScene2D::RenderPolicy m_renderPolicy; - - bool m_requested; - bool m_initialized; - bool m_renderSyncRequested; - bool m_backendInitialized; - bool m_noSourceMode; - bool m_ownEngine; - - void requestRender(); - void requestRenderSync(); - void doRenderSync(); - void startIfInitialized(); - void stopAndClean(); - void run(); - void updateSizes(); - - void setSource(const QUrl &url); - void setItem(QQuickItem *item); - - bool event(QEvent *e) Q_DECL_OVERRIDE; - bool forwardEvent(QEvent *event); - - Q_SIGNAL void onLoadedChanged(); - - void cleanup(); - void setEngine(QQmlEngine *engine); - void engineDestroyed(); -}; - } // namespace Quick } // namespace Qt3DRender QT_END_NAMESPACE -Q_DECLARE_METATYPE(Qt3DRender::Quick::Scene2DSharedObjectPtr) - #endif // QT3DRENDER_QUICK3DSCENE2D_QSCENE2D_P_H diff --git a/src/quick3d/quick3dscene2d/items/scene2d.cpp b/src/quick3d/quick3dscene2d/items/scene2d.cpp index ef677bab8..fc2cf2c0e 100644 --- a/src/quick3d/quick3dscene2d/items/scene2d.cpp +++ b/src/quick3d/quick3dscene2d/items/scene2d.cpp @@ -42,6 +42,7 @@ #include #include +#include #include #include #include diff --git a/src/quick3d/quick3dscene2d/items/scene2d_p.h b/src/quick3d/quick3dscene2d/items/scene2d_p.h index db32264c0..608ecc5dc 100644 --- a/src/quick3d/quick3dscene2d/items/scene2d_p.h +++ b/src/quick3d/quick3dscene2d/items/scene2d_p.h @@ -51,9 +51,6 @@ #include #include -#include -#include - #include #include #include diff --git a/src/quick3d/quick3dscene2d/items/scene2dmanager.cpp b/src/quick3d/quick3dscene2d/items/scene2dmanager.cpp new file mode 100644 index 000000000..10d116127 --- /dev/null +++ b/src/quick3d/quick3dscene2d/items/scene2dmanager.cpp @@ -0,0 +1,368 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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 "qscene2d.h" +#include "qscene2d_p.h" +#include "scene2d_p.h" +#include "scene2dmanager_p.h" + +#include + +QT_BEGIN_NAMESPACE + +using namespace Qt3DCore; + +namespace Qt3DRender { + +namespace Quick { + +class RenderControl : public QQuickRenderControl +{ +public: + RenderControl(QWindow *w) : m_window(w) { } + QWindow *renderWindow(QPoint *offset) Q_DECL_OVERRIDE; + +private: + QWindow *m_window; +}; + +QWindow *RenderControl::renderWindow(QPoint *offset) +{ + if (offset) + *offset = QPoint(0, 0); + return m_window; +} + +/*! + \internal + Constructs qml render manager. + */ +Scene2DManager::Scene2DManager(QScene2DPrivate *priv) + : m_priv(priv) + , m_qmlEngine(nullptr) + , m_qmlComponent(nullptr) + , m_rootItem(nullptr) + , m_source(nullptr) + , m_requested(false) + , m_initialized(false) + , m_renderSyncRequested(false) + , m_sharedObject(new Scene2DSharedObject(this)) + , m_renderPolicy(QScene2D::Continuous) + , m_backendInitialized(false) + , m_noSourceMode(false) + , m_item(nullptr) + , m_ownEngine(false) +{ + m_sharedObject->m_surface = new QOffscreenSurface; + m_sharedObject->m_surface->setFormat(QSurfaceFormat::defaultFormat()); + m_sharedObject->m_surface->create(); + + // Create render control + m_sharedObject->m_renderControl = new RenderControl(nullptr); + + // Create window to render the QML with + m_sharedObject->m_quickWindow = new QQuickWindow(m_sharedObject->m_renderControl); + m_sharedObject->m_quickWindow->setClearBeforeRendering(false); + + connect(m_sharedObject->m_renderControl, &QQuickRenderControl::renderRequested, + this, &Scene2DManager::requestRender); + connect(m_sharedObject->m_renderControl, &QQuickRenderControl::sceneChanged, + this, &Scene2DManager::requestRenderSync); +} + +Scene2DManager::~Scene2DManager() +{ + m_sharedObject = nullptr; +} + +void Scene2DManager::requestRender() +{ + // Don't request render until the backend is initialized. + if (m_sharedObject->canRender()) { + if (!m_requested) { + m_requested = true; + QCoreApplication::postEvent(this, new QEvent(RENDER)); + } + } +} + +void Scene2DManager::requestRenderSync() +{ + // Don't request render until the backed is initialized. + if (m_sharedObject->canRender()) { + if (!m_requested) { + m_requested = true; + QCoreApplication::postEvent(this, new QEvent(RENDERSYNC)); + } + } else { + m_renderSyncRequested = true; + } +} + +void Scene2DManager::startIfInitialized() +{ + if (!m_initialized && m_backendInitialized) { + if (m_source.isValid() && !m_noSourceMode) { + // Create a QML engine. + if (!m_qmlEngine) { + m_qmlEngine = new QQmlEngine; + if (!m_qmlEngine->incubationController()) { + m_qmlEngine->setIncubationController(m_sharedObject->m_quickWindow + ->incubationController()); + } + } + + // create component + m_ownEngine = true; + m_qmlComponent = new QQmlComponent(m_qmlEngine, m_source); + if (m_qmlComponent->isLoading()) { + connect(m_qmlComponent, &QQmlComponent::statusChanged, + this, &Scene2DManager::run); + } else { + run(); + } + } else if (m_item != nullptr) { + m_rootItem = m_item; + + // Associate root item with the window. + m_rootItem->setParentItem(m_sharedObject->m_quickWindow->contentItem()); + + // Update window size. + updateSizes(); + + m_initialized = true; + m_sharedObject->setInitialized(); + } + } +} + +void Scene2DManager::stopAndClean() +{ + if (m_sharedObject->isInitialized()) { + QMutexLocker lock(&m_sharedObject->m_mutex); + m_sharedObject->requestQuit(); + m_sharedObject->wait(); + m_sharedObject->cleanup(); + if (m_ownEngine) { + QObject::disconnect(m_connection); + delete m_qmlEngine; + } + delete m_qmlComponent; + m_qmlEngine = nullptr; + m_qmlComponent = nullptr; + } +} + +void Scene2DManager::run() +{ + disconnect(m_qmlComponent, &QQmlComponent::statusChanged, this, &Scene2DManager::run); + + if (m_qmlComponent->isError()) { + QList errorList = m_qmlComponent->errors(); + for (const QQmlError &error: errorList) + qWarning() << error.url() << error.line() << error; + return; + } + + QObject *rootObject = m_qmlComponent->create(); + if (m_qmlComponent->isError()) { + QList errorList = m_qmlComponent->errors(); + for (const QQmlError &error: errorList) + qWarning() << error.url() << error.line() << error; + return; + } + + m_rootItem = qobject_cast(rootObject); + if (!m_rootItem) { + qWarning("QScene2D: Root item is not a QQuickItem."); + delete rootObject; + return; + } + + // The root item is ready. Associate it with the window. + m_rootItem->setParentItem(m_sharedObject->m_quickWindow->contentItem()); + + // Update window size. + updateSizes(); + + m_initialized = true; + m_sharedObject->setInitialized(); + + emit onLoadedChanged(); +} + +void Scene2DManager::updateSizes() +{ + const int width = m_rootItem->width(); + const int height = m_rootItem->height(); + if (width == 0 || height == 0) { + qWarning() << "QScene2D: Root item size not set."; + return; + } + m_sharedObject->m_quickWindow->setGeometry(0, 0, width, height); +} + +void Scene2DManager::setSource(const QUrl &url) +{ + m_source = url; + startIfInitialized(); +} + +void Scene2DManager::setItem(QQuickItem *item) +{ + m_noSourceMode = true; + m_item = item; + startIfInitialized(); +} + +bool Scene2DManager::event(QEvent *e) +{ + switch (e->type()) { + + case RENDER: { + // just render request, don't need to call sync in render thread + QMutexLocker lock(&m_sharedObject->m_mutex); + m_sharedObject->requestRender(false); + m_requested = false; + return true; + } + + case RENDERSYNC: { + // sync and render request, main and render threads must be synchronized + if (!m_sharedObject->isQuit()) + doRenderSync(); + m_requested = false; + return true; + } + + case PREPARE: { + m_sharedObject->m_renderControl->prepareThread(m_sharedObject->m_renderThread); + m_sharedObject->setPrepared(); + + if (m_renderSyncRequested) { + if (!m_requested) { + m_requested = true; + QCoreApplication::postEvent(this, new QEvent(RENDERSYNC)); + } + m_renderSyncRequested = false; + } + return true; + } + + case INITIALIZED: { + // backend is initialized, start the qml + m_backendInitialized = true; + startIfInitialized(); + return true; + } + + case RENDERED: { + // render is done, excellent, now clean anything not needed anymore. + stopAndClean(); + return true; + } + + default: + break; + } + return QObject::event(e); +} + +bool Scene2DManager::forwardEvent(QEvent *event) +{ + switch (event->type()) { + + case QEvent::MouseMove: + case QEvent::MouseButtonDblClick: + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: { + QMouseEvent* me = static_cast(event); + QPointF pos = me->localPos(); + pos = QPointF(pos.x() * m_rootItem->width(), pos.y() * m_rootItem->height()); + QMouseEvent nme = QMouseEvent(me->type(), pos, pos, pos, me->button(), me->buttons(), + me->modifiers(), Qt::MouseEventSynthesizedByApplication); + QCoreApplication::sendEvent(m_sharedObject->m_quickWindow, &nme); + } break; + + case QEvent::KeyPress: + case QEvent::KeyRelease: { + QCoreApplication::sendEvent(m_sharedObject->m_quickWindow, event); + } break; + + default: + break; + } + return false; +} + +void Scene2DManager::doRenderSync() +{ + QMutexLocker lock(&m_sharedObject->m_mutex); + + m_sharedObject->requestRender(true); + m_sharedObject->m_renderControl->polishItems(); + + // begin waiting render thread + m_sharedObject->wait(); + m_requested = false; +} + +void Scene2DManager::cleanup() +{ + stopAndClean(); +} + +void Scene2DManager::setEngine(QQmlEngine *engine) +{ + m_qmlEngine = engine; + m_ownEngine = false; + if (engine) { + m_connection = QObject::connect(engine, &QObject::destroyed, + this, &Scene2DManager::engineDestroyed); + } +} + +void Scene2DManager::engineDestroyed() +{ + QObject::disconnect(m_connection); + m_qmlEngine = nullptr; + m_ownEngine = false; +} + +} // namespace Quick +} // namespace Qt3DRender + +QT_END_NAMESPACE diff --git a/src/quick3d/quick3dscene2d/items/scene2dmanager_p.h b/src/quick3d/quick3dscene2d/items/scene2dmanager_p.h new file mode 100644 index 000000000..4b3eeceec --- /dev/null +++ b/src/quick3d/quick3dscene2d/items/scene2dmanager_p.h @@ -0,0 +1,124 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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$ +** +****************************************************************************/ + +#ifndef QT3DRENDER_QUICK3DRENDER_SCENE2DMANAGER_P_H +#define QT3DRENDER_QUICK3DRENDER_SCENE2DMANAGER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include + +#include +#include +#include + +#include + +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +namespace Quick { + +class QScene2DPrivate; +class Scene2DSharedObject; + +class Scene2DManager : public QObject +{ + Q_OBJECT +public: + Scene2DManager(QScene2DPrivate *priv); + ~Scene2DManager(); + + QQmlEngine *m_qmlEngine; + QQmlComponent *m_qmlComponent; + QQuickItem *m_rootItem; + QQuickItem *m_item; + + QScene2DPrivate *m_priv; + QSharedPointer m_sharedObject; + + QUrl m_source; + Qt3DCore::QNodeId m_id; + QMetaObject::Connection m_connection; + QScene2D::RenderPolicy m_renderPolicy; + + bool m_requested; + bool m_initialized; + bool m_renderSyncRequested; + bool m_backendInitialized; + bool m_noSourceMode; + bool m_ownEngine; + + void requestRender(); + void requestRenderSync(); + void doRenderSync(); + void startIfInitialized(); + void stopAndClean(); + void run(); + void updateSizes(); + + void setSource(const QUrl &url); + void setItem(QQuickItem *item); + + bool event(QEvent *e) Q_DECL_OVERRIDE; + bool forwardEvent(QEvent *event); + + Q_SIGNAL void onLoadedChanged(); + + void cleanup(); + void setEngine(QQmlEngine *engine); + void engineDestroyed(); +}; + +} // namespace Quick +} // namespace Qt3DRender + +QT_END_NAMESPACE + +#endif // QT3DRENDER_QUICK3DRENDER_SCENE2DMANAGER_P_H diff --git a/src/quick3d/quick3dscene2d/items/scene2dsharedobject.cpp b/src/quick3d/quick3dscene2d/items/scene2dsharedobject.cpp new file mode 100644 index 000000000..5e91d9a11 --- /dev/null +++ b/src/quick3d/quick3dscene2d/items/scene2dsharedobject.cpp @@ -0,0 +1,161 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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 "qscene2d.h" +#include "qscene2d_p.h" +#include "scene2d_p.h" +#include "scene2dmanager_p.h" +#include "scene2dsharedobject_p.h" + +#include + +QT_BEGIN_NAMESPACE + +using namespace Qt3DCore; + +namespace Qt3DRender { + +namespace Quick { + + +/*! + \internal + Constructs object shared by the front-end and back-end to synchronize the rendering. + */ +Scene2DSharedObject::Scene2DSharedObject(Scene2DManager *manager) + : m_quit(false) + , m_requestSync(false) + , m_prepared(false) + , m_initialized(false) + , m_renderControl(nullptr) + , m_quickWindow(nullptr) + , m_renderManager(manager) + , m_surface(nullptr) + , m_renderObject(nullptr) + , m_disallowed(false) +{ +} + +Scene2DSharedObject::~Scene2DSharedObject() +{ +} + +void Scene2DSharedObject::cleanup() +{ + delete m_renderControl; + delete m_quickWindow; + delete m_surface; + m_renderControl = nullptr; + m_quickWindow = nullptr; + m_surface = nullptr; + m_initialized = false; +} + +bool Scene2DSharedObject::canRender() const +{ + return m_initialized && m_prepared && !m_disallowed; +} + +bool Scene2DSharedObject::isInitialized() const +{ + return m_initialized; +} + +void Scene2DSharedObject::disallowRender() +{ + m_disallowed = true; +} + +void Scene2DSharedObject::setInitialized() +{ + m_initialized = true; +} + +bool Scene2DSharedObject::isPrepared() const +{ + return m_prepared; +} + +void Scene2DSharedObject::setPrepared() +{ + m_prepared = true; +} + +// not protected, call only from main thread +bool Scene2DSharedObject::isQuit() const +{ + Q_ASSERT(QThread::currentThread() == QCoreApplication::instance()->thread()); + return m_quit; +} + +// not protected, call only from main thread +void Scene2DSharedObject::requestQuit() +{ + Q_ASSERT(QThread::currentThread() == QCoreApplication::instance()->thread()); + m_quit = true; + QCoreApplication::postEvent(m_renderObject, new QEvent(QUIT)); +} + +bool Scene2DSharedObject::isSyncRequested() const +{ + return m_requestSync; +} + +void Scene2DSharedObject::requestRender(bool sync) +{ + m_requestSync = sync; + QCoreApplication::postEvent(m_renderObject, new QEvent(RENDER)); +} + +void Scene2DSharedObject::wait() +{ + m_cond.wait(&m_mutex); +} + +void Scene2DSharedObject::wake() +{ + m_cond.wakeOne(); +} + +void Scene2DSharedObject::clearSyncRequest() +{ + m_requestSync = false; +} + +} // namespace Quick +} // namespace Qt3DRender + +QT_END_NAMESPACE diff --git a/src/quick3d/quick3dscene2d/items/scene2dsharedobject_p.h b/src/quick3d/quick3dscene2d/items/scene2dsharedobject_p.h new file mode 100644 index 000000000..bac6fb555 --- /dev/null +++ b/src/quick3d/quick3dscene2d/items/scene2dsharedobject_p.h @@ -0,0 +1,131 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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$ +** +****************************************************************************/ + +#ifndef QT3DRENDER_QUICK3DRENDER_SCENE2DSHAREDOBJECT_P_H +#define QT3DRENDER_QUICK3DRENDER_SCENE2DSHAREDOBJECT_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +namespace Quick { + +class Scene2DManager; + +class Q_AUTOTEST_EXPORT Scene2DSharedObject +{ +public: + Scene2DSharedObject(Scene2DManager *manager); + ~Scene2DSharedObject(); + + QQuickRenderControl *m_renderControl; + QQuickWindow *m_quickWindow; + Scene2DManager *m_renderManager; + QOffscreenSurface *m_surface; + + QThread *m_renderThread; + QObject *m_renderObject; + + QWaitCondition m_cond; + QMutex m_mutex; + + bool isInitialized() const; + void setInitialized(); + + void requestQuit(); + bool isQuit() const; + + void requestRender(bool sync); + + bool isSyncRequested() const; + void clearSyncRequest(); + + void wait(); + void wake(); + + bool isPrepared() const; + void setPrepared(); + + void disallowRender(); + bool canRender() const; + + void cleanup(); + +private: + + bool m_disallowed; + bool m_quit; + bool m_requestSync; + bool m_requestRender; + bool m_prepared; + bool m_initialized; +}; + +typedef QSharedPointer Scene2DSharedObjectPtr; + +} // namespace Quick +} // namespace Qt3DRender + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(Qt3DRender::Quick::Scene2DSharedObjectPtr) + +#endif // QT3DRENDER_QUICK3DRENDER_SCENE2DSHAREDOBJECT_P_H -- cgit v1.2.3 From 725d9ec67f003ed077cc01b15f13d86551c4586f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Wed, 1 Feb 2017 15:23:54 +0200 Subject: Enumerize event ids MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add Scene2DEvent to holds the enums. Change-Id: Icd8febe7808acdbe639f9f5aaa5caba0548aa363 Reviewed-by: Tomi Korpipää Reviewed-by: Kevin Ottens --- src/quick3d/quick3dscene2d/items/items.pri | 3 +- src/quick3d/quick3dscene2d/items/qscene2d.cpp | 2 +- src/quick3d/quick3dscene2d/items/qscene2d_p.h | 18 ----- src/quick3d/quick3dscene2d/items/scene2d.cpp | 29 +++++--- src/quick3d/quick3dscene2d/items/scene2devent_p.h | 84 ++++++++++++++++++++++ .../quick3dscene2d/items/scene2dmanager.cpp | 17 ++--- .../quick3dscene2d/items/scene2dsharedobject.cpp | 5 +- 7 files changed, 117 insertions(+), 41 deletions(-) create mode 100644 src/quick3d/quick3dscene2d/items/scene2devent_p.h diff --git a/src/quick3d/quick3dscene2d/items/items.pri b/src/quick3d/quick3dscene2d/items/items.pri index 5faa3f729..f79fc1f69 100644 --- a/src/quick3d/quick3dscene2d/items/items.pri +++ b/src/quick3d/quick3dscene2d/items/items.pri @@ -3,7 +3,8 @@ HEADERS += \ $$PWD/qscene2d_p.h \ $$PWD/qscene2d.h \ $$PWD/scene2dmanager_p.h \ - $$PWD/scene2dsharedobject_p.h + $$PWD/scene2dsharedobject_p.h \ + $$PWD/scene2devent_p.h SOURCES += \ $$PWD/qscene2d.cpp \ diff --git a/src/quick3d/quick3dscene2d/items/qscene2d.cpp b/src/quick3d/quick3dscene2d/items/qscene2d.cpp index e70855ce1..b797a5f5e 100644 --- a/src/quick3d/quick3dscene2d/items/qscene2d.cpp +++ b/src/quick3d/quick3dscene2d/items/qscene2d.cpp @@ -38,6 +38,7 @@ #include "qscene2d_p.h" #include "scene2d_p.h" #include "scene2dmanager_p.h" +#include "scene2devent_p.h" #include @@ -102,7 +103,6 @@ namespace Quick { Holds whether the source has been loaded. */ - QScene2DPrivate::QScene2DPrivate() : Qt3DCore::QNodePrivate() , m_renderManager(new Scene2DManager(this)) diff --git a/src/quick3d/quick3dscene2d/items/qscene2d_p.h b/src/quick3d/quick3dscene2d/items/qscene2d_p.h index 4c9a6a842..82865035f 100644 --- a/src/quick3d/quick3dscene2d/items/qscene2d_p.h +++ b/src/quick3d/quick3dscene2d/items/qscene2d_p.h @@ -62,24 +62,6 @@ namespace Quick { class QScene2D; class Scene2DManager; -// render thread -> render thread -static const QEvent::Type INITIALIZE = QEvent::Type(QEvent::User + 1); - -// main thread -> main thread, render thread -static const QEvent::Type RENDER = QEvent::Type(QEvent::User + 2); - -// main thread -> main thread -static const QEvent::Type RENDERSYNC = QEvent::Type(QEvent::User + 3); - -// render thread -> main thread -static const QEvent::Type PREPARE = QEvent::Type(QEvent::User + 4); -static const QEvent::Type INITIALIZED = QEvent::Type(QEvent::User + 5); -static const QEvent::Type RENDERED = QEvent::Type(QEvent::User + 6); - -// main thread -> render thread -static const QEvent::Type QUIT = QEvent::Type(QEvent::User + 7); - - class Q_AUTOTEST_EXPORT QScene2DPrivate : public Qt3DCore::QNodePrivate { public: diff --git a/src/quick3d/quick3dscene2d/items/scene2d.cpp b/src/quick3d/quick3dscene2d/items/scene2d.cpp index fc2cf2c0e..3e6dc12b4 100644 --- a/src/quick3d/quick3dscene2d/items/scene2d.cpp +++ b/src/quick3d/quick3dscene2d/items/scene2d.cpp @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -82,17 +83,17 @@ bool RenderQmlEventHandler::event(QEvent *e) { switch (e->type()) { - case RENDER: { + case Scene2DEvent::Render: { m_node->render(); return true; } - case INITIALIZE: { + case Scene2DEvent::Initialize: { m_node->initializeRender(); return true; } - case QUIT: { + case Scene2DEvent::Quit: { m_node->cleanup(); return true; } @@ -147,11 +148,13 @@ void Scene2D::initializeSharedObject() m_sharedObject->m_renderThread->start(); // Notify main thread we have been initialized - if (m_sharedObject->m_renderManager) - QCoreApplication::postEvent(m_sharedObject->m_renderManager, new QEvent(INITIALIZED)); - + if (m_sharedObject->m_renderManager) { + QCoreApplication::postEvent(m_sharedObject->m_renderManager, + new Scene2DEvent(Scene2DEvent::Initialized)); + } // Initialize render thread - QCoreApplication::postEvent(m_sharedObject->m_renderObject, new QEvent(INITIALIZE)); + QCoreApplication::postEvent(m_sharedObject->m_renderObject, + new Scene2DEvent(Scene2DEvent::Initialize)); m_initialized = true; } @@ -198,7 +201,8 @@ void Scene2D::initializeRender() m_shareContext = renderer()->shareContext(); if (!m_shareContext){ qCDebug(Qt3DRender::Quick::Scene2D) << Q_FUNC_INFO << "Renderer not initialized."; - QCoreApplication::postEvent(m_sharedObject->m_renderObject, new QEvent(INITIALIZE)); + QCoreApplication::postEvent(m_sharedObject->m_renderObject, + new Scene2DEvent(Scene2DEvent::Initialize)); return; } m_context = new QOpenGLContext(); @@ -217,7 +221,8 @@ void Scene2D::initializeRender() m_sharedObject->m_renderControl->initialize(m_context); m_context->doneCurrent(); - QCoreApplication::postEvent(m_sharedObject->m_renderManager, new QEvent(PREPARE)); + QCoreApplication::postEvent(m_sharedObject->m_renderManager, + new Scene2DEvent(Scene2DEvent::Prepare)); m_renderInitialized = true; } } @@ -279,7 +284,8 @@ void Scene2D::render() syncRenderControl(); m_context->doneCurrent(); qCDebug(Qt3DRender::Quick::Scene2D) << Q_FUNC_INFO << "Texture not in use."; - QCoreApplication::postEvent(m_sharedObject->m_renderObject, new QEvent(RENDER)); + QCoreApplication::postEvent(m_sharedObject->m_renderObject, + new Scene2DEvent(Scene2DEvent::Render)); return; } textureLock->lock(); @@ -323,7 +329,8 @@ void Scene2D::render() // Tell main thread we are done so it can begin cleanup if this is final frame if (m_renderPolicy == QScene2D::SingleShot) - QCoreApplication::postEvent(m_sharedObject->m_renderManager, new QEvent(RENDERED)); + QCoreApplication::postEvent(m_sharedObject->m_renderManager, + new Scene2DEvent(Scene2DEvent::Rendered)); m_sharedObject->m_quickWindow->resetOpenGLState(); m_context->functions()->glFlush(); diff --git a/src/quick3d/quick3dscene2d/items/scene2devent_p.h b/src/quick3d/quick3dscene2d/items/scene2devent_p.h new file mode 100644 index 000000000..bcc808a4d --- /dev/null +++ b/src/quick3d/quick3dscene2d/items/scene2devent_p.h @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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$ +** +****************************************************************************/ + +#ifndef QT3DRENDER_QUICK3DRENDER_SCENE2DEVENT_P_H +#define QT3DRENDER_QUICK3DRENDER_SCENE2DEVENT_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +namespace Quick { + +class Scene2DEvent : public QEvent +{ +public: + enum Type { + Initialize = QEvent::User + 1, + Render, + RenderSync, + Prepare, + Initialized, + Rendered, + Quit + }; + Scene2DEvent(Type type) + : QEvent(static_cast(type)) + { + } +}; + +} // namespace Quick +} // namespace Qt3DRender + +QT_END_NAMESPACE + +#endif // QT3DRENDER_QUICK3DRENDER_SCENE2DEVENT_P_H diff --git a/src/quick3d/quick3dscene2d/items/scene2dmanager.cpp b/src/quick3d/quick3dscene2d/items/scene2dmanager.cpp index 10d116127..a2daee49b 100644 --- a/src/quick3d/quick3dscene2d/items/scene2dmanager.cpp +++ b/src/quick3d/quick3dscene2d/items/scene2dmanager.cpp @@ -38,6 +38,7 @@ #include "qscene2d_p.h" #include "scene2d_p.h" #include "scene2dmanager_p.h" +#include "scene2devent_p.h" #include @@ -114,7 +115,7 @@ void Scene2DManager::requestRender() if (m_sharedObject->canRender()) { if (!m_requested) { m_requested = true; - QCoreApplication::postEvent(this, new QEvent(RENDER)); + QCoreApplication::postEvent(this, new Scene2DEvent(Scene2DEvent::Render)); } } } @@ -125,7 +126,7 @@ void Scene2DManager::requestRenderSync() if (m_sharedObject->canRender()) { if (!m_requested) { m_requested = true; - QCoreApplication::postEvent(this, new QEvent(RENDERSYNC)); + QCoreApplication::postEvent(this, new Scene2DEvent(Scene2DEvent::RenderSync)); } } else { m_renderSyncRequested = true; @@ -252,7 +253,7 @@ bool Scene2DManager::event(QEvent *e) { switch (e->type()) { - case RENDER: { + case Scene2DEvent::Render: { // just render request, don't need to call sync in render thread QMutexLocker lock(&m_sharedObject->m_mutex); m_sharedObject->requestRender(false); @@ -260,7 +261,7 @@ bool Scene2DManager::event(QEvent *e) return true; } - case RENDERSYNC: { + case Scene2DEvent::RenderSync: { // sync and render request, main and render threads must be synchronized if (!m_sharedObject->isQuit()) doRenderSync(); @@ -268,28 +269,28 @@ bool Scene2DManager::event(QEvent *e) return true; } - case PREPARE: { + case Scene2DEvent::Prepare: { m_sharedObject->m_renderControl->prepareThread(m_sharedObject->m_renderThread); m_sharedObject->setPrepared(); if (m_renderSyncRequested) { if (!m_requested) { m_requested = true; - QCoreApplication::postEvent(this, new QEvent(RENDERSYNC)); + QCoreApplication::postEvent(this, new Scene2DEvent(Scene2DEvent::RenderSync)); } m_renderSyncRequested = false; } return true; } - case INITIALIZED: { + case Scene2DEvent::Initialized: { // backend is initialized, start the qml m_backendInitialized = true; startIfInitialized(); return true; } - case RENDERED: { + case Scene2DEvent::Rendered: { // render is done, excellent, now clean anything not needed anymore. stopAndClean(); return true; diff --git a/src/quick3d/quick3dscene2d/items/scene2dsharedobject.cpp b/src/quick3d/quick3dscene2d/items/scene2dsharedobject.cpp index 5e91d9a11..9f1873eac 100644 --- a/src/quick3d/quick3dscene2d/items/scene2dsharedobject.cpp +++ b/src/quick3d/quick3dscene2d/items/scene2dsharedobject.cpp @@ -38,6 +38,7 @@ #include "qscene2d_p.h" #include "scene2d_p.h" #include "scene2dmanager_p.h" +#include "scene2devent_p.h" #include "scene2dsharedobject_p.h" #include @@ -126,7 +127,7 @@ void Scene2DSharedObject::requestQuit() { Q_ASSERT(QThread::currentThread() == QCoreApplication::instance()->thread()); m_quit = true; - QCoreApplication::postEvent(m_renderObject, new QEvent(QUIT)); + QCoreApplication::postEvent(m_renderObject, new Scene2DEvent(Scene2DEvent::Quit)); } bool Scene2DSharedObject::isSyncRequested() const @@ -137,7 +138,7 @@ bool Scene2DSharedObject::isSyncRequested() const void Scene2DSharedObject::requestRender(bool sync) { m_requestSync = sync; - QCoreApplication::postEvent(m_renderObject, new QEvent(RENDER)); + QCoreApplication::postEvent(m_renderObject, new Scene2DEvent(Scene2DEvent::Render)); } void Scene2DSharedObject::wait() -- cgit v1.2.3 From bec33082f5ec09e067b30c8a560ffb5e8a20c154 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Mon, 20 Feb 2017 10:07:23 +0200 Subject: Cleanup scene2d - remove duplicate ifndef Remove duplicate GL_DEPTH24_STENCIL8 ifndef. Change-Id: I882ad42d61146478290e6b0fc73691ec6d42b2a2 Reviewed-by: Kevin Ottens --- src/quick3d/quick3dscene2d/items/scene2d.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/quick3d/quick3dscene2d/items/scene2d.cpp b/src/quick3d/quick3dscene2d/items/scene2d.cpp index 3e6dc12b4..80ed19053 100644 --- a/src/quick3d/quick3dscene2d/items/scene2d.cpp +++ b/src/quick3d/quick3dscene2d/items/scene2d.cpp @@ -68,10 +68,6 @@ namespace Quick { Q_GLOBAL_STATIC(QThread, renderThread) Q_GLOBAL_STATIC(QAtomicInt, renderThreadClientCount) -#ifndef GL_DEPTH24_STENCIL8 -#define GL_DEPTH24_STENCIL8 0x88F0 -#endif - RenderQmlEventHandler::RenderQmlEventHandler(Scene2D *node) : QObject() , m_node(node) -- cgit v1.2.3 From b8f5f4447caef56be5500b5c35383b5d65836072 Mon Sep 17 00:00:00 2001 From: Mike Krus Date: Mon, 20 Feb 2017 11:36:32 +0000 Subject: Update documentation related to picking Change-Id: I67f37da8d4534938e252a0c96735e6efe58cb6e3 Reviewed-by: Paul Lemire --- src/render/frontend/qpickingsettings.cpp | 60 +++++++++++++++++++++++++++---- src/render/geometry/qgeometry.cpp | 16 +++++++-- src/render/picking/qobjectpicker.cpp | 44 ++++++++++++++++++++--- src/render/picking/qpickevent.cpp | 27 ++++++++------ src/render/picking/qpicktriangleevent.cpp | 33 ++++++++++++----- 5 files changed, 147 insertions(+), 33 deletions(-) diff --git a/src/render/frontend/qpickingsettings.cpp b/src/render/frontend/qpickingsettings.cpp index db6840d7f..1cda638cb 100644 --- a/src/render/frontend/qpickingsettings.cpp +++ b/src/render/frontend/qpickingsettings.cpp @@ -53,6 +53,11 @@ namespace Qt3DRender { The picking settings determine how the entity picking is handled. For more details about entity picking, see QObjectPicker component documentation. + + Picking is triggered by mouse events. It will cast a ray through the scene and look for + geometry intersecting the ray. + + \sa QObjectPicker, QPickEvent, QPickTriangleEvent */ /*! @@ -64,6 +69,11 @@ namespace Qt3DRender { The picking settings determine how the entity picking is handled. For more details about entity picking, see Qt3DRender::QObjectPicker component documentation. + + Picking is triggered by mouse events. It will cast a ray through the scene and look for + geometry intersecting the ray. + + \sa ObjectPicker */ QPickingSettingsPrivate::QPickingSettingsPrivate() @@ -104,9 +114,6 @@ QPickingSettings::PickResultMode QPickingSettings::pickResultMode() const return d->m_pickResultMode; } -/*! - * \return the back facing picking flag - */ QPickingSettings::FaceOrientationPickingMode QPickingSettings::faceOrientationPickingMode() const { Q_D(const QPickingSettings); @@ -119,7 +126,7 @@ QPickingSettings::FaceOrientationPickingMode QPickingSettings::faceOrientationPi * Specifies the picking method. * * \value BoundingVolumePicking An entity is considered picked if the picking ray intersects - * the bounding volume of the entity. + * the bounding volume of the entity (default). * \value TrianglePicking An entity is considered picked if the picking ray intersects with * any triangle of the entity's mesh component. */ @@ -140,6 +147,12 @@ QPickingSettings::FaceOrientationPickingMode QPickingSettings::faceOrientationPi \property QPickingSettings::pickMethod Holds the current pick method. + + By default, for performance reasons, ray casting will use bounding volume picking. + This may however lead to unexpected results if a small object is englobed + in the bounding sphere of a large object behind it. + + Triangle picking will produce exact results but is computationally more expensive. */ void QPickingSettings::setPickMethod(QPickingSettings::PickMethod pickMethod) { @@ -157,8 +170,10 @@ void QPickingSettings::setPickMethod(QPickingSettings::PickMethod pickMethod) * Specifies what is included into the picking results. * * \value NearestPick Only the nearest entity to picking ray origin intersected by the picking ray - * is picked. + * is picked (default). * \value AllPicks All entities that intersect the picking ray are picked. + * + * \sa Qt3DRender::QPickEvent */ /*! @@ -177,6 +192,14 @@ void QPickingSettings::setPickMethod(QPickingSettings::PickMethod pickMethod) \property QPickingSettings::pickResultMode Holds the current pick results mode. + + By default, pick results will only be produced for the entity closest to the camera. + + When setting the pick method to AllPicks, events will be triggered for all the + entities with a QObjectPicker along the ray. + + If a QObjectPicker is assigned to an entity with multiple children, an event will + be triggered for each child entity that intersects the ray. */ void QPickingSettings::setPickResultMode(QPickingSettings::PickResultMode pickResultMode) { @@ -189,8 +212,31 @@ void QPickingSettings::setPickResultMode(QPickingSettings::PickResultMode pickRe } /*! - * \a faceOrientationPickingMode determines whether back facing faces are picked or not. - */ + \enum Qt3DRender::QPickingSettings::FaceOrientationPickingMode + + Specifies how face orientation affects triangle picking + + \value FrontFace Only front-facing triangles will be picked (default). + \value BackFace Only back-facing triangles will be picked. + \value FrontAndBackFace Both front- and back-facing triangles will be picked. +*/ + +/*! + \qmlproperty enumeration PickingSettings::faceOrientationPickingMode + + Specifies how face orientation affects triangle picking + + \list + \li PickingSettings.FrontFace Only front-facing triangles will be picked (default). + \li PickingSettings.BackFace Only back-facing triangles will be picked. + \li PickingSettings.FrontAndBackFace Both front- and back-facing triangles will be picked. + \endlist +*/ +/*! + \property QPickingSettings::faceOrientationPickingMode + + Specifies how face orientation affects triangle picking +*/ void QPickingSettings::setFaceOrientationPickingMode(QPickingSettings::FaceOrientationPickingMode faceOrientationPickingMode) { Q_D(QPickingSettings); diff --git a/src/render/geometry/qgeometry.cpp b/src/render/geometry/qgeometry.cpp index 95405d64d..3d281866d 100644 --- a/src/render/geometry/qgeometry.cpp +++ b/src/render/geometry/qgeometry.cpp @@ -94,7 +94,13 @@ QGeometryPrivate::~QGeometryPrivate() /*! \qmlproperty Attribute Geometry::boundingVolumePositionAttribute - Holds the attribute used to compute the bounding volume. + Holds the attribute used to compute the bounding volume. The bounding volume is used internally + for picking and view frustum culling. + + If unspecified, the system will look for the attribute using the name returned by + QAttribute::defaultPositionAttributeName. + + \sa Attribute */ /*! \qmlproperty list Geometry::attributes @@ -105,7 +111,13 @@ QGeometryPrivate::~QGeometryPrivate() /*! \property QGeometry::boundingVolumePositionAttribute - Holds the attribute used to compute the bounding volume. + Holds the attribute used to compute the bounding volume. The bounding volume is used internally + for picking and view frustum culling. + + If unspecified, the system will look for the attribute using the name returned by + QAttribute::defaultPositionAttributeName. + + \sa Qt3DRender::QAttribute */ diff --git a/src/render/picking/qobjectpicker.cpp b/src/render/picking/qobjectpicker.cpp index 9fa8b774c..45f7ff135 100644 --- a/src/render/picking/qobjectpicker.cpp +++ b/src/render/picking/qobjectpicker.cpp @@ -56,14 +56,25 @@ namespace Qt3DRender { \brief The QObjectPicker class instantiates a component that can be used to interact with a QEntity by a process known as picking. + For every combination of viewport and camera, picking casts a ray through the scene to + find entities who's bounding volume intersects the ray. The bounding volume is computed using + the values in the attribute buffer specified by the boundingVolumePositionAttribute of the + geometry. + The signals pressed(), released(), clicked(), moved(), entered(), and exited() are emitted when the bounding volume defined by the pickAttribute property intersects with a ray. + Most signals carry a QPickEvent instance. If QPickingSettings::pickMode() is set to + QPickingSettings::TrianglePicking, the actual type of the pick parameter will be + QPickTriangleEvent. + Pick queries are performed on mouse press and mouse release. If drag is enabled, queries also happen on each mouse move while any button is pressed. If hover is enabled, queries happen on every mouse move even if no button is pressed. - \sa QPickingSettings + + \sa Qt3DRender::QPickingSettings, Qt3DRender::QGeometry, Qt3DRender::QAttribute, + Qt3DRender::QPickEvent, Qt3DRender::QPickTriangleEvent \note Instances of this component shouldn't be shared, not respecting that condition will most likely result in undefined behavior. @@ -77,28 +88,51 @@ namespace Qt3DRender { * \inqmlmodule Qt3D.Render * \brief The ObjectPicker class instantiates a component that can be used to interact with an Entity by a process known as picking. + + For every combination of viewport and camera, picking casts a ray through the scene to + find entities who's bounding volume intersects the ray. The bounding volume is computed using + the values in the attribute buffer specified by the boundingVolumePositionAttribute of the + geometry. + + The signals pressed(), released(), clicked(), moved(), entered(), and exited() are + emitted when the bounding volume defined by the pickAttribute property intersects + with a ray. + + Most signals carry a PickEvent instance. If PickingSettings.pickMode is set to + PickingSettings.TrianglePicking, the actual type of the pick parameter will be + PickTriangleEvent. + + Pick queries are performed on mouse press and mouse release. + If drag is enabled, queries also happen on each mouse move while any button is pressed. + If hover is enabled, queries happen on every mouse move even if no button is pressed. + + \sa PickingSettings, Geometry, Attribute, PickEvent, PickTriangleEvent + + \note Instances of this component shouldn't be shared, not respecting that + condition will most likely result in undefined behavior. + */ /*! - \qmlsignal Qt3D.Render::ObjectPicker::pressed() + \qmlsignal Qt3D.Render::ObjectPicker::pressed(PickEvent pick) This signal is emitted when the bounding volume defined by the pickAttribute property intersects with a ray on a mouse press. */ /*! - \qmlsignal Qt3D.Render::ObjectPicker::released() + \qmlsignal Qt3D.Render::ObjectPicker::released(PickEvent pick) This signal is emitted when the bounding volume defined by the pickAttribute property intersects with a ray on a mouse release. */ /*! - \qmlsignal Qt3D.Render::ObjectPicker::clicked() + \qmlsignal Qt3D.Render::ObjectPicker::clicked(PickEvent pick) This signal is emitted when the bounding volume defined by the pickAttribute property intersects with a ray on a mouse click. */ /*! - \qmlsignal Qt3D.Render::ObjectPicker::moved() + \qmlsignal Qt3D.Render::ObjectPicker::moved(PickEvent pick) This signal is emitted when the bounding volume defined by the pickAttribute property intersects with a ray on a mouse move with a button pressed. */ diff --git a/src/render/picking/qpickevent.cpp b/src/render/picking/qpickevent.cpp index c7abf639c..806d91dc0 100644 --- a/src/render/picking/qpickevent.cpp +++ b/src/render/picking/qpickevent.cpp @@ -50,6 +50,10 @@ namespace Qt3DRender { \inmodule Qt3DRender \brief The QPickEvent class holds information when an object is picked + + This is received as a parameter in most of the QObjectPicker component signals when picking + succeeds. + \sa QPickingSettings, QPickTriangleEvent, QObjectPicker \since 5.7 @@ -61,9 +65,10 @@ namespace Qt3DRender { * \inqmlmodule Qt3D.Render * \sa ObjectPicker PickingSettings * \brief PickEvent holds information when an object is picked. + * This is received as a parameter in most of the QObjectPicker component signals when picking + * succeeds. */ - /*! \fn Qt3DRender::QPickEvent::QPickEvent() Constructs a new QPickEvent. @@ -147,11 +152,11 @@ void QPickEvent::setAccepted(bool accepted) /*! \qmlproperty bool Qt3D.Render::PickEvent::position - Specifies the position of the event + Specifies the mouse position with respect to the render area (window or quick item) */ /*! \property Qt3DRender::QPickEvent::position - Specifies the position of the event + Specifies the mouse position with respect to the render area (window or quick item) */ /*! * \brief QPickEvent::position @@ -165,11 +170,11 @@ QPointF QPickEvent::position() const /*! \qmlproperty bool Qt3D.Render::PickEvent::distance - Specifies the distance of the event + Specifies the distance of the hit to the camera */ /*! \property Qt3DRender::QPickEvent::distance - Specifies the distance of the event + Specifies the distance of the hit to the camera */ /*! * \brief QPickEvent::distance @@ -183,15 +188,15 @@ float QPickEvent::distance() const /*! \qmlproperty bool Qt3D.Render::PickEvent::worldIntersection - Specifies the world intersection of the event + Specifies the coordinates of the hit in world coordinate system */ /*! \property Qt3DRender::QPickEvent::worldIntersection - Specifies the world intersection of the event + Specifies the coordinates of the hit in world coordinate system */ /*! * \brief QPickEvent::worldIntersection - * \return world coordinate of the pick point + * \return coordinates of the hit in world coordinate system */ QVector3D QPickEvent::worldIntersection() const { @@ -201,15 +206,15 @@ QVector3D QPickEvent::worldIntersection() const /*! \qmlproperty bool Qt3D.Render::PickEvent::localIntersection - Specifies the world local intersection of the event + Specifies the coordinates of the hit in the local coordinate system of the picked entity */ /*! \property Qt3DRender::QPickEvent::localIntersection - Specifies the local intersection of the event + Specifies the coordinates of the hit in the local coordinate system of the picked entity */ /*! * \brief QPickEvent::localIntersection - * \return local coordinate of pick point + * \return coordinates of the hit in the local coordinate system of the picked entity */ QVector3D QPickEvent::localIntersection() const { diff --git a/src/render/picking/qpicktriangleevent.cpp b/src/render/picking/qpicktriangleevent.cpp index a1da8b975..3077cc91a 100644 --- a/src/render/picking/qpicktriangleevent.cpp +++ b/src/render/picking/qpicktriangleevent.cpp @@ -69,7 +69,15 @@ public: \brief The QPickTriangleEvent class holds information when a triangle is picked - \sa QPickEvent + When QPickingSettings::pickMode() is set to QPickingSettings::TrianglePicking, the signals + on QObjectPicker will carry an instance of QPickTriangleEvent. + + This contains the details of the triangle that was picked. + + \note In the case of indexed rendering, the point indices are relative to the + array of coordinates, not the array of indices. + + \sa QPickingSettings, QPickEvent, QObjectPicker, QAttribute \since 5.7 */ @@ -78,7 +86,16 @@ public: * \instantiates Qt3DRender::QPickTriangleEvent * \inqmlmodule Qt3D.Render * \brief PickTriangleEvent holds information when a triangle is picked. - * \sa ObjectPicker + * + * When QPickingSettings::pickMode() is set to QPickingSettings::TrianglePicking, the signals + * on QObjectPicker will carry an instance of QPickTriangleEvent. + * + * This contains the details of the triangle that was picked. + * + * \note In case of indexed rendering, the point indices are relative to the + * array of indices, not the array of coordinates. + * + * \sa PickingSettings, PickEvent, ObjectPicker, Attribute */ @@ -160,11 +177,11 @@ uint QPickTriangleEvent::triangleIndex() const /*! \qmlproperty uint Qt3D.Render::PickTriangleEvent::vertex1Index - Specifies the vertex 1 index of the event + Specifies the index of the first vertex in the triangle */ /*! \property Qt3DRender::QPickTriangleEvent::vertex1Index - Specifies the vertex 1 index of the event + Specifies the index of the first vertex in the triangle */ /*! * \brief QPickTriangleEvent::vertex1Index @@ -178,11 +195,11 @@ uint QPickTriangleEvent::vertex1Index() const /*! \qmlproperty uint Qt3D.Render::PickTriangleEvent::vertex2Index - Specifies the vertex 2 index of the event + Specifies the index of the second vertex in the triangle */ /*! \property Qt3DRender::QPickTriangleEvent::vertex2Index - Specifies the vertex 2 index of the event + Specifies the index of the second vertex in the triangle */ /*! * \brief QPickTriangleEvent::vertex2Index @@ -196,11 +213,11 @@ uint QPickTriangleEvent::vertex2Index() const /*! \qmlproperty uint Qt3D.Render::PickTriangleEvent::vertex3Index - Specifies the vertex 3 index of the event + Specifies the index of the third vertex in the triangle */ /*! \property Qt3DRender::QPickTriangleEvent::vertex3Index - Specifies the vertex 3 index of the event + Specifies the index of the third vertex in the triangle */ /*! * \brief QPickTriangleEvent::vertex3Index -- cgit v1.2.3 From ff6089aca0ec77c6304a04de268e6d27e97d6c32 Mon Sep 17 00:00:00 2001 From: Mike Krus Date: Wed, 1 Mar 2017 17:13:39 +0000 Subject: Silence unused variable warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I798658e943c726e480e0e6f8a1169d968b4fe4c4 Reviewed-by: Antti Määttä --- src/render/frontend/qlevelofdetail.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/render/frontend/qlevelofdetail.cpp b/src/render/frontend/qlevelofdetail.cpp index b62bf2277..9194c7556 100644 --- a/src/render/frontend/qlevelofdetail.cpp +++ b/src/render/frontend/qlevelofdetail.cpp @@ -53,7 +53,6 @@ QLevelOfDetailPrivate::QLevelOfDetailPrivate() , m_thresholdType(QLevelOfDetail::DistanceToCamera) , m_volumeOverride() { - Q_Q(QLevelOfDetail); } /*! -- cgit v1.2.3 From 0e6f59aed2a79cf54505070ad7757527c8a04993 Mon Sep 17 00:00:00 2001 From: Robert Brock Date: Tue, 17 Jan 2017 12:09:40 +0000 Subject: Coding convention fix for Src/logic Reordering the header includes to comply with Qt coding conventions Task-number: QTBUG-56185 Change-Id: I900997e93ba0e25351e74a91d4d43c5123431b97 Reviewed-by: Sean Harmer --- src/logic/callbackjob.cpp | 5 +++-- src/logic/executor.cpp | 4 +++- src/logic/handler.cpp | 6 ++++-- src/logic/manager.cpp | 11 ++++++----- src/logic/manager_p.h | 3 ++- src/logic/managers_p.h | 5 +++-- src/logic/qframeaction.cpp | 1 + src/logic/qframeaction_p.h | 2 +- src/logic/qlogicaspect.cpp | 15 ++++++++------- src/logic/qlogicaspect_p.h | 3 ++- 10 files changed, 33 insertions(+), 22 deletions(-) diff --git a/src/logic/callbackjob.cpp b/src/logic/callbackjob.cpp index bc974c792..5c04d8838 100644 --- a/src/logic/callbackjob.cpp +++ b/src/logic/callbackjob.cpp @@ -38,8 +38,9 @@ ****************************************************************************/ #include "callbackjob_p.h" -#include "manager_p.h" -#include "job_common_p.h" + +#include +#include QT_BEGIN_NAMESPACE diff --git a/src/logic/executor.cpp b/src/logic/executor.cpp index 74267379e..ab4ac154d 100644 --- a/src/logic/executor.cpp +++ b/src/logic/executor.cpp @@ -38,11 +38,13 @@ ****************************************************************************/ #include "executor_p.h" + #include #include -#include #include +#include + QT_BEGIN_NAMESPACE using namespace Qt3DCore; diff --git a/src/logic/handler.cpp b/src/logic/handler.cpp index 777637640..884d5f582 100644 --- a/src/logic/handler.cpp +++ b/src/logic/handler.cpp @@ -38,10 +38,12 @@ ****************************************************************************/ #include "handler_p.h" -#include "manager_p.h" -#include "managers_p.h" + #include +#include +#include + QT_BEGIN_NAMESPACE namespace Qt3DLogic { diff --git a/src/logic/manager.cpp b/src/logic/manager.cpp index 7f0a6b4eb..7b654ccd4 100644 --- a/src/logic/manager.cpp +++ b/src/logic/manager.cpp @@ -38,15 +38,16 @@ ****************************************************************************/ #include "manager_p.h" -#include "qlogicaspect.h" + +#include +#include +#include +#include + #include #include #include #include -#include - -#include -#include QT_BEGIN_NAMESPACE diff --git a/src/logic/manager_p.h b/src/logic/manager_p.h index 58e6e655b..39c0b5342 100644 --- a/src/logic/manager_p.h +++ b/src/logic/manager_p.h @@ -52,12 +52,13 @@ // #include -#include #include #include #include #include +#include + QT_BEGIN_NAMESPACE namespace Qt3DLogic { diff --git a/src/logic/managers_p.h b/src/logic/managers_p.h index b09104850..6194d260a 100644 --- a/src/logic/managers_p.h +++ b/src/logic/managers_p.h @@ -51,10 +51,11 @@ // We mean it. // -#include +#include + +#include #include #include -#include QT_BEGIN_NAMESPACE diff --git a/src/logic/qframeaction.cpp b/src/logic/qframeaction.cpp index fa4cefe06..f6ae70516 100644 --- a/src/logic/qframeaction.cpp +++ b/src/logic/qframeaction.cpp @@ -38,6 +38,7 @@ ****************************************************************************/ #include "qframeaction.h" + #include "qframeaction_p.h" QT_BEGIN_NAMESPACE diff --git a/src/logic/qframeaction_p.h b/src/logic/qframeaction_p.h index 17155ffd3..a83efe77a 100644 --- a/src/logic/qframeaction_p.h +++ b/src/logic/qframeaction_p.h @@ -51,7 +51,7 @@ // We mean it. // -#include +#include QT_BEGIN_NAMESPACE diff --git a/src/logic/qlogicaspect.cpp b/src/logic/qlogicaspect.cpp index 369410585..4aabf8888 100644 --- a/src/logic/qlogicaspect.cpp +++ b/src/logic/qlogicaspect.cpp @@ -37,21 +37,22 @@ ** ****************************************************************************/ + #include "qlogicaspect.h" #include "qlogicaspect_p.h" -#include "executor_p.h" -#include "handler_p.h" -#include "manager_p.h" -#include "qframeaction.h" +#include #include +#include +#include + +#include +#include +#include #include #include #include -#include -#include - QT_BEGIN_NAMESPACE using namespace Qt3DCore; diff --git a/src/logic/qlogicaspect_p.h b/src/logic/qlogicaspect_p.h index 052fdb244..ee7131a3e 100644 --- a/src/logic/qlogicaspect_p.h +++ b/src/logic/qlogicaspect_p.h @@ -51,9 +51,10 @@ // We mean it. // +#include + #include #include -#include QT_BEGIN_NAMESPACE -- cgit v1.2.3 From 7c59817810e74269a48b9f522a4b2013b426d3c2 Mon Sep 17 00:00:00 2001 From: Kevin Funk Date: Thu, 2 Mar 2017 12:51:22 +0100 Subject: assimp: Don't use -Wno-reorder on C compiler Fixes warning: cc1: warning: command line option "-Wno-reorder" is valid for C++/ObjC++ but not for C Change-Id: I0892d07ec15d40a361b728fd05dcf0234b69292f Reviewed-by: Sean Harmer --- src/3rdparty/assimp/assimp.pri | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/3rdparty/assimp/assimp.pri b/src/3rdparty/assimp/assimp.pri index d3282fb56..985f491a4 100644 --- a/src/3rdparty/assimp/assimp.pri +++ b/src/3rdparty/assimp/assimp.pri @@ -30,8 +30,8 @@ intel_icc: { QMAKE_CXXFLAGS_WARN_ON += $$QMAKE_CFLAGS_WARN_ON } else:gcc|clang: { # Stop compiler complaining about ignored qualifiers on return types - QMAKE_CFLAGS_WARN_ON += -Wno-ignored-qualifiers -Wno-unused-parameter -Wno-unused-variable -Wno-deprecated-declarations -Wno-unused-function -Wno-reorder - QMAKE_CXXFLAGS_WARN_ON = $$QMAKE_CFLAGS_WARN_ON + QMAKE_CFLAGS_WARN_ON += -Wno-ignored-qualifiers -Wno-unused-parameter -Wno-unused-variable -Wno-deprecated-declarations -Wno-unused-function + QMAKE_CXXFLAGS_WARN_ON = $$QMAKE_CFLAGS_WARN_ON -Wno-reorder } else:msvc { # Disabled Warnings: # 4100: 'identifier' : unreferenced formal parameter -- cgit v1.2.3 From 8e1834262da4e7f29b63b8211bbd1419814814c4 Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Thu, 23 Feb 2017 16:58:36 +0000 Subject: Add new QClipBlendValue to hold the leaf values of blend trees Will hold a single animation clip to be used as input to a blend tree. Has the advantage of preventing accidentally assigning a blend tree to a simple QClipAnimator in the alternative of making QAbstractClipBlendNode inheriting from QAbstractAnimationClip. Task-number: QTBUG-58901 Change-Id: Id99c1fb4284d0159ec3e520abb650f6595323661 Reviewed-by: Mike Krus --- src/animation/frontend/frontend.pri | 7 +- src/animation/frontend/qclipblendvalue.cpp | 105 ++++++++++ src/animation/frontend/qclipblendvalue.h | 81 ++++++++ src/animation/frontend/qclipblendvalue_p.h | 80 ++++++++ tests/auto/animation/animation.pro | 3 +- .../animation/qclipblendvalue/qclipblendvalue.pro | 12 ++ .../qclipblendvalue/tst_qclipblendvalue.cpp | 212 +++++++++++++++++++++ 7 files changed, 497 insertions(+), 3 deletions(-) create mode 100644 src/animation/frontend/qclipblendvalue.cpp create mode 100644 src/animation/frontend/qclipblendvalue.h create mode 100644 src/animation/frontend/qclipblendvalue_p.h create mode 100644 tests/auto/animation/qclipblendvalue/qclipblendvalue.pro create mode 100644 tests/auto/animation/qclipblendvalue/tst_qclipblendvalue.cpp diff --git a/src/animation/frontend/frontend.pri b/src/animation/frontend/frontend.pri index 01f74eedd..439f204d1 100644 --- a/src/animation/frontend/frontend.pri +++ b/src/animation/frontend/frontend.pri @@ -36,7 +36,9 @@ HEADERS += \ $$PWD/qlerpclipblend.h \ $$PWD/qlerpclipblend_p.h \ $$PWD/qadditiveclipblend.h \ - $$PWD/qadditiveclipblend_p.h + $$PWD/qadditiveclipblend_p.h \ + $$PWD/qclipblendvalue.h \ + $$PWD/qclipblendvalue_p.h SOURCES += \ $$PWD/qanimationaspect.cpp \ @@ -57,6 +59,7 @@ SOURCES += \ $$PWD/qvertexblendanimation.cpp \ $$PWD/qanimationcliploader.cpp \ $$PWD/qlerpclipblend.cpp \ - $$PWD/qadditiveclipblend.cpp + $$PWD/qadditiveclipblend.cpp \ + $$PWD/qclipblendvalue.cpp INCLUDEPATH += $$PWD diff --git a/src/animation/frontend/qclipblendvalue.cpp b/src/animation/frontend/qclipblendvalue.cpp new file mode 100644 index 000000000..db62209fc --- /dev/null +++ b/src/animation/frontend/qclipblendvalue.cpp @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qclipblendvalue.h" +#include "qclipblendvalue_p.h" +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { + +QClipBlendValuePrivate::QClipBlendValuePrivate() + : QAbstractClipBlendNodePrivate() + , m_clip(nullptr) +{ +} + +QClipBlendValue::QClipBlendValue(Qt3DCore::QNode *parent) + : QAbstractClipBlendNode(*new QClipBlendValuePrivate(), parent) +{ +} + +QClipBlendValue::QClipBlendValue(QClipBlendValuePrivate &dd, Qt3DCore::QNode *parent) + : QAbstractClipBlendNode(dd, parent) +{ +} + +QClipBlendValue::~QClipBlendValue() +{ +} + +Qt3DAnimation::QAbstractAnimationClip *QClipBlendValue::clip() const +{ + Q_D(const QClipBlendValue); + return d->m_clip; +} + +void QClipBlendValue::setClip(Qt3DAnimation::QAbstractAnimationClip *clip) +{ + Q_D(QClipBlendValue); + if (d->m_clip == clip) + return; + + if (d->m_clip) + d->unregisterDestructionHelper(d->m_clip); + + if (clip && !clip->parent()) + clip->setParent(this); + d->m_clip = clip; + + // Ensures proper bookkeeping + if (d->m_clip) + d->registerDestructionHelper(d->m_clip, &QClipBlendValue::setClip, d->m_clip); + emit clipChanged(clip); +} + +Qt3DCore::QNodeCreatedChangeBasePtr QClipBlendValue::createNodeCreationChange() const +{ + Q_D(const QClipBlendValue); + auto creationChange = QClipBlendNodeCreatedChangePtr::create(this); + QClipBlendValueData &data = creationChange->data; + data.clipId = Qt3DCore::qIdForNode(d->m_clip); + return creationChange; +} + +} // namespace Qt3DAnimation + +QT_END_NAMESPACE diff --git a/src/animation/frontend/qclipblendvalue.h b/src/animation/frontend/qclipblendvalue.h new file mode 100644 index 000000000..a40f71a6c --- /dev/null +++ b/src/animation/frontend/qclipblendvalue.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3DANIMATION_QCLIPBLENDVALUE_H +#define QT3DANIMATION_QCLIPBLENDVALUE_H + +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { + +class QClipBlendValuePrivate; + +class QT3DANIMATIONSHARED_EXPORT QClipBlendValue : public Qt3DAnimation::QAbstractClipBlendNode +{ + Q_OBJECT + Q_PROPERTY(Qt3DAnimation::QAbstractAnimationClip *clip READ clip WRITE setClip NOTIFY clipChanged) + +public: + QClipBlendValue(Qt3DCore::QNode *parent = nullptr); + ~QClipBlendValue(); + + Qt3DAnimation::QAbstractAnimationClip *clip() const; + +public Q_SLOTS: + void setClip(Qt3DAnimation::QAbstractAnimationClip *clip); + +Q_SIGNALS: + void clipChanged(Qt3DAnimation::QAbstractAnimationClip *clip); + +protected: + explicit QClipBlendValue(QClipBlendValuePrivate &dd, Qt3DCore::QNode *parent = nullptr); + +private: + Q_DECLARE_PRIVATE(QClipBlendValue) + Qt3DCore::QNodeCreatedChangeBasePtr createNodeCreationChange() const Q_DECL_OVERRIDE; +}; + +} // namespace Qt3DAnimation + +QT_END_NAMESPACE + +#endif // QT3DANIMATION_QCLIPBLENDVALUE_H diff --git a/src/animation/frontend/qclipblendvalue_p.h b/src/animation/frontend/qclipblendvalue_p.h new file mode 100644 index 000000000..7a397a1b8 --- /dev/null +++ b/src/animation/frontend/qclipblendvalue_p.h @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3DANIMATION_QCLIPBLENDNODE_P_H +#define QT3DANIMATION_QCLIPBLENDNODE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { + +class QClipBlendValuePrivate : public QAbstractClipBlendNodePrivate +{ +public: + QClipBlendValuePrivate(); + + Q_DECLARE_PUBLIC(QClipBlendValue) + + Qt3DAnimation::QAbstractAnimationClip *m_clip; +}; + +struct QClipBlendValueData +{ + Qt3DCore::QNodeId clipId; +}; + +} // namespace Qt3DAnimation + +QT_END_NAMESPACE + +#endif // QT3DANIMATION_QCLIPBLENDNODE_P_H diff --git a/tests/auto/animation/animation.pro b/tests/auto/animation/animation.pro index e756290f7..e4913986a 100644 --- a/tests/auto/animation/animation.pro +++ b/tests/auto/animation/animation.pro @@ -6,7 +6,8 @@ SUBDIRS += \ qclipanimator \ qblendedclipanimator \ qchannelmapping \ - qchannelmapper + qchannelmapper \ + qclipblendvalue qtConfig(private_tests) { SUBDIRS += \ diff --git a/tests/auto/animation/qclipblendvalue/qclipblendvalue.pro b/tests/auto/animation/qclipblendvalue/qclipblendvalue.pro new file mode 100644 index 000000000..b44b387db --- /dev/null +++ b/tests/auto/animation/qclipblendvalue/qclipblendvalue.pro @@ -0,0 +1,12 @@ +TEMPLATE = app + +TARGET = tst_qclipblendvalue + +QT += 3dcore 3dcore-private 3danimation 3danimation-private testlib + +CONFIG += testcase + +SOURCES += \ + tst_qclipblendvalue.cpp + +include(../../core/common/common.pri) diff --git a/tests/auto/animation/qclipblendvalue/tst_qclipblendvalue.cpp b/tests/auto/animation/qclipblendvalue/tst_qclipblendvalue.cpp new file mode 100644 index 000000000..6be6970ae --- /dev/null +++ b/tests/auto/animation/qclipblendvalue/tst_qclipblendvalue.cpp @@ -0,0 +1,212 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Paul Lemire +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "testpostmanarbiter.h" + +class tst_QClipBlendValue : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void initTestCase() + { + qRegisterMetaType(); + } + + void checkDefaultConstruction() + { + // GIVEN + Qt3DAnimation::QClipBlendValue clipBlendNode; + + // THEN; + QCOMPARE(clipBlendNode.clip(), static_cast(nullptr)); + } + + void checkPropertyChanges() + { + // GIVEN + Qt3DAnimation::QClipBlendValue clipBlendNode; + + { + // WHEN + QSignalSpy spy(&clipBlendNode, SIGNAL(clipChanged(Qt3DAnimation::QAbstractAnimationClip*))); + auto newValue = new Qt3DAnimation::QAnimationClipLoader(); + clipBlendNode.setClip(newValue); + + // THEN + QVERIFY(spy.isValid()); + QCOMPARE(clipBlendNode.clip(), newValue); + QCOMPARE(spy.count(), 1); + + // WHEN + spy.clear(); + clipBlendNode.setClip(newValue); + + // THEN + QCOMPARE(clipBlendNode.clip(), newValue); + QCOMPARE(spy.count(), 0); + } + } + + void checkCreationData() + { + // GIVEN + Qt3DAnimation::QClipBlendValue clipBlendNode; + Qt3DAnimation::QAnimationClipLoader clip; + + clipBlendNode.setClip(&clip); + + // WHEN + QVector creationChanges; + + { + Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&clipBlendNode); + creationChanges = creationChangeGenerator.creationChanges(); + } + + // THEN + { + QCOMPARE(creationChanges.size(), 2); // 1 + 1 clip + + const auto creationChangeData = qSharedPointerCast>(creationChanges.first()); + const Qt3DAnimation::QClipBlendValueData cloneData = creationChangeData->data; + + QCOMPARE(clipBlendNode.id(), creationChangeData->subjectId()); + QCOMPARE(clipBlendNode.isEnabled(), true); + QCOMPARE(clipBlendNode.isEnabled(), creationChangeData->isNodeEnabled()); + QCOMPARE(clipBlendNode.metaObject(), creationChangeData->metaObject()); + QCOMPARE(cloneData.clipId, clip.id()); + QCOMPARE(creationChangeData->parentClipBlendNodeId(), Qt3DCore::QNodeId()); + } + + // WHEN + clipBlendNode.setEnabled(false); + + { + Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&clipBlendNode); + creationChanges = creationChangeGenerator.creationChanges(); + } + + // THEN + { + QCOMPARE(creationChanges.size(), 2); // 1 + 1 clip + + const auto creationChangeData = qSharedPointerCast>(creationChanges.first()); + const Qt3DAnimation::QClipBlendValueData cloneData = creationChangeData->data; + + QCOMPARE(clipBlendNode.id(), creationChangeData->subjectId()); + QCOMPARE(clipBlendNode.isEnabled(), false); + QCOMPARE(clipBlendNode.isEnabled(), creationChangeData->isNodeEnabled()); + QCOMPARE(clipBlendNode.metaObject(), creationChangeData->metaObject()); + QCOMPARE(cloneData.clipId, clip.id()); + QCOMPARE(creationChangeData->parentClipBlendNodeId(), Qt3DCore::QNodeId()); + } + } + + void checkClipUpdate() + { + // GIVEN + TestArbiter arbiter; + Qt3DAnimation::QClipBlendValue clipBlendNode; + arbiter.setArbiterOnNode(&clipBlendNode); + auto clip = new Qt3DAnimation::QAnimationClipLoader(); + + { + // WHEN + clipBlendNode.setClip(clip); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 1); + auto change = arbiter.events.first().staticCast(); + QCOMPARE(change->propertyName(), "clip"); + QCOMPARE(change->value().value(), clipBlendNode.clip()->id()); + QCOMPARE(change->type(), Qt3DCore::PropertyUpdated); + + arbiter.events.clear(); + } + + { + // WHEN + clipBlendNode.setClip(clip); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 0); + } + } + + void checkStartClipBookkeeping() + { + // GIVEN + QScopedPointer clipBlendNode(new Qt3DAnimation::QClipBlendValue); + { + // WHEN + Qt3DAnimation::QAnimationClipLoader clip; + clipBlendNode->setClip(&clip); + + // THEN + QCOMPARE(clip.parent(), clipBlendNode.data()); + QCOMPARE(clipBlendNode->clip(), &clip); + } + // THEN (Should not crash and clip be unset) + QVERIFY(clipBlendNode->clip() == nullptr); + + { + // WHEN + Qt3DAnimation::QClipBlendValue someOtherNode; + QScopedPointer clip(new Qt3DAnimation::QAnimationClipLoader(&someOtherNode)); + clipBlendNode->setClip(clip.data()); + + // THEN + QCOMPARE(clip->parent(), &someOtherNode); + QCOMPARE(clipBlendNode->clip(), clip.data()); + + // WHEN + clipBlendNode.reset(); + clip.reset(); + + // THEN Should not crash when the effect is destroyed (tests for failed removal of destruction helper) + } + } +}; + +QTEST_MAIN(tst_QClipBlendValue) + +#include "tst_qclipblendvalue.moc" -- cgit v1.2.3 From 58e35c1ea87f5d4ef6a4666623c0f6fa245c4412 Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Fri, 24 Feb 2017 16:58:08 +0000 Subject: Add ClipBlendValue backend node and test Task-number: QTBUG-58901 Change-Id: Ifa18b6bae2f8db802e6561d23a19435c32fe7559 Reviewed-by: Mike Krus --- src/animation/backend/backend.pri | 6 +- src/animation/backend/clipblendnode_p.h | 3 +- src/animation/backend/clipblendvalue.cpp | 87 ++++++++++++++++ src/animation/backend/clipblendvalue_p.h | 82 +++++++++++++++ tests/auto/animation/animation.pro | 3 +- .../animation/clipblendvalue/clipblendvalue.pro | 12 +++ .../clipblendvalue/tst_clipblendvalue.cpp | 115 +++++++++++++++++++++ 7 files changed, 304 insertions(+), 4 deletions(-) create mode 100644 src/animation/backend/clipblendvalue.cpp create mode 100644 src/animation/backend/clipblendvalue_p.h create mode 100644 tests/auto/animation/clipblendvalue/clipblendvalue.pro create mode 100644 tests/auto/animation/clipblendvalue/tst_clipblendvalue.cpp diff --git a/src/animation/backend/backend.pri b/src/animation/backend/backend.pri index bb69eb473..ec87ee2a2 100644 --- a/src/animation/backend/backend.pri +++ b/src/animation/backend/backend.pri @@ -25,7 +25,8 @@ HEADERS += \ $$PWD/evaluateblendclipanimatorjob_p.h \ $$PWD/animationcliploader_p.h \ $$PWD/lerpclipblend_p.h \ - $$PWD/additiveclipblend_p.h + $$PWD/additiveclipblend_p.h \ + $$PWD/clipblendvalue_p.h SOURCES += \ $$PWD/handler.cpp \ @@ -48,4 +49,5 @@ SOURCES += \ $$PWD/evaluateblendclipanimatorjob.cpp \ $$PWD/animationcliploader.cpp \ $$PWD/lerpclipblend.cpp \ - $$PWD/additiveclipblend.cpp + $$PWD/additiveclipblend.cpp \ + $$PWD/clipblendvalue.cpp diff --git a/src/animation/backend/clipblendnode_p.h b/src/animation/backend/clipblendnode_p.h index 4ce1816b9..afa395e12 100644 --- a/src/animation/backend/clipblendnode_p.h +++ b/src/animation/backend/clipblendnode_p.h @@ -68,7 +68,8 @@ public: enum BlendType { NoneBlendType, LerpBlendType, - AdditiveBlendType + AdditiveBlendType, + ValueType }; void setClipBlendNodeManager(ClipBlendNodeManager *manager); diff --git a/src/animation/backend/clipblendvalue.cpp b/src/animation/backend/clipblendvalue.cpp new file mode 100644 index 000000000..0607340c7 --- /dev/null +++ b/src/animation/backend/clipblendvalue.cpp @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** 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 "clipblendvalue_p.h" +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { +namespace Animation { + +ClipBlendValue::ClipBlendValue() + : ClipBlendNode(ValueType) +{ +} + +ClipBlendValue::~ClipBlendValue() +{ +} + +void ClipBlendValue::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) +{ + ClipBlendNode::initializeFromPeer(change); + const auto creationChange + = qSharedPointerCast>(change); + const Qt3DAnimation::QClipBlendValueData data = creationChange->data; + m_clipId = data.clipId; +} + +void ClipBlendValue::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) +{ + if (e->type() == Qt3DCore::PropertyUpdated) { + Qt3DCore::QPropertyUpdatedChangePtr change = qSharedPointerCast(e); + if (change->propertyName() == QByteArrayLiteral("clip")) + m_clipId = change->value().value(); + } +} + +float ClipBlendValue::blend(float value1, float value2) const +{ + // Should never be called for the value node + Q_UNUSED(value1); + Q_UNUSED(value2); + Q_UNREACHABLE(); + return 0.0f; +} + +} // namespace Animation +} // namespace Qt3DAnimation + +QT_END_NAMESPACE diff --git a/src/animation/backend/clipblendvalue_p.h b/src/animation/backend/clipblendvalue_p.h new file mode 100644 index 000000000..4de47b862 --- /dev/null +++ b/src/animation/backend/clipblendvalue_p.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** 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$ +** +****************************************************************************/ + +#ifndef QT3DANIMATION_ANIMATION_CLIPBLENDVALUE_H +#define QT3DANIMATION_ANIMATION_CLIPBLENDVALUE_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { +namespace Animation { + +class Q_AUTOTEST_EXPORT ClipBlendValue : public ClipBlendNode +{ +public: + ClipBlendValue(); + ~ClipBlendValue(); + + inline Qt3DCore::QNodeId clipId() const { return m_clipId; } + void setClipId(Qt3DCore::QNodeId clipId) { m_clipId = clipId; } // For unit tests + + void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_OVERRIDE; + float blend(float value1, float value2) const Q_DECL_OVERRIDE; + +private: + void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL; + + Qt3DCore::QNodeId m_clipId; +}; + +} // namespace Animation +} // namespace Qt3DAnimation + + +QT_END_NAMESPACE + +#endif // QT3DANIMATION_ANIMATION_CLIPBLENDVALUE_H diff --git a/tests/auto/animation/animation.pro b/tests/auto/animation/animation.pro index e4913986a..536fb2f21 100644 --- a/tests/auto/animation/animation.pro +++ b/tests/auto/animation/animation.pro @@ -26,5 +26,6 @@ qtConfig(private_tests) { lerpclipblend \ clipblendnodevisitor \ qadditiveclipblend \ - additiveclipblend + additiveclipblend \ + clipblendvalue } diff --git a/tests/auto/animation/clipblendvalue/clipblendvalue.pro b/tests/auto/animation/clipblendvalue/clipblendvalue.pro new file mode 100644 index 000000000..ff50f0bbd --- /dev/null +++ b/tests/auto/animation/clipblendvalue/clipblendvalue.pro @@ -0,0 +1,12 @@ +TEMPLATE = app + +TARGET = tst_clipblendvalue + +QT += 3dcore 3dcore-private 3danimation 3danimation-private testlib + +CONFIG += testcase + +SOURCES += \ + tst_clipblendvalue.cpp + +include(../../core/common/common.pri) diff --git a/tests/auto/animation/clipblendvalue/tst_clipblendvalue.cpp b/tests/auto/animation/clipblendvalue/tst_clipblendvalue.cpp new file mode 100644 index 000000000..5bed23704 --- /dev/null +++ b/tests/auto/animation/clipblendvalue/tst_clipblendvalue.cpp @@ -0,0 +1,115 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Paul Lemire +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $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 +#include +#include +#include +#include +#include +#include "qbackendnodetester.h" + +class tst_ClipBlendValue : public Qt3DCore::QBackendNodeTester +{ + Q_OBJECT + +private Q_SLOTS: + void checkInitialState() + { + // GIVEN + Qt3DAnimation::Animation::ClipBlendValue backendClipBlendValue; + + // THEN + QCOMPARE(backendClipBlendValue.isEnabled(), false); + QVERIFY(backendClipBlendValue.peerId().isNull()); + QCOMPARE(backendClipBlendValue.clipId(), Qt3DCore::QNodeId()); + QCOMPARE(backendClipBlendValue.blendType(), Qt3DAnimation::Animation::ClipBlendNode::ValueType); + } + + void checkInitializeFromPeer() + { + // GIVEN + Qt3DAnimation::QClipBlendValue clipBlendValue; + Qt3DAnimation::QAnimationClipLoader clip; + clipBlendValue.setClip(&clip); + + { + // WHEN + Qt3DAnimation::Animation::ClipBlendValue backendClipBlendValue; + simulateInitialization(&clipBlendValue, &backendClipBlendValue); + + // THEN + QCOMPARE(backendClipBlendValue.isEnabled(), true); + QCOMPARE(backendClipBlendValue.peerId(), clipBlendValue.id()); + QCOMPARE(backendClipBlendValue.clipId(), clip.id()); + } + { + // WHEN + Qt3DAnimation::Animation::ClipBlendValue backendClipBlendValue; + clipBlendValue.setEnabled(false); + simulateInitialization(&clipBlendValue, &backendClipBlendValue); + + // THEN + QCOMPARE(backendClipBlendValue.peerId(), clipBlendValue.id()); + QCOMPARE(backendClipBlendValue.isEnabled(), false); + } + } + + void checkSceneChangeEvents() + { + // GIVEN + Qt3DAnimation::Animation::ClipBlendValue backendClipBlendValue; + { + // WHEN + const bool newValue = false; + const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId()); + change->setPropertyName("enabled"); + change->setValue(newValue); + backendClipBlendValue.sceneChangeEvent(change); + + // THEN + QCOMPARE(backendClipBlendValue.isEnabled(), newValue); + } + { + // WHEN + const Qt3DAnimation::QAnimationClipLoader newValue; + const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId()); + change->setPropertyName("clip"); + change->setValue(QVariant::fromValue(newValue.id())); + backendClipBlendValue.sceneChangeEvent(change); + + // THEN + QCOMPARE(backendClipBlendValue.clipId(), newValue.id()); + } + } +}; + +QTEST_MAIN(tst_ClipBlendValue) + +#include "tst_clipblendvalue.moc" -- cgit v1.2.3 From 0d9c1a4004577a38b955d08fc86ee4a2cdd95fee Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Fri, 24 Feb 2017 17:02:23 +0000 Subject: Register QClipBlendValue with the animation aspect Task-number: QTBUG-58901 Change-Id: I48f2adc1d1e2ee89c613663cf0a56e75d637e771 Reviewed-by: Mike Krus --- src/animation/frontend/qanimationaspect.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/animation/frontend/qanimationaspect.cpp b/src/animation/frontend/qanimationaspect.cpp index 56dd012ed..75b057a9a 100644 --- a/src/animation/frontend/qanimationaspect.cpp +++ b/src/animation/frontend/qanimationaspect.cpp @@ -46,10 +46,12 @@ #include #include #include +#include #include #include #include #include +#include #include QT_BEGIN_NAMESPACE @@ -112,6 +114,9 @@ QAnimationAspect::QAnimationAspect(QAnimationAspectPrivate &dd, QObject *parent) registerBackendType( QSharedPointer>::create(d->m_handler.data(), d->m_handler->clipBlendNodeManager())); + registerBackendType( + QSharedPointer>::create(d->m_handler.data(), + d->m_handler->clipBlendNodeManager())); } /*! \internal */ -- cgit v1.2.3 From e9a958e93b6332b2f79d9d5ce7207143be049753 Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Fri, 24 Feb 2017 17:03:52 +0000 Subject: Export QClipBlendValue to QML Task-number: QTBUG-58901 Change-Id: I1a944da01a948a5e5821ecba307a898d8a0129ad Reviewed-by: Mike Krus --- src/quick3d/imports/animation/qt3dquick3danimationplugin.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/quick3d/imports/animation/qt3dquick3danimationplugin.cpp b/src/quick3d/imports/animation/qt3dquick3danimationplugin.cpp index 29b4fe076..85c5c270c 100644 --- a/src/quick3d/imports/animation/qt3dquick3danimationplugin.cpp +++ b/src/quick3d/imports/animation/qt3dquick3danimationplugin.cpp @@ -46,6 +46,7 @@ #include #include #include +#include #include #include @@ -83,6 +84,7 @@ void Qt3DQuick3DAnimationPlugin::registerTypes(const char *uri) Qt3DAnimation::Animation::Quick::Quick3DAbstractClipBlendNode>(uri, 2, 9, "AbstractClipBlendNode", QStringLiteral("QAbstractClipBlendNode is abstract")); qmlRegisterType(uri, 2, 9, "LerpClipBlend"); qmlRegisterType(uri, 2, 9, "AdditiveClipBlend"); + qmlRegisterType(uri, 2, 9, "ClipBlendValue"); qmlRegisterUncreatableType(uri, 2, 9, "AbstractAnimation", QStringLiteral("AbstractAnimation is abstract")); qmlRegisterExtendedType(uri, 2, 9, "KeyframeAnimation"); -- cgit v1.2.3 From b875246d29352f4d930222537f8f55f5f3fdafb4 Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Tue, 28 Feb 2017 09:48:41 +0000 Subject: Remove unused member channelBaseIndex from MappingData The m_channelIndices already contain the offset so no need to store it separately. Change-Id: Id4b651f07262f2716c2b8136a16612285b3443b1 Reviewed-by: Mike Krus --- src/animation/backend/animationutils_p.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/animation/backend/animationutils_p.h b/src/animation/backend/animationutils_p.h index 6f541998e..d88492e98 100644 --- a/src/animation/backend/animationutils_p.h +++ b/src/animation/backend/animationutils_p.h @@ -70,7 +70,6 @@ public: Qt3DCore::QNodeId targetId; const char *propertyName; int type; - int channelBaseIndex; QVector channelIndices; }; -- cgit v1.2.3 From 195cb92b8be0159c9fabe672ec67655ea9dad6a6 Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Tue, 28 Feb 2017 11:15:12 +0000 Subject: Allow QBackendNodeTester to set peer id of backend nodes This allows to directly create backend nodes without having to create the corresponding frontend node and using simulateInitialization(). Change-Id: I212795f6483f84e3b81e10f92696583841872bb1 Reviewed-by: Mike Krus --- tests/auto/core/common/qbackendnodetester.cpp | 6 ++++++ tests/auto/core/common/qbackendnodetester.h | 1 + 2 files changed, 7 insertions(+) diff --git a/tests/auto/core/common/qbackendnodetester.cpp b/tests/auto/core/common/qbackendnodetester.cpp index 8534a05cd..6f87e10d9 100644 --- a/tests/auto/core/common/qbackendnodetester.cpp +++ b/tests/auto/core/common/qbackendnodetester.cpp @@ -47,6 +47,12 @@ QBackendNodeTester::QBackendNodeTester(QObject *parent) { } +void QBackendNodeTester::setPeerId(QBackendNode *backend, QNodeId id) +{ + Q_ASSERT(backend); + backend->setPeerId(id); +} + void QBackendNodeTester::simulateInitialization(QNode *frontend, QBackendNode *backend) { Q_ASSERT(frontend); diff --git a/tests/auto/core/common/qbackendnodetester.h b/tests/auto/core/common/qbackendnodetester.h index fbd6c9581..9f266e40d 100644 --- a/tests/auto/core/common/qbackendnodetester.h +++ b/tests/auto/core/common/qbackendnodetester.h @@ -55,6 +55,7 @@ public: explicit QBackendNodeTester(QObject *parent = 0); // Proxies to allow test classes to call private methods on QBackendNode + void setPeerId(QBackendNode *backend, QNodeId id); void simulateInitialization(QNode *frontend, QBackendNode *backend); void sceneChangeEvent(QBackendNode *backend, const Qt3DCore::QSceneChangePtr &e); }; -- cgit v1.2.3 From 5ef53cecfdb2243ba5435e0c377b562bea5358a2 Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Tue, 28 Feb 2017 11:16:21 +0000 Subject: Add setters to mapping and mapper backend nodes This will make them testable and also useable in other tests without having to create them via frontend nodes. Change-Id: I792236b46d84a690eba3b2994821e69b1ca0e72a Reviewed-by: Mike Krus --- src/animation/backend/channelmapper_p.h | 1 + src/animation/backend/channelmapping_p.h | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/src/animation/backend/channelmapper_p.h b/src/animation/backend/channelmapper_p.h index 66654d56d..710de01ab 100644 --- a/src/animation/backend/channelmapper_p.h +++ b/src/animation/backend/channelmapper_p.h @@ -71,6 +71,7 @@ public: void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_OVERRIDE; + void setMappingIds(const QVector &mappingIds) { m_mappingIds = mappingIds; } QVector mappingIds() const { return m_mappingIds; } private: diff --git a/src/animation/backend/channelmapping_p.h b/src/animation/backend/channelmapping_p.h index 4d6d80bf2..154e8b228 100644 --- a/src/animation/backend/channelmapping_p.h +++ b/src/animation/backend/channelmapping_p.h @@ -70,10 +70,18 @@ public: void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_OVERRIDE; + void setChannelName(const QString &channelName) { m_channelName = channelName; } QString channelName() const { return m_channelName; } + + void setTargetId(Qt3DCore::QNodeId targetId) { m_targetId = targetId; } Qt3DCore::QNodeId targetId() const { return m_targetId; } + + void setProperty(const QString &property) { m_property = property; } QString property() const { return m_property; } + + void setType(int type) { m_type = type; } int type() const { return m_type; } + const char *propertyName() const { return m_propertyName; } private: -- cgit v1.2.3 From 8e36d0645788308b62b795821f968cc18a40fbab Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Tue, 28 Feb 2017 11:17:32 +0000 Subject: Output clip duration in debug output Useful for checking loaded data in tests. Change-Id: Ica80272b4ec3b02ba676102cbd84ff740b72d5d3 Reviewed-by: Mike Krus --- src/animation/backend/animationcliploader_p.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/animation/backend/animationcliploader_p.h b/src/animation/backend/animationcliploader_p.h index c6f942dcd..cca624605 100644 --- a/src/animation/backend/animationcliploader_p.h +++ b/src/animation/backend/animationcliploader_p.h @@ -106,6 +106,7 @@ inline QDebug operator<<(QDebug dbg, const AnimationClipLoader &animationClip) dbg << "QNodeId =" << animationClip.peerId() << endl << "Name =" << animationClip.name() << endl << "Object Name =" << animationClip.objectName() << endl + << "Duration: " << animationClip.duration() << endl << "Channel Groups:" << endl; const QVector channelGroups = animationClip.channelGroups(); -- cgit v1.2.3 From 4abd7bbfdb33200346c67b5d3af0f743793a3a39 Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Tue, 28 Feb 2017 11:18:14 +0000 Subject: Cleanup coding style a little Change-Id: I8459ea5f16a11fc99b0743145d7a2b3c2f29d0c4 Reviewed-by: Mike Krus --- src/animation/backend/animationutils.cpp | 4 +++- src/animation/backend/buildblendtreesjob.cpp | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/animation/backend/animationutils.cpp b/src/animation/backend/animationutils.cpp index db2d6eadb..d2d7313ab 100644 --- a/src/animation/backend/animationutils.cpp +++ b/src/animation/backend/animationutils.cpp @@ -263,7 +263,9 @@ QVector AnimationUtils::preparePropertyChanges(Qt3DCo return changes; } -QVector AnimationUtils::buildPropertyMappings(Handler *handler, const AnimationClipLoader *clip, const ChannelMapper *mapper) +QVector AnimationUtils::buildPropertyMappings(Handler *handler, + const AnimationClipLoader *clip, + const ChannelMapper *mapper) { QVector mappingDataVec; ChannelMappingManager *mappingManager = handler->channelMappingManager(); diff --git a/src/animation/backend/buildblendtreesjob.cpp b/src/animation/backend/buildblendtreesjob.cpp index f5d4036d2..cac15ac5c 100644 --- a/src/animation/backend/buildblendtreesjob.cpp +++ b/src/animation/backend/buildblendtreesjob.cpp @@ -192,7 +192,9 @@ void BuildBlendTreesJob::run() visitor.traverse(blendClipAnimator->blendTreeRootId(), [&] (ClipBlendNode *node) { BlendedClipAnimator::BlendNodeData nodeData; nodeData.blendNodeId = node->peerId(); - nodeData.type = (node->childrenIds().size() > 0) ? BlendedClipAnimator::BlendNodeData::BlendNodeType : BlendedClipAnimator::BlendNodeData::ClipType; + nodeData.type = (node->childrenIds().size() > 0) + ? BlendedClipAnimator::BlendNodeData::BlendNodeType + : BlendedClipAnimator::BlendNodeData::ClipType; if (nodeData.type == BlendedClipAnimator::BlendNodeData::BlendNodeType) { Q_ASSERT(node->childrenIds().size() == 2); -- cgit v1.2.3 From 6ad5c82af256c6d2409de451cba166d53c89bbd0 Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Tue, 28 Feb 2017 11:18:38 +0000 Subject: Add test for AnimationUtils Will extend in further commits. Change-Id: Idbdd95bdd3cfe0ab3f5d12295d15b32c116bc26b Reviewed-by: Mike Krus --- tests/auto/animation/animation.pro | 3 +- .../animation/animationutils/animationutils.pro | 15 ++++ .../animation/animationutils/animationutils.qrc | 5 ++ tests/auto/animation/animationutils/clip1.json | 48 +++++++++++ .../animationutils/tst_animationutils.cpp | 96 ++++++++++++++++++++++ 5 files changed, 166 insertions(+), 1 deletion(-) create mode 100644 tests/auto/animation/animationutils/animationutils.pro create mode 100644 tests/auto/animation/animationutils/animationutils.qrc create mode 100644 tests/auto/animation/animationutils/clip1.json create mode 100644 tests/auto/animation/animationutils/tst_animationutils.cpp diff --git a/tests/auto/animation/animation.pro b/tests/auto/animation/animation.pro index 536fb2f21..a608c6cbb 100644 --- a/tests/auto/animation/animation.pro +++ b/tests/auto/animation/animation.pro @@ -27,5 +27,6 @@ qtConfig(private_tests) { clipblendnodevisitor \ qadditiveclipblend \ additiveclipblend \ - clipblendvalue + clipblendvalue \ + animationutils } diff --git a/tests/auto/animation/animationutils/animationutils.pro b/tests/auto/animation/animationutils/animationutils.pro new file mode 100644 index 000000000..5c7e3c510 --- /dev/null +++ b/tests/auto/animation/animationutils/animationutils.pro @@ -0,0 +1,15 @@ +TEMPLATE = app + +TARGET = tst_animationutils + +QT += 3dcore 3dcore-private 3danimation 3danimation-private testlib + +CONFIG += testcase + +SOURCES += \ + tst_animationutils.cpp + +include(../../core/common/common.pri) + +RESOURCES += \ + animationutils.qrc diff --git a/tests/auto/animation/animationutils/animationutils.qrc b/tests/auto/animation/animationutils/animationutils.qrc new file mode 100644 index 000000000..72234ec64 --- /dev/null +++ b/tests/auto/animation/animationutils/animationutils.qrc @@ -0,0 +1,5 @@ + + + clip1.json + + diff --git a/tests/auto/animation/animationutils/clip1.json b/tests/auto/animation/animationutils/clip1.json new file mode 100644 index 000000000..e54858a2d --- /dev/null +++ b/tests/auto/animation/animationutils/clip1.json @@ -0,0 +1,48 @@ +{ + "animations": [ + { "object": "Cube", + "action": "CubeAction", + "range": [0.0, 60.0], + "groups": [ + { "group": "channelFoo", + "channels": [ + { "name": "x", + "keyframes": [ + { "co": [0.0, 0.0], + "handle_left": [-0.4717472394307454, 0.0], + "handle_right": [0.4717472394307454, 0.0]} + ,{ "co": [1.2083333333333333, 2.430499792098999], + "handle_left": [0.7365860939025879, 1.4711904525756836], + "handle_right": [1.696347713470459, 3.42288875579834]} + ,{ "co": [2.4583333333333335, 5.0], + "handle_left": [1.9703189531962078, 5.0], + "handle_right": [2.9463475545247397, 5.0]} + ]} + ,{ "name": "y", + "keyframes": [ + { "co": [0.0, 0.0], + "handle_left": [-0.4717472394307454, 0.0], + "handle_right": [0.4717472394307454, 0.0]} + ,{ "co": [1.2083333333333333, 3.0], + "handle_left": [0.7365860939025879, 3.0], + "handle_right": [1.696347713470459, 3.0]} + ,{ "co": [2.4583333333333335, 0.0], + "handle_left": [1.9703189531962078, 0.0], + "handle_right": [2.9463475545247397, 0.0]} + ]} + ,{ "name": "z", + "keyframes": [ + { "co": [0.0, 0.0], + "handle_left": [-0.4717472394307454, 0.0], + "handle_right": [0.4717472394307454, 0.0]} + ,{ "co": [1.2083333333333333, 0.0], + "handle_left": [0.7365860939025879, 0.0], + "handle_right": [1.696347713470459, 0.0]} + ,{ "co": [2.4583333333333335, 0.0], + "handle_left": [1.9703189531962078, 0.0], + "handle_right": [2.9463475545247397, 0.0]} + ]} + ]} + ]} + ] +} diff --git a/tests/auto/animation/animationutils/tst_animationutils.cpp b/tests/auto/animation/animationutils/tst_animationutils.cpp new file mode 100644 index 000000000..e4170381e --- /dev/null +++ b/tests/auto/animation/animationutils/tst_animationutils.cpp @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $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 +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace Qt3DAnimation::Animation; + +class tst_AnimationUtils : public Qt3DCore::QBackendNodeTester +{ + Q_OBJECT + +private Q_SLOTS: + void checkBuildPropertyMappings() + { + // GIVEN + Handler handler; + + // Create a channel mapping, set properties, and add it to manager + auto channelMappingId = Qt3DCore::QNodeId::createId(); + ChannelMapping *channelMapping = handler.channelMappingManager()->getOrCreateResource(channelMappingId); + setPeerId(channelMapping, channelMappingId); + + auto targetId = Qt3DCore::QNodeId::createId(); + channelMapping->setTargetId(targetId); + channelMapping->setProperty("foo"); + channelMapping->setChannelName("channelFoo"); + channelMapping->setType(static_cast(QVariant::Vector3D)); + + // Create a channel mapper and add mapping to it + auto channelMapperId = Qt3DCore::QNodeId::createId(); + ChannelMapper *channelMapper = handler.channelMapperManager()->getOrCreateResource(channelMapperId); + setPeerId(channelMapper, channelMapperId); + channelMapper->setMappingIds(QVector() << channelMappingId); + + // Create an animation clip + auto clipId = Qt3DCore::QNodeId::createId(); + AnimationClipLoader *clip = handler.animationClipLoaderManager()->getOrCreateResource(clipId); + setPeerId(clip, clipId); + clip->setSource(QUrl("qrc:/clip1.json")); + clip->loadAnimation(); + + // WHEN + // Build the mapping data for the above configuration + QVector mappingData = AnimationUtils::buildPropertyMappings(&handler, clip, channelMapper); + + // THEN + QCOMPARE(mappingData.size(), channelMapper->mappingIds().size()); + for (int i = 0; i < mappingData.size(); ++i) { + const auto mapping = mappingData[i]; + QCOMPARE(mapping.targetId, targetId); + QCOMPARE(mapping.propertyName, channelMapping->propertyName()); + QCOMPARE(mapping.type, channelMapping->type()); + QCOMPARE(mapping.channelIndices.size(), 3); + for (int j = 0; j < 3; ++j) { + QCOMPARE(mapping.channelIndices[j], j); + } + } + } +}; + +QTEST_MAIN(tst_AnimationUtils) + +#include "tst_animationutils.moc" -- cgit v1.2.3 From 836d4076f07b2c6a53aa0e9699129cf0a9d15258 Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Tue, 28 Feb 2017 13:11:16 +0000 Subject: Declare animation logging categories to log warnings and above Keeps the noise down in unit tests. Change-Id: Ib08c50f6b85f0e98e87c34e43e6070d8eb356529 Reviewed-by: Mike Krus --- src/animation/animationlogging.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/animation/animationlogging.cpp b/src/animation/animationlogging.cpp index a822f0346..11bd47a23 100644 --- a/src/animation/animationlogging.cpp +++ b/src/animation/animationlogging.cpp @@ -44,10 +44,10 @@ QT_BEGIN_NAMESPACE namespace Qt3DAnimation { namespace Animation { -Q_LOGGING_CATEGORY(Backend, "Qt3D.Animation.Backend") -Q_LOGGING_CATEGORY(Frontend, "Qt3D.Animation.Frontend") -Q_LOGGING_CATEGORY(Jobs, "Qt3D.Animation.Jobs") -Q_LOGGING_CATEGORY(HandlerLogic, "Qt3D.Animation.Handler") +Q_LOGGING_CATEGORY(Backend, "Qt3D.Animation.Backend", QtWarningMsg) +Q_LOGGING_CATEGORY(Frontend, "Qt3D.Animation.Frontend", QtWarningMsg) +Q_LOGGING_CATEGORY(Jobs, "Qt3D.Animation.Jobs", QtWarningMsg) +Q_LOGGING_CATEGORY(HandlerLogic, "Qt3D.Animation.Handler", QtWarningMsg) } // namespace Animation } // namespace Qt3DAnimation -- cgit v1.2.3 From 69b659b2cb5beabe1b75f62fa454d164c837122f Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Tue, 28 Feb 2017 13:12:01 +0000 Subject: Declare render logging categories to log warnings and above Change-Id: I2b6414c3b73969e06914468f6d6204e550f22a49 Reviewed-by: Mike Krus --- src/render/renderlogging.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/render/renderlogging.cpp b/src/render/renderlogging.cpp index 820392b68..b9d423163 100644 --- a/src/render/renderlogging.cpp +++ b/src/render/renderlogging.cpp @@ -45,17 +45,17 @@ namespace Qt3DRender { namespace Render { -Q_LOGGING_CATEGORY(Backend, "Qt3D.Renderer.Backend") -Q_LOGGING_CATEGORY(Frontend, "Qt3D.Renderer.Frontend") -Q_LOGGING_CATEGORY(Io, "Qt3D.Renderer.IO") -Q_LOGGING_CATEGORY(Jobs, "Qt3D.Renderer.Jobs") -Q_LOGGING_CATEGORY(Framegraph, "Qt3D.Renderer.Framegraph") -Q_LOGGING_CATEGORY(RenderNodes, "Qt3D.Renderer.RenderNodes") -Q_LOGGING_CATEGORY(Rendering, "Qt3D.Renderer.Rendering") -Q_LOGGING_CATEGORY(Memory, "Qt3D.Renderer.Memory") -Q_LOGGING_CATEGORY(Shaders, "Qt3D.Renderer.Shaders") -Q_LOGGING_CATEGORY(RenderStates, "Qt3D.Renderer.RenderStates") -Q_LOGGING_CATEGORY(VSyncAdvanceService, "Qt3D.Renderer.VsyncAdvanceService") +Q_LOGGING_CATEGORY(Backend, "Qt3D.Renderer.Backend", QtWarningMsg) +Q_LOGGING_CATEGORY(Frontend, "Qt3D.Renderer.Frontend", QtWarningMsg) +Q_LOGGING_CATEGORY(Io, "Qt3D.Renderer.IO", QtWarningMsg) +Q_LOGGING_CATEGORY(Jobs, "Qt3D.Renderer.Jobs", QtWarningMsg) +Q_LOGGING_CATEGORY(Framegraph, "Qt3D.Renderer.Framegraph", QtWarningMsg) +Q_LOGGING_CATEGORY(RenderNodes, "Qt3D.Renderer.RenderNodes", QtWarningMsg) +Q_LOGGING_CATEGORY(Rendering, "Qt3D.Renderer.Rendering", QtWarningMsg) +Q_LOGGING_CATEGORY(Memory, "Qt3D.Renderer.Memory", QtWarningMsg) +Q_LOGGING_CATEGORY(Shaders, "Qt3D.Renderer.Shaders", QtWarningMsg) +Q_LOGGING_CATEGORY(RenderStates, "Qt3D.Renderer.RenderStates", QtWarningMsg) +Q_LOGGING_CATEGORY(VSyncAdvanceService, "Qt3D.Renderer.VsyncAdvanceService", QtWarningMsg) } // namespace Render -- cgit v1.2.3 From bac5181c60690cfe85d69de74153137713219a65 Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Tue, 28 Feb 2017 13:26:32 +0000 Subject: Add script for blender to export animations for Qt 3D Change-Id: Icfcdaf52fb619d76e0edbca47995bc9028952dea Reviewed-by: Mike Krus --- .../exporters/blender/qt3d_animation_export.py | 433 +++++++++++++++++++++ 1 file changed, 433 insertions(+) create mode 100644 tools/utils/exporters/blender/qt3d_animation_export.py diff --git a/tools/utils/exporters/blender/qt3d_animation_export.py b/tools/utils/exporters/blender/qt3d_animation_export.py new file mode 100644 index 000000000..2d6575198 --- /dev/null +++ b/tools/utils/exporters/blender/qt3d_animation_export.py @@ -0,0 +1,433 @@ +############################################################################# +## +## Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the Qt3D module of the Qt Toolkit. +## +## $QT_BEGIN_LICENSE:LGPL$ +## 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 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.LGPL3 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-3.0.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 (at your option) the GNU General +## Public license version 3 or any later version approved by the KDE Free +## Qt Foundation. The licenses are as published by the Free Software +## Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +## 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-2.0.html and +## https://www.gnu.org/licenses/gpl-3.0.html. +## +## $QT_END_LICENSE$ +## +############################################################################# + +# Required Blender information. +bl_info = { + "name": "Qt3D Animation Exporter", + "author": "Sean Harmer , Paul Lemire ", + "version": (0, 4), + "blender": (2, 72, 0), + "location": "File > Export > Qt3D Animation (.json)", + "description": "Export animations to json to use with Qt3D", + "warning": "", + "wiki_url": "", + "tracker_url": "", + "category": "Import-Export" + } + +import bpy +import os +import struct +import mathutils +import math +import json +from array import array +from bpy_extras.io_utils import ExportHelper +from bpy.props import ( + BoolProperty, + FloatProperty, + StringProperty, + EnumProperty, + ) +from collections import defaultdict + +def frameToTime(frame): + # Get the fps to convert from frame number to time in seconds for x values + fps = bpy.context.scene.render.fps + + # Calculate time, remembering that blender uses 1-based frame numbers + return (frame - 1) / fps; + +def findResolvingObject(rootId): + if rootId == "OBJECT": + return bpy.data.objects[0] + elif rootId == "MATERIAL": + return bpy.data.materials[0] + return None + +# Note that we swap the Y and Z components because blender uses Z-up +# whereas Qt 3D tends to use Y-Up convention. +def arrayIndexFromTypeAndIndex(dataPath, index): + if dataPath.startswith("rotation"): + # Swap Y and Z components of rotations + if index == 2: + return 3 + elif index == 3: + return 2 + elif dataPath.startswith("location"): + # Swap Y and Z components of locations + if index == 1: + return 2 + elif index == 2: + return 1 + + # Otherwise keep the original index + return index + +def componentSuffix(typeName, componentIndex): + vectorComponents = ["X", "Y", "Z", "W"] + quaternionComponents = ["W", "X", "Y", "Z"] + colorComponents = ["R", "G", "B"] + + if typeName == "Vector": + return vectorComponents[componentIndex] + elif typeName == "Quaternion": + return quaternionComponents[componentIndex] + elif typeName == "Color": + return colorComponents[componentIndex] + return "Unknown" + +def resolveDataType(object, dataPath): + value = object.path_resolve(dataPath) + if isinstance(value, mathutils.Vector): + return "Vector" + elif isinstance(value, mathutils.Quaternion): + return "Quaternion" + elif isinstance(value, mathutils.Euler): + return "Euler" + value.order + elif isinstance(value, mathutils.Color): + return "Color" + return "Unknown type" + +class PropertyData: + m_action = None + m_name = "" + m_resolverObject = None + m_dataPath = "" + m_fcurveIndices = [] + m_componentIndices = [] + m_dataType = "" + m_outputDataType = "" + m_outputChannelCount = 0 + m_outputChannelSuffixes = [] + + def __init__(self): + self.m_action = None + self.m_resolverObject = None + self.m_dataPath = "" + self.m_fcurveIndices = [] + self.m_componentIndices = [] + self.m_dataType = "" + self.m_outputDataType = "" + self.m_outputChannelCount = 0 + self.m_outputChannelSuffixes = [] + + def setDataPath(self, dataPath): + self.m_dataPath = dataPath + if dataPath.startswith("rotation"): + self.m_name = "Rotation" + else: + self.m_name = dataPath.title() + self.m_name = self.m_name.replace("_", " ") + + def print(self): + print("Action = " + self.m_action.name \ + + "DataPath = " + self.m_dataPath \ + + "Name = " + self.m_name) + # + "fcurve indices =" + self.m_componentIndices + + def generateKeyframesData(self, outputComponentIndex): + outputKeyframes = [] + + # Lookup fcurve index for this component + fcurveIndex = self.m_fcurveIndices[outputComponentIndex] + + # Invert the sign of the 2nd component of quaternions for rotations + # We already swap the Y and Z components in the componentSuffix function + axisOrientationfactor = 1.0 + if self.m_name == "Rotation" and outputComponentIndex == 2: + axisOrientationfactor = -1.0 + + if self.m_dataType == self.m_outputDataType: + # We can take easy route if no data type conversion is needed + # Iterate over keyframes + fcurve = self.m_action.fcurves[fcurveIndex] + for keyframe in fcurve.keyframe_points: + outputKeyframe = { \ + "coords": [frameToTime(keyframe.co.x), axisOrientationfactor * keyframe.co.y], \ + "leftHandle": [frameToTime(keyframe.handle_left.x), axisOrientationfactor * keyframe.handle_left.y], \ + "rightHandle": [frameToTime(keyframe.handle_right.x), axisOrientationfactor * keyframe.handle_right.y] } + outputKeyframes.append(outputKeyframe) + else: + # Iterate over keyframes - we assume that all channels were keyed at the same times + # This is usually the case as blender doesn't support keying individual components + # but a user could have tweaked the individual channels + fcurve = self.m_action.fcurves[self.m_fcurveIndices[0]] + for keyframeIndex, keyframe in enumerate(fcurve.keyframe_points): + # Get data for this property + if not self.m_dataType.startswith("Euler"): + print("Unhandled data type conversion") + return None + + # Convert the control point to a quaternion + eulerOrder = self.m_dataType[-3:] + time_co = frameToTime(self.m_action.fcurves[self.m_fcurveIndices[0]].keyframe_points[keyframeIndex].co.x) + rotX = self.m_action.fcurves[self.m_fcurveIndices[0]].keyframe_points[keyframeIndex].co.y + rotY = self.m_action.fcurves[self.m_fcurveIndices[1]].keyframe_points[keyframeIndex].co.y + rotZ = self.m_action.fcurves[self.m_fcurveIndices[2]].keyframe_points[keyframeIndex].co.y + euler = mathutils.Euler((rotX, rotY, rotZ), eulerOrder) + q_co = euler.to_quaternion() + + # Convert the left handle to a quaternion + time_hl = frameToTime(self.m_action.fcurves[self.m_fcurveIndices[0]].keyframe_points[keyframeIndex].handle_left.x) + rotX = self.m_action.fcurves[self.m_fcurveIndices[0]].keyframe_points[keyframeIndex].handle_left.y + rotY = self.m_action.fcurves[self.m_fcurveIndices[1]].keyframe_points[keyframeIndex].handle_left.y + rotZ = self.m_action.fcurves[self.m_fcurveIndices[2]].keyframe_points[keyframeIndex].handle_left.y + euler = mathutils.Euler((rotX, rotY, rotZ), eulerOrder) + q_hl = euler.to_quaternion() + + # Convert the right handle to a quaternion + time_hr = frameToTime(self.m_action.fcurves[self.m_fcurveIndices[0]].keyframe_points[keyframeIndex].handle_left.x) + rotX = self.m_action.fcurves[self.m_fcurveIndices[0]].keyframe_points[keyframeIndex].handle_left.y + rotY = self.m_action.fcurves[self.m_fcurveIndices[1]].keyframe_points[keyframeIndex].handle_left.y + rotZ = self.m_action.fcurves[self.m_fcurveIndices[2]].keyframe_points[keyframeIndex].handle_left.y + euler = mathutils.Euler((rotX, rotY, rotZ), eulerOrder) + q_hr = euler.to_quaternion() + + # Extract the corresponding component + co = [] + handle_left = [] + handle_right = [] + if outputComponentIndex == 0: + co = [time_co, axisOrientationfactor * q_co.w] + handle_left = [time_hl, axisOrientationfactor * q_hl.w] + handle_right = [time_hr, axisOrientationfactor * q_hr.w] + elif outputComponentIndex == 1: + co = [time_co, axisOrientationfactor * q_co.x] + handle_left = [time_hl, axisOrientationfactor * q_hl.x] + handle_right = [time_hr, axisOrientationfactor * q_hr.x] + elif outputComponentIndex == 2: + co = [time_co, axisOrientationfactor * q_co.y] + handle_left = [time_hl, axisOrientationfactor * q_hl.y] + handle_right = [time_hr, axisOrientationfactor * q_hr.y] + elif outputComponentIndex == 3: + co = [time_co, axisOrientationfactor * q_co.z] + handle_left = [time_hl, axisOrientationfactor * q_hl.z] + handle_right = [time_hr, axisOrientationfactor * q_hr.z] + + outputKeyframe = { \ + "coords": co, \ + "leftHandle": handle_left, \ + "rightHandle": handle_right } + outputKeyframes.append(outputKeyframe) + return outputKeyframes + + def generateChannelComponentsData(self): + # First find the data type stored in the blender file + self.m_dataType = resolveDataType(self.m_resolverObject, self.m_dataPath) + + # Convert this to an output data type - we force rotations as quaternions + if self.m_dataType.startswith("Euler"): + self.m_outputDataType = "Quaternion" + self.m_outputChannelCount = 4 + for i in range(0, 4): + index = arrayIndexFromTypeAndIndex(self.m_dataPath, i) + suffix = componentSuffix(self.m_outputDataType, index) + self.m_outputChannelSuffixes.append(suffix) + else: + self.m_outputDataType = self.m_dataType + self.m_outputChannelCount = len(self.m_componentIndices) + for i in self.m_componentIndices: + index = arrayIndexFromTypeAndIndex(self.m_dataPath, i) + suffix = componentSuffix(self.m_outputDataType, index) + self.m_outputChannelSuffixes.append(suffix) + + outputChannels = [] + for i in range(0, self.m_outputChannelCount): + outputChannel = { "channelComponentName": self.m_name + " " + self.m_outputChannelSuffixes[i], "keyFrames": [] } + keyframes = self.generateKeyframesData(i) + outputChannel["keyFrames"] = keyframes + outputChannels.append(outputChannel) + + return outputChannels + + +class Qt3DAnimationConverter: + def animationsToJson(self): + propertyDataMap = defaultdict(list) + + # Pass 1 - collect data we need to produce the output in pass 2 + for action in bpy.data.actions: + groupCount = len(action.groups) + #print(" " + action.name + " for type " + action.id_root) + + # We need a datablock of the right type to be able to resolve an fcurve data path to a value. + # We need the value to be able to determine the type and eventually the correct name for the + # exported fcurve. + resolverObject = findResolvingObject(action.id_root) + + fcurveCount = len(action.fcurves) + #print(" " + action.name + " has " + str(fcurveCount) + " fcurves") + + if fcurveCount == 0: + break + + lastTitle = "" + property = PropertyData() + for fcurveIndex,fcurve in enumerate(action.fcurves): + title = fcurve.data_path.title() + + # For debugging + groupName = "" + if fcurve.group != None: + groupName = fcurve.group.name + dataPath = fcurve.data_path + type = resolveDataType(resolverObject, dataPath) + labelSuffix = componentSuffix("Vector", fcurve.array_index) + print(" " + str(fcurveIndex) + ": Group: " + groupName \ + + ", Title = " + title \ + + ", Component:" + str(fcurve.array_index) \ + + ", Data Path: " + dataPath \ + + ", Data Type: " + type \ + + ", Label: " + labelSuffix) + + # Create a new PropertyData if this fcurve is for a new property + if title != lastTitle: + property = PropertyData() + property.m_action = action + property.setDataPath(fcurve.data_path) + property.m_resolverObject = resolverObject + arrayIndex = arrayIndexFromTypeAndIndex(fcurve.data_path, fcurve.array_index) + property.m_componentIndices.append(arrayIndex) + #property.m_componentIndices.append(fcurve.array_index) + property.m_fcurveIndices.append(fcurveIndex) + propertyDataMap[action.name].append(property) + else: + property.m_componentIndices.append(fcurve.array_index) + property.m_fcurveIndices.append(fcurveIndex) + + lastTitle = title + print("") + + # For debugging + print("Pass 1 - Collected data for " + str(len(propertyDataMap)) + " actions") + actionIndex = 0 + for key in propertyDataMap: + print(str(actionIndex) + ": " + key + " has " + str(len(propertyDataMap[key])) + " properties") + for propertyIndex, property in enumerate(propertyDataMap[key]): + print(" " + str(propertyIndex) + ": " + property.m_name) + actionIndex = actionIndex + 1 + + # Pass 2 + + # The data structure that will be exported + output = {"animations": []} + + actionIndex = 0 + for key in propertyDataMap: + #print(str(actionIndex) + ": " + key) + + # Create an output action + outputAction = { "animationName": key, "channels": []} + for propertyIndex, property in enumerate(propertyDataMap[key]): + #print(" " + str(propertyIndex) + ": " + property.m_name) + + # Create an output group and append it to the output action + outputGroup = { "channelComponents": [], "channelName": property.m_name } + + # Populate the channels list from the property object + outputChannels = property.generateChannelComponentsData() + outputGroup["channelComponents"] = outputChannels + + outputAction["channels"].append(outputGroup) + + output["animations"].append(outputAction) + actionIndex = actionIndex + 1 + + jsonData = json.dumps(output, indent=2, sort_keys=True, separators=(',', ': ')) + return jsonData + + +class Qt3DExporter(bpy.types.Operator, ExportHelper): + """Qt3D Exporter""" + bl_idname = "export_scene.qt3d_exporter"; + bl_label = "Qt3DExporter"; + bl_options = {'PRESET'}; + + filename_ext = "" + use_filter_folder = True + + # TO DO: Handle properly + use_mesh_modifiers = BoolProperty( + name="Apply Modifiers", + description="Apply modifiers (preview resolution)", + default=True, + ) + + # TO DO: Handle properly + use_selection_only = BoolProperty( + name="Selection Only", + description="Only export select objects", + default=False, + ) + + def __init__(self): + pass + + def execute(self, context): + print("In Execute" + bpy.context.scene.name) + + self.userpath = self.properties.filepath + + # unselect all + bpy.ops.object.select_all(action='DESELECT') + + converter = Qt3DAnimationConverter() + fileContent = converter.animationsToJson() + with open(self.userpath + ".json", '+w') as f: + f.write(fileContent) + + return {'FINISHED'} + +def createBlenderMenu(self, context): + self.layout.operator(Qt3DExporter.bl_idname, text="Qt3D Animation(.json)") + +# Register against Blender +def register(): + bpy.utils.register_class(Qt3DExporter) + bpy.types.INFO_MT_file_export.append(createBlenderMenu) + +def unregister(): + bpy.utils.unregister_class(Qt3DExporter) + bpy.types.INFO_MT_file_export.remove(createBlenderMenu) + +# Handle running the script from Blender's text editor. +if (__name__ == "__main__"): + register(); + bpy.ops.export_scene.qt3d_exporter(); -- cgit v1.2.3 From 7cb291ba90cfb08053bba37ef6ff6b003900b501 Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Tue, 28 Feb 2017 17:02:54 +0000 Subject: Update naming of animation building blocks Rename: Groups -> Channels Channels -> ChannelComponents Update function and variable names accordingly. Also updated ChannelComponents to contain not only the component suffix to make them more readable in large files. Replaced animation clip in AnimationUtils unit test and adjusted suffix -> component index mapping code to use upper case. Will update clips in manual test in a follow up commit. Change-Id: If5ed565d57efbed07a4d6771336a14f6a4cddb65 Reviewed-by: Mike Krus --- src/animation/backend/animationcliploader.cpp | 49 ++++--- src/animation/backend/animationcliploader_p.h | 16 +-- src/animation/backend/animationutils.cpp | 47 +++--- src/animation/backend/animationutils_p.h | 16 +-- src/animation/backend/clipanimator_p.h | 2 +- src/animation/backend/fcurve.cpp | 26 ++-- src/animation/backend/fcurve_p.h | 22 +-- tests/auto/animation/animationutils/clip1.json | 157 +++++++++++++++------ .../animationutils/tst_animationutils.cpp | 4 +- 9 files changed, 202 insertions(+), 137 deletions(-) diff --git a/src/animation/backend/animationcliploader.cpp b/src/animation/backend/animationcliploader.cpp index 88d615a04..259ce6b24 100644 --- a/src/animation/backend/animationcliploader.cpp +++ b/src/animation/backend/animationcliploader.cpp @@ -58,7 +58,7 @@ AnimationClipLoader::AnimationClipLoader() , m_status(QAnimationClipLoader::NotReady) , m_name() , m_objectName() - , m_channelGroups() + , m_channels() , m_duration(0.0f) { } @@ -78,7 +78,7 @@ void AnimationClipLoader::cleanup() m_handler = nullptr; m_source.clear(); m_status = QAnimationClipLoader::NotReady; - m_channelGroups.clear(); + m_channels.clear(); m_duration = 0.0f; clearData(); @@ -141,26 +141,25 @@ void AnimationClipLoader::loadAnimation() qCDebug(Jobs) << "Found" << animationsArray.size() << "animations:"; for (int i = 0; i < animationsArray.size(); ++i) { QJsonObject animation = animationsArray.at(i).toObject(); - qCDebug(Jobs) << "\tName:" << animation[QLatin1String("action")].toString() - << "Object:" << animation[QLatin1String("object")].toString(); + qCDebug(Jobs) << "Animation Name:" << animation[QLatin1String("animationName")].toString(); } // For now just load the first animation + // TODO: Allow loading a named animation from within the file analogous to QMesh QJsonObject animation = animationsArray.at(0).toObject(); - m_name = animation[QLatin1String("action")].toString(); - m_objectName = animation[QLatin1String("object")].toString(); - QJsonArray groupsArray = animation[QLatin1String("groups")].toArray(); - const int groupCount = groupsArray.size(); - m_channelGroups.resize(groupCount); - for (int i = 0; i < groupCount; ++i) { - const QJsonObject group = groupsArray.at(i).toObject(); - m_channelGroups[i].read(group); + m_name = animation[QLatin1String("animationName")].toString(); + QJsonArray channelsArray = animation[QLatin1String("channels")].toArray(); + const int channelCount = channelsArray.size(); + m_channels.resize(channelCount); + for (int i = 0; i < channelCount; ++i) { + const QJsonObject group = channelsArray.at(i).toObject(); + m_channels[i].read(group); } const float t = findDuration(); setDuration(t); - m_channelCount = findChannelCount(); + m_channelCount = findChannelComponentCount(); if (qFuzzyIsNull(t) || m_channelCount == 0) setStatus(QAnimationClipLoader::Error); @@ -188,18 +187,18 @@ void AnimationClipLoader::setDuration(float duration) /*! \internal - Given the index of a channel group, \a channelGroupIndex, calculates - the base index of the first channel in this group. For example, if + Given the index of a channel, \a channelIndex, calculates + the base index of the first channelComponent in this group. For example, if there are two channel groups each with 3 channels and you request the channelBaseIndex(1), the return value will be 3. Indices 0-2 are for the first group, so the first channel of the second group occurs at index 3. */ -int AnimationClipLoader::channelBaseIndex(int channelGroupIndex) const +int AnimationClipLoader::channelComponentBaseIndex(int channelIndex) const { int index = 0; - for (int i = 0; i < channelGroupIndex; ++i) - index += m_channelGroups[i].channels.size(); + for (int i = 0; i < channelIndex; ++i) + index += m_channels[i].channelComponents.size(); return index; } @@ -207,16 +206,16 @@ void AnimationClipLoader::clearData() { m_name.clear(); m_objectName.clear(); - m_channelGroups.clear(); + m_channels.clear(); } float AnimationClipLoader::findDuration() { // Iterate over the contained fcurves and find the longest one double tMax = 0.0; - for (const ChannelGroup &channelGroup : qAsConst(m_channelGroups)) { - for (const Channel &channel : qAsConst(channelGroup.channels)) { - const float t = channel.fcurve.endTime(); + for (const Channel &channel : qAsConst(m_channels)) { + for (const ChannelComponent &channelComponent : qAsConst(channel.channelComponents)) { + const float t = channelComponent.fcurve.endTime(); if (t > tMax) tMax = t; } @@ -224,11 +223,11 @@ float AnimationClipLoader::findDuration() return tMax; } -int AnimationClipLoader::findChannelCount() +int AnimationClipLoader::findChannelComponentCount() { int channelCount = 0; - for (const ChannelGroup &channelGroup : qAsConst(m_channelGroups)) - channelCount += channelGroup.channels.size(); + for (const Channel &channel : qAsConst(m_channels)) + channelCount += channel.channelComponents.size(); return channelCount; } diff --git a/src/animation/backend/animationcliploader_p.h b/src/animation/backend/animationcliploader_p.h index cca624605..b1cf61430 100644 --- a/src/animation/backend/animationcliploader_p.h +++ b/src/animation/backend/animationcliploader_p.h @@ -74,27 +74,27 @@ public: QString name() const { return m_name; } QString objectName() const { return m_objectName; } - const QVector &channelGroups() const { return m_channelGroups; } + const QVector &channels() const { return m_channels; } // Called from jobs void loadAnimation(); void setDuration(float duration); float duration() const { return m_duration; } int channelCount() const { return m_channelCount; } - int channelBaseIndex(int channelGroupIndex) const; + int channelComponentBaseIndex(int channelGroupIndex) const; private: void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL; void clearData(); float findDuration(); - int findChannelCount(); + int findChannelComponentCount(); QUrl m_source; QAnimationClipLoader::Status m_status; QString m_name; QString m_objectName; - QVector m_channelGroups; + QVector m_channels; float m_duration; int m_channelCount; }; @@ -107,11 +107,11 @@ inline QDebug operator<<(QDebug dbg, const AnimationClipLoader &animationClip) << "Name =" << animationClip.name() << endl << "Object Name =" << animationClip.objectName() << endl << "Duration: " << animationClip.duration() << endl - << "Channel Groups:" << endl; + << "Channels:" << endl; - const QVector channelGroups = animationClip.channelGroups(); - for (const auto channelGroup : channelGroups) { - dbg << channelGroup; + const QVector channels = animationClip.channels(); + for (const auto channel : channels) { + dbg << channel; } return dbg; diff --git a/src/animation/backend/animationutils.cpp b/src/animation/backend/animationutils.cpp index d2d7313ab..85fbab42a 100644 --- a/src/animation/backend/animationutils.cpp +++ b/src/animation/backend/animationutils.cpp @@ -103,27 +103,27 @@ double AnimationUtils::localTimeFromGlobalTime(double t_global, return t_local; } -QVector AnimationUtils::channelsToIndices(const ChannelGroup &channelGroup, int dataType, int offset) +QVector AnimationUtils::channelComponentsToIndices(const Channel &channelGroup, int dataType, int offset) { static const QStringList standardSuffixes = (QStringList() - << QLatin1String("x") - << QLatin1String("y") - << QLatin1String("z") - << QLatin1String("w")); + << QLatin1String("X") + << QLatin1String("Y") + << QLatin1String("Z") + << QLatin1String("W")); static const QStringList quaternionSuffixes = (QStringList() - << QLatin1String("w") - << QLatin1String("x") - << QLatin1String("y") - << QLatin1String("z")); + << QLatin1String("W") + << QLatin1String("X") + << QLatin1String("Y") + << QLatin1String("Z")); if (dataType != QVariant::Quaternion) - return channelsToIndicesHelper(channelGroup, dataType, offset, standardSuffixes); + return channelComponentsToIndicesHelper(channelGroup, dataType, offset, standardSuffixes); else - return channelsToIndicesHelper(channelGroup, dataType, offset, quaternionSuffixes); + return channelComponentsToIndicesHelper(channelGroup, dataType, offset, quaternionSuffixes); } -QVector AnimationUtils::channelsToIndicesHelper(const ChannelGroup &channelGroup, int dataType, int offset, const QStringList &suffixes) +QVector AnimationUtils::channelComponentsToIndicesHelper(const Channel &channel, int dataType, int offset, const QStringList &suffixes) { int expectedChannelCount = 1; switch (dataType) { @@ -148,7 +148,7 @@ QVector AnimationUtils::channelsToIndicesHelper(const ChannelGroup &channel qWarning() << "Unhandled animation type"; } - const int foundChannelCount = channelGroup.channels.size(); + const int foundChannelCount = channel.channelComponents.size(); if (foundChannelCount != expectedChannelCount) { qWarning() << "Data type expects" << expectedChannelCount << "but found" << foundChannelCount << "channels in the animation clip"; @@ -156,7 +156,8 @@ QVector AnimationUtils::channelsToIndicesHelper(const ChannelGroup &channel QVector indices(expectedChannelCount); for (int i = 0; i < expectedChannelCount; ++i) { - int index = suffixes.indexOf(channelGroup.channels[i].name); + const QString channelComponentSuffix = channel.channelComponents[i].name.right(1); + int index = suffixes.indexOf(channelComponentSuffix); if (index != -1) indices[i] = index + offset; else @@ -174,11 +175,11 @@ QVector AnimationUtils::evaluateClipAtLocalTime(AnimationClipLoader *clip channelResults.resize(clip->channelCount()); // Iterate over channels and evaluate the fcurves - const QVector &channelGroups = clip->channelGroups(); + const QVector &channels = clip->channels(); int i = 0; - for (const ChannelGroup &channelGroup : channelGroups) { - for (const auto channel : qAsConst(channelGroup.channels)) - channelResults[i++] = channel.fcurve.evaluateAtTime(localTime); + for (const Channel &channel : channels) { + for (const auto channelComponent : qAsConst(channel.channelComponents)) + channelResults[i++] = channelComponent.fcurve.evaluateAtTime(localTime); } return channelResults; } @@ -269,7 +270,7 @@ QVector AnimationUtils::buildPropertyMappings(Handl { QVector mappingDataVec; ChannelMappingManager *mappingManager = handler->channelMappingManager(); - const QVector &channelGroups = clip->channelGroups(); + const QVector &channels = clip->channels(); // Iterate over the mappings in the mapper object for (const Qt3DCore::QNodeId mappingId : mapper->mappingIds()) { @@ -294,13 +295,13 @@ QVector AnimationUtils::buildPropertyMappings(Handl const QString channelName = mapping->channelName(); int channelGroupIndex = 0; bool foundMatch = false; - for (const ChannelGroup &channelGroup : channelGroups) { - if (channelGroup.name == channelName) { + for (const Channel &channel : channels) { + if (channel.name == channelName) { foundMatch = true; - const int channelBaseIndex = clip->channelBaseIndex(channelGroupIndex); + const int channelBaseIndex = clip->channelComponentBaseIndex(channelGroupIndex); // Within this group, match channel names with index ordering - mappingData.channelIndices = channelsToIndices(channelGroup, mappingData.type, channelBaseIndex); + mappingData.channelIndices = channelComponentsToIndices(channel, mappingData.type, channelBaseIndex); // Store the mapping data mappingDataVec.push_back(mappingData); diff --git a/src/animation/backend/animationutils_p.h b/src/animation/backend/animationutils_p.h index d88492e98..cb8014e7b 100644 --- a/src/animation/backend/animationutils_p.h +++ b/src/animation/backend/animationutils_p.h @@ -57,7 +57,7 @@ QT_BEGIN_NAMESPACE namespace Qt3DAnimation { namespace Animation { -struct ChannelGroup; +struct Channel; class Handler; class AnimationClipLoader; class ChannelMapper; @@ -114,13 +114,13 @@ public: static ClipPreEvaluationData evaluationDataForClip(AnimationClipLoader *clip, const AnimatorEvaluationData &animatorData); - static QVector channelsToIndices(const ChannelGroup &channelGroup, - int dataType, - int offset = 0); - static QVector channelsToIndicesHelper(const ChannelGroup &channelGroup, - int dataType, - int offset, - const QStringList &suffixes); + static QVector channelComponentsToIndices(const Channel &channelGroup, + int dataType, + int offset = 0); + static QVector channelComponentsToIndicesHelper(const Channel &channelGroup, + int dataType, + int offset, + const QStringList &suffixes); static QVector evaluateClipAtLocalTime(AnimationClipLoader *clip, float localTime); static QVector preparePropertyChanges(Qt3DCore::QNodeId peerId, diff --git a/src/animation/backend/clipanimator_p.h b/src/animation/backend/clipanimator_p.h index f182920b1..b896bc7f1 100644 --- a/src/animation/backend/clipanimator_p.h +++ b/src/animation/backend/clipanimator_p.h @@ -57,7 +57,7 @@ QT_BEGIN_NAMESPACE namespace Qt3DAnimation { namespace Animation { -struct ChannelGroup; +struct Channel; class Handler; class Q_AUTOTEST_EXPORT ClipAnimator : public BackendNode diff --git a/src/animation/backend/fcurve.cpp b/src/animation/backend/fcurve.cpp index ce16fb429..39a7e8bff 100644 --- a/src/animation/backend/fcurve.cpp +++ b/src/animation/backend/fcurve.cpp @@ -92,25 +92,25 @@ void FCurve::read(const QJsonObject &json) { clearKeyframes(); - const QJsonArray keyframeArray = json[QLatin1String("keyframes")].toArray(); + const QJsonArray keyframeArray = json[QLatin1String("keyFrames")].toArray(); const int keyframeCount = keyframeArray.size(); for (int i = 0; i < keyframeCount; ++i) { const QJsonObject keyframeData = keyframeArray.at(i).toObject(); // Extract the keyframe local time and value - const QJsonArray keyframeCoords = keyframeData[QLatin1String("co")].toArray(); + const QJsonArray keyframeCoords = keyframeData[QLatin1String("coords")].toArray(); float localTime = keyframeCoords.at(0).toDouble(); Keyframe keyframe; keyframe.interpolation = Keyframe::Bezier; keyframe.value = keyframeCoords.at(1).toDouble(); - const QJsonArray leftHandle = keyframeData[QLatin1String("handle_left")].toArray(); + const QJsonArray leftHandle = keyframeData[QLatin1String("leftHandle")].toArray(); keyframe.leftControlPoint[0] = leftHandle.at(0).toDouble(); keyframe.leftControlPoint[1] = leftHandle.at(1).toDouble(); - const QJsonArray rightHandle = keyframeData[QLatin1String("handle_right")].toArray(); + const QJsonArray rightHandle = keyframeData[QLatin1String("rightHandle")].toArray(); keyframe.rightControlPoint[0] = rightHandle.at(0).toDouble(); keyframe.rightControlPoint[1] = rightHandle.at(1).toDouble(); @@ -121,22 +121,22 @@ void FCurve::read(const QJsonObject &json) // back so they do not interset. } -void Channel::read(const QJsonObject &json) +void ChannelComponent::read(const QJsonObject &json) { - name = json[QLatin1String("name")].toString(); + name = json[QLatin1String("channelComponentName")].toString(); fcurve.read(json); } -void ChannelGroup::read(const QJsonObject &json) +void Channel::read(const QJsonObject &json) { - name = json[QLatin1String("group")].toString(); - const QJsonArray channelsArray = json[QLatin1String("channels")].toArray(); - const int channelCount = channelsArray.size(); - channels.resize(channelCount); + name = json[QLatin1String("channelName")].toString(); + const QJsonArray channelComponentsArray = json[QLatin1String("channelComponents")].toArray(); + const int channelCount = channelComponentsArray.size(); + channelComponents.resize(channelCount); for (int i = 0; i < channelCount; ++i) { - const QJsonObject channel = channelsArray.at(i).toObject(); - channels[i].read(channel); + const QJsonObject channel = channelComponentsArray.at(i).toObject(); + channelComponents[i].read(channel); } } diff --git a/src/animation/backend/fcurve_p.h b/src/animation/backend/fcurve_p.h index def33941e..a3cb2f0b9 100644 --- a/src/animation/backend/fcurve_p.h +++ b/src/animation/backend/fcurve_p.h @@ -106,7 +106,7 @@ inline QDebug operator<<(QDebug dbg, const FCurve &fcurve) } #endif -struct Channel +struct ChannelComponent { QString name; FCurve fcurve; @@ -115,32 +115,32 @@ struct Channel }; #ifndef QT_NO_DEBUG_STREAM -inline QDebug operator<<(QDebug dbg, const Channel &channel) +inline QDebug operator<<(QDebug dbg, const ChannelComponent &channelComponent) { QDebugStateSaver saver(dbg); - dbg << "Channel Name: " << channel.name << endl - << "Fcurve:" << channel.fcurve << endl; + dbg << "Channel Component Name: " << channelComponent.name << endl + << "FCurve:" << channelComponent.fcurve << endl; return dbg; } #endif -struct ChannelGroup +struct Channel { QString name; - QVector channels; + QVector channelComponents; void read(const QJsonObject &json); }; #ifndef QT_NO_DEBUG_STREAM -inline QDebug operator<<(QDebug dbg, const ChannelGroup &channelGroup) +inline QDebug operator<<(QDebug dbg, const Channel &channel) { QDebugStateSaver saver(dbg); - dbg << "Name: " << channelGroup.name << endl - << "Channels:" << channelGroup.channels.size() << endl; + dbg << "Channel Name: " << channel.name << endl + << "Channels:" << channel.channelComponents.size() << endl; - for (const auto channel : qAsConst(channelGroup.channels)) { - dbg << channel; + for (const auto channelComponent : qAsConst(channel.channelComponents)) { + dbg << channelComponent; } return dbg; } diff --git a/tests/auto/animation/animationutils/clip1.json b/tests/auto/animation/animationutils/clip1.json index e54858a2d..8fa382589 100644 --- a/tests/auto/animation/animationutils/clip1.json +++ b/tests/auto/animation/animationutils/clip1.json @@ -1,48 +1,113 @@ { "animations": [ - { "object": "Cube", - "action": "CubeAction", - "range": [0.0, 60.0], - "groups": [ - { "group": "channelFoo", - "channels": [ - { "name": "x", - "keyframes": [ - { "co": [0.0, 0.0], - "handle_left": [-0.4717472394307454, 0.0], - "handle_right": [0.4717472394307454, 0.0]} - ,{ "co": [1.2083333333333333, 2.430499792098999], - "handle_left": [0.7365860939025879, 1.4711904525756836], - "handle_right": [1.696347713470459, 3.42288875579834]} - ,{ "co": [2.4583333333333335, 5.0], - "handle_left": [1.9703189531962078, 5.0], - "handle_right": [2.9463475545247397, 5.0]} - ]} - ,{ "name": "y", - "keyframes": [ - { "co": [0.0, 0.0], - "handle_left": [-0.4717472394307454, 0.0], - "handle_right": [0.4717472394307454, 0.0]} - ,{ "co": [1.2083333333333333, 3.0], - "handle_left": [0.7365860939025879, 3.0], - "handle_right": [1.696347713470459, 3.0]} - ,{ "co": [2.4583333333333335, 0.0], - "handle_left": [1.9703189531962078, 0.0], - "handle_right": [2.9463475545247397, 0.0]} - ]} - ,{ "name": "z", - "keyframes": [ - { "co": [0.0, 0.0], - "handle_left": [-0.4717472394307454, 0.0], - "handle_right": [0.4717472394307454, 0.0]} - ,{ "co": [1.2083333333333333, 0.0], - "handle_left": [0.7365860939025879, 0.0], - "handle_right": [1.696347713470459, 0.0]} - ,{ "co": [2.4583333333333335, 0.0], - "handle_left": [1.9703189531962078, 0.0], - "handle_right": [2.9463475545247397, 0.0]} - ]} - ]} - ]} - ] -} + { + "animationName": "CubeAction", + "channels": [ + { + "channelComponents": [ + { + "channelComponentName": "Location X", + "keyFrames": [ + { + "coords": [ + 0.0, + 0.0 + ], + "leftHandle": [ + -0.9597616195678711, + 0.0 + ], + "rightHandle": [ + 0.9597616195678711, + 0.0 + ] + }, + { + "coords": [ + 2.4583333333333335, + 5.0 + ], + "leftHandle": [ + 1.4985717137654622, + 5.0 + ], + "rightHandle": [ + 3.4180949529012046, + 5.0 + ] + } + ] + }, + { + "channelComponentName": "Location Y", + "keyFrames": [ + { + "coords": [ + 0.0, + 0.0 + ], + "leftHandle": [ + -0.9597616195678711, + 0.0 + ], + "rightHandle": [ + 0.9597616195678711, + 0.0 + ] + }, + { + "coords": [ + 2.4583333333333335, + 0.0 + ], + "leftHandle": [ + 1.4985717137654622, + 0.0 + ], + "rightHandle": [ + 3.4180949529012046, + 0.0 + ] + } + ] + }, + { + "channelComponentName": "Location Z", + "keyFrames": [ + { + "coords": [ + 0.0, + 0.0 + ], + "leftHandle": [ + -0.9597616195678711, + 0.0 + ], + "rightHandle": [ + 0.9597616195678711, + 0.0 + ] + }, + { + "coords": [ + 2.4583333333333335, + 0.0 + ], + "leftHandle": [ + 1.4985717137654622, + 0.0 + ], + "rightHandle": [ + 3.4180949529012046, + 0.0 + ] + } + ] + } + ], + "channelName": "Location" + } + ] + } + ] +} \ No newline at end of file diff --git a/tests/auto/animation/animationutils/tst_animationutils.cpp b/tests/auto/animation/animationutils/tst_animationutils.cpp index e4170381e..0981f2590 100644 --- a/tests/auto/animation/animationutils/tst_animationutils.cpp +++ b/tests/auto/animation/animationutils/tst_animationutils.cpp @@ -55,8 +55,8 @@ private Q_SLOTS: auto targetId = Qt3DCore::QNodeId::createId(); channelMapping->setTargetId(targetId); - channelMapping->setProperty("foo"); - channelMapping->setChannelName("channelFoo"); + channelMapping->setProperty("translation"); + channelMapping->setChannelName("Location"); channelMapping->setType(static_cast(QVariant::Vector3D)); // Create a channel mapper and add mapping to it -- cgit v1.2.3 From f2b06f224127b9f0291084e3010cc5b5d03c4487 Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Tue, 28 Feb 2017 18:54:15 +0000 Subject: Remove unneeded AnimationClipLoader::m_objectName No need to relate a clip directly to an object name as we have the QChannelMapper/QChannelMapping types for that task. Change-Id: I5b6410e96c729b66ed51797ea2bbcf2ae7e6919d Reviewed-by: Mike Krus --- src/animation/backend/animationcliploader.cpp | 2 -- src/animation/backend/animationcliploader_p.h | 3 --- 2 files changed, 5 deletions(-) diff --git a/src/animation/backend/animationcliploader.cpp b/src/animation/backend/animationcliploader.cpp index 259ce6b24..8db7ba89a 100644 --- a/src/animation/backend/animationcliploader.cpp +++ b/src/animation/backend/animationcliploader.cpp @@ -57,7 +57,6 @@ AnimationClipLoader::AnimationClipLoader() , m_source() , m_status(QAnimationClipLoader::NotReady) , m_name() - , m_objectName() , m_channels() , m_duration(0.0f) { @@ -205,7 +204,6 @@ int AnimationClipLoader::channelComponentBaseIndex(int channelIndex) const void AnimationClipLoader::clearData() { m_name.clear(); - m_objectName.clear(); m_channels.clear(); } diff --git a/src/animation/backend/animationcliploader_p.h b/src/animation/backend/animationcliploader_p.h index b1cf61430..557d7bb9b 100644 --- a/src/animation/backend/animationcliploader_p.h +++ b/src/animation/backend/animationcliploader_p.h @@ -73,7 +73,6 @@ public: void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_OVERRIDE; QString name() const { return m_name; } - QString objectName() const { return m_objectName; } const QVector &channels() const { return m_channels; } // Called from jobs @@ -93,7 +92,6 @@ private: QAnimationClipLoader::Status m_status; QString m_name; - QString m_objectName; QVector m_channels; float m_duration; int m_channelCount; @@ -105,7 +103,6 @@ inline QDebug operator<<(QDebug dbg, const AnimationClipLoader &animationClip) QDebugStateSaver saver(dbg); dbg << "QNodeId =" << animationClip.peerId() << endl << "Name =" << animationClip.name() << endl - << "Object Name =" << animationClip.objectName() << endl << "Duration: " << animationClip.duration() << endl << "Channels:" << endl; -- cgit v1.2.3 From faa2db2dc1c654616ca5651cec4e57893774015e Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Wed, 1 Mar 2017 12:34:34 +0000 Subject: Factor out some helper functions in AnimationUtils test Will make it easier to write additional tests that create these backend nodes. Change-Id: Ie2ce4427b495847451974b079e513e134d069d11 Reviewed-by: Mike Krus --- .../animationutils/tst_animationutils.cpp | 59 ++++++++++++++++------ 1 file changed, 43 insertions(+), 16 deletions(-) diff --git a/tests/auto/animation/animationutils/tst_animationutils.cpp b/tests/auto/animation/animationutils/tst_animationutils.cpp index 0981f2590..a1b9e1e86 100644 --- a/tests/auto/animation/animationutils/tst_animationutils.cpp +++ b/tests/auto/animation/animationutils/tst_animationutils.cpp @@ -42,35 +42,62 @@ class tst_AnimationUtils : public Qt3DCore::QBackendNodeTester { Q_OBJECT -private Q_SLOTS: - void checkBuildPropertyMappings() +public: + ChannelMapping *createChannelMapping(Handler &handler, + const QString &channelName, + const Qt3DCore::QNodeId targetId, + const QString &propertyName, + int type) { - // GIVEN - Handler handler; - - // Create a channel mapping, set properties, and add it to manager auto channelMappingId = Qt3DCore::QNodeId::createId(); ChannelMapping *channelMapping = handler.channelMappingManager()->getOrCreateResource(channelMappingId); setPeerId(channelMapping, channelMappingId); - - auto targetId = Qt3DCore::QNodeId::createId(); channelMapping->setTargetId(targetId); - channelMapping->setProperty("translation"); - channelMapping->setChannelName("Location"); - channelMapping->setType(static_cast(QVariant::Vector3D)); + channelMapping->setProperty(propertyName); + channelMapping->setChannelName(channelName); + channelMapping->setType(type); + return channelMapping; + } - // Create a channel mapper and add mapping to it + ChannelMapper *createChannelMapper(Handler &handler, + const QVector &mappingIds) + { auto channelMapperId = Qt3DCore::QNodeId::createId(); ChannelMapper *channelMapper = handler.channelMapperManager()->getOrCreateResource(channelMapperId); setPeerId(channelMapper, channelMapperId); - channelMapper->setMappingIds(QVector() << channelMappingId); + channelMapper->setMappingIds(mappingIds); + return channelMapper; + } - // Create an animation clip + AnimationClipLoader *createAnimationClipLoader(Handler &handler, + const QUrl &source) + { auto clipId = Qt3DCore::QNodeId::createId(); AnimationClipLoader *clip = handler.animationClipLoaderManager()->getOrCreateResource(clipId); setPeerId(clip, clipId); - clip->setSource(QUrl("qrc:/clip1.json")); + clip->setSource(source); clip->loadAnimation(); + return clip; + } + +private Q_SLOTS: + void checkBuildPropertyMappings() + { + // GIVEN + Handler handler; + + // Create a channel mapping... + auto channelMapping = createChannelMapping(handler, + QLatin1String("Location"), + Qt3DCore::QNodeId::createId(), + QLatin1String("translation"), + static_cast(QVariant::Vector3D)); + + // ... a channel mapper... + auto channelMapper = createChannelMapper(handler, QVector() << channelMapping->peerId()); + + // ...and an animation clip + auto clip = createAnimationClipLoader(handler, QUrl("qrc:/clip1.json")); // WHEN // Build the mapping data for the above configuration @@ -80,7 +107,7 @@ private Q_SLOTS: QCOMPARE(mappingData.size(), channelMapper->mappingIds().size()); for (int i = 0; i < mappingData.size(); ++i) { const auto mapping = mappingData[i]; - QCOMPARE(mapping.targetId, targetId); + QCOMPARE(mapping.targetId, channelMapping->targetId()); QCOMPARE(mapping.propertyName, channelMapping->propertyName()); QCOMPARE(mapping.type, channelMapping->type()); QCOMPARE(mapping.channelIndices.size(), 3); -- cgit v1.2.3 From d024347bc358f8202465374ca3958738df580984 Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Thu, 2 Mar 2017 09:28:27 +0000 Subject: Refactor tst_animationutils to be data driven Will allow to easily add more tests for other animation clips and mapping configurations. Change-Id: Ib125106f838d2e36c3ffefe5f5dcdfa869363f19 Reviewed-by: Mike Krus --- src/animation/backend/channelmapping_p.h | 1 + .../animationutils/tst_animationutils.cpp | 83 ++++++++++++++++------ 2 files changed, 64 insertions(+), 20 deletions(-) diff --git a/src/animation/backend/channelmapping_p.h b/src/animation/backend/channelmapping_p.h index 154e8b228..93cf5efed 100644 --- a/src/animation/backend/channelmapping_p.h +++ b/src/animation/backend/channelmapping_p.h @@ -82,6 +82,7 @@ public: void setType(int type) { m_type = type; } int type() const { return m_type; } + void setPropertyName(const char *propertyName) { m_propertyName = propertyName; } const char *propertyName() const { return m_propertyName; } private: diff --git a/tests/auto/animation/animationutils/tst_animationutils.cpp b/tests/auto/animation/animationutils/tst_animationutils.cpp index a1b9e1e86..1a4c861c5 100644 --- a/tests/auto/animation/animationutils/tst_animationutils.cpp +++ b/tests/auto/animation/animationutils/tst_animationutils.cpp @@ -38,42 +38,50 @@ using namespace Qt3DAnimation::Animation; +Q_DECLARE_METATYPE(Qt3DAnimation::Animation::Handler*) +Q_DECLARE_METATYPE(QVector) +Q_DECLARE_METATYPE(ChannelMapper *) +Q_DECLARE_METATYPE(AnimationClipLoader *) +Q_DECLARE_METATYPE(QVector) + class tst_AnimationUtils : public Qt3DCore::QBackendNodeTester { Q_OBJECT public: - ChannelMapping *createChannelMapping(Handler &handler, + ChannelMapping *createChannelMapping(Handler *handler, const QString &channelName, const Qt3DCore::QNodeId targetId, - const QString &propertyName, + const QString &property, + const char *propertyName, int type) { auto channelMappingId = Qt3DCore::QNodeId::createId(); - ChannelMapping *channelMapping = handler.channelMappingManager()->getOrCreateResource(channelMappingId); + ChannelMapping *channelMapping = handler->channelMappingManager()->getOrCreateResource(channelMappingId); setPeerId(channelMapping, channelMappingId); channelMapping->setTargetId(targetId); - channelMapping->setProperty(propertyName); + channelMapping->setProperty(property); + channelMapping->setPropertyName(propertyName); channelMapping->setChannelName(channelName); channelMapping->setType(type); return channelMapping; } - ChannelMapper *createChannelMapper(Handler &handler, + ChannelMapper *createChannelMapper(Handler *handler, const QVector &mappingIds) { auto channelMapperId = Qt3DCore::QNodeId::createId(); - ChannelMapper *channelMapper = handler.channelMapperManager()->getOrCreateResource(channelMapperId); + ChannelMapper *channelMapper = handler->channelMapperManager()->getOrCreateResource(channelMapperId); setPeerId(channelMapper, channelMapperId); channelMapper->setMappingIds(mappingIds); return channelMapper; } - AnimationClipLoader *createAnimationClipLoader(Handler &handler, + AnimationClipLoader *createAnimationClipLoader(Handler *handler, const QUrl &source) { auto clipId = Qt3DCore::QNodeId::createId(); - AnimationClipLoader *clip = handler.animationClipLoaderManager()->getOrCreateResource(clipId); + AnimationClipLoader *clip = handler->animationClipLoaderManager()->getOrCreateResource(clipId); setPeerId(clip, clipId); clip->setSource(source); clip->loadAnimation(); @@ -81,17 +89,23 @@ public: } private Q_SLOTS: - void checkBuildPropertyMappings() + void checkBuildPropertyMappings_data() { - // GIVEN - Handler handler; + QTest::addColumn("handler"); + QTest::addColumn>("channelMappings"); + QTest::addColumn("channelMapper"); + QTest::addColumn("clip"); + QTest::addColumn>("expectedMappingData"); - // Create a channel mapping... + auto handler = new Handler; auto channelMapping = createChannelMapping(handler, QLatin1String("Location"), Qt3DCore::QNodeId::createId(), QLatin1String("translation"), + "translation", static_cast(QVariant::Vector3D)); + QVector channelMappings; + channelMappings.push_back(channelMapping); // ... a channel mapper... auto channelMapper = createChannelMapper(handler, QVector() << channelMapping->peerId()); @@ -99,22 +113,51 @@ private Q_SLOTS: // ...and an animation clip auto clip = createAnimationClipLoader(handler, QUrl("qrc:/clip1.json")); + QVector mappingData; + AnimationUtils::MappingData mapping; + mapping.targetId = channelMapping->targetId(); + mapping.propertyName = channelMapping->propertyName(); // Location + mapping.type = channelMapping->type(); + mapping.channelIndices = QVector() << 0 << 1 << 2; // Location X, Y, Z + mappingData.push_back(mapping); + + QTest::newRow("clip1.json") << handler + << channelMappings + << channelMapper + << clip + << mappingData; + } + + void checkBuildPropertyMappings() + { + // GIVEN + QFETCH(Handler *, handler); + QFETCH(QVector, channelMappings); + QFETCH(ChannelMapper *, channelMapper); + QFETCH(AnimationClipLoader *, clip); + QFETCH(QVector, expectedMappingData); + // WHEN // Build the mapping data for the above configuration - QVector mappingData = AnimationUtils::buildPropertyMappings(&handler, clip, channelMapper); + QVector mappingData = AnimationUtils::buildPropertyMappings(handler, clip, channelMapper); // THEN - QCOMPARE(mappingData.size(), channelMapper->mappingIds().size()); + QCOMPARE(mappingData.size(), expectedMappingData.size()); for (int i = 0; i < mappingData.size(); ++i) { const auto mapping = mappingData[i]; - QCOMPARE(mapping.targetId, channelMapping->targetId()); - QCOMPARE(mapping.propertyName, channelMapping->propertyName()); - QCOMPARE(mapping.type, channelMapping->type()); - QCOMPARE(mapping.channelIndices.size(), 3); - for (int j = 0; j < 3; ++j) { - QCOMPARE(mapping.channelIndices[j], j); + const auto expectedMapping = expectedMappingData[i]; + + QCOMPARE(mapping.targetId, expectedMapping.targetId); + QCOMPARE(mapping.propertyName, expectedMapping.propertyName); + QCOMPARE(mapping.type, expectedMapping.type); + QCOMPARE(mapping.channelIndices.size(), expectedMapping.channelIndices.size()); + for (int j = 0; j < mapping.channelIndices.size(); ++j) { + QCOMPARE(mapping.channelIndices[j], expectedMapping.channelIndices[j]); } } + + // Cleanup + delete handler; } }; -- cgit v1.2.3 From 2519573517979f6a2995f9a445321ef7d62091e8 Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Thu, 2 Mar 2017 10:09:32 +0000 Subject: Split blend tree manual test out from simple key frame test Change-Id: I9aba21499008980f3bd07efb14c912961090ecb1 Reviewed-by: Mike Krus --- .../DefaultSceneEntity.qml | 35 +++ .../animation-keyframe-blendtree.pro | 5 + .../cubeanimation.json | 87 +++++++ tests/manual/animation-keyframe-blendtree/main.cpp | 25 ++ tests/manual/animation-keyframe-blendtree/main.qml | 260 +++++++++++++++++++++ tests/manual/animation-keyframe-blendtree/main.qrc | 9 + .../pulsing-cube-additive.json | 84 +++++++ .../pulsing-moving-cube.json | 114 +++++++++ tests/manual/animation-keyframe-simple/main.qml | 185 --------------- tests/manual/manual.pro | 1 + 10 files changed, 620 insertions(+), 185 deletions(-) create mode 100644 tests/manual/animation-keyframe-blendtree/DefaultSceneEntity.qml create mode 100644 tests/manual/animation-keyframe-blendtree/animation-keyframe-blendtree.pro create mode 100644 tests/manual/animation-keyframe-blendtree/cubeanimation.json create mode 100644 tests/manual/animation-keyframe-blendtree/main.cpp create mode 100644 tests/manual/animation-keyframe-blendtree/main.qml create mode 100644 tests/manual/animation-keyframe-blendtree/main.qrc create mode 100644 tests/manual/animation-keyframe-blendtree/pulsing-cube-additive.json create mode 100644 tests/manual/animation-keyframe-blendtree/pulsing-moving-cube.json diff --git a/tests/manual/animation-keyframe-blendtree/DefaultSceneEntity.qml b/tests/manual/animation-keyframe-blendtree/DefaultSceneEntity.qml new file mode 100644 index 000000000..efffd44c9 --- /dev/null +++ b/tests/manual/animation-keyframe-blendtree/DefaultSceneEntity.qml @@ -0,0 +1,35 @@ +/************************************************************************* + * + * Copyright (c) 2016, Klaralvdalens Datakonsult AB (KDAB) + * All rights reserved. + * + * See the LICENSE.txt file shipped along with this file for the license. + * + *************************************************************************/ + +import Qt3D.Core 2.0 +import Qt3D.Render 2.0 +import Qt3D.Input 2.0 +import Qt3D.Extras 2.0 + +Entity { + id: root + property Camera camera + + components: [ + RenderSettings { + activeFrameGraph: ForwardRenderer { + camera: root.camera + } + }, + // Event Source will be set by the Qt3DQuickWindow + InputSettings { } + ] + + Entity { + components: [ + PointLight { intensity: 0.5 }, + Transform { translation: camera.position } + ] + } +} diff --git a/tests/manual/animation-keyframe-blendtree/animation-keyframe-blendtree.pro b/tests/manual/animation-keyframe-blendtree/animation-keyframe-blendtree.pro new file mode 100644 index 000000000..04db4207e --- /dev/null +++ b/tests/manual/animation-keyframe-blendtree/animation-keyframe-blendtree.pro @@ -0,0 +1,5 @@ +TEMPLATE = app +QT += 3dquickextras 3dquickanimation +SOURCES += main.cpp +RESOURCES += main.qrc +OTHER_FILES += main.qml DefaultSceneEntity.qml diff --git a/tests/manual/animation-keyframe-blendtree/cubeanimation.json b/tests/manual/animation-keyframe-blendtree/cubeanimation.json new file mode 100644 index 000000000..addf92907 --- /dev/null +++ b/tests/manual/animation-keyframe-blendtree/cubeanimation.json @@ -0,0 +1,87 @@ +{ + "animations": [ + { "object": "Cube", + "action": "CubeAction", + "range": [0.0, 60.0], + "groups": [ + { "group": "Location", + "channels": [ + { "name": "x", + "keyframes": [ + { "co": [0.0, 0.0], + "handle_left": [-0.4717472394307454, 0.0], + "handle_right": [0.4717472394307454, 0.0]} + ,{ "co": [1.2083333333333333, 2.430499792098999], + "handle_left": [0.7365860939025879, 1.4711904525756836], + "handle_right": [1.696347713470459, 3.42288875579834]} + ,{ "co": [2.4583333333333335, 5.0], + "handle_left": [1.9703189531962078, 5.0], + "handle_right": [2.9463475545247397, 5.0]} + ]} + ,{ "name": "z", + "keyframes": [ + { "co": [0.0, 0.0], + "handle_left": [-0.4717472394307454, 0.0], + "handle_right": [0.4717472394307454, 0.0]} + ,{ "co": [1.2083333333333333, 0.0], + "handle_left": [0.7365860939025879, 0.0], + "handle_right": [1.696347713470459, 0.0]} + ,{ "co": [2.4583333333333335, 0.0], + "handle_left": [1.9703189531962078, 0.0], + "handle_right": [2.9463475545247397, 0.0]} + ]} + ,{ "name": "y", + "keyframes": [ + { "co": [0.0, 0.0], + "handle_left": [-0.4717472394307454, 0.0], + "handle_right": [0.4717472394307454, 0.0]} + ,{ "co": [1.2083333333333333, 3.0], + "handle_left": [0.7365860939025879, 3.0], + "handle_right": [1.696347713470459, 3.0]} + ,{ "co": [2.4583333333333335, 0.0], + "handle_left": [1.9703189531962078, 0.0], + "handle_right": [2.9463475545247397, 0.0]} + ]} + ]} + ,{ "group": "Rotation", + "channels": [ + { "name": "w", + "keyframes": [ + { "co": [0.0, 1.0], + "handle_left": [-0.9597616195678711, 1.0], + "handle_right": [0.9597616195678711, 1.0]} + ,{ "co": [2.4583333333333335, -4.371138828673793e-08], + "handle_left": [1.4985717137654622, -4.371138828673793e-08], + "handle_right": [3.4180949529012046, -4.371138828673793e-08]} + ]} + ,{ "name": "x", + "keyframes": [ + { "co": [0.0, 0.0], + "handle_left": [-0.9597616195678711, 0.0], + "handle_right": [0.9597616195678711, 0.0]} + ,{ "co": [2.4583333333333335, 0.0], + "handle_left": [1.4985717137654622, 0.0], + "handle_right": [3.4180949529012046, 0.0]} + ]} + ,{ "name": "z", + "keyframes": [ + { "co": [0.0, -0.0], + "handle_left": [-0.9597616195678711, -0.0], + "handle_right": [0.9597616195678711, -0.0]} + ,{ "co": [2.4583333333333335, -1.0], + "handle_left": [1.4985717137654622, -1.0], + "handle_right": [3.4180949529012046, -1.0]} + ]} + ,{ "name": "y", + "keyframes": [ + { "co": [0.0, 0.0], + "handle_left": [-0.9597616195678711, 0.0], + "handle_right": [0.9597616195678711, 0.0]} + ,{ "co": [2.4583333333333335, 0.0], + "handle_left": [1.4985717137654622, 0.0], + "handle_right": [3.4180949529012046, 0.0]} + ]} + ]} + ]} + ] +} diff --git a/tests/manual/animation-keyframe-blendtree/main.cpp b/tests/manual/animation-keyframe-blendtree/main.cpp new file mode 100644 index 000000000..fc48fc702 --- /dev/null +++ b/tests/manual/animation-keyframe-blendtree/main.cpp @@ -0,0 +1,25 @@ +/************************************************************************* + * + * Copyright (c) 2016, Klaralvdalens Datakonsult AB (KDAB) + * All rights reserved. + * + * See the LICENSE.txt file shipped along with this file for the license. + * + *************************************************************************/ + +#include +#include +#include +#include +#include +#include + +int main(int argc, char **argv) +{ + QGuiApplication app(argc, argv); + Qt3DExtras::Quick::Qt3DQuickWindow view; + view.registerAspect(new Qt3DAnimation::QAnimationAspect()); + view.setSource(QUrl("qrc:/main.qml")); + view.show(); + return app.exec(); +} diff --git a/tests/manual/animation-keyframe-blendtree/main.qml b/tests/manual/animation-keyframe-blendtree/main.qml new file mode 100644 index 000000000..2c7be6879 --- /dev/null +++ b/tests/manual/animation-keyframe-blendtree/main.qml @@ -0,0 +1,260 @@ +/************************************************************************* + * + * Copyright (c) 2016, Klaralvdalens Datakonsult AB (KDAB) + * All rights reserved. + * + * See the LICENSE.txt file shipped along with this file for the license. + * + *************************************************************************/ + +import Qt3D.Core 2.0 +import Qt3D.Render 2.0 +import Qt3D.Input 2.0 +import Qt3D.Animation 2.9 +import Qt3D.Extras 2.0 + +DefaultSceneEntity { + id: scene + + Entity { + id: cube + + components: [ + Transform { + id: cubeTransform + + onTranslationChanged: console.log("t = " + translation) + }, + CuboidMesh { + }, + PhongMaterial { + id: cubeMaterial + ambient: Qt.rgba(0.02, 0.02, 0.02, 1.0) + diffuse: "blue" + shininess: 50 + }, + ObjectPicker { + onClicked: animator.running = true + }, + ClipAnimator { + id: animator + loops: 3 + onRunningChanged: console.log("running = " + running) + + clip: AnimationClip { + source: "cubeanimation.json" + onDurationChanged: console.log("duration = " + duration) + } + + // By default introspect parent Entity and try + // to map fcurve groups to properties of QTransform + // mapping: AutomaticAnimationMapping {} + + // To do more, we can be explicit + channelMapper: ChannelMapper { + mappings: [ + ChannelMapping { channelName: "Location"; target: cubeTransform; property: "translation" }, + ChannelMapping { channelName: "Rotation"; target: cubeTransform; property: "rotation" }, + ChannelMapping { channelName: "Diffuse Color"; target: cubeMaterial; property: "diffuse" } + ] + } + } + ] + } + + Entity { + id: sphere + + components: [ + Transform { + id: sphereTransform + translation: Qt.vector3d(5, 0, 0) + onTranslationChanged: console.log("t = " + translation) + }, + SphereMesh { + }, + PhongMaterial { + id: sphereMaterial + ambient: Qt.rgba(0.02, 0.02, 0.02, 1.0) + diffuse: "red" + shininess: 50 + }, + ObjectPicker { + onClicked: blendedAnimator.running = true + }, + BlendedClipAnimator { + id: blendedAnimator + loops: 2 + + onRunningChanged: console.log("running = " + running) + + blendTree: LerpBlend { + blendFactor: 0.5 + clips: [ + AnimationClip { + source: "cubeanimation.json" + onDurationChanged: console.log("duration = " + duration) + }, + AnimationClip { + source: "pulsing-moving-cube.json" + onDurationChanged: console.log("duration = " + duration) + }] + } + + + // By default introspect parent Entity and try + // to map fcurve groups to properties of QTransform + // mapping: AutomaticAnimationMapping {} + + // To do more, we can be explicit + channelMapper: ChannelMapper { + mappings: [ + ChannelMapping { channelName: "Location"; target: sphereTransform; property: "translation" }, + ChannelMapping { channelName: "Rotation"; target: sphereTransform; property: "rotation" }, + ChannelMapping { channelName: "Scaling"; target: sphereTransform; property: "scale3D" }, + ChannelMapping { channelName: "Diffuse Color"; target: sphereMaterial; property: "diffuse" } + ] + } + } + ] + } + + Entity { + id: cube2 + + components: [ + Transform { + id: cube2Transform + translation: Qt.vector3d(2.5, 0, 0) + onTranslationChanged: console.log("t = " + translation) + }, + CuboidMesh { + }, + PhongMaterial { + id: cube2Material + ambient: Qt.rgba(0.8, 0.8, 0.8, 1.0) + diffuse: Qt.rgba(0.7, 0.7, 0.7, 1.0) + shininess: 50 + }, + ObjectPicker { + onClicked: blendedAnimator2.running = true + }, + BlendedClipAnimator { + id: blendedAnimator2 + loops: 2 + + onRunningChanged: console.log("running = " + running) + + blendTree: AdditiveBlend { + blendFactor: 0.5 + clips: [ + AnimationClip { + source: "pulsing-moving-cube.json" + onDurationChanged: console.log("duration = " + duration) + }, + AnimationClip { + source: "pulsing-cube-additive.json" + onDurationChanged: console.log("duration = " + duration) + }] + } + + // By default introspect parent Entity and try + // to map fcurve groups to properties of QTransform + // mapping: AutomaticAnimationMapping {} + + // To do more, we can be explicit + channelMapper: ChannelMapper { + mappings: [ + ChannelMapping { channelName: "Location"; target: cube2Transform; property: "translation" }, + ChannelMapping { channelName: "Rotation"; target: cube2Transform; property: "rotation" }, + ChannelMapping { channelName: "Scaling"; target: cube2Transform; property: "scale3D" }, + ChannelMapping { channelName: "Diffuse Color"; target: cube2Transform; property: "diffuse" } + ] + } + } + ] + } + + Entity { + id: cube3 + + components: [ + Transform { + id: cube3Transform + translation: Qt.vector3d(2.5, 0, 2) + onTranslationChanged: console.log("t = " + translation) + }, + CuboidMesh { + }, + PhongMaterial { + id: cube3Material + ambient: Qt.rgba(0.8, 0.8, 0.8, 1.0) + diffuse: "green" + shininess: 50 + }, + ObjectPicker { + onClicked: blendedAnimator3.running = true + }, + BlendedClipAnimator { + id: blendedAnimator3 + loops: 2 + + onRunningChanged: console.log("running = " + running) + + blendTree: LerpBlend { + blendFactor: 0.5 + AdditiveBlend { + blendFactor: 0.5 + clips: [ + AnimationClip { + source: "pulsing-moving-cube.json" + onDurationChanged: console.log("duration = " + duration) + }, + AnimationClip { + source: "pulsing-cube-additive.json" + onDurationChanged: console.log("duration = " + duration) + }] + } + LerpBlend { + blendFactor: 0.5 + clips: [ + AnimationClip { + source: "cubeanimation.json" + onDurationChanged: console.log("duration = " + duration) + }, + AnimationClip { + source: "pulsing-moving-cube.json" + onDurationChanged: console.log("duration = " + duration) + }] + } + } + + // By default introspect parent Entity and try + // to map fcurve groups to properties of QTransform + // mapping: AutomaticAnimationMapping {} + + // To do more, we can be explicit + channelMapper: ChannelMapper { + mappings: [ + ChannelMapping { channelName: "Location"; target: cube3Transform; property: "translation" }, + ChannelMapping { channelName: "Rotation"; target: cube3Transform; property: "rotation" }, + ChannelMapping { channelName: "Scaling"; target: cube3Transform; property: "scale3D" }, + ChannelMapping { channelName: "Diffuse Color"; target: cube3Transform; property: "diffuse" } + ] + } + } + ] + } + + + camera: Camera { + position: Qt.vector3d(10, 3, 15) + viewCenter: Qt.vector3d(2.5, 1, 0) + } + + OrbitCameraController { + camera: scene.camera + linearSpeed: 8 + lookSpeed: 180 + } +} diff --git a/tests/manual/animation-keyframe-blendtree/main.qrc b/tests/manual/animation-keyframe-blendtree/main.qrc new file mode 100644 index 000000000..b59429895 --- /dev/null +++ b/tests/manual/animation-keyframe-blendtree/main.qrc @@ -0,0 +1,9 @@ + + + main.qml + DefaultSceneEntity.qml + cubeanimation.json + pulsing-moving-cube.json + pulsing-cube-additive.json + + diff --git a/tests/manual/animation-keyframe-blendtree/pulsing-cube-additive.json b/tests/manual/animation-keyframe-blendtree/pulsing-cube-additive.json new file mode 100644 index 000000000..1373a5002 --- /dev/null +++ b/tests/manual/animation-keyframe-blendtree/pulsing-cube-additive.json @@ -0,0 +1,84 @@ +{ + "animations": [ + { "object": "Cube", + "action": "CubeAction", + "range": [0.0, 60.0], + "groups": [ + { "group": "Scaling", + "channels": [ + { "name": "x", + "keyframes": [ + { "co": [0.0, 1.0], + "handle_left": [-0.1464043160279592, 1.0], + "handle_right": [0.14640430609385172, 1.0]} + ,{ "co": [0.375, 0.5], + "handle_left": [0.22859569390614828, 0.5], + "handle_right": [0.5376714468002319, 0.5]} + ,{ "co": [0.7916666666666666, 1.0], + "handle_left": [0.6289951801300049, 1.0], + "handle_right": [0.9543381532033285, 1.0]} + ,{ "co": [1.2083333333333333, 0.5], + "handle_left": [1.0456619262695312, 0.5], + "handle_right": [1.371035893758138, 0.5]} + ,{ "co": [1.625, 1.0], + "handle_left": [1.462328592936198, 1.0], + "handle_right": [1.787671407063802, 1.0]} + ,{ "co": [2.0416666666666665, 0.5], + "handle_left": [1.8789952596028645, 0.5], + "handle_right": [2.2043380737304688, 0.5]} + ,{ "co": [2.4583333333333335, 1.0], + "handle_left": [2.2956619262695312, 1.0], + "handle_right": [2.6210047403971353, 1.0]} + ]} + ,{ "name": "z", + "keyframes": [ + { "co": [0.0, 1.0], + "handle_left": [-0.1464043160279592, 1.0], + "handle_right": [0.14640430609385172, 1.0]} + ,{ "co": [0.375, 0.5], + "handle_left": [0.22859569390614828, 0.5], + "handle_right": [0.5376714468002319, 0.5]} + ,{ "co": [0.7916666666666666, 1.0], + "handle_left": [0.6289951801300049, 1.0], + "handle_right": [0.9543381532033285, 1.0]} + ,{ "co": [1.2083333333333333, 0.5], + "handle_left": [1.0456618467966716, 0.5], + "handle_right": [1.3710047403971355, 0.5]} + ,{ "co": [1.625, 1.0], + "handle_left": [1.462328592936198, 1.0], + "handle_right": [1.787671407063802, 1.0]} + ,{ "co": [2.0416666666666665, 0.5], + "handle_left": [1.8789952596028645, 0.5], + "handle_right": [2.2043380737304688, 0.5]} + ,{ "co": [2.4583333333333335, 1.0], + "handle_left": [2.2956619262695312, 1.0], + "handle_right": [2.6210047403971353, 1.0]} + ]} + ,{ "name": "y", + "keyframes": [ + { "co": [0.0, 1.0], + "handle_left": [-0.1464043160279592, 1.0], + "handle_right": [0.14640430609385172, 1.0]} + ,{ "co": [0.375, 0.5], + "handle_left": [0.22859569390614828, 0.5], + "handle_right": [0.5376714468002319, 0.5]} + ,{ "co": [0.7916666666666666, 1.0], + "handle_left": [0.6289951801300049, 1.0], + "handle_right": [0.9543381532033285, 1.0]} + ,{ "co": [1.2083333333333333, 0.5441937446594238], + "handle_left": [1.0456618467966716, 0.5441937446594238], + "handle_right": [1.3710047403971355, 0.5441937446594238]} + ,{ "co": [1.625, 1.0], + "handle_left": [1.462328592936198, 1.0], + "handle_right": [1.787671407063802, 1.0]} + ,{ "co": [2.0416666666666665, 0.5771476030349731], + "handle_left": [1.8789952596028645, 0.5771476030349731], + "handle_right": [2.2043380737304688, 0.5771476030349731]} + ,{ "co": [2.4583333333333335, 1.0], + "handle_left": [2.2956619262695312, 1.0], + "handle_right": [2.6210047403971353, 1.0]} + ]} + ]} + ]} + ] +} diff --git a/tests/manual/animation-keyframe-blendtree/pulsing-moving-cube.json b/tests/manual/animation-keyframe-blendtree/pulsing-moving-cube.json new file mode 100644 index 000000000..147c31e76 --- /dev/null +++ b/tests/manual/animation-keyframe-blendtree/pulsing-moving-cube.json @@ -0,0 +1,114 @@ +{ + "animations": [ + { "object": "Cube", + "action": "CubeAction", + "range": [0.0, 60.0], + "groups": [ + { "group": "Location", + "channels": [ + { "name": "x", + "keyframes": [ + { "co": [0.0, 0.0], + "handle_left": [-0.9597616195678711, 0.0], + "handle_right": [0.9597616195678711, 0.0]} + ,{ "co": [2.4583333333333335, 5.0], + "handle_left": [1.4985717137654622, 5.0], + "handle_right": [3.4180949529012046, 5.0]} + ]} + ,{ "name": "z", + "keyframes": [ + { "co": [0.0, 0.0], + "handle_left": [-0.9597616195678711, 0.0], + "handle_right": [0.9597616195678711, 0.0]} + ,{ "co": [2.4583333333333335, 0.0], + "handle_left": [1.4985717137654622, 0.0], + "handle_right": [3.4180949529012046, 0.0]} + ]} + ,{ "name": "y", + "keyframes": [ + { "co": [0.0, 0.0], + "handle_left": [-0.9597616195678711, 0.0], + "handle_right": [0.9597616195678711, 0.0]} + ,{ "co": [2.4583333333333335, 0.0], + "handle_left": [1.4985717137654622, 0.0], + "handle_right": [3.4180949529012046, 0.0]} + ]} + ]} + ,{ "group": "Scaling", + "channels": [ + { "name": "x", + "keyframes": [ + { "co": [0.0, 1.0], + "handle_left": [-0.1464043160279592, 1.0], + "handle_right": [0.14640430609385172, 1.0]} + ,{ "co": [0.375, 0.5], + "handle_left": [0.22859569390614828, 0.5], + "handle_right": [0.5376714468002319, 0.5]} + ,{ "co": [0.7916666666666666, 1.0], + "handle_left": [0.6289951801300049, 1.0], + "handle_right": [0.9543381532033285, 1.0]} + ,{ "co": [1.2083333333333333, 0.5], + "handle_left": [1.0456619262695312, 0.5], + "handle_right": [1.371035893758138, 0.5]} + ,{ "co": [1.625, 1.0], + "handle_left": [1.462328592936198, 1.0], + "handle_right": [1.787671407063802, 1.0]} + ,{ "co": [2.0416666666666665, 0.5], + "handle_left": [1.8789952596028645, 0.5], + "handle_right": [2.2043380737304688, 0.5]} + ,{ "co": [2.4583333333333335, 1.0], + "handle_left": [2.2956619262695312, 1.0], + "handle_right": [2.6210047403971353, 1.0]} + ]} + ,{ "name": "z", + "keyframes": [ + { "co": [0.0, 1.0], + "handle_left": [-0.1464043160279592, 1.0], + "handle_right": [0.14640430609385172, 1.0]} + ,{ "co": [0.375, 0.5], + "handle_left": [0.22859569390614828, 0.5], + "handle_right": [0.5376714468002319, 0.5]} + ,{ "co": [0.7916666666666666, 1.0], + "handle_left": [0.6289951801300049, 1.0], + "handle_right": [0.9543381532033285, 1.0]} + ,{ "co": [1.2083333333333333, 0.5], + "handle_left": [1.0456618467966716, 0.5], + "handle_right": [1.3710047403971355, 0.5]} + ,{ "co": [1.625, 1.0], + "handle_left": [1.462328592936198, 1.0], + "handle_right": [1.787671407063802, 1.0]} + ,{ "co": [2.0416666666666665, 0.5], + "handle_left": [1.8789952596028645, 0.5], + "handle_right": [2.2043380737304688, 0.5]} + ,{ "co": [2.4583333333333335, 1.0], + "handle_left": [2.2956619262695312, 1.0], + "handle_right": [2.6210047403971353, 1.0]} + ]} + ,{ "name": "y", + "keyframes": [ + { "co": [0.0, 1.0], + "handle_left": [-0.1464043160279592, 1.0], + "handle_right": [0.14640430609385172, 1.0]} + ,{ "co": [0.375, 0.5], + "handle_left": [0.22859569390614828, 0.5], + "handle_right": [0.5376714468002319, 0.5]} + ,{ "co": [0.7916666666666666, 1.0], + "handle_left": [0.6289951801300049, 1.0], + "handle_right": [0.9543381532033285, 1.0]} + ,{ "co": [1.2083333333333333, 0.5441937446594238], + "handle_left": [1.0456618467966716, 0.5441937446594238], + "handle_right": [1.3710047403971355, 0.5441937446594238]} + ,{ "co": [1.625, 1.0], + "handle_left": [1.462328592936198, 1.0], + "handle_right": [1.787671407063802, 1.0]} + ,{ "co": [2.0416666666666665, 0.5771476030349731], + "handle_left": [1.8789952596028645, 0.5771476030349731], + "handle_right": [2.2043380737304688, 0.5771476030349731]} + ,{ "co": [2.4583333333333335, 1.0], + "handle_left": [2.2956619262695312, 1.0], + "handle_right": [2.6210047403971353, 1.0]} + ]} + ]} + ]} + ] +} diff --git a/tests/manual/animation-keyframe-simple/main.qml b/tests/manual/animation-keyframe-simple/main.qml index 2c7be6879..17744209a 100644 --- a/tests/manual/animation-keyframe-simple/main.qml +++ b/tests/manual/animation-keyframe-simple/main.qml @@ -62,191 +62,6 @@ DefaultSceneEntity { ] } - Entity { - id: sphere - - components: [ - Transform { - id: sphereTransform - translation: Qt.vector3d(5, 0, 0) - onTranslationChanged: console.log("t = " + translation) - }, - SphereMesh { - }, - PhongMaterial { - id: sphereMaterial - ambient: Qt.rgba(0.02, 0.02, 0.02, 1.0) - diffuse: "red" - shininess: 50 - }, - ObjectPicker { - onClicked: blendedAnimator.running = true - }, - BlendedClipAnimator { - id: blendedAnimator - loops: 2 - - onRunningChanged: console.log("running = " + running) - - blendTree: LerpBlend { - blendFactor: 0.5 - clips: [ - AnimationClip { - source: "cubeanimation.json" - onDurationChanged: console.log("duration = " + duration) - }, - AnimationClip { - source: "pulsing-moving-cube.json" - onDurationChanged: console.log("duration = " + duration) - }] - } - - - // By default introspect parent Entity and try - // to map fcurve groups to properties of QTransform - // mapping: AutomaticAnimationMapping {} - - // To do more, we can be explicit - channelMapper: ChannelMapper { - mappings: [ - ChannelMapping { channelName: "Location"; target: sphereTransform; property: "translation" }, - ChannelMapping { channelName: "Rotation"; target: sphereTransform; property: "rotation" }, - ChannelMapping { channelName: "Scaling"; target: sphereTransform; property: "scale3D" }, - ChannelMapping { channelName: "Diffuse Color"; target: sphereMaterial; property: "diffuse" } - ] - } - } - ] - } - - Entity { - id: cube2 - - components: [ - Transform { - id: cube2Transform - translation: Qt.vector3d(2.5, 0, 0) - onTranslationChanged: console.log("t = " + translation) - }, - CuboidMesh { - }, - PhongMaterial { - id: cube2Material - ambient: Qt.rgba(0.8, 0.8, 0.8, 1.0) - diffuse: Qt.rgba(0.7, 0.7, 0.7, 1.0) - shininess: 50 - }, - ObjectPicker { - onClicked: blendedAnimator2.running = true - }, - BlendedClipAnimator { - id: blendedAnimator2 - loops: 2 - - onRunningChanged: console.log("running = " + running) - - blendTree: AdditiveBlend { - blendFactor: 0.5 - clips: [ - AnimationClip { - source: "pulsing-moving-cube.json" - onDurationChanged: console.log("duration = " + duration) - }, - AnimationClip { - source: "pulsing-cube-additive.json" - onDurationChanged: console.log("duration = " + duration) - }] - } - - // By default introspect parent Entity and try - // to map fcurve groups to properties of QTransform - // mapping: AutomaticAnimationMapping {} - - // To do more, we can be explicit - channelMapper: ChannelMapper { - mappings: [ - ChannelMapping { channelName: "Location"; target: cube2Transform; property: "translation" }, - ChannelMapping { channelName: "Rotation"; target: cube2Transform; property: "rotation" }, - ChannelMapping { channelName: "Scaling"; target: cube2Transform; property: "scale3D" }, - ChannelMapping { channelName: "Diffuse Color"; target: cube2Transform; property: "diffuse" } - ] - } - } - ] - } - - Entity { - id: cube3 - - components: [ - Transform { - id: cube3Transform - translation: Qt.vector3d(2.5, 0, 2) - onTranslationChanged: console.log("t = " + translation) - }, - CuboidMesh { - }, - PhongMaterial { - id: cube3Material - ambient: Qt.rgba(0.8, 0.8, 0.8, 1.0) - diffuse: "green" - shininess: 50 - }, - ObjectPicker { - onClicked: blendedAnimator3.running = true - }, - BlendedClipAnimator { - id: blendedAnimator3 - loops: 2 - - onRunningChanged: console.log("running = " + running) - - blendTree: LerpBlend { - blendFactor: 0.5 - AdditiveBlend { - blendFactor: 0.5 - clips: [ - AnimationClip { - source: "pulsing-moving-cube.json" - onDurationChanged: console.log("duration = " + duration) - }, - AnimationClip { - source: "pulsing-cube-additive.json" - onDurationChanged: console.log("duration = " + duration) - }] - } - LerpBlend { - blendFactor: 0.5 - clips: [ - AnimationClip { - source: "cubeanimation.json" - onDurationChanged: console.log("duration = " + duration) - }, - AnimationClip { - source: "pulsing-moving-cube.json" - onDurationChanged: console.log("duration = " + duration) - }] - } - } - - // By default introspect parent Entity and try - // to map fcurve groups to properties of QTransform - // mapping: AutomaticAnimationMapping {} - - // To do more, we can be explicit - channelMapper: ChannelMapper { - mappings: [ - ChannelMapping { channelName: "Location"; target: cube3Transform; property: "translation" }, - ChannelMapping { channelName: "Rotation"; target: cube3Transform; property: "rotation" }, - ChannelMapping { channelName: "Scaling"; target: cube3Transform; property: "scale3D" }, - ChannelMapping { channelName: "Diffuse Color"; target: cube3Transform; property: "diffuse" } - ] - } - } - ] - } - - camera: Camera { position: Qt.vector3d(10, 3, 15) viewCenter: Qt.vector3d(2.5, 1, 0) diff --git a/tests/manual/manual.pro b/tests/manual/manual.pro index a7fe4b90d..a5f07b55d 100644 --- a/tests/manual/manual.pro +++ b/tests/manual/manual.pro @@ -43,6 +43,7 @@ SUBDIRS += \ render-qml-to-texture-qml \ video-texture-qml \ animation-keyframe-simple \ + animation-keyframe-blendtree \ distancefieldtext \ mesh-morphing \ anim-viewer -- cgit v1.2.3 From d2910f97dc8a754cd8d41efdae8004e1b752cd51 Mon Sep 17 00:00:00 2001 From: Mike Krus Date: Wed, 1 Mar 2017 16:18:26 +0000 Subject: Make QAbstractServiceProvider a QObject so it can have signals and slots Change-Id: I269ee6d1c8fb035864a8d46e9ace18de82911755 Reviewed-by: Sean Harmer --- src/core/services/qabstractserviceprovider_p.h | 9 +++++---- src/core/services/qeventfilterservice.cpp | 2 ++ src/core/services/qopenglinformationservice.cpp | 2 +- src/core/services/qservicelocator.cpp | 10 ++++------ src/core/services/qservicelocator_p.h | 9 +++++---- 5 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/core/services/qabstractserviceprovider_p.h b/src/core/services/qabstractserviceprovider_p.h index 2913cee31..a176f0727 100644 --- a/src/core/services/qabstractserviceprovider_p.h +++ b/src/core/services/qabstractserviceprovider_p.h @@ -51,6 +51,7 @@ // We mean it. // +#include #include #include @@ -58,16 +59,16 @@ QT_BEGIN_NAMESPACE namespace Qt3DCore { -class QAbstractServiceProviderPrivate +class QAbstractServiceProviderPrivate : public QObjectPrivate { public: - QAbstractServiceProviderPrivate(int type, const QString &description = QString()) - : m_type(type) + explicit QAbstractServiceProviderPrivate(int type, const QString &description = QString()) + : QObjectPrivate() + , m_type(type) , m_description(description) {} Q_DECLARE_PUBLIC(QAbstractServiceProvider) - QAbstractServiceProvider *q_ptr; int m_type; QString m_description; diff --git a/src/core/services/qeventfilterservice.cpp b/src/core/services/qeventfilterservice.cpp index 489ab9b45..8f6687001 100644 --- a/src/core/services/qeventfilterservice.cpp +++ b/src/core/services/qeventfilterservice.cpp @@ -83,6 +83,8 @@ public: : QAbstractServiceProviderPrivate(QServiceLocator::EventFilterService, QStringLiteral("Default event filter service implementation")) {} + Q_DECLARE_PUBLIC(QEventFilterService) + void registerEventFilter(QObject *eventFilter, int priority) { for (int i = 0, m = m_eventFilters.size(); i < m; ++i) diff --git a/src/core/services/qopenglinformationservice.cpp b/src/core/services/qopenglinformationservice.cpp index 0f62544c8..c1c05018e 100644 --- a/src/core/services/qopenglinformationservice.cpp +++ b/src/core/services/qopenglinformationservice.cpp @@ -62,7 +62,7 @@ namespace Qt3DCore { instantiate a QOpenGLInformationService object. */ QOpenGLInformationService::QOpenGLInformationService(const QString &description) - : QAbstractServiceProvider(QServiceLocator::OpenGLInformation, description) + : QAbstractServiceProvider(*new QOpenGLInformationServicePrivate(description)) { } diff --git a/src/core/services/qservicelocator.cpp b/src/core/services/qservicelocator.cpp index 3d3d56386..176d9b078 100644 --- a/src/core/services/qservicelocator.cpp +++ b/src/core/services/qservicelocator.cpp @@ -53,17 +53,15 @@ namespace Qt3DCore { \inmodule Qt3DCore */ -QAbstractServiceProvider::QAbstractServiceProvider(int type, const QString &description) - : d_ptr(new QAbstractServiceProviderPrivate(type, description)) +QAbstractServiceProvider::QAbstractServiceProvider(int type, const QString &description, QObject *parent) + : QObject(*new QAbstractServiceProviderPrivate(type, description), parent) { - d_ptr->q_ptr = this; } /* \internal */ -QAbstractServiceProvider::QAbstractServiceProvider(QAbstractServiceProviderPrivate &dd) - : d_ptr(&dd) +QAbstractServiceProvider::QAbstractServiceProvider(QAbstractServiceProviderPrivate &dd, QObject *parent) + : QObject(dd, parent) { - d_ptr->q_ptr = this; } QAbstractServiceProvider::~QAbstractServiceProvider() diff --git a/src/core/services/qservicelocator_p.h b/src/core/services/qservicelocator_p.h index c68b56ffd..db402bb90 100644 --- a/src/core/services/qservicelocator_p.h +++ b/src/core/services/qservicelocator_p.h @@ -53,6 +53,7 @@ #include #include +#include QT_BEGIN_NAMESPACE @@ -60,8 +61,9 @@ namespace Qt3DCore { class QAbstractServiceProviderPrivate; -class QT3DCORESHARED_EXPORT QAbstractServiceProvider +class QT3DCORESHARED_EXPORT QAbstractServiceProvider : public QObject { + Q_OBJECT public: virtual ~QAbstractServiceProvider(); @@ -69,9 +71,8 @@ public: QString description() const; protected: - QAbstractServiceProvider(int type, const QString &description); - QAbstractServiceProvider(QAbstractServiceProviderPrivate &dd); - QScopedPointer d_ptr; + explicit QAbstractServiceProvider(int type, const QString &description, QObject* parent = nullptr); + explicit QAbstractServiceProvider(QAbstractServiceProviderPrivate &dd, QObject* parent = nullptr); private: Q_DISABLE_COPY(QAbstractServiceProvider) -- cgit v1.2.3 From 5b43b8d785351310d1f0869c9c065bf8c840d055 Mon Sep 17 00:00:00 2001 From: Kimmo Ollila Date: Fri, 3 Mar 2017 00:38:21 +0200 Subject: Remove unnecessary QT_CONFIG(library) QFactoryLoader is available without QLibrary Change-Id: I3676abe03c1d84107efe5a45915cf0c0d1b4fd49 Reviewed-by: Ulf Hermann --- src/render/geometry/qmesh.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/render/geometry/qmesh.cpp b/src/render/geometry/qmesh.cpp index 3305fc915..81e86c9c8 100644 --- a/src/render/geometry/qmesh.cpp +++ b/src/render/geometry/qmesh.cpp @@ -55,9 +55,7 @@ QT_BEGIN_NAMESPACE namespace Qt3DRender { -#ifndef QT_NO_LIBRARY Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, geometryLoader, (QGeometryLoaderFactory_iid, QLatin1String("/geometryloaders"), Qt::CaseInsensitive)) -#endif QMeshPrivate::QMeshPrivate() : QGeometryRendererPrivate() -- cgit v1.2.3 From fddaeae702df644c1792a29f1875201e8bd64e94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Fri, 17 Feb 2017 15:53:30 +0200 Subject: cleanup scene2d - change mouse event handling Task-number: QTBUG-58876 Change-Id: I103125ff15a4b28a67832eb7b86b1abbd2f3fde8 Reviewed-by: Sean Harmer --- src/quick3d/imports/scene2d/importsscene2d.pro | 2 +- .../imports/scene2d/qtquickscene2dplugin.cpp | 3 +- src/quick3d/quick3dscene2d/items/items.pri | 6 +- src/quick3d/quick3dscene2d/items/qscene2d.cpp | 61 ++++++++- src/quick3d/quick3dscene2d/items/qscene2d.h | 9 ++ src/quick3d/quick3dscene2d/items/qscene2d_p.h | 2 + .../quick3dscene2d/items/qt3dquick3dscene2d.cpp | 100 +++++++++++++++ .../quick3dscene2d/items/qt3dquick3dscene2d_p.h | 93 ++++++++++++++ src/quick3d/quick3dscene2d/items/scene2d.cpp | 141 ++++++++++++++++++++- src/quick3d/quick3dscene2d/items/scene2d_p.h | 8 ++ .../quick3dscene2d/items/scene2dmanager.cpp | 1 + .../quick3dscene2d/items/scene2dmanager_p.h | 1 + src/render/backend/entity_p.h | 8 +- src/render/backend/resourceaccessor.cpp | 56 +++++--- src/render/backend/resourceaccessor_p.h | 12 +- src/render/backend/trianglesvisitor_p.h | 4 +- src/render/jobs/pickboundingvolumejob.cpp | 10 +- src/render/picking/qpickevent.cpp | 5 + src/render/picking/qpickevent_p.h | 11 +- src/render/picking/qpicktriangleevent.cpp | 17 ++- src/render/picking/qpicktriangleevent.h | 5 +- tests/manual/render-qml-to-texture-qml/main.qml | 16 +-- 22 files changed, 520 insertions(+), 51 deletions(-) create mode 100644 src/quick3d/quick3dscene2d/items/qt3dquick3dscene2d.cpp create mode 100644 src/quick3d/quick3dscene2d/items/qt3dquick3dscene2d_p.h diff --git a/src/quick3d/imports/scene2d/importsscene2d.pro b/src/quick3d/imports/scene2d/importsscene2d.pro index 13ccf7818..32fbc5b1b 100644 --- a/src/quick3d/imports/scene2d/importsscene2d.pro +++ b/src/quick3d/imports/scene2d/importsscene2d.pro @@ -3,7 +3,7 @@ TARGET = qtquickscene2dplugin TARGETPATH = QtQuick/Scene2D IMPORT_VERSION = 2.0 -QT += qml quick 3dcore 3drender 3drender-private 3dinput 3dlogic 3dquickscene2d +QT += qml quick 3dcore 3drender 3drender-private 3dinput 3dlogic 3dquickscene2d 3dquickscene2d-private # Qt3D is free of Q_FOREACH - make sure it stays that way: DEFINES += QT_NO_FOREACH diff --git a/src/quick3d/imports/scene2d/qtquickscene2dplugin.cpp b/src/quick3d/imports/scene2d/qtquickscene2dplugin.cpp index 44ca596d3..c67271adb 100644 --- a/src/quick3d/imports/scene2d/qtquickscene2dplugin.cpp +++ b/src/quick3d/imports/scene2d/qtquickscene2dplugin.cpp @@ -38,6 +38,7 @@ #include #include +#include QT_BEGIN_NAMESPACE @@ -50,7 +51,7 @@ Q_COREAPP_STARTUP_FUNCTION(initScene2dPlugin) void QtQuickScene2DPlugin::registerTypes(const char *uri) { - qmlRegisterType(uri, 2, 9, "Scene2D"); + qmlRegisterExtendedType(uri, 2, 9, "Scene2D"); } QT_END_NAMESPACE diff --git a/src/quick3d/quick3dscene2d/items/items.pri b/src/quick3d/quick3dscene2d/items/items.pri index f79fc1f69..45d18dc40 100644 --- a/src/quick3d/quick3dscene2d/items/items.pri +++ b/src/quick3d/quick3dscene2d/items/items.pri @@ -4,12 +4,14 @@ HEADERS += \ $$PWD/qscene2d.h \ $$PWD/scene2dmanager_p.h \ $$PWD/scene2dsharedobject_p.h \ - $$PWD/scene2devent_p.h + $$PWD/scene2devent_p.h \ + $$PWD/qt3dquick3dscene2d_p.h SOURCES += \ $$PWD/qscene2d.cpp \ $$PWD/scene2d.cpp \ $$PWD/scene2dmanager.cpp \ - $$PWD/scene2dsharedobject.cpp + $$PWD/scene2dsharedobject.cpp \ + $$PWD/qt3dquick3dscene2d.cpp INCLUDEPATH += $$PWD diff --git a/src/quick3d/quick3dscene2d/items/qscene2d.cpp b/src/quick3d/quick3dscene2d/items/qscene2d.cpp index b797a5f5e..8b6c511eb 100644 --- a/src/quick3d/quick3dscene2d/items/qscene2d.cpp +++ b/src/quick3d/quick3dscene2d/items/qscene2d.cpp @@ -40,7 +40,9 @@ #include "scene2dmanager_p.h" #include "scene2devent_p.h" -#include +#include +#include +#include QT_BEGIN_NAMESPACE @@ -246,6 +248,8 @@ Qt3DCore::QNodeCreatedChangeBasePtr QScene2D::createNodeCreationChange() const data.renderPolicy = d->m_renderManager->m_renderPolicy; data.sharedObject = d->m_renderManager->m_sharedObject; data.output = d->m_output ? d->m_output->id() : Qt3DCore::QNodeId(); + for (Qt3DCore::QEntity *e : d->m_entities) + data.entityIds.append(e->id()); return creationChange; } @@ -265,6 +269,12 @@ QQmlEngine *QScene2D::engine() const return d->m_renderManager->m_qmlEngine; } +bool QScene2D::isGrabMouseEnabled() const +{ + Q_D(const QScene2D); + return d->m_renderManager->m_grabMouse; +} + /*! \internal */ @@ -273,6 +283,55 @@ void QScene2D::sourceLoaded() emit loadedChanged(true); } + +QVector QScene2D::entities() +{ + Q_D(const QScene2D); + return d->m_entities; +} + +void QScene2D::addEntity(Qt3DCore::QEntity *entity) +{ + Q_D(QScene2D); + if (!d->m_entities.contains(entity)) { + d->m_entities.append(entity); + + d->registerDestructionHelper(entity, &QScene2D::removeEntity, d->m_entities); + + if (d->m_changeArbiter != nullptr) { + const auto change = Qt3DCore::QPropertyNodeAddedChangePtr::create(id(), entity); + change->setPropertyName("entities"); + d->notifyObservers(change); + } + } +} + +void QScene2D::removeEntity(Qt3DCore::QEntity *entity) +{ + Q_D(QScene2D); + if (d->m_entities.contains(entity)) { + d->m_entities.removeAll(entity); + + d->unregisterDestructionHelper(entity); + + if (d->m_changeArbiter != nullptr) { + const auto change = Qt3DCore::QPropertyNodeRemovedChangePtr::create(id(), entity); + change->setPropertyName("entities"); + d->notifyObservers(change); + } + } +} + +void QScene2D::setGrabMouseEnabled(bool grab) +{ + Q_D(QScene2D); + if (d->m_renderManager->m_grabMouse != grab) { + d->m_renderManager->m_grabMouse = grab; + emit grabMouseChanged(grab); + } +} + + } // namespace Quick } // namespace Qt3DRender diff --git a/src/quick3d/quick3dscene2d/items/qscene2d.h b/src/quick3d/quick3dscene2d/items/qscene2d.h index c9bd9bea2..2c982668a 100644 --- a/src/quick3d/quick3dscene2d/items/qscene2d.h +++ b/src/quick3d/quick3dscene2d/items/qscene2d.h @@ -64,6 +64,7 @@ class QT3DQUICKSCENE2DSHARED_EXPORT QScene2D : public Qt3DCore::QNode Q_PROPERTY(QScene2D::RenderPolicy renderPolicy READ renderPolicy WRITE setRenderPolicy NOTIFY renderPolicyChanged) Q_PROPERTY(bool loaded READ loaded NOTIFY loadedChanged) Q_PROPERTY(QQuickItem *item READ item WRITE setItem NOTIFY itemChanged) + Q_PROPERTY(bool grabMouse READ isGrabMouseEnabled WRITE setGrabMouseEnabled NOTIFY grabMouseChanged) Q_CLASSINFO("DefaultProperty", "item") @@ -85,13 +86,20 @@ public: QScene2D::RenderPolicy renderPolicy() const; QQuickItem *item() const; QQmlEngine *engine() const; + bool isGrabMouseEnabled() const; + bool event(QEvent *event) Q_DECL_OVERRIDE; + QVector entities(); + void addEntity(Qt3DCore::QEntity *entity); + void removeEntity(Qt3DCore::QEntity *entity); + public Q_SLOTS: void setOutput(Qt3DRender::QRenderTargetOutput *output); void setSource(const QUrl &url); void setRenderPolicy(QScene2D::RenderPolicy policy); void setItem(QQuickItem *item); + void setGrabMouseEnabled(bool grab); Q_SIGNALS: void outputChanged(Qt3DRender::QRenderTargetOutput *output); @@ -99,6 +107,7 @@ Q_SIGNALS: void loadedChanged(bool loaded); void renderPolicyChanged(QScene2D::RenderPolicy policy); void itemChanged(QQuickItem *item); + void grabMouseChanged(bool grab); protected: Q_DECLARE_PRIVATE(QScene2D) diff --git a/src/quick3d/quick3dscene2d/items/qscene2d_p.h b/src/quick3d/quick3dscene2d/items/qscene2d_p.h index 82865035f..e40d3d6a9 100644 --- a/src/quick3d/quick3dscene2d/items/qscene2d_p.h +++ b/src/quick3d/quick3dscene2d/items/qscene2d_p.h @@ -73,6 +73,7 @@ public: Scene2DManager *m_renderManager; QMetaObject::Connection m_textureDestroyedConnection; Qt3DRender::QRenderTargetOutput *m_output; + QVector m_entities; }; struct QScene2DData @@ -80,6 +81,7 @@ struct QScene2DData QScene2D::RenderPolicy renderPolicy; Scene2DSharedObjectPtr sharedObject; Qt3DCore::QNodeId output; + QVector entityIds; }; } // namespace Quick diff --git a/src/quick3d/quick3dscene2d/items/qt3dquick3dscene2d.cpp b/src/quick3d/quick3dscene2d/items/qt3dquick3dscene2d.cpp new file mode 100644 index 000000000..83cbefc59 --- /dev/null +++ b/src/quick3d/quick3dscene2d/items/qt3dquick3dscene2d.cpp @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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 "qt3dquick3dscene2d_p.h" +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { +namespace Render { +namespace Quick { + +QQuick3DScene2D::QQuick3DScene2D(QObject *parent) + : QObject(parent) +{ +} + +QQmlListProperty QQuick3DScene2D::entities() +{ + return QQmlListProperty(this, 0, + &QQuick3DScene2D::appendEntity, + &QQuick3DScene2D::entityCount, + &QQuick3DScene2D::entityAt, + &QQuick3DScene2D::clearEntities); +} + +void QQuick3DScene2D::appendEntity(QQmlListProperty *list, + Qt3DCore::QEntity *entity) +{ + QQuick3DScene2D *scene2d = qobject_cast(list->object); + if (scene2d) + scene2d->parentScene2D()->addEntity(entity); +} + +int QQuick3DScene2D::entityCount(QQmlListProperty *list) +{ + QQuick3DScene2D *scene2d = qobject_cast(list->object); + if (scene2d) + return scene2d->parentScene2D()->entities().count(); + return 0; +} + +Qt3DCore::QEntity *QQuick3DScene2D::entityAt(QQmlListProperty *list, int index) +{ + QQuick3DScene2D *scene2d = qobject_cast(list->object); + if (scene2d) { + return qobject_cast( + scene2d->parentScene2D()->entities().at(index)); + } + return nullptr; +} + +void QQuick3DScene2D::clearEntities(QQmlListProperty *list) +{ + QQuick3DScene2D *scene2d = qobject_cast(list->object); + if (scene2d) { + QVector entities = scene2d->parentScene2D()->entities(); + for (Qt3DCore::QEntity *e : entities) + scene2d->parentScene2D()->removeEntity(e); + } +} + +} // namespace Quick +} // namespace Render +} // namespace Qt3DRender + +QT_END_NAMESPACE diff --git a/src/quick3d/quick3dscene2d/items/qt3dquick3dscene2d_p.h b/src/quick3d/quick3dscene2d/items/qt3dquick3dscene2d_p.h new file mode 100644 index 000000000..57734223b --- /dev/null +++ b/src/quick3d/quick3dscene2d/items/qt3dquick3dscene2d_p.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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$ +** +****************************************************************************/ + +#ifndef QT3DSCENE2D_QUICK_QUICK3DSCENE2D_P_H +#define QT3DSCENE2D_QUICK_QUICK3DSCENE2D_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +#include + +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { +namespace Render { +namespace Quick { + +class QT3DQUICKSCENE2DSHARED_EXPORT QQuick3DScene2D : public QObject +{ + Q_OBJECT + Q_PROPERTY(QQmlListProperty entities READ entities) + +public: + QQuick3DScene2D(QObject *parent = nullptr); + + inline Qt3DRender::Quick::QScene2D *parentScene2D() const + { + return qobject_cast(parent()); + } + + QQmlListProperty entities(); + +private: + + static void appendEntity(QQmlListProperty *list, Qt3DCore::QEntity *entity); + static Qt3DCore::QEntity *entityAt(QQmlListProperty *list, int index); + static int entityCount(QQmlListProperty *list); + static void clearEntities(QQmlListProperty *list); +}; + +} // namespace Quick +} // namespace Render +} // namespace Qt3DRender + +QT_END_NAMESPACE + +#endif // QT3DANIMATION_QUICK_QUICK3DMORPHINGANIMATION_P_H + diff --git a/src/quick3d/quick3dscene2d/items/scene2d.cpp b/src/quick3d/quick3dscene2d/items/scene2d.cpp index 80ed19053..0ecb49ab3 100644 --- a/src/quick3d/quick3dscene2d/items/scene2d.cpp +++ b/src/quick3d/quick3dscene2d/items/scene2d.cpp @@ -35,10 +35,14 @@ ****************************************************************************/ #include +#include +#include #include +#include #include #include +#include #include #include @@ -50,6 +54,9 @@ #include #include #include +#include +#include +#include QT_BEGIN_NAMESPACE @@ -101,7 +108,8 @@ bool RenderQmlEventHandler::event(QEvent *e) } Scene2D::Scene2D() - : m_context(nullptr) + : Qt3DRender::Render::BackendNode(Qt3DCore::QBackendNode::ReadWrite) + , m_context(nullptr) , m_shareContext(nullptr) , m_renderThread(nullptr) , m_sharedObject(nullptr) @@ -163,11 +171,15 @@ void Scene2D::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &chan m_renderPolicy = data.renderPolicy; setSharedObject(data.sharedObject); setOutput(data.output); + m_entities = data.entityIds; } void Scene2D::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) { - if (e->type() == Qt3DCore::PropertyUpdated) { + switch (e->type()) { + + case Qt3DCore::PropertyUpdated: { + Qt3DCore::QPropertyUpdatedChangePtr propertyChange = qSharedPointerCast(e); if (propertyChange->propertyName() == QByteArrayLiteral("renderPolicy")) { @@ -179,7 +191,50 @@ void Scene2D::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) const Scene2DSharedObjectPtr sharedObject = propertyChange->value().value(); setSharedObject(sharedObject); + } else if (propertyChange->propertyName() == QByteArrayLiteral("pressed")) { + QPickEventPtr ev = propertyChange->value().value(); + handlePickEvent(QEvent::MouseButtonPress, ev); + } else if (propertyChange->propertyName() == QByteArrayLiteral("released")) { + QPickEventPtr ev = propertyChange->value().value(); + handlePickEvent(QEvent::MouseButtonRelease, ev); + } else if (propertyChange->propertyName() == QByteArrayLiteral("clicked")) { + QPickEventPtr ev = propertyChange->value().value(); + handlePickEvent(QEvent::MouseButtonDblClick, ev); + } else if (propertyChange->propertyName() == QByteArrayLiteral("moved")) { + QPickEventPtr ev = propertyChange->value().value(); + handlePickEvent(QEvent::MouseMove, ev); + } else if (propertyChange->propertyName() == QByteArrayLiteral("grabMouseEvents")) { + if (propertyChange->value().toBool()) { + startGrabbing(); + } else { + stopGrabbing(); + } } + /* TODO: handle these? + else if (propertyChange->propertyName() == QByteArrayLiteral("entered")) { + + } else if (propertyChange->propertyName() == QByteArrayLiteral("exited")) { + + }*/ + break; + } + + case Qt3DCore::PropertyValueAdded: { + const auto change = qSharedPointerCast(e); + if (change->propertyName() == QByteArrayLiteral("entities")) + m_entities.push_back(change->addedNodeId()); + break; + } + + case Qt3DCore::PropertyValueRemoved: { + const auto change = qSharedPointerCast(e); + if (change->propertyName() == QByteArrayLiteral("entities")) + m_entities.removeOne(change->removedNodeId()); + break; + } + + default: + break; } BackendNode::sceneChangeEvent(e); } @@ -273,8 +328,10 @@ void Scene2D::render() m_context->makeCurrent(m_sharedObject->m_surface); - if (resourceAccessor()->accessResource(m_outputId, (void**)&attachmentData, nullptr)) { - if (!resourceAccessor()->accessResource(attachmentData->m_textureUuid, + if (resourceAccessor()->accessResource(RenderBackendResourceAccessor::OutputAttachment, + m_outputId, (void**)&attachmentData, nullptr)) { + if (!resourceAccessor()->accessResource(RenderBackendResourceAccessor::OGLTexture, + attachmentData->m_textureUuid, (void**)&texture, &textureLock)) { // Need to call sync even if the texture is not in use syncRenderControl(); @@ -369,6 +426,82 @@ void Scene2D::cleanup() renderThread->quit(); } + +bool Scene2D::registerObjectPickerEvents(Qt3DCore::QNodeId entityId) +{ + Entity *entity = nullptr; + if (!resourceAccessor()->accessResource(RenderBackendResourceAccessor::EntityHandle, + entityId, (void**)&entity, nullptr)) { + return false; + } + if (!entity->containsComponentsOfType() || + !entity->containsComponentsOfType()) { + qCWarning(Qt3DRender::Quick::Scene2D) << Q_FUNC_INFO + << "Entity does not contain required components: ObjectPicker and GeometryRenderer"; + return false; + } + Qt3DCore::QBackendNodePrivate *priv = Qt3DCore::QBackendNodePrivate::get(this); + Qt3DCore::QChangeArbiter *arbiter = static_cast(priv->m_arbiter); + arbiter->registerObserver(d_ptr, entity->componentUuid()); + return true; +} + +void Scene2D::unregisterObjectPickerEvents(Qt3DCore::QNodeId entityId) +{ + Entity *entity = nullptr; + if (!resourceAccessor()->accessResource(RenderBackendResourceAccessor::EntityHandle, + entityId, (void**)&entity, nullptr)) { + return; + } + Qt3DCore::QBackendNodePrivate *priv = Qt3DCore::QBackendNodePrivate::get(this); + Qt3DCore::QChangeArbiter *arbiter = static_cast(priv->m_arbiter); + arbiter->unregisterObserver(d_ptr, entity->componentUuid()); +} + +void Scene2D::handlePickEvent(int type, const Qt3DRender::QPickEventPtr &ev) +{ + QPickTriangleEvent *pickTriangle = static_cast(ev.data()); + Entity *entity = nullptr; + if (!resourceAccessor()->accessResource(RenderBackendResourceAccessor::EntityHandle, + QPickEventPrivate::get(pickTriangle)->m_entity, + (void**)&entity, nullptr)) { + return; + } + CoordinateReader reader(renderer()->nodeManagers()); + if (reader.setGeometry(entity->renderComponent(), + QAttribute::defaultTextureCoordinateAttributeName())) { + QVector4D c0 = reader.getCoordinate(pickTriangle->vertex1Index()); + QVector4D c1 = reader.getCoordinate(pickTriangle->vertex2Index()); + QVector4D c2 = reader.getCoordinate(pickTriangle->vertex3Index()); + QVector4D ci = c2 * pickTriangle->uvw().x() + + c1 * pickTriangle->uvw().y() + c0 * pickTriangle->uvw().z(); + ci.setW(1.0f); + + QPointF pos = QPointF(ci.x(), ci.y()); + QMouseEvent *mouseEvent + = new QMouseEvent(static_cast(type), + pos, pos, pos, + static_cast(pickTriangle->button()), + static_cast(pickTriangle->buttons()), + static_cast(pickTriangle->modifiers()), + Qt::MouseEventSynthesizedByApplication); + + QCoreApplication::postEvent(m_sharedObject->m_quickWindow, mouseEvent); + } +} + +void Scene2D::startGrabbing() +{ + for (Qt3DCore::QNodeId e : m_entities) + registerObjectPickerEvents(e); +} + +void Scene2D::stopGrabbing() +{ + for (Qt3DCore::QNodeId e : m_entities) + unregisterObjectPickerEvents(e); +} + } // namespace Quick } // namespace Render } // namespace Qt3DRender diff --git a/src/quick3d/quick3dscene2d/items/scene2d_p.h b/src/quick3d/quick3dscene2d/items/scene2d_p.h index 608ecc5dc..d2845d847 100644 --- a/src/quick3d/quick3dscene2d/items/scene2d_p.h +++ b/src/quick3d/quick3dscene2d/items/scene2d_p.h @@ -49,6 +49,8 @@ // #include +#include +#include #include #include @@ -97,6 +99,11 @@ public: bool updateFbo(QOpenGLTexture *texture); void syncRenderControl(); + void startGrabbing(); + void stopGrabbing(); + bool registerObjectPickerEvents(Qt3DCore::QNodeId entityId); + void unregisterObjectPickerEvents(Qt3DCore::QNodeId entityId); + void handlePickEvent(int type, const Qt3DRender::QPickEventPtr &ev); QOpenGLContext *m_context; QOpenGLContext *m_shareContext; @@ -113,6 +120,7 @@ public: bool m_initialized; bool m_renderInitialized; Qt3DRender::Quick::QScene2D::RenderPolicy m_renderPolicy; + QVector m_entities; }; } // Quick diff --git a/src/quick3d/quick3dscene2d/items/scene2dmanager.cpp b/src/quick3d/quick3dscene2d/items/scene2dmanager.cpp index a2daee49b..e595ed58d 100644 --- a/src/quick3d/quick3dscene2d/items/scene2dmanager.cpp +++ b/src/quick3d/quick3dscene2d/items/scene2dmanager.cpp @@ -86,6 +86,7 @@ Scene2DManager::Scene2DManager(QScene2DPrivate *priv) , m_noSourceMode(false) , m_item(nullptr) , m_ownEngine(false) + , m_grabMouse(false) { m_sharedObject->m_surface = new QOffscreenSurface; m_sharedObject->m_surface->setFormat(QSurfaceFormat::defaultFormat()); diff --git a/src/quick3d/quick3dscene2d/items/scene2dmanager_p.h b/src/quick3d/quick3dscene2d/items/scene2dmanager_p.h index 4b3eeceec..d3c3a60a2 100644 --- a/src/quick3d/quick3dscene2d/items/scene2dmanager_p.h +++ b/src/quick3d/quick3dscene2d/items/scene2dmanager_p.h @@ -94,6 +94,7 @@ public: bool m_backendInitialized; bool m_noSourceMode; bool m_ownEngine; + bool m_grabMouse; void requestRender(); void requestRenderSync(); diff --git a/src/render/backend/entity_p.h b/src/render/backend/entity_p.h index 9f010509a..4619314ad 100644 --- a/src/render/backend/entity_p.h +++ b/src/render/backend/entity_p.h @@ -250,10 +250,10 @@ template<> Transform *Entity::renderComponent() const; template<> -Q_AUTOTEST_EXPORT GeometryRenderer *Entity::renderComponent() const; +QT3DRENDERSHARED_PRIVATE_EXPORT GeometryRenderer *Entity::renderComponent() const; template<> -Q_AUTOTEST_EXPORT ObjectPicker *Entity::renderComponent() const; +QT3DRENDERSHARED_PRIVATE_EXPORT ObjectPicker *Entity::renderComponent() const; template<> QVector Entity::renderComponents() const; @@ -296,10 +296,10 @@ template<> Q_AUTOTEST_EXPORT QVector Entity::componentsUuid() const; template<> -Q_AUTOTEST_EXPORT Qt3DCore::QNodeId Entity::componentUuid() const; +QT3DRENDERSHARED_PRIVATE_EXPORT Qt3DCore::QNodeId Entity::componentUuid() const; template<> -Q_AUTOTEST_EXPORT Qt3DCore::QNodeId Entity::componentUuid() const; +QT3DRENDERSHARED_PRIVATE_EXPORT Qt3DCore::QNodeId Entity::componentUuid() const; //template<> //Q_AUTOTEST_EXPORT Qt3DCore::QNodeId Entity::componentUuid() const; diff --git a/src/render/backend/resourceaccessor.cpp b/src/render/backend/resourceaccessor.cpp index 9c7211a70..7558eb4ad 100644 --- a/src/render/backend/resourceaccessor.cpp +++ b/src/render/backend/resourceaccessor.cpp @@ -63,34 +63,58 @@ ResourceAccessor::ResourceAccessor(NodeManagers *mgr) : m_glTextureManager(mgr->glTextureManager()) , m_textureManager(mgr->textureManager()) , m_attachmentManager(mgr->attachmentManager()) + , m_entityManager(mgr->renderNodesManager()) { } // called by render plugins from arbitrary thread -bool ResourceAccessor::accessResource(Qt3DCore::QNodeId nodeId, void **handle, QMutex **lock) +bool ResourceAccessor::accessResource(ResourceType type, Qt3DCore::QNodeId nodeId, void **handle, QMutex **lock) { - Texture *tex = m_textureManager->lookupResource(nodeId); - if (!tex) { - RenderTargetOutput *output = m_attachmentManager->lookupResource(nodeId); - if (!output) + switch (type) { + + case RenderBackendResourceAccessor::OGLTexture: { + Texture *tex = m_textureManager->lookupResource(nodeId); + if (!tex) + return false; + + GLTexture *glTex = m_glTextureManager->lookupResource(tex->peerId()); + if (!glTex) + return false; + + if (glTex->isDirty()) return false; - Attachment **attachmentData = reinterpret_cast(handle); - *attachmentData = output->attachment(); + QOpenGLTexture **glTextureHandle = reinterpret_cast(handle); + *glTextureHandle = glTex->getOrCreateGLTexture(); + *lock = glTex->textureLock(); return true; } - GLTexture *glTex = m_glTextureManager->lookupResource(tex->peerId()); - if (!glTex) - return false; - if (glTex->isDirty()) - return false; + case RenderBackendResourceAccessor::OutputAttachment: { + RenderTargetOutput *output = m_attachmentManager->lookupResource(nodeId); + if (output) { + Attachment **attachmentData = reinterpret_cast(handle); + *attachmentData = output->attachment(); + return true; + } + break; + } - QOpenGLTexture** glTextureHandle = reinterpret_cast(handle); - *glTextureHandle = glTex->getOrCreateGLTexture(); - *lock = glTex->textureLock(); - return true; + case RenderBackendResourceAccessor::EntityHandle: { + Entity *entity = m_entityManager->lookupResource(nodeId); + if (entity) { + Entity **pEntity = reinterpret_cast(handle); + *pEntity = entity; + return true; + } + break; + } + + default: + break; + } + return false; } } // namespace Render diff --git a/src/render/backend/resourceaccessor_p.h b/src/render/backend/resourceaccessor_p.h index d99a64ddb..b4ed2a3eb 100644 --- a/src/render/backend/resourceaccessor_p.h +++ b/src/render/backend/resourceaccessor_p.h @@ -66,24 +66,32 @@ namespace Render { class TextureManager; class AttachmentManager; class GLTextureManager; +class EntityManager; class NodeManagers; class RenderBackendResourceAccessor { public: + enum ResourceType { + OGLTexture, + OutputAttachment, + EntityHandle, + }; + virtual ~RenderBackendResourceAccessor(); - virtual bool accessResource(Qt3DCore::QNodeId nodeId, void **handle, QMutex **lock) = 0; + virtual bool accessResource(ResourceType type, Qt3DCore::QNodeId nodeId, void **handle, QMutex **lock) = 0; }; class QT3DRENDERSHARED_PRIVATE_EXPORT ResourceAccessor : public RenderBackendResourceAccessor { public: ResourceAccessor(NodeManagers *mgr); - bool accessResource(Qt3DCore::QNodeId nodeId, void **handle, QMutex **lock) Q_DECL_FINAL; + bool accessResource(ResourceType type, Qt3DCore::QNodeId nodeId, void **handle, QMutex **lock) Q_DECL_FINAL; private: GLTextureManager *m_glTextureManager; TextureManager *m_textureManager; AttachmentManager *m_attachmentManager; + EntityManager *m_entityManager; }; } // namespace Render diff --git a/src/render/backend/trianglesvisitor_p.h b/src/render/backend/trianglesvisitor_p.h index 149ac2a65..9428857ac 100644 --- a/src/render/backend/trianglesvisitor_p.h +++ b/src/render/backend/trianglesvisitor_p.h @@ -55,6 +55,8 @@ #include #include +#include + QT_BEGIN_NAMESPACE namespace Qt3DCore { @@ -88,7 +90,7 @@ protected: Qt3DCore::QNodeId m_nodeId; }; -class Q_AUTOTEST_EXPORT CoordinateReader +class QT3DRENDERSHARED_PRIVATE_EXPORT CoordinateReader { public: explicit CoordinateReader(NodeManagers *manager) diff --git a/src/render/jobs/pickboundingvolumejob.cpp b/src/render/jobs/pickboundingvolumejob.cpp index ecb16f985..3430c293b 100644 --- a/src/render/jobs/pickboundingvolumejob.cpp +++ b/src/render/jobs/pickboundingvolumejob.cpp @@ -49,6 +49,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE @@ -362,14 +363,15 @@ void PickBoundingVolumeJob::dispatchPickEvents(const QMouseEvent &event, localIntersection = hit.m_intersection * entity->worldTransform()->inverted(); QPickEventPtr pickEvent; - if (trianglePickingRequested) + if (trianglePickingRequested) { pickEvent.reset(new QPickTriangleEvent(event.localPos(), hit.m_intersection, localIntersection, hit.m_distance, hit.m_triangleIndex, hit.m_vertexIndex[0], hit.m_vertexIndex[1], hit.m_vertexIndex[2], - eventButton, eventButtons, eventModifiers)); - else + eventButton, eventButtons, eventModifiers, hit.m_uvw)); + QPickEventPrivate::get(pickEvent.data())->m_entity = hit.m_entityId; + } else { pickEvent.reset(new QPickEvent(event.localPos(), hit.m_intersection, localIntersection, hit.m_distance, eventButton, eventButtons, eventModifiers)); - + } switch (event.type()) { case QEvent::MouseButtonPress: { // Store pressed object handle diff --git a/src/render/picking/qpickevent.cpp b/src/render/picking/qpickevent.cpp index 806d91dc0..148850baf 100644 --- a/src/render/picking/qpickevent.cpp +++ b/src/render/picking/qpickevent.cpp @@ -78,6 +78,11 @@ QPickEvent::QPickEvent() { } +QPickEventPrivate *QPickEventPrivate::get(QPickEvent *object) +{ + return object->d_func(); +} + /*! \fn Qt3DRender::QPickEvent::QPickEvent(const QPointF &position, const QVector3D &intersection, const QVector3D &localIntersection, float distance) Constructs a new QPickEvent with the given parameters: \a position, \a intersection, \a localIntersection and \a distance diff --git a/src/render/picking/qpickevent_p.h b/src/render/picking/qpickevent_p.h index 399795619..ced36c9bb 100644 --- a/src/render/picking/qpickevent_p.h +++ b/src/render/picking/qpickevent_p.h @@ -48,13 +48,19 @@ // We mean it. // +#include + #include +#include + QT_BEGIN_NAMESPACE namespace Qt3DRender { -class QPickEventPrivate : public QObjectPrivate +class QPickEvent; + +class QT3DRENDERSHARED_PRIVATE_EXPORT QPickEventPrivate : public QObjectPrivate { public: QPickEventPrivate() @@ -75,6 +81,9 @@ public: QPickEvent::Buttons m_button; int m_buttons; int m_modifiers; + Qt3DCore::QNodeId m_entity; + + static QPickEventPrivate *get(QPickEvent *object); }; } // Qt3DRender diff --git a/src/render/picking/qpicktriangleevent.cpp b/src/render/picking/qpicktriangleevent.cpp index 3077cc91a..2a4cdfea2 100644 --- a/src/render/picking/qpicktriangleevent.cpp +++ b/src/render/picking/qpicktriangleevent.cpp @@ -61,6 +61,7 @@ public: uint m_vertex1Index; uint m_vertex2Index; uint m_vertex3Index; + QVector3D m_uvw; }; /*! @@ -121,7 +122,8 @@ QPickTriangleEvent::QPickTriangleEvent() */ // NOTE: remove in Qt6 QPickTriangleEvent::QPickTriangleEvent(const QPointF &position, const QVector3D &worldIntersection, const QVector3D &localIntersection, float distance, - uint triangleIndex, uint vertex1Index, uint vertex2Index, uint vertex3Index) + uint triangleIndex, uint vertex1Index, uint vertex2Index, + uint vertex3Index) : QPickEvent(*new QPickTriangleEventPrivate()) { Q_D(QPickTriangleEvent); @@ -135,7 +137,11 @@ QPickTriangleEvent::QPickTriangleEvent(const QPointF &position, const QVector3D d->m_vertex3Index = vertex3Index; } -QPickTriangleEvent::QPickTriangleEvent(const QPointF &position, const QVector3D &worldIntersection, const QVector3D &localIntersection, float distance, uint triangleIndex, uint vertex1Index, uint vertex2Index, uint vertex3Index, QPickEvent::Buttons button, int buttons, int modifiers) +QPickTriangleEvent::QPickTriangleEvent(const QPointF &position, const QVector3D &worldIntersection, + const QVector3D &localIntersection, float distance, + uint triangleIndex, uint vertex1Index, uint vertex2Index, + uint vertex3Index, QPickEvent::Buttons button, int buttons, + int modifiers, const QVector3D &uvw) : QPickEvent(*new QPickTriangleEventPrivate()) { Q_D(QPickTriangleEvent); @@ -150,6 +156,7 @@ QPickTriangleEvent::QPickTriangleEvent(const QPointF &position, const QVector3D d->m_button = button; d->m_buttons = buttons; d->m_modifiers = modifiers; + d->m_uvw = uvw; } /*! \internal */ @@ -229,6 +236,12 @@ uint QPickTriangleEvent::vertex3Index() const return d->m_vertex3Index; } +QVector3D QPickTriangleEvent::uvw() const +{ + Q_D(const QPickTriangleEvent); + return d->m_uvw; +} + } // Qt3DRender QT_END_NAMESPACE diff --git a/src/render/picking/qpicktriangleevent.h b/src/render/picking/qpicktriangleevent.h index 7cafa1aeb..7655a0b94 100644 --- a/src/render/picking/qpicktriangleevent.h +++ b/src/render/picking/qpicktriangleevent.h @@ -54,12 +54,14 @@ class QT3DRENDERSHARED_EXPORT QPickTriangleEvent : public QPickEvent Q_PROPERTY(uint vertex1Index READ vertex1Index CONSTANT) Q_PROPERTY(uint vertex2Index READ vertex2Index CONSTANT) Q_PROPERTY(uint vertex3Index READ vertex3Index CONSTANT) + Q_PROPERTY(QVector3D uvw READ uvw CONSTANT) public: QPickTriangleEvent(); QPickTriangleEvent(const QPointF &position, const QVector3D& worldIntersection, const QVector3D& localIntersection, float distance, uint triangleIndex, uint vertex1Index, uint vertex2Index, uint vertex3Index); QPickTriangleEvent(const QPointF &position, const QVector3D& worldIntersection, const QVector3D& localIntersection, float distance, - uint triangleIndex, uint vertex1Index, uint vertex2Index, uint vertex3Index, Buttons button, int buttons, int modifiers); + uint triangleIndex, uint vertex1Index, uint vertex2Index, uint vertex3Index, Buttons button, int buttons, int modifiers, + const QVector3D &uvw); ~QPickTriangleEvent(); public: @@ -67,6 +69,7 @@ public: uint vertex1Index() const; uint vertex2Index() const; uint vertex3Index() const; + QVector3D uvw() const; private: Q_DECLARE_PRIVATE(QPickTriangleEvent) diff --git a/tests/manual/render-qml-to-texture-qml/main.qml b/tests/manual/render-qml-to-texture-qml/main.qml index c793078d3..748e14f6e 100644 --- a/tests/manual/render-qml-to-texture-qml/main.qml +++ b/tests/manual/render-qml-to-texture-qml/main.qml @@ -89,6 +89,10 @@ QQ2.Item { } } + + entities: [plane1] + grabMouse: plane1.picker.pressed + InteractiveGui { } @@ -97,6 +101,7 @@ QQ2.Item { FirstPersonCameraController { id: controller camera: camera + enabled: !plane1.picker.pressed } components: [ @@ -132,17 +137,6 @@ QQ2.Item { property ObjectPicker picker: ObjectPicker { hoverEnabled: true dragEnabled: true - eventForward: EventForward { - id: eventForward - target: qmlTexture - focus: true - } - onPressed: { - controller.enabled = false - } - onReleased: { - controller.enabled = true - } } components: [planeMesh, material, transform, picker] -- cgit v1.2.3 From 2b4bfd065ecfa28d8b7399ffed35a2f35834c461 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Thu, 2 Feb 2017 16:57:02 +0200 Subject: Fix crash in scene2d when using angle Angle can't do multithreaded rendering on shared context so it needs to synchronize the rendering with qt3d render thread. The SurfaceLocker uses static mutex, so using it to lock the surface will prevent simulatious rendering as well. Flag the surface lock for angle build only. Change-Id: I83d4e1f1d6a48e86196bc113cbab4ee79205b61f Reviewed-by: Sean Harmer --- src/quick3d/quick3dscene2d/items/scene2d.cpp | 4 ++++ src/render/backend/platformsurfacefilter_p.h | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/quick3d/quick3dscene2d/items/scene2d.cpp b/src/quick3d/quick3dscene2d/items/scene2d.cpp index 0ecb49ab3..88bbb4e94 100644 --- a/src/quick3d/quick3dscene2d/items/scene2d.cpp +++ b/src/quick3d/quick3dscene2d/items/scene2d.cpp @@ -57,6 +57,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE @@ -326,6 +327,9 @@ void Scene2D::render() const Qt3DRender::Render::Attachment *attachmentData = nullptr; QMutex *textureLock = nullptr; +#ifdef QT_OPENGL_ES_2_ANGLE + SurfaceLocker surfaceLocker(m_sharedObject->m_surface); +#endif m_context->makeCurrent(m_sharedObject->m_surface); if (resourceAccessor()->accessResource(RenderBackendResourceAccessor::OutputAttachment, diff --git a/src/render/backend/platformsurfacefilter_p.h b/src/render/backend/platformsurfacefilter_p.h index ec10327fe..dbdc07b01 100644 --- a/src/render/backend/platformsurfacefilter_p.h +++ b/src/render/backend/platformsurfacefilter_p.h @@ -51,6 +51,8 @@ // We mean it. // +#include + #include #include #include @@ -106,7 +108,7 @@ private: void markSurfaceAsValid(); }; -class SurfaceLocker +class QT3DRENDERSHARED_PRIVATE_EXPORT SurfaceLocker { public: explicit SurfaceLocker(QSurface *surface); -- cgit v1.2.3 From f13d072a12d53e489f2647916a119878ea8208bb Mon Sep 17 00:00:00 2001 From: Mike Krus Date: Sat, 4 Mar 2017 10:05:51 +0000 Subject: Fix clang warnings in Scene2D - out of order initialization - unused data member - switch case values not in enum Change-Id: I9640d0ee2cbc058fbb2e2e89e5bcb839163bf49c Reviewed-by: Sean Harmer --- src/quick3d/quick3dscene2d/items/scene2d.cpp | 2 +- src/quick3d/quick3dscene2d/items/scene2dmanager.cpp | 13 ++++++------- src/quick3d/quick3dscene2d/items/scene2dsharedobject.cpp | 10 +++++----- src/quick3d/quick3dscene2d/items/scene2dsharedobject_p.h | 1 - 4 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/quick3d/quick3dscene2d/items/scene2d.cpp b/src/quick3d/quick3dscene2d/items/scene2d.cpp index 88bbb4e94..624a67ed6 100644 --- a/src/quick3d/quick3dscene2d/items/scene2d.cpp +++ b/src/quick3d/quick3dscene2d/items/scene2d.cpp @@ -85,7 +85,7 @@ RenderQmlEventHandler::RenderQmlEventHandler(Scene2D *node) // Event handler for the RenderQmlToTexture::renderThread bool RenderQmlEventHandler::event(QEvent *e) { - switch (e->type()) { + switch (static_cast(e->type())) { case Scene2DEvent::Render: { m_node->render(); diff --git a/src/quick3d/quick3dscene2d/items/scene2dmanager.cpp b/src/quick3d/quick3dscene2d/items/scene2dmanager.cpp index e595ed58d..f0d6a6e34 100644 --- a/src/quick3d/quick3dscene2d/items/scene2dmanager.cpp +++ b/src/quick3d/quick3dscene2d/items/scene2dmanager.cpp @@ -72,19 +72,18 @@ QWindow *RenderControl::renderWindow(QPoint *offset) Constructs qml render manager. */ Scene2DManager::Scene2DManager(QScene2DPrivate *priv) - : m_priv(priv) - , m_qmlEngine(nullptr) + : m_qmlEngine(nullptr) , m_qmlComponent(nullptr) , m_rootItem(nullptr) - , m_source(nullptr) + , m_item(nullptr) + , m_priv(priv) + , m_sharedObject(new Scene2DSharedObject(this)) + , m_renderPolicy(QScene2D::Continuous) , m_requested(false) , m_initialized(false) , m_renderSyncRequested(false) - , m_sharedObject(new Scene2DSharedObject(this)) - , m_renderPolicy(QScene2D::Continuous) , m_backendInitialized(false) , m_noSourceMode(false) - , m_item(nullptr) , m_ownEngine(false) , m_grabMouse(false) { @@ -252,7 +251,7 @@ void Scene2DManager::setItem(QQuickItem *item) bool Scene2DManager::event(QEvent *e) { - switch (e->type()) { + switch (static_cast(e->type())) { case Scene2DEvent::Render: { // just render request, don't need to call sync in render thread diff --git a/src/quick3d/quick3dscene2d/items/scene2dsharedobject.cpp b/src/quick3d/quick3dscene2d/items/scene2dsharedobject.cpp index 9f1873eac..1dd798d94 100644 --- a/src/quick3d/quick3dscene2d/items/scene2dsharedobject.cpp +++ b/src/quick3d/quick3dscene2d/items/scene2dsharedobject.cpp @@ -57,16 +57,16 @@ namespace Quick { Constructs object shared by the front-end and back-end to synchronize the rendering. */ Scene2DSharedObject::Scene2DSharedObject(Scene2DManager *manager) - : m_quit(false) - , m_requestSync(false) - , m_prepared(false) - , m_initialized(false) - , m_renderControl(nullptr) + : m_renderControl(nullptr) , m_quickWindow(nullptr) , m_renderManager(manager) , m_surface(nullptr) , m_renderObject(nullptr) , m_disallowed(false) + , m_quit(false) + , m_requestSync(false) + , m_prepared(false) + , m_initialized(false) { } diff --git a/src/quick3d/quick3dscene2d/items/scene2dsharedobject_p.h b/src/quick3d/quick3dscene2d/items/scene2dsharedobject_p.h index bac6fb555..83863be20 100644 --- a/src/quick3d/quick3dscene2d/items/scene2dsharedobject_p.h +++ b/src/quick3d/quick3dscene2d/items/scene2dsharedobject_p.h @@ -114,7 +114,6 @@ private: bool m_disallowed; bool m_quit; bool m_requestSync; - bool m_requestRender; bool m_prepared; bool m_initialized; }; -- cgit v1.2.3 From 84f907017bb4fc72faf86bd70fbf49d629bc93f3 Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Fri, 3 Mar 2017 09:37:06 +0000 Subject: Remove AnimationUtils class It was stateless, so make the static member functions free functions and export them for auto tests. We're already in the Qt3DAnimation::Animation namespace so this removes some visual clutter. Change-Id: I4e1a72c47d5bd4afb807ce5f6dc80dc0ce4bb213 Reviewed-by: Mike Krus --- src/animation/backend/animationutils.cpp | 39 +++--- src/animation/backend/animationutils_p.h | 141 +++++++++++---------- src/animation/backend/blendedclipanimator_p.h | 2 +- src/animation/backend/buildblendtreesjob.cpp | 36 +++--- src/animation/backend/clipanimator.cpp | 2 +- src/animation/backend/clipanimator_p.h | 6 +- .../backend/evaluateblendclipanimatorjob.cpp | 35 ++--- .../backend/evaluateblendclipanimatorjob_p.h | 2 +- src/animation/backend/evaluateclipanimatorjob.cpp | 14 +- .../backend/findrunningclipanimatorsjob.cpp | 2 +- .../animationutils/tst_animationutils.cpp | 12 +- 11 files changed, 151 insertions(+), 140 deletions(-) diff --git a/src/animation/backend/animationutils.cpp b/src/animation/backend/animationutils.cpp index 85fbab42a..be76e1bed 100644 --- a/src/animation/backend/animationutils.cpp +++ b/src/animation/backend/animationutils.cpp @@ -51,8 +51,8 @@ QT_BEGIN_NAMESPACE namespace Qt3DAnimation { namespace Animation { -AnimationUtils::ClipPreEvaluationData AnimationUtils::evaluationDataForClip(AnimationClipLoader *clip, - const AnimationUtils::AnimatorEvaluationData &animatorData) +ClipPreEvaluationData evaluationDataForClip(AnimationClipLoader *clip, + const AnimatorEvaluationData &animatorData) { // global time values expected in seconds ClipPreEvaluationData result; @@ -65,12 +65,12 @@ AnimationUtils::ClipPreEvaluationData AnimationUtils::evaluationDataForClip(Anim return result; } -double AnimationUtils::localTimeFromGlobalTime(double t_global, - double t_start_global, - double playbackRate, - double duration, - int loopCount, - int ¤tLoop) +double localTimeFromGlobalTime(double t_global, + double t_start_global, + double playbackRate, + double duration, + int loopCount, + int ¤tLoop) { double t_local = playbackRate * (t_global - t_start_global); double loopNumber = 0; @@ -103,7 +103,7 @@ double AnimationUtils::localTimeFromGlobalTime(double t_global, return t_local; } -QVector AnimationUtils::channelComponentsToIndices(const Channel &channelGroup, int dataType, int offset) +QVector channelComponentsToIndices(const Channel &channelGroup, int dataType, int offset) { static const QStringList standardSuffixes = (QStringList() << QLatin1String("X") @@ -123,7 +123,10 @@ QVector AnimationUtils::channelComponentsToIndices(const Channel &channelGr } -QVector AnimationUtils::channelComponentsToIndicesHelper(const Channel &channel, int dataType, int offset, const QStringList &suffixes) +QVector channelComponentsToIndicesHelper(const Channel &channel, + int dataType, + int offset, + const QStringList &suffixes) { int expectedChannelCount = 1; switch (dataType) { @@ -166,7 +169,7 @@ QVector AnimationUtils::channelComponentsToIndicesHelper(const Channel &cha return indices; } -QVector AnimationUtils::evaluateClipAtLocalTime(AnimationClipLoader *clip, float localTime) +QVector evaluateClipAtLocalTime(AnimationClipLoader *clip, float localTime) { QVector channelResults; Q_ASSERT(clip); @@ -184,10 +187,10 @@ QVector AnimationUtils::evaluateClipAtLocalTime(AnimationClipLoader *clip return channelResults; } -QVector AnimationUtils::preparePropertyChanges(Qt3DCore::QNodeId peerId, - const QVector &mappingDataVec, - const QVector &channelResults, - bool finalFrame) +QVector preparePropertyChanges(Qt3DCore::QNodeId peerId, + const QVector &mappingDataVec, + const QVector &channelResults, + bool finalFrame) { QVector changes; // Iterate over the mappings @@ -264,9 +267,9 @@ QVector AnimationUtils::preparePropertyChanges(Qt3DCo return changes; } -QVector AnimationUtils::buildPropertyMappings(Handler *handler, - const AnimationClipLoader *clip, - const ChannelMapper *mapper) +QVector buildPropertyMappings(Handler *handler, + const AnimationClipLoader *clip, + const ChannelMapper *mapper) { QVector mappingDataVec; ChannelMappingManager *mappingManager = handler->channelMappingManager(); diff --git a/src/animation/backend/animationutils_p.h b/src/animation/backend/animationutils_p.h index cb8014e7b..f66b3999d 100644 --- a/src/animation/backend/animationutils_p.h +++ b/src/animation/backend/animationutils_p.h @@ -62,81 +62,88 @@ class Handler; class AnimationClipLoader; class ChannelMapper; -class Q_AUTOTEST_EXPORT AnimationUtils +struct MappingData { -public: - struct MappingData - { - Qt3DCore::QNodeId targetId; - const char *propertyName; - int type; - QVector channelIndices; - }; - - struct BlendingMappingData : public MappingData - { - QVector channelIndicesClip1; - QVector channelIndicesClip2; + Qt3DCore::QNodeId targetId; + const char *propertyName; + int type; + QVector channelIndices; +}; - enum BlendAction { - NoBlending, // Use the channel from Clip1 only - ClipBlending, // Blending 2 clips sharing the same channel - }; - BlendAction blendAction; - }; +struct BlendingMappingData : public MappingData +{ + QVector channelIndicesClip1; + QVector channelIndicesClip2; - struct AnimatorEvaluationData - { - double globalTime; - double startTime; - int loopCount; - double playbackRate; + enum BlendAction { + NoBlending, // Use the channel from Clip1 only + ClipBlending, // Blending 2 clips sharing the same channel }; + BlendAction blendAction; +}; - struct ClipPreEvaluationData - { - int currentLoop; - double localTime; - bool isFinalFrame; - }; +struct AnimatorEvaluationData +{ + double globalTime; + double startTime; + int loopCount; + double playbackRate; +}; - template - static AnimatorEvaluationData animatorEvaluationDataForAnimator(Animator animator, qint64 globalTime) - { - AnimationUtils::AnimatorEvaluationData data; - data.loopCount = animator->loops(); - data.playbackRate = 1.0; // should be a property on the animator - // Convert global time from nsec to sec - data.startTime = double(animator->startTime()) / 1.0e9; - data.globalTime = double(globalTime) / 1.0e9; - return data; - } - - static ClipPreEvaluationData evaluationDataForClip(AnimationClipLoader *clip, const AnimatorEvaluationData &animatorData); - - static QVector channelComponentsToIndices(const Channel &channelGroup, - int dataType, - int offset = 0); - static QVector channelComponentsToIndicesHelper(const Channel &channelGroup, - int dataType, - int offset, - const QStringList &suffixes); - static QVector evaluateClipAtLocalTime(AnimationClipLoader *clip, - float localTime); - static QVector preparePropertyChanges(Qt3DCore::QNodeId peerId, - const QVector &mappingData, - const QVector &channelResults, - bool finalFrame); - static QVector buildPropertyMappings(Handler *handler, - const AnimationClipLoader *clip, - const ChannelMapper *mapper); - -private: - static double localTimeFromGlobalTime(double t_global, double t_start_global, - double playbackRate, double duration, - int loopCount, int ¤tLoop); +struct ClipPreEvaluationData +{ + int currentLoop; + double localTime; + bool isFinalFrame; }; +template +AnimatorEvaluationData animatorEvaluationDataForAnimator(Animator animator, qint64 globalTime) +{ + AnimatorEvaluationData data; + data.loopCount = animator->loops(); + data.playbackRate = 1.0; // should be a property on the animator + // Convert global time from nsec to sec + data.startTime = double(animator->startTime()) / 1.0e9; + data.globalTime = double(globalTime) / 1.0e9; + return data; +} + +Q_AUTOTEST_EXPORT +ClipPreEvaluationData evaluationDataForClip(AnimationClipLoader *clip, + const AnimatorEvaluationData &animatorData); + +Q_AUTOTEST_EXPORT +QVector channelComponentsToIndices(const Channel &channelGroup, + int dataType, + int offset = 0); + +Q_AUTOTEST_EXPORT +QVector channelComponentsToIndicesHelper(const Channel &channelGroup, + int dataType, + int offset, + const QStringList &suffixes); + +Q_AUTOTEST_EXPORT +QVector evaluateClipAtLocalTime(AnimationClipLoader *clip, + float localTime); + +Q_AUTOTEST_EXPORT +QVector preparePropertyChanges(Qt3DCore::QNodeId peerId, + const QVector &mappingData, + const QVector &channelResults, + bool finalFrame); + +Q_AUTOTEST_EXPORT +QVector buildPropertyMappings(Handler *handler, + const AnimationClipLoader *clip, + const ChannelMapper *mapper); + +Q_AUTOTEST_EXPORT +double localTimeFromGlobalTime(double t_global, double t_start_global, + double playbackRate, double duration, + int loopCount, int ¤tLoop); + } // Animation } // Qt3DAnimation diff --git a/src/animation/backend/blendedclipanimator_p.h b/src/animation/backend/blendedclipanimator_p.h index d83f8458e..aff8b97fd 100644 --- a/src/animation/backend/blendedclipanimator_p.h +++ b/src/animation/backend/blendedclipanimator_p.h @@ -97,7 +97,7 @@ public: ChildType type; Qt3DCore::QNodeId left; Qt3DCore::QNodeId right; - QVector mappingData; + QVector mappingData; }; void setBlendTreeTable(const QHash &blendTreeTable) { m_blendTreeTable = blendTreeTable; } diff --git a/src/animation/backend/buildblendtreesjob.cpp b/src/animation/backend/buildblendtreesjob.cpp index cac15ac5c..ef8c82ce1 100644 --- a/src/animation/backend/buildblendtreesjob.cpp +++ b/src/animation/backend/buildblendtreesjob.cpp @@ -61,62 +61,62 @@ void BuildBlendTreesJob::setBlendedClipAnimators(const QVector -QVector buildBlendMappingDataForNode(const QVector &mappingInNode1, - const QVector &mappingInNode2) +QVector buildBlendMappingDataForNode(const QVector &mappingInNode1, + const QVector &mappingInNode2) { // We can only blend channels that are in both clips // If a channel is present in one clip and not the other, we use 100% of its value (no blending) - QVector blendingMappingData; + QVector blendingMappingData; const int mappingInNode1Size = mappingInNode1.size(); blendingMappingData.reserve(mappingInNode1Size); // Find mappings that are in both vectors and build mappingData out of that for (const MappingDataType &mappingDataInNode1 : mappingInNode1) { - AnimationUtils::BlendingMappingData mappingData; + BlendingMappingData mappingData; mappingData.channelIndicesClip1 = mappingDataInNode1.channelIndices; mappingData.propertyName = mappingDataInNode1.propertyName; mappingData.targetId = mappingDataInNode1.targetId; mappingData.type = mappingDataInNode1.type; - mappingData.blendAction = AnimationUtils::BlendingMappingData::NoBlending; + mappingData.blendAction = BlendingMappingData::NoBlending; blendingMappingData.push_back(mappingData); } for (const MappingDataType &mappingDataInNode2 : mappingInNode2) { bool sharedChannel = false; for (int i = 0; i < mappingInNode1Size; ++i) { - AnimationUtils::BlendingMappingData &mappingDataInNode1 = blendingMappingData[i]; + BlendingMappingData &mappingDataInNode1 = blendingMappingData[i]; if ((strcmp(mappingDataInNode1.propertyName, mappingDataInNode2.propertyName) == 0) && mappingDataInNode1.targetId == mappingDataInNode2.targetId && mappingDataInNode1.type == mappingDataInNode2.type) { // We have a channel shared in both clips mappingDataInNode1.channelIndicesClip2 = mappingDataInNode2.channelIndices; - mappingDataInNode1.blendAction = AnimationUtils::BlendingMappingData::ClipBlending; + mappingDataInNode1.blendAction = BlendingMappingData::ClipBlending; sharedChannel = true; break; } } if (!sharedChannel) { // We have a channel defined in only one of the clips - AnimationUtils::BlendingMappingData mappingData; + BlendingMappingData mappingData; mappingData.channelIndicesClip2 = mappingDataInNode2.channelIndices; mappingData.propertyName = mappingDataInNode2.propertyName; mappingData.targetId = mappingDataInNode2.targetId; mappingData.type = mappingDataInNode2.type; - mappingData.blendAction = AnimationUtils::BlendingMappingData::NoBlending; + mappingData.blendAction = BlendingMappingData::NoBlending; blendingMappingData.push_back(mappingData); } } // Final indices (indices into the final blended result vector of floats for the node) int idx = 0; - for (AnimationUtils::BlendingMappingData &mapping : blendingMappingData) { + for (BlendingMappingData &mapping : blendingMappingData) { switch (mapping.blendAction) { - case AnimationUtils::BlendingMappingData::ClipBlending: { + case BlendingMappingData::ClipBlending: { Q_ASSERT(mapping.channelIndicesClip1.size() == mapping.channelIndicesClip2.size()); for (int i = 0, m = mapping.channelIndicesClip1.size(); i < m; ++i) mapping.channelIndices.push_back(idx++); break; } - case AnimationUtils::BlendingMappingData::NoBlending: { + case BlendingMappingData::NoBlending: { const bool useClip1 = !mapping.channelIndicesClip1.empty(); const QVector channelIndices = useClip1 ? mapping.channelIndicesClip1 : mapping.channelIndicesClip2; for (int i = 0, m = channelIndices.size(); i < m; ++i) { @@ -142,12 +142,12 @@ void buildEntryForBlendClipNode(Handler *handler, const ChannelMapper *mapper, B Q_ASSERT(clip1 && clip2); // Build mappings for the 2 clips - const QVector mappingDataClip1 = AnimationUtils::buildPropertyMappings(handler, clip1, mapper); - const QVector mappingDataClip2 = AnimationUtils::buildPropertyMappings(handler, clip2, mapper); + const QVector mappingDataClip1 = buildPropertyMappings(handler, clip1, mapper); + const QVector mappingDataClip2 = buildPropertyMappings(handler, clip2, mapper); // We can only blend channels that are in both clips // If a channel is present in one clip and not the other, we use 100% of its value (no blending) - const QVector blendingMappingData = buildBlendMappingDataForNode(mappingDataClip1, mappingDataClip2); + const QVector blendingMappingData = buildBlendMappingDataForNode(mappingDataClip1, mappingDataClip2); nodeData.mappingData = blendingMappingData; } @@ -157,12 +157,12 @@ void buildEntryForBlendNodeNode(BlendedClipAnimator::BlendNodeData &nodeData, co const BlendedClipAnimator::BlendNodeData &node2Data = blendingNodeTable.value(nodeData.right); // Build mappings for the 2 nodes - const QVector mappingDataNode1 = node1Data.mappingData; - const QVector mappingDataNode2 = node2Data.mappingData; + const QVector mappingDataNode1 = node1Data.mappingData; + const QVector mappingDataNode2 = node2Data.mappingData; // We can only blend channels that are in both clips // If a channel is present in one clip and not the other, we use 100% of its value (no blending) - const QVector blendingMappingData = buildBlendMappingDataForNode(mappingDataNode1, mappingDataNode2); + const QVector blendingMappingData = buildBlendMappingDataForNode(mappingDataNode1, mappingDataNode2); nodeData.mappingData = blendingMappingData; } diff --git a/src/animation/backend/clipanimator.cpp b/src/animation/backend/clipanimator.cpp index 72f818d88..63aca447b 100644 --- a/src/animation/backend/clipanimator.cpp +++ b/src/animation/backend/clipanimator.cpp @@ -123,7 +123,7 @@ void ClipAnimator::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) QBackendNode::sceneChangeEvent(e); } -void ClipAnimator::setMappingData(const QVector mappingData) +void ClipAnimator::setMappingData(const QVector mappingData) { m_mappingData = mappingData; } diff --git a/src/animation/backend/clipanimator_p.h b/src/animation/backend/clipanimator_p.h index b896bc7f1..8c1ea393d 100644 --- a/src/animation/backend/clipanimator_p.h +++ b/src/animation/backend/clipanimator_p.h @@ -80,8 +80,8 @@ public: // Called by jobs bool canRun() const { return !m_clipId.isNull() && !m_mapperId.isNull() && m_running; } - void setMappingData(const QVector mappingData); - QVector mappingData() const { return m_mappingData; } + void setMappingData(const QVector mappingData); + QVector mappingData() const { return m_mappingData; } void setStartTime(qint64 globalTime) { m_startGlobalTime = globalTime; } qint64 startTime() const { return m_startGlobalTime; } @@ -101,7 +101,7 @@ private: // Working state qint64 m_startGlobalTime; - QVector m_mappingData; + QVector m_mappingData; int m_currentLoop; }; diff --git a/src/animation/backend/evaluateblendclipanimatorjob.cpp b/src/animation/backend/evaluateblendclipanimatorjob.cpp index e2ba523bc..da7442d1c 100644 --- a/src/animation/backend/evaluateblendclipanimatorjob.cpp +++ b/src/animation/backend/evaluateblendclipanimatorjob.cpp @@ -61,16 +61,16 @@ namespace { QVector blendValuesBasedOnMappings(ClipBlendNode *node, const QVector &channelResults1, const QVector &channelResults2, - const QVector &blendingMappingData) + const QVector &blendingMappingData) { QVector blendedValues; blendedValues.reserve(blendingMappingData.size()); // Build a combined vector of blended value - for (const AnimationUtils::BlendingMappingData &mapping : blendingMappingData) { + for (const BlendingMappingData &mapping : blendingMappingData) { switch (mapping.blendAction) { - case AnimationUtils::BlendingMappingData::ClipBlending: { + case BlendingMappingData::ClipBlending: { Q_ASSERT(mapping.channelIndicesClip1.size() == mapping.channelIndicesClip2.size()); for (int i = 0, m = mapping.channelIndicesClip1.size(); i < m; ++i) { const float value1 = channelResults1.at(mapping.channelIndicesClip1[i]); @@ -80,7 +80,7 @@ QVector blendValuesBasedOnMappings(ClipBlendNode *node, } break; } - case AnimationUtils::BlendingMappingData::NoBlending: { + case BlendingMappingData::NoBlending: { const bool useClip1 = !mapping.channelIndicesClip1.empty(); const QVector channelIndices = useClip1 ? mapping.channelIndicesClip1 : mapping.channelIndicesClip2; const QVector values = useClip1 ? channelResults1 : channelResults2; @@ -98,10 +98,10 @@ QVector blendValuesBasedOnMappings(ClipBlendNode *node, return blendedValues; } -QVector fromBlendingMappingData(const QVector &blendingMappingData) +QVector fromBlendingMappingData(const QVector &blendingMappingData) { const int blendingMappingDataSize = blendingMappingData.size(); - QVector mappingData(blendingMappingDataSize); + QVector mappingData(blendingMappingDataSize); for (int i = 0; i < blendingMappingDataSize; ++i) { mappingData[i] = blendingMappingData[i]; } @@ -110,27 +110,28 @@ QVector fromBlendingMappingData(const QVectoranimationClipLoaderManager()->lookupResource(nodeData.left); AnimationClipLoader *clip2 = m_handler->animationClipLoaderManager()->lookupResource(nodeData.right); Q_ASSERT(clip1 && clip2); // Prepare for evaluation (convert global time to local time ....) - const AnimationUtils::ClipPreEvaluationData preEvaluationDataForClip1 = AnimationUtils::evaluationDataForClip(clip1, animatorEvaluationData); - const AnimationUtils::ClipPreEvaluationData preEvaluationDataForClip2 = AnimationUtils::evaluationDataForClip(clip2, animatorEvaluationData); + const ClipPreEvaluationData preEvaluationDataForClip1 = evaluationDataForClip(clip1, animatorEvaluationData); + const ClipPreEvaluationData preEvaluationDataForClip2 = evaluationDataForClip(clip2, animatorEvaluationData); // Evaluate the fcurves for both clip - const QVector channelResultsClip1 = AnimationUtils::evaluateClipAtLocalTime(clip1, preEvaluationDataForClip1.localTime); - const QVector channelResultsClip2 = AnimationUtils::evaluateClipAtLocalTime(clip2, preEvaluationDataForClip2.localTime); + const QVector channelResultsClip1 = evaluateClipAtLocalTime(clip1, preEvaluationDataForClip1.localTime); + const QVector channelResultsClip2 = evaluateClipAtLocalTime(clip2, preEvaluationDataForClip2.localTime); // Update loops and running of the animator m_currentLoop = std::min(m_currentLoop, std::min(preEvaluationDataForClip1.currentLoop, preEvaluationDataForClip2.currentLoop)); // isFinalFrame remains true only if all the clips have reached their final frame m_isFinalFrame &= (preEvaluationDataForClip1.isFinalFrame && preEvaluationDataForClip2.isFinalFrame); - const QVector blendingMappingData = nodeData.mappingData; + const QVector blendingMappingData = nodeData.mappingData; // Perform blending between the two clips const QVector blendedValues = blendValuesBasedOnMappings(node, channelResultsClip1, channelResultsClip2, blendingMappingData); @@ -149,7 +150,7 @@ void EvaluateBlendClipAnimatorJob::blendNodes(ClipBlendNode *node, const Blended const QVector channelResultsNode2 = m_clipBlendResultsTable.take(node2); // Build a combined vector of blended value - const QVector blendingMappingData = nodeData.mappingData; + const QVector blendingMappingData = nodeData.mappingData; // Perform blending between the two nodes const QVector blendedValues = blendValuesBasedOnMappings(node, channelResultsNode1, channelResultsNode2, blendingMappingData); @@ -164,7 +165,7 @@ void EvaluateBlendClipAnimatorJob::run() BlendedClipAnimator *blendedClipAnimator = m_handler->blendedClipAnimatorManager()->data(m_blendClipAnimatorHandle); Q_ASSERT(blendedClipAnimator); - const AnimationUtils::AnimatorEvaluationData animatorEvaluationData = AnimationUtils::animatorEvaluationDataForAnimator(blendedClipAnimator, globalTime); + const AnimatorEvaluationData animatorEvaluationData = animatorEvaluationDataForAnimator(blendedClipAnimator, globalTime); const QHash blendindNodeTable = blendedClipAnimator->blendTreeTable(); // Reset globals @@ -204,10 +205,10 @@ void EvaluateBlendClipAnimatorJob::run() const QVector blendedValues = m_clipBlendResultsTable.take(rootBlendNode); const BlendedClipAnimator::BlendNodeData &rootNodeData = blendindNodeTable.value(rootBlendNode->peerId()); - const QVector mappingData = fromBlendingMappingData(rootNodeData.mappingData); + const QVector mappingData = fromBlendingMappingData(rootNodeData.mappingData); // Prepare property changes (if finalFrame it also prepares the change for the running property for the frontend) - const QVector changes = AnimationUtils::preparePropertyChanges(blendedClipAnimator->peerId(), + const QVector changes = preparePropertyChanges(blendedClipAnimator->peerId(), mappingData, blendedValues, m_isFinalFrame); diff --git a/src/animation/backend/evaluateblendclipanimatorjob_p.h b/src/animation/backend/evaluateblendclipanimatorjob_p.h index 8090a025a..60426d460 100644 --- a/src/animation/backend/evaluateblendclipanimatorjob_p.h +++ b/src/animation/backend/evaluateblendclipanimatorjob_p.h @@ -80,7 +80,7 @@ private: Handler *m_handler; void blendClips(ClipBlendNode *node, const BlendedClipAnimator::BlendNodeData &nodeData, - const AnimationUtils::AnimatorEvaluationData &animatorEvaluationData); + const AnimatorEvaluationData &animatorEvaluationData); void blendNodes(ClipBlendNode *node, const BlendedClipAnimator::BlendNodeData &nodeData); QHash> m_clipBlendResultsTable; diff --git a/src/animation/backend/evaluateclipanimatorjob.cpp b/src/animation/backend/evaluateclipanimatorjob.cpp index a2e481371..cbad58638 100644 --- a/src/animation/backend/evaluateclipanimatorjob.cpp +++ b/src/animation/backend/evaluateclipanimatorjob.cpp @@ -66,9 +66,9 @@ void EvaluateClipAnimatorJob::run() AnimationClipLoader *clip = m_handler->animationClipLoaderManager()->lookupResource(clipAnimator->clipId()); Q_ASSERT(clip); // Prepare for evaluation (convert global time to local time ....) - const AnimationUtils::AnimatorEvaluationData animatorEvaluationData = AnimationUtils::animatorEvaluationDataForAnimator(clipAnimator, globalTime); - const AnimationUtils::ClipPreEvaluationData preEvaluationDataForClip = AnimationUtils::evaluationDataForClip(clip, animatorEvaluationData); - const QVector channelResults = AnimationUtils::evaluateClipAtLocalTime(clip, preEvaluationDataForClip.localTime); + const AnimatorEvaluationData animatorEvaluationData = animatorEvaluationDataForAnimator(clipAnimator, globalTime); + const ClipPreEvaluationData preEvaluationDataForClip = evaluationDataForClip(clip, animatorEvaluationData); + const QVector channelResults = evaluateClipAtLocalTime(clip, preEvaluationDataForClip.localTime); if (preEvaluationDataForClip.isFinalFrame) clipAnimator->setRunning(false); @@ -76,10 +76,10 @@ void EvaluateClipAnimatorJob::run() clipAnimator->setCurrentLoop(preEvaluationDataForClip.currentLoop); // Prepare property changes (if finalFrame it also prepares the change for the running property for the frontend) - const QVector changes = AnimationUtils::preparePropertyChanges(clipAnimator->peerId(), - clipAnimator->mappingData(), - channelResults, - preEvaluationDataForClip.isFinalFrame); + const QVector changes = preparePropertyChanges(clipAnimator->peerId(), + clipAnimator->mappingData(), + channelResults, + preEvaluationDataForClip.isFinalFrame); // Send the property changes clipAnimator->sendPropertyChanges(changes); diff --git a/src/animation/backend/findrunningclipanimatorsjob.cpp b/src/animation/backend/findrunningclipanimatorsjob.cpp index bdc12e2a2..d5599c0fe 100644 --- a/src/animation/backend/findrunningclipanimatorsjob.cpp +++ b/src/animation/backend/findrunningclipanimatorsjob.cpp @@ -76,7 +76,7 @@ void FindRunningClipAnimatorsJob::run() const AnimationClipLoader *clip = m_handler->animationClipLoaderManager()->lookupResource(clipAnimator->clipId()); const ChannelMapper *mapper = m_handler->channelMapperManager()->lookupResource(clipAnimator->mapperId()); Q_ASSERT(clip && mapper); - const QVector mappingData = AnimationUtils::buildPropertyMappings(m_handler, clip, mapper); + const QVector mappingData = buildPropertyMappings(m_handler, clip, mapper); clipAnimator->setMappingData(mappingData); } } diff --git a/tests/auto/animation/animationutils/tst_animationutils.cpp b/tests/auto/animation/animationutils/tst_animationutils.cpp index 1a4c861c5..09ebd595f 100644 --- a/tests/auto/animation/animationutils/tst_animationutils.cpp +++ b/tests/auto/animation/animationutils/tst_animationutils.cpp @@ -42,7 +42,7 @@ Q_DECLARE_METATYPE(Qt3DAnimation::Animation::Handler*) Q_DECLARE_METATYPE(QVector) Q_DECLARE_METATYPE(ChannelMapper *) Q_DECLARE_METATYPE(AnimationClipLoader *) -Q_DECLARE_METATYPE(QVector) +Q_DECLARE_METATYPE(QVector) class tst_AnimationUtils : public Qt3DCore::QBackendNodeTester { @@ -95,7 +95,7 @@ private Q_SLOTS: QTest::addColumn>("channelMappings"); QTest::addColumn("channelMapper"); QTest::addColumn("clip"); - QTest::addColumn>("expectedMappingData"); + QTest::addColumn>("expectedMappingData"); auto handler = new Handler; auto channelMapping = createChannelMapping(handler, @@ -113,8 +113,8 @@ private Q_SLOTS: // ...and an animation clip auto clip = createAnimationClipLoader(handler, QUrl("qrc:/clip1.json")); - QVector mappingData; - AnimationUtils::MappingData mapping; + QVector mappingData; + MappingData mapping; mapping.targetId = channelMapping->targetId(); mapping.propertyName = channelMapping->propertyName(); // Location mapping.type = channelMapping->type(); @@ -135,11 +135,11 @@ private Q_SLOTS: QFETCH(QVector, channelMappings); QFETCH(ChannelMapper *, channelMapper); QFETCH(AnimationClipLoader *, clip); - QFETCH(QVector, expectedMappingData); + QFETCH(QVector, expectedMappingData); // WHEN // Build the mapping data for the above configuration - QVector mappingData = AnimationUtils::buildPropertyMappings(handler, clip, channelMapper); + QVector mappingData = buildPropertyMappings(handler, clip, channelMapper); // THEN QCOMPARE(mappingData.size(), expectedMappingData.size()); -- cgit v1.2.3 From bc1495b525fa3343b85c3d187202d03aa7eeea17 Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Fri, 3 Mar 2017 10:04:58 +0000 Subject: Rename animationEvaluationDataForAnimator Be less verbose and for consistency with evaluationDataForClip. Change-Id: Ifcd1ffe5275dab8dfbfcd4c90719bf33d4a9509f Reviewed-by: Mike Krus --- src/animation/backend/animationutils_p.h | 2 +- src/animation/backend/evaluateblendclipanimatorjob.cpp | 2 +- src/animation/backend/evaluateclipanimatorjob.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/animation/backend/animationutils_p.h b/src/animation/backend/animationutils_p.h index f66b3999d..60454d469 100644 --- a/src/animation/backend/animationutils_p.h +++ b/src/animation/backend/animationutils_p.h @@ -98,7 +98,7 @@ struct ClipPreEvaluationData }; template -AnimatorEvaluationData animatorEvaluationDataForAnimator(Animator animator, qint64 globalTime) +AnimatorEvaluationData evaluationDataForAnimator(Animator animator, qint64 globalTime) { AnimatorEvaluationData data; data.loopCount = animator->loops(); diff --git a/src/animation/backend/evaluateblendclipanimatorjob.cpp b/src/animation/backend/evaluateblendclipanimatorjob.cpp index da7442d1c..afef3acad 100644 --- a/src/animation/backend/evaluateblendclipanimatorjob.cpp +++ b/src/animation/backend/evaluateblendclipanimatorjob.cpp @@ -165,7 +165,7 @@ void EvaluateBlendClipAnimatorJob::run() BlendedClipAnimator *blendedClipAnimator = m_handler->blendedClipAnimatorManager()->data(m_blendClipAnimatorHandle); Q_ASSERT(blendedClipAnimator); - const AnimatorEvaluationData animatorEvaluationData = animatorEvaluationDataForAnimator(blendedClipAnimator, globalTime); + const AnimatorEvaluationData animatorEvaluationData = evaluationDataForAnimator(blendedClipAnimator, globalTime); const QHash blendindNodeTable = blendedClipAnimator->blendTreeTable(); // Reset globals diff --git a/src/animation/backend/evaluateclipanimatorjob.cpp b/src/animation/backend/evaluateclipanimatorjob.cpp index cbad58638..06f2cdf7e 100644 --- a/src/animation/backend/evaluateclipanimatorjob.cpp +++ b/src/animation/backend/evaluateclipanimatorjob.cpp @@ -66,7 +66,7 @@ void EvaluateClipAnimatorJob::run() AnimationClipLoader *clip = m_handler->animationClipLoaderManager()->lookupResource(clipAnimator->clipId()); Q_ASSERT(clip); // Prepare for evaluation (convert global time to local time ....) - const AnimatorEvaluationData animatorEvaluationData = animatorEvaluationDataForAnimator(clipAnimator, globalTime); + const AnimatorEvaluationData animatorEvaluationData = evaluationDataForAnimator(clipAnimator, globalTime); const ClipPreEvaluationData preEvaluationDataForClip = evaluationDataForClip(clip, animatorEvaluationData); const QVector channelResults = evaluateClipAtLocalTime(clip, preEvaluationDataForClip.localTime); -- cgit v1.2.3 From 964a254ef557d06190863344f8c5b0ab7c8ce9d5 Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Fri, 3 Mar 2017 10:06:54 +0000 Subject: Rename ClipPreEvaluationData to ClipEvaluationData For consistency. Change-Id: I83bce109ee12fee1688d8ac9d120b82cd6c47659 Reviewed-by: Mike Krus --- src/animation/backend/animationutils.cpp | 6 +++--- src/animation/backend/animationutils_p.h | 6 +++--- src/animation/backend/evaluateblendclipanimatorjob.cpp | 4 ++-- src/animation/backend/evaluateclipanimatorjob.cpp | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/animation/backend/animationutils.cpp b/src/animation/backend/animationutils.cpp index be76e1bed..46839d961 100644 --- a/src/animation/backend/animationutils.cpp +++ b/src/animation/backend/animationutils.cpp @@ -51,11 +51,11 @@ QT_BEGIN_NAMESPACE namespace Qt3DAnimation { namespace Animation { -ClipPreEvaluationData evaluationDataForClip(AnimationClipLoader *clip, - const AnimatorEvaluationData &animatorData) +ClipEvaluationData evaluationDataForClip(AnimationClipLoader *clip, + const AnimatorEvaluationData &animatorData) { // global time values expected in seconds - ClipPreEvaluationData result; + ClipEvaluationData result; result.localTime = localTimeFromGlobalTime(animatorData.globalTime, animatorData.startTime, animatorData.playbackRate, clip->duration(), animatorData.loopCount, result.currentLoop); diff --git a/src/animation/backend/animationutils_p.h b/src/animation/backend/animationutils_p.h index 60454d469..5d837c7d6 100644 --- a/src/animation/backend/animationutils_p.h +++ b/src/animation/backend/animationutils_p.h @@ -90,7 +90,7 @@ struct AnimatorEvaluationData double playbackRate; }; -struct ClipPreEvaluationData +struct ClipEvaluationData { int currentLoop; double localTime; @@ -110,8 +110,8 @@ AnimatorEvaluationData evaluationDataForAnimator(Animator animator, qint64 globa } Q_AUTOTEST_EXPORT -ClipPreEvaluationData evaluationDataForClip(AnimationClipLoader *clip, - const AnimatorEvaluationData &animatorData); +ClipEvaluationData evaluationDataForClip(AnimationClipLoader *clip, + const AnimatorEvaluationData &animatorData); Q_AUTOTEST_EXPORT QVector channelComponentsToIndices(const Channel &channelGroup, diff --git a/src/animation/backend/evaluateblendclipanimatorjob.cpp b/src/animation/backend/evaluateblendclipanimatorjob.cpp index afef3acad..be1591b92 100644 --- a/src/animation/backend/evaluateblendclipanimatorjob.cpp +++ b/src/animation/backend/evaluateblendclipanimatorjob.cpp @@ -119,8 +119,8 @@ void EvaluateBlendClipAnimatorJob::blendClips(ClipBlendNode *node, Q_ASSERT(clip1 && clip2); // Prepare for evaluation (convert global time to local time ....) - const ClipPreEvaluationData preEvaluationDataForClip1 = evaluationDataForClip(clip1, animatorEvaluationData); - const ClipPreEvaluationData preEvaluationDataForClip2 = evaluationDataForClip(clip2, animatorEvaluationData); + const ClipEvaluationData preEvaluationDataForClip1 = evaluationDataForClip(clip1, animatorEvaluationData); + const ClipEvaluationData preEvaluationDataForClip2 = evaluationDataForClip(clip2, animatorEvaluationData); // Evaluate the fcurves for both clip const QVector channelResultsClip1 = evaluateClipAtLocalTime(clip1, preEvaluationDataForClip1.localTime); diff --git a/src/animation/backend/evaluateclipanimatorjob.cpp b/src/animation/backend/evaluateclipanimatorjob.cpp index 06f2cdf7e..8f72f1d99 100644 --- a/src/animation/backend/evaluateclipanimatorjob.cpp +++ b/src/animation/backend/evaluateclipanimatorjob.cpp @@ -67,7 +67,7 @@ void EvaluateClipAnimatorJob::run() Q_ASSERT(clip); // Prepare for evaluation (convert global time to local time ....) const AnimatorEvaluationData animatorEvaluationData = evaluationDataForAnimator(clipAnimator, globalTime); - const ClipPreEvaluationData preEvaluationDataForClip = evaluationDataForClip(clip, animatorEvaluationData); + const ClipEvaluationData preEvaluationDataForClip = evaluationDataForClip(clip, animatorEvaluationData); const QVector channelResults = evaluateClipAtLocalTime(clip, preEvaluationDataForClip.localTime); if (preEvaluationDataForClip.isFinalFrame) -- cgit v1.2.3 From 5d68d1b260054b575c32a791117575503bcb00a7 Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Fri, 3 Mar 2017 10:50:44 +0000 Subject: Add test for localTimeFromGLobalTime helper Change-Id: Icdf6ae7062ba4afc27fc7cd0573029a5c5b32bf5 Reviewed-by: Mike Krus --- .../animationutils/tst_animationutils.cpp | 165 +++++++++++++++++++++ 1 file changed, 165 insertions(+) diff --git a/tests/auto/animation/animationutils/tst_animationutils.cpp b/tests/auto/animation/animationutils/tst_animationutils.cpp index 09ebd595f..419bff1fa 100644 --- a/tests/auto/animation/animationutils/tst_animationutils.cpp +++ b/tests/auto/animation/animationutils/tst_animationutils.cpp @@ -159,6 +159,171 @@ private Q_SLOTS: // Cleanup delete handler; } + + void checkLocalTimeFromGlobalTime_data() + { + QTest::addColumn("globalTime"); + QTest::addColumn("globalStartTime"); + QTest::addColumn("playbackRate"); + QTest::addColumn("duration"); + QTest::addColumn("loopCount"); + QTest::addColumn("expectedLocalTime"); + QTest::addColumn("expectedCurrentLoop"); + + double globalTime; + double globalStartTime; + double playbackRate; + double duration; + int loopCount; + double expectedLocalTime; + int expectedCurrentLoop; + + globalTime = 0.0; + globalStartTime = 0.0; + playbackRate = 1.0; + duration = 1.0; + loopCount = 1; + expectedLocalTime = 0.0; + expectedCurrentLoop = 0; + QTest::newRow("simple, t_global = 0") + << globalTime << globalStartTime << playbackRate << duration << loopCount + << expectedLocalTime << expectedCurrentLoop; + + globalTime = 0.5; + globalStartTime = 0.0; + playbackRate = 1.0; + duration = 1.0; + loopCount = 1; + expectedLocalTime = 0.5; + expectedCurrentLoop = 0; + QTest::newRow("simple, t_global = 0.5") + << globalTime << globalStartTime << playbackRate << duration << loopCount + << expectedLocalTime << expectedCurrentLoop; + + globalTime = 1.0; + globalStartTime = 0.0; + playbackRate = 1.0; + duration = 1.0; + loopCount = 1; + expectedLocalTime = 1.0; + expectedCurrentLoop = 0; + QTest::newRow("simple, t_global = 1.0") + << globalTime << globalStartTime << playbackRate << duration << loopCount + << expectedLocalTime << expectedCurrentLoop; + + globalTime = -0.5; + globalStartTime = 0.0; + playbackRate = 1.0; + duration = 1.0; + loopCount = 1; + expectedLocalTime = 0.0; + expectedCurrentLoop = 0; + QTest::newRow("simple, t_global = -0.5") + << globalTime << globalStartTime << playbackRate << duration << loopCount + << expectedLocalTime << expectedCurrentLoop; + + globalTime = 1.5; + globalStartTime = 0.0; + playbackRate = 1.0; + duration = 1.0; + loopCount = 1; + expectedLocalTime = 1.0; + expectedCurrentLoop = 0; + QTest::newRow("simple, t_global = 1.5") + << globalTime << globalStartTime << playbackRate << duration << loopCount + << expectedLocalTime << expectedCurrentLoop; + + globalTime = 0.5; + globalStartTime = 0.0; + playbackRate = 1.0; + duration = 1.0; + loopCount = 2; + expectedLocalTime = 0.5; + expectedCurrentLoop = 0; + QTest::newRow("simple, loopCount = 2, t_global = 0.5") + << globalTime << globalStartTime << playbackRate << duration << loopCount + << expectedLocalTime << expectedCurrentLoop; + + globalTime = 1.5; + globalStartTime = 0.0; + playbackRate = 1.0; + duration = 1.0; + loopCount = 2; + expectedLocalTime = 0.5; + expectedCurrentLoop = 1; + QTest::newRow("simple, loopCount = 2, t_global = 1.5") + << globalTime << globalStartTime << playbackRate << duration << loopCount + << expectedLocalTime << expectedCurrentLoop; + + globalTime = 3.5; + globalStartTime = 0.0; + playbackRate = 1.0; + duration = 2.0; + loopCount = 2; + expectedLocalTime = 1.5; + expectedCurrentLoop = 1; + QTest::newRow("duration = 2, loopCount = 2, t_global = 3.5") + << globalTime << globalStartTime << playbackRate << duration << loopCount + << expectedLocalTime << expectedCurrentLoop; + + globalTime = 4.5; + globalStartTime = 0.0; + playbackRate = 1.0; + duration = 2.0; + loopCount = 2; + expectedLocalTime = 2.0; + expectedCurrentLoop = 1; + QTest::newRow("duration = 2, loopCount = 2, t_global = 4.5") + << globalTime << globalStartTime << playbackRate << duration << loopCount + << expectedLocalTime << expectedCurrentLoop; + + globalTime = 1.5; + globalStartTime = 0.0; + playbackRate = 1.0; + duration = 1.0; + loopCount = 0; + expectedLocalTime = 0.5; + expectedCurrentLoop = 1; + QTest::newRow("simple, loopCount = inf, t_global = 1.5") + << globalTime << globalStartTime << playbackRate << duration << loopCount + << expectedLocalTime << expectedCurrentLoop; + + globalTime = 10.2; + globalStartTime = 0.0; + playbackRate = 1.0; + duration = 1.0; + loopCount = 0; + expectedLocalTime = 0.2; + expectedCurrentLoop = 10; + QTest::newRow("simple, loopCount = inf, t_global = 10.2") + << globalTime << globalStartTime << playbackRate << duration << loopCount + << expectedLocalTime << expectedCurrentLoop; + } + + void checkLocalTimeFromGlobalTime() + { + // GIVEN + QFETCH(double, globalTime); + QFETCH(double, globalStartTime); + QFETCH(double, playbackRate); + QFETCH(double, duration); + QFETCH(int, loopCount); + QFETCH(double, expectedLocalTime); + QFETCH(int, expectedCurrentLoop); + + // WHEN + int actualCurrentLoop = 0; + double actualLocalTime = localTimeFromGlobalTime(globalTime, + globalStartTime, + playbackRate, + duration, + loopCount, + actualCurrentLoop); + + // THEN + QCOMPARE(actualCurrentLoop, expectedCurrentLoop); + QCOMPARE(actualLocalTime, expectedLocalTime); + } }; QTEST_MAIN(tst_AnimationUtils) -- cgit v1.2.3 From 3c842c9272df2e3df8edd3797fddd26203f98994 Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Fri, 3 Mar 2017 11:09:04 +0000 Subject: Rename peerId argument to animatorId in preparePropertyChanges() Gives more clue as to its intended use. Change-Id: I3b92827b8373eee384a48b599edf04b6fa3cf461 Reviewed-by: Mike Krus --- src/animation/backend/animationutils.cpp | 4 ++-- src/animation/backend/animationutils_p.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/animation/backend/animationutils.cpp b/src/animation/backend/animationutils.cpp index 46839d961..13cb27d4a 100644 --- a/src/animation/backend/animationutils.cpp +++ b/src/animation/backend/animationutils.cpp @@ -187,7 +187,7 @@ QVector evaluateClipAtLocalTime(AnimationClipLoader *clip, float localTim return channelResults; } -QVector preparePropertyChanges(Qt3DCore::QNodeId peerId, +QVector preparePropertyChanges(Qt3DCore::QNodeId animatorId, const QVector &mappingDataVec, const QVector &channelResults, bool finalFrame) @@ -258,7 +258,7 @@ QVector preparePropertyChanges(Qt3DCore::QNodeId peer // If it's the final frame, notify the frontend that we've stopped if (finalFrame) { - auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId); + auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(animatorId); e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll); e->setPropertyName("running"); e->setValue(false); diff --git a/src/animation/backend/animationutils_p.h b/src/animation/backend/animationutils_p.h index 5d837c7d6..184b2422e 100644 --- a/src/animation/backend/animationutils_p.h +++ b/src/animation/backend/animationutils_p.h @@ -129,7 +129,7 @@ QVector evaluateClipAtLocalTime(AnimationClipLoader *clip, float localTime); Q_AUTOTEST_EXPORT -QVector preparePropertyChanges(Qt3DCore::QNodeId peerId, +QVector preparePropertyChanges(Qt3DCore::QNodeId animatorId, const QVector &mappingData, const QVector &channelResults, bool finalFrame); -- cgit v1.2.3 From e6b0d847c0ef1ffa512b275a817881c6244ef37c Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Fri, 3 Mar 2017 12:39:00 +0000 Subject: Extend test to cover preparePropertyChanges helper Change-Id: Ic89792a47ea6ec85924d9d7ba352d98bf86f0469 Reviewed-by: Mike Krus --- .../animationutils/tst_animationutils.cpp | 248 +++++++++++++++++++++ 1 file changed, 248 insertions(+) diff --git a/tests/auto/animation/animationutils/tst_animationutils.cpp b/tests/auto/animation/animationutils/tst_animationutils.cpp index 419bff1fa..622990829 100644 --- a/tests/auto/animation/animationutils/tst_animationutils.cpp +++ b/tests/auto/animation/animationutils/tst_animationutils.cpp @@ -33,6 +33,12 @@ #include #include #include +#include +#include +#include +#include +#include + #include #include @@ -43,6 +49,7 @@ Q_DECLARE_METATYPE(QVector) Q_DECLARE_METATYPE(ChannelMapper *) Q_DECLARE_METATYPE(AnimationClipLoader *) Q_DECLARE_METATYPE(QVector) +Q_DECLARE_METATYPE(QVector) class tst_AnimationUtils : public Qt3DCore::QBackendNodeTester { @@ -324,6 +331,247 @@ private Q_SLOTS: QCOMPARE(actualCurrentLoop, expectedCurrentLoop); QCOMPARE(actualLocalTime, expectedLocalTime); } + + void checkPreparePropertyChanges_data() + { + QTest::addColumn("animatorId"); + QTest::addColumn>("mappingData"); + QTest::addColumn>("channelResults"); + QTest::addColumn("finalFrame"); + QTest::addColumn>("expectedChanges"); + + Qt3DCore::QNodeId animatorId; + QVector mappingData; + QVector channelResults; + bool finalFrame; + QVector expectedChanges; + + // Single property, vec3 + { + animatorId = Qt3DCore::QNodeId::createId(); + MappingData mapping; + mapping.targetId = Qt3DCore::QNodeId::createId(); + mapping.propertyName = "translation"; + mapping.type = static_cast(QVariant::Vector3D); + mapping.channelIndices = QVector() << 0 << 1 << 2; + mappingData.push_back(mapping); + channelResults = QVector() << 1.0f << 2.0f << 3.0f; + finalFrame = false; + + auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(mapping.targetId); + change->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll); + change->setPropertyName(mapping.propertyName); + change->setValue(QVariant::fromValue(QVector3D(1.0f, 2.0f, 3.0f))); + expectedChanges.push_back(change); + + QTest::newRow("vec3 translation, final = false") + << animatorId << mappingData << channelResults << finalFrame + << expectedChanges; + + finalFrame = true; + auto animatorChange = Qt3DCore::QPropertyUpdatedChangePtr::create(animatorId); + animatorChange->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll); + animatorChange->setPropertyName("running"); + animatorChange->setValue(false); + expectedChanges.push_back(animatorChange); + + QTest::newRow("vec3 translation, final = true") + << animatorId << mappingData << channelResults << finalFrame + << expectedChanges; + + mappingData.clear(); + channelResults.clear(); + expectedChanges.clear(); + } + + // Multiple properties, all vec3 + { + animatorId = Qt3DCore::QNodeId::createId(); + MappingData translationMapping; + translationMapping.targetId = Qt3DCore::QNodeId::createId(); + translationMapping.propertyName = "translation"; + translationMapping.type = static_cast(QVariant::Vector3D); + translationMapping.channelIndices = QVector() << 0 << 1 << 2; + mappingData.push_back(translationMapping); + + MappingData scaleMapping; + scaleMapping.targetId = Qt3DCore::QNodeId::createId(); + scaleMapping.propertyName = "scale"; + scaleMapping.type = static_cast(QVariant::Vector3D); + scaleMapping.channelIndices = QVector() << 3 << 4 << 5; + mappingData.push_back(scaleMapping); + + channelResults = QVector() << 1.0f << 2.0f << 3.0f + << 4.0f << 5.0f << 6.0f; + finalFrame = false; + + auto translationChange = Qt3DCore::QPropertyUpdatedChangePtr::create(translationMapping.targetId); + translationChange->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll); + translationChange->setPropertyName(translationMapping.propertyName); + translationChange->setValue(QVariant::fromValue(QVector3D(1.0f, 2.0f, 3.0f))); + expectedChanges.push_back(translationChange); + + auto scaleChange = Qt3DCore::QPropertyUpdatedChangePtr::create(scaleMapping.targetId); + scaleChange->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll); + scaleChange->setPropertyName(scaleMapping.propertyName); + scaleChange->setValue(QVariant::fromValue(QVector3D(4.0f, 5.0f, 6.0f))); + expectedChanges.push_back(scaleChange); + + QTest::newRow("vec3 translation, vec3 scale, final = false") + << animatorId << mappingData << channelResults << finalFrame + << expectedChanges; + + finalFrame = true; + auto animatorChange = Qt3DCore::QPropertyUpdatedChangePtr::create(animatorId); + animatorChange->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll); + animatorChange->setPropertyName("running"); + animatorChange->setValue(false); + expectedChanges.push_back(animatorChange); + + QTest::newRow("vec3 translation, vec3 scale, final = true") + << animatorId << mappingData << channelResults << finalFrame + << expectedChanges; + + mappingData.clear(); + channelResults.clear(); + expectedChanges.clear(); + } + + // Single property, double + { + animatorId = Qt3DCore::QNodeId::createId(); + MappingData mapping; + mapping.targetId = Qt3DCore::QNodeId::createId(); + mapping.propertyName = "mass"; + mapping.type = static_cast(QVariant::Double); + mapping.channelIndices = QVector() << 0; + mappingData.push_back(mapping); + channelResults = QVector() << 3.5f; + finalFrame = false; + + auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(mapping.targetId); + change->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll); + change->setPropertyName(mapping.propertyName); + change->setValue(QVariant::fromValue(3.5f)); + expectedChanges.push_back(change); + + QTest::newRow("double mass") + << animatorId << mappingData << channelResults << finalFrame + << expectedChanges; + + mappingData.clear(); + channelResults.clear(); + expectedChanges.clear(); + } + + // Single property, vec2 + { + animatorId = Qt3DCore::QNodeId::createId(); + MappingData mapping; + mapping.targetId = Qt3DCore::QNodeId::createId(); + mapping.propertyName = "pos"; + mapping.type = static_cast(QVariant::Vector2D); + mapping.channelIndices = QVector() << 0 << 1; + mappingData.push_back(mapping); + channelResults = QVector() << 2.0f << 1.0f; + finalFrame = false; + + auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(mapping.targetId); + change->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll); + change->setPropertyName(mapping.propertyName); + change->setValue(QVariant::fromValue(QVector2D(2.0f, 1.0f))); + expectedChanges.push_back(change); + + QTest::newRow("vec2 pos") + << animatorId << mappingData << channelResults << finalFrame + << expectedChanges; + + mappingData.clear(); + channelResults.clear(); + expectedChanges.clear(); + } + + // Single property, vec4 + { + animatorId = Qt3DCore::QNodeId::createId(); + MappingData mapping; + mapping.targetId = Qt3DCore::QNodeId::createId(); + mapping.propertyName = "foo"; + mapping.type = static_cast(QVariant::Vector2D); + mapping.channelIndices = QVector() << 0 << 1 << 2 << 3; + mappingData.push_back(mapping); + channelResults = QVector() << 4.0f << 3.0f << 2.0f << 1.0f; + finalFrame = false; + + auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(mapping.targetId); + change->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll); + change->setPropertyName(mapping.propertyName); + change->setValue(QVariant::fromValue(QVector4D(4.0f, 3.0f, 2.0f, 1.0f))); + expectedChanges.push_back(change); + + QTest::newRow("vec4 foo") + << animatorId << mappingData << channelResults << finalFrame + << expectedChanges; + + mappingData.clear(); + channelResults.clear(); + expectedChanges.clear(); + } + + // Single property, quaternion + { + animatorId = Qt3DCore::QNodeId::createId(); + MappingData mapping; + mapping.targetId = Qt3DCore::QNodeId::createId(); + mapping.propertyName = "rotation"; + mapping.type = static_cast(QVariant::Quaternion); + mapping.channelIndices = QVector() << 0 << 1 << 2 << 3; + mappingData.push_back(mapping); + channelResults = QVector() << 1.0f << 0.0f << 0.0f << 1.0f; + finalFrame = false; + + auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(mapping.targetId); + change->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll); + change->setPropertyName(mapping.propertyName); + change->setValue(QVariant::fromValue(QQuaternion(1.0f, 0.0f, 0.0f, 1.0f))); + expectedChanges.push_back(change); + + QTest::newRow("quaternion rotation") + << animatorId << mappingData << channelResults << finalFrame + << expectedChanges; + + mappingData.clear(); + channelResults.clear(); + expectedChanges.clear(); + } + } + + void checkPreparePropertyChanges() + { + // GIVEN + QFETCH(Qt3DCore::QNodeId, animatorId); + QFETCH(QVector, mappingData); + QFETCH(QVector, channelResults); + QFETCH(bool, finalFrame); + QFETCH(QVector, expectedChanges); + + // WHEN + QVector actualChanges + = preparePropertyChanges(animatorId, mappingData, channelResults, finalFrame); + + // THEN + QCOMPARE(actualChanges.size(), expectedChanges.size()); + for (int i = 0; i < actualChanges.size(); ++i) { + auto expectedChange = expectedChanges[i]; + auto actualChange + = qSharedPointerCast(expectedChanges[i]); + + QCOMPARE(actualChange->subjectId(), expectedChange->subjectId()); + QCOMPARE(actualChange->deliveryFlags(), expectedChange->deliveryFlags()); + QCOMPARE(actualChange->propertyName(), expectedChange->propertyName()); + QCOMPARE(actualChange->value(), expectedChange->value()); + } + } }; QTEST_MAIN(tst_AnimationUtils) -- cgit v1.2.3 From c8f2258aa24b38326cb576f82f738e242f44cd84 Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Fri, 3 Mar 2017 13:17:15 +0000 Subject: Extend animation utils test to cover evlaluateClipAtLocalTime() Change-Id: I5fb07fa2f8efe8e89fa33e0af7378d38d2488d00 Reviewed-by: Mike Krus --- .../animation/animationutils/animationutils.qrc | 1 + tests/auto/animation/animationutils/clip2.json | 250 +++++++++++++++++++++ .../animationutils/tst_animationutils.cpp | 119 ++++++++++ 3 files changed, 370 insertions(+) create mode 100644 tests/auto/animation/animationutils/clip2.json diff --git a/tests/auto/animation/animationutils/animationutils.qrc b/tests/auto/animation/animationutils/animationutils.qrc index 72234ec64..aeb8112f3 100644 --- a/tests/auto/animation/animationutils/animationutils.qrc +++ b/tests/auto/animation/animationutils/animationutils.qrc @@ -1,5 +1,6 @@ clip1.json + clip2.json diff --git a/tests/auto/animation/animationutils/clip2.json b/tests/auto/animation/animationutils/clip2.json new file mode 100644 index 000000000..3faff409c --- /dev/null +++ b/tests/auto/animation/animationutils/clip2.json @@ -0,0 +1,250 @@ +{ + "animations": [ + { + "animationName": "CubeAction", + "channels": [ + { + "channelComponents": [ + { + "channelComponentName": "Location X", + "keyFrames": [ + { + "coords": [ + 0.0, + 0.0 + ], + "leftHandle": [ + -0.9597616195678711, + 0.0 + ], + "rightHandle": [ + 0.9597616195678711, + 0.0 + ] + }, + { + "coords": [ + 2.4583333333333335, + 5.0 + ], + "leftHandle": [ + 1.4985717137654622, + 5.0 + ], + "rightHandle": [ + 3.4180949529012046, + 5.0 + ] + } + ] + }, + { + "channelComponentName": "Location Z", + "keyFrames": [ + { + "coords": [ + 0.0, + 0.0 + ], + "leftHandle": [ + -0.9597616195678711, + 0.0 + ], + "rightHandle": [ + 0.9597616195678711, + 0.0 + ] + }, + { + "coords": [ + 2.4583333333333335, + 0.0 + ], + "leftHandle": [ + 1.4985717137654622, + 0.0 + ], + "rightHandle": [ + 3.4180949529012046, + 0.0 + ] + } + ] + }, + { + "channelComponentName": "Location Y", + "keyFrames": [ + { + "coords": [ + 0.0, + 0.0 + ], + "leftHandle": [ + -0.9597616195678711, + 0.0 + ], + "rightHandle": [ + 0.9597616195678711, + 0.0 + ] + }, + { + "coords": [ + 2.4583333333333335, + 0.0 + ], + "leftHandle": [ + 1.4985717137654622, + 0.0 + ], + "rightHandle": [ + 3.4180949529012046, + 0.0 + ] + } + ] + } + ], + "channelName": "Location" + }, + { + "channelComponents": [ + { + "channelComponentName": "Rotation W", + "keyFrames": [ + { + "coords": [ + 0.0, + 1.0 + ], + "leftHandle": [ + -0.9597616195678711, + 1.0 + ], + "rightHandle": [ + 0.9597616195678711, + 1.0 + ] + }, + { + "coords": [ + 2.4583333333333335, + -4.371138828673793e-08 + ], + "leftHandle": [ + 1.4985717137654622, + -4.371138828673793e-08 + ], + "rightHandle": [ + 3.4180949529012046, + -4.371138828673793e-08 + ] + } + ] + }, + { + "channelComponentName": "Rotation X", + "keyFrames": [ + { + "coords": [ + 0.0, + 0.0 + ], + "leftHandle": [ + -0.9597616195678711, + 0.0 + ], + "rightHandle": [ + 0.9597616195678711, + 0.0 + ] + }, + { + "coords": [ + 2.4583333333333335, + 0.0 + ], + "leftHandle": [ + 1.4985717137654622, + 0.0 + ], + "rightHandle": [ + 3.4180949529012046, + 0.0 + ] + } + ] + }, + { + "channelComponentName": "Rotation Z", + "keyFrames": [ + { + "coords": [ + 0.0, + -0.0 + ], + "leftHandle": [ + -0.9597616195678711, + -0.0 + ], + "rightHandle": [ + 0.9597616195678711, + -0.0 + ] + }, + { + "coords": [ + 2.4583333333333335, + -1.0 + ], + "leftHandle": [ + 1.4985717137654622, + -1.0 + ], + "rightHandle": [ + 3.4180949529012046, + -1.0 + ] + } + ] + }, + { + "channelComponentName": "Rotation Y", + "keyFrames": [ + { + "coords": [ + 0.0, + 0.0 + ], + "leftHandle": [ + -0.9597616195678711, + 0.0 + ], + "rightHandle": [ + 0.9597616195678711, + 0.0 + ] + }, + { + "coords": [ + 2.4583333333333335, + 0.0 + ], + "leftHandle": [ + 1.4985717137654622, + 0.0 + ], + "rightHandle": [ + 3.4180949529012046, + 0.0 + ] + } + ] + } + ], + "channelName": "Rotation" + } + ] + } + ] +} \ No newline at end of file diff --git a/tests/auto/animation/animationutils/tst_animationutils.cpp b/tests/auto/animation/animationutils/tst_animationutils.cpp index 622990829..00f857d1d 100644 --- a/tests/auto/animation/animationutils/tst_animationutils.cpp +++ b/tests/auto/animation/animationutils/tst_animationutils.cpp @@ -51,6 +51,18 @@ Q_DECLARE_METATYPE(AnimationClipLoader *) Q_DECLARE_METATYPE(QVector) Q_DECLARE_METATYPE(QVector) +bool fuzzyCompare(float x1, float x2) +{ + if (qFuzzyIsNull(x1) && qFuzzyIsNull(x2)) { + return true; + } else if (qFuzzyIsNull(x1) && !qFuzzyIsNull(x2) || + !qFuzzyIsNull(x1) && qFuzzyIsNull(x2)) { + return false; + } else { + return qFuzzyCompare(x1, x2); + } +} + class tst_AnimationUtils : public Qt3DCore::QBackendNodeTester { Q_OBJECT @@ -572,6 +584,113 @@ private Q_SLOTS: QCOMPARE(actualChange->value(), expectedChange->value()); } } + + void checkEvaluateClipAtLocalTime_data() + { + QTest::addColumn("handler"); + QTest::addColumn("clip"); + QTest::addColumn("localTime"); + QTest::addColumn>("expectedResults"); + + Handler *handler; + AnimationClipLoader *clip; + float localTime; + QVector expectedResults; + + { + handler = new Handler(); + clip = createAnimationClipLoader(handler, QUrl("qrc:/clip1.json")); + localTime = 0.0f; + expectedResults = QVector() << 0.0f << 0.0f << 0.0f; + + QTest::newRow("clip1.json, t = 0.0") + << handler << clip << localTime << expectedResults; + expectedResults.clear(); + } + + { + handler = new Handler(); + clip = createAnimationClipLoader(handler, QUrl("qrc:/clip1.json")); + localTime = clip->duration(); + expectedResults = QVector() << 5.0f << 0.0f << 0.0f; + + QTest::newRow("clip1.json, t = duration") + << handler << clip << localTime << expectedResults; + expectedResults.clear(); + } + + { + handler = new Handler(); + clip = createAnimationClipLoader(handler, QUrl("qrc:/clip1.json")); + localTime = clip->duration() / 2.0f; + expectedResults = QVector() << 2.5f << 0.0f << 0.0f; + + QTest::newRow("clip1.json, t = duration/2") + << handler << clip << localTime << expectedResults; + expectedResults.clear(); + } + + { + handler = new Handler(); + clip = createAnimationClipLoader(handler, QUrl("qrc:/clip2.json")); + localTime = 0.0f; + expectedResults = QVector() + << 0.0f << 0.0f << 0.0f // Translation + << 1.0f << 0.0f << 0.0f << 0.0f; // Rotation + + QTest::newRow("clip2.json, t = 0.0") + << handler << clip << localTime << expectedResults; + expectedResults.clear(); + } + { + handler = new Handler(); + clip = createAnimationClipLoader(handler, QUrl("qrc:/clip2.json")); + localTime = clip->duration(); + expectedResults = QVector() + << 5.0f << 0.0f << 0.0f // Translation + << 0.0f << 0.0f << -1.0f << 0.0f; // Rotation + + QTest::newRow("clip2.json, t = duration") + << handler << clip << localTime << expectedResults; + expectedResults.clear(); + } + { + handler = new Handler(); + clip = createAnimationClipLoader(handler, QUrl("qrc:/clip2.json")); + localTime = clip->duration() / 2.0f; + expectedResults = QVector() + << 2.5f << 0.0f << 0.0f // Translation + << 0.5f << 0.0f << -0.5f << 0.0f; // Rotation + + QTest::newRow("clip2.json, t = duration/2") + << handler << clip << localTime << expectedResults; + expectedResults.clear(); + } + } + + void checkEvaluateClipAtLocalTime() + { + // GIVEN + QFETCH(Handler *, handler); + QFETCH(AnimationClipLoader *, clip); + QFETCH(float, localTime); + QFETCH(QVector, expectedResults); + + // WHEN + QVector actualResults = evaluateClipAtLocalTime(clip, localTime); + + // THEN + QCOMPARE(actualResults.size(), expectedResults.size()); + for (int i = 0; i < actualResults.size(); ++i) { + auto actual = actualResults[i]; + auto expected = expectedResults[i]; + + QVERIFY(fuzzyCompare(actual, expected) == true); + } + + // Cleanup + delete handler; + } }; QTEST_MAIN(tst_AnimationUtils) -- cgit v1.2.3 From ca9faa8dc1f5f195999c050aecb143a005d98663 Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Thu, 2 Mar 2017 10:10:04 +0000 Subject: Update animation clip in keyframe manual test Change-Id: I8f4678828c6e8265ce212fc5bbc5f2f4c9128b0f Reviewed-by: Mike Krus --- .../animation-keyframe-simple/cubeanimation.json | 333 +++++++++++++++------ 1 file changed, 248 insertions(+), 85 deletions(-) diff --git a/tests/manual/animation-keyframe-simple/cubeanimation.json b/tests/manual/animation-keyframe-simple/cubeanimation.json index addf92907..3faff409c 100644 --- a/tests/manual/animation-keyframe-simple/cubeanimation.json +++ b/tests/manual/animation-keyframe-simple/cubeanimation.json @@ -1,87 +1,250 @@ { "animations": [ - { "object": "Cube", - "action": "CubeAction", - "range": [0.0, 60.0], - "groups": [ - { "group": "Location", - "channels": [ - { "name": "x", - "keyframes": [ - { "co": [0.0, 0.0], - "handle_left": [-0.4717472394307454, 0.0], - "handle_right": [0.4717472394307454, 0.0]} - ,{ "co": [1.2083333333333333, 2.430499792098999], - "handle_left": [0.7365860939025879, 1.4711904525756836], - "handle_right": [1.696347713470459, 3.42288875579834]} - ,{ "co": [2.4583333333333335, 5.0], - "handle_left": [1.9703189531962078, 5.0], - "handle_right": [2.9463475545247397, 5.0]} - ]} - ,{ "name": "z", - "keyframes": [ - { "co": [0.0, 0.0], - "handle_left": [-0.4717472394307454, 0.0], - "handle_right": [0.4717472394307454, 0.0]} - ,{ "co": [1.2083333333333333, 0.0], - "handle_left": [0.7365860939025879, 0.0], - "handle_right": [1.696347713470459, 0.0]} - ,{ "co": [2.4583333333333335, 0.0], - "handle_left": [1.9703189531962078, 0.0], - "handle_right": [2.9463475545247397, 0.0]} - ]} - ,{ "name": "y", - "keyframes": [ - { "co": [0.0, 0.0], - "handle_left": [-0.4717472394307454, 0.0], - "handle_right": [0.4717472394307454, 0.0]} - ,{ "co": [1.2083333333333333, 3.0], - "handle_left": [0.7365860939025879, 3.0], - "handle_right": [1.696347713470459, 3.0]} - ,{ "co": [2.4583333333333335, 0.0], - "handle_left": [1.9703189531962078, 0.0], - "handle_right": [2.9463475545247397, 0.0]} - ]} - ]} - ,{ "group": "Rotation", - "channels": [ - { "name": "w", - "keyframes": [ - { "co": [0.0, 1.0], - "handle_left": [-0.9597616195678711, 1.0], - "handle_right": [0.9597616195678711, 1.0]} - ,{ "co": [2.4583333333333335, -4.371138828673793e-08], - "handle_left": [1.4985717137654622, -4.371138828673793e-08], - "handle_right": [3.4180949529012046, -4.371138828673793e-08]} - ]} - ,{ "name": "x", - "keyframes": [ - { "co": [0.0, 0.0], - "handle_left": [-0.9597616195678711, 0.0], - "handle_right": [0.9597616195678711, 0.0]} - ,{ "co": [2.4583333333333335, 0.0], - "handle_left": [1.4985717137654622, 0.0], - "handle_right": [3.4180949529012046, 0.0]} - ]} - ,{ "name": "z", - "keyframes": [ - { "co": [0.0, -0.0], - "handle_left": [-0.9597616195678711, -0.0], - "handle_right": [0.9597616195678711, -0.0]} - ,{ "co": [2.4583333333333335, -1.0], - "handle_left": [1.4985717137654622, -1.0], - "handle_right": [3.4180949529012046, -1.0]} - ]} - ,{ "name": "y", - "keyframes": [ - { "co": [0.0, 0.0], - "handle_left": [-0.9597616195678711, 0.0], - "handle_right": [0.9597616195678711, 0.0]} - ,{ "co": [2.4583333333333335, 0.0], - "handle_left": [1.4985717137654622, 0.0], - "handle_right": [3.4180949529012046, 0.0]} - ]} - ]} - ]} - ] -} + { + "animationName": "CubeAction", + "channels": [ + { + "channelComponents": [ + { + "channelComponentName": "Location X", + "keyFrames": [ + { + "coords": [ + 0.0, + 0.0 + ], + "leftHandle": [ + -0.9597616195678711, + 0.0 + ], + "rightHandle": [ + 0.9597616195678711, + 0.0 + ] + }, + { + "coords": [ + 2.4583333333333335, + 5.0 + ], + "leftHandle": [ + 1.4985717137654622, + 5.0 + ], + "rightHandle": [ + 3.4180949529012046, + 5.0 + ] + } + ] + }, + { + "channelComponentName": "Location Z", + "keyFrames": [ + { + "coords": [ + 0.0, + 0.0 + ], + "leftHandle": [ + -0.9597616195678711, + 0.0 + ], + "rightHandle": [ + 0.9597616195678711, + 0.0 + ] + }, + { + "coords": [ + 2.4583333333333335, + 0.0 + ], + "leftHandle": [ + 1.4985717137654622, + 0.0 + ], + "rightHandle": [ + 3.4180949529012046, + 0.0 + ] + } + ] + }, + { + "channelComponentName": "Location Y", + "keyFrames": [ + { + "coords": [ + 0.0, + 0.0 + ], + "leftHandle": [ + -0.9597616195678711, + 0.0 + ], + "rightHandle": [ + 0.9597616195678711, + 0.0 + ] + }, + { + "coords": [ + 2.4583333333333335, + 0.0 + ], + "leftHandle": [ + 1.4985717137654622, + 0.0 + ], + "rightHandle": [ + 3.4180949529012046, + 0.0 + ] + } + ] + } + ], + "channelName": "Location" + }, + { + "channelComponents": [ + { + "channelComponentName": "Rotation W", + "keyFrames": [ + { + "coords": [ + 0.0, + 1.0 + ], + "leftHandle": [ + -0.9597616195678711, + 1.0 + ], + "rightHandle": [ + 0.9597616195678711, + 1.0 + ] + }, + { + "coords": [ + 2.4583333333333335, + -4.371138828673793e-08 + ], + "leftHandle": [ + 1.4985717137654622, + -4.371138828673793e-08 + ], + "rightHandle": [ + 3.4180949529012046, + -4.371138828673793e-08 + ] + } + ] + }, + { + "channelComponentName": "Rotation X", + "keyFrames": [ + { + "coords": [ + 0.0, + 0.0 + ], + "leftHandle": [ + -0.9597616195678711, + 0.0 + ], + "rightHandle": [ + 0.9597616195678711, + 0.0 + ] + }, + { + "coords": [ + 2.4583333333333335, + 0.0 + ], + "leftHandle": [ + 1.4985717137654622, + 0.0 + ], + "rightHandle": [ + 3.4180949529012046, + 0.0 + ] + } + ] + }, + { + "channelComponentName": "Rotation Z", + "keyFrames": [ + { + "coords": [ + 0.0, + -0.0 + ], + "leftHandle": [ + -0.9597616195678711, + -0.0 + ], + "rightHandle": [ + 0.9597616195678711, + -0.0 + ] + }, + { + "coords": [ + 2.4583333333333335, + -1.0 + ], + "leftHandle": [ + 1.4985717137654622, + -1.0 + ], + "rightHandle": [ + 3.4180949529012046, + -1.0 + ] + } + ] + }, + { + "channelComponentName": "Rotation Y", + "keyFrames": [ + { + "coords": [ + 0.0, + 0.0 + ], + "leftHandle": [ + -0.9597616195678711, + 0.0 + ], + "rightHandle": [ + 0.9597616195678711, + 0.0 + ] + }, + { + "coords": [ + 2.4583333333333335, + 0.0 + ], + "leftHandle": [ + 1.4985717137654622, + 0.0 + ], + "rightHandle": [ + 3.4180949529012046, + 0.0 + ] + } + ] + } + ], + "channelName": "Rotation" + } + ] + } + ] +} \ No newline at end of file -- cgit v1.2.3 From f8e30ae6113bfb55cd8bf706790a94f6a4720ef5 Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Fri, 3 Mar 2017 15:04:33 +0000 Subject: Rename Channel -> Component in channelComponentsToIndicesHelper() For consistency with new animation terminology. Change-Id: Ic2c07ad0b98b7ab754eff0c36ab6147ea1e7ce37 Reviewed-by: Mike Krus --- src/animation/backend/animationutils.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/animation/backend/animationutils.cpp b/src/animation/backend/animationutils.cpp index 13cb27d4a..0c6ea54f4 100644 --- a/src/animation/backend/animationutils.cpp +++ b/src/animation/backend/animationutils.cpp @@ -128,37 +128,37 @@ QVector channelComponentsToIndicesHelper(const Channel &channel, int offset, const QStringList &suffixes) { - int expectedChannelCount = 1; + int expectedComponentCount = 1; switch (dataType) { case QVariant::Double: - expectedChannelCount = 1; + expectedComponentCount = 1; break; case QVariant::Vector2D: - expectedChannelCount = 2; + expectedComponentCount = 2; break; case QVariant::Vector3D: - expectedChannelCount = 3; + expectedComponentCount = 3; break; case QVariant::Vector4D: case QVariant::Quaternion: - expectedChannelCount = 4; + expectedComponentCount = 4; break; default: qWarning() << "Unhandled animation type"; } - const int foundChannelCount = channel.channelComponents.size(); - if (foundChannelCount != expectedChannelCount) { - qWarning() << "Data type expects" << expectedChannelCount - << "but found" << foundChannelCount << "channels in the animation clip"; + const int actualComponentCount = channel.channelComponents.size(); + if (actualComponentCount != expectedComponentCount) { + qWarning() << "Data type expects" << expectedComponentCount + << "but found" << actualComponentCount << "components in the animation clip"; } - QVector indices(expectedChannelCount); - for (int i = 0; i < expectedChannelCount; ++i) { + QVector indices(expectedComponentCount); + for (int i = 0; i < expectedComponentCount; ++i) { const QString channelComponentSuffix = channel.channelComponents[i].name.right(1); int index = suffixes.indexOf(channelComponentSuffix); if (index != -1) -- cgit v1.2.3 From bef195f739a99f9b3fcfaa0c26b2ebdc8173a5ce Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Fri, 3 Mar 2017 15:55:41 +0000 Subject: Use QVector rather than QStringList for channel suffixes No need for full strings when only checking a single character. Change-Id: I7d59c7f67b753694c34d0845b0bfcb014e929344 Reviewed-by: Mike Krus --- src/animation/backend/animationutils.cpp | 24 +++++++++++------------- src/animation/backend/animationutils_p.h | 2 +- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/animation/backend/animationutils.cpp b/src/animation/backend/animationutils.cpp index 0c6ea54f4..18c340b15 100644 --- a/src/animation/backend/animationutils.cpp +++ b/src/animation/backend/animationutils.cpp @@ -105,16 +105,13 @@ double localTimeFromGlobalTime(double t_global, QVector channelComponentsToIndices(const Channel &channelGroup, int dataType, int offset) { - static const QStringList standardSuffixes = (QStringList() - << QLatin1String("X") - << QLatin1String("Y") - << QLatin1String("Z") - << QLatin1String("W")); - static const QStringList quaternionSuffixes = (QStringList() - << QLatin1String("W") - << QLatin1String("X") - << QLatin1String("Y") - << QLatin1String("Z")); +#if defined Q_COMPILER_UNIFORM_INIT + static const QVector standardSuffixes = { 'X', 'Y', 'Z', 'W' }; + static const QVector quaternionSuffixes = { 'W', 'X', 'Y', 'Z' }; +#else + static const QVector standardSuffixes = (QVector() << 'X' << 'Y' << 'Z' << 'W'); + static const QVector quaternionSuffixes = (QVector() << 'W' << 'X' << 'Y' << 'Z'); +#endif if (dataType != QVariant::Quaternion) return channelComponentsToIndicesHelper(channelGroup, dataType, offset, standardSuffixes); @@ -126,7 +123,7 @@ QVector channelComponentsToIndices(const Channel &channelGroup, int dataTyp QVector channelComponentsToIndicesHelper(const Channel &channel, int dataType, int offset, - const QStringList &suffixes) + const QVector &suffixes) { int expectedComponentCount = 1; switch (dataType) { @@ -159,8 +156,9 @@ QVector channelComponentsToIndicesHelper(const Channel &channel, QVector indices(expectedComponentCount); for (int i = 0; i < expectedComponentCount; ++i) { - const QString channelComponentSuffix = channel.channelComponents[i].name.right(1); - int index = suffixes.indexOf(channelComponentSuffix); + const QString &componentName = channel.channelComponents[i].name; + char suffix = componentName.at(componentName.length() - 1).toLatin1(); + int index = suffixes.indexOf(suffix); if (index != -1) indices[i] = index + offset; else diff --git a/src/animation/backend/animationutils_p.h b/src/animation/backend/animationutils_p.h index 184b2422e..26dc047eb 100644 --- a/src/animation/backend/animationutils_p.h +++ b/src/animation/backend/animationutils_p.h @@ -122,7 +122,7 @@ Q_AUTOTEST_EXPORT QVector channelComponentsToIndicesHelper(const Channel &channelGroup, int dataType, int offset, - const QStringList &suffixes); + const QVector &suffixes); Q_AUTOTEST_EXPORT QVector evaluateClipAtLocalTime(AnimationClipLoader *clip, -- cgit v1.2.3 From a6a539da453eb50aca665fdd09b53e17b4d395a7 Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Fri, 3 Mar 2017 16:53:16 +0000 Subject: Extend animation utils test to cover channelComponentsToIndicesHelper Change-Id: I4284d43da48a25dac6ff4c3c7b5f1b30e1b8e74f Reviewed-by: Mike Krus --- .../animationutils/tst_animationutils.cpp | 204 +++++++++++++++++++++ 1 file changed, 204 insertions(+) diff --git a/tests/auto/animation/animationutils/tst_animationutils.cpp b/tests/auto/animation/animationutils/tst_animationutils.cpp index 00f857d1d..a69e1114b 100644 --- a/tests/auto/animation/animationutils/tst_animationutils.cpp +++ b/tests/auto/animation/animationutils/tst_animationutils.cpp @@ -50,6 +50,7 @@ Q_DECLARE_METATYPE(ChannelMapper *) Q_DECLARE_METATYPE(AnimationClipLoader *) Q_DECLARE_METATYPE(QVector) Q_DECLARE_METATYPE(QVector) +Q_DECLARE_METATYPE(Channel) bool fuzzyCompare(float x1, float x2) { @@ -691,6 +692,209 @@ private Q_SLOTS: // Cleanup delete handler; } + + void checkChannelComponentsToIndicesHelper_data() + { + QTest::addColumn("channel"); + QTest::addColumn("dataType"); + QTest::addColumn("offset"); + QTest::addColumn>("suffixes"); + QTest::addColumn>("expectedResults"); + + Channel channel; + int dataType; + int offset; + QVector suffixes; + QVector expectedResults; + + // vec3 with and without offset + { + channel = Channel(); + channel.name = QLatin1String("Location"); + channel.channelComponents.resize(3); + channel.channelComponents[0].name = QLatin1String("Location X"); + channel.channelComponents[1].name = QLatin1String("Location Y"); + channel.channelComponents[2].name = QLatin1String("Location Z"); + + dataType = static_cast(QVariant::Vector3D); + offset = 0; + suffixes = (QVector() << 'X' << 'Y' << 'Z' << 'W'); + expectedResults = (QVector() << 0 << 1 << 2); + + QTest::newRow("vec3 location, offset = 0") + << channel << dataType << offset << suffixes << expectedResults; + + expectedResults.clear(); + + offset = 4; + expectedResults = (QVector() << 4 << 5 << 6); + QTest::newRow("vec3 location, offset = 4") + << channel << dataType << offset << suffixes << expectedResults; + + suffixes.clear(); + expectedResults.clear(); + } + + // vec2 with and without offset + { + channel = Channel(); + channel.name = QLatin1String("pos"); + channel.channelComponents.resize(2); + channel.channelComponents[0].name = QLatin1String("pos X"); + channel.channelComponents[1].name = QLatin1String("pos Y"); + + dataType = static_cast(QVariant::Vector2D); + offset = 0; + suffixes = (QVector() << 'X' << 'Y' << 'Z' << 'W'); + expectedResults = (QVector() << 0 << 1); + + QTest::newRow("vec2 pos, offset = 0") + << channel << dataType << offset << suffixes << expectedResults; + + expectedResults.clear(); + + offset = 2; + expectedResults = (QVector() << 2 << 3); + QTest::newRow("vec2 pos, offset = 2") + << channel << dataType << offset << suffixes << expectedResults; + + suffixes.clear(); + expectedResults.clear(); + } + + // vec4 with and without offset + { + channel = Channel(); + channel.name = QLatin1String("foo"); + channel.channelComponents.resize(4); + channel.channelComponents[0].name = QLatin1String("foo X"); + channel.channelComponents[1].name = QLatin1String("foo Y"); + channel.channelComponents[2].name = QLatin1String("foo Z"); + channel.channelComponents[3].name = QLatin1String("foo W"); + + dataType = static_cast(QVariant::Vector4D); + offset = 0; + suffixes = (QVector() << 'X' << 'Y' << 'Z' << 'W'); + expectedResults = (QVector() << 0 << 1 << 2 << 3); + + QTest::newRow("vec4 foo, offset = 0") + << channel << dataType << offset << suffixes << expectedResults; + + expectedResults.clear(); + + offset = 10; + expectedResults = (QVector() << 10 << 11 << 12 << 13); + QTest::newRow("vec4 foo, offset = 10") + << channel << dataType << offset << suffixes << expectedResults; + + suffixes.clear(); + expectedResults.clear(); + } + + // double with and without offset + { + channel = Channel(); + channel.name = QLatin1String("foo"); + channel.channelComponents.resize(1); + channel.channelComponents[0].name = QLatin1String("Mass X"); + + dataType = static_cast(QVariant::Double); + offset = 0; + suffixes = (QVector() << 'X' << 'Y' << 'Z' << 'W'); + expectedResults = (QVector() << 0); + + QTest::newRow("double Mass, offset = 0") + << channel << dataType << offset << suffixes << expectedResults; + + expectedResults.clear(); + + offset = 5; + expectedResults = (QVector() << 5); + QTest::newRow("double Mass, offset = 5") + << channel << dataType << offset << suffixes << expectedResults; + + suffixes.clear(); + expectedResults.clear(); + } + + // quaternion with and without offset + { + channel = Channel(); + channel.name = QLatin1String("Rotation"); + channel.channelComponents.resize(4); + channel.channelComponents[0].name = QLatin1String("Rotation W"); + channel.channelComponents[1].name = QLatin1String("Rotation X"); + channel.channelComponents[2].name = QLatin1String("Rotation Y"); + channel.channelComponents[3].name = QLatin1String("Rotation Z"); + + dataType = static_cast(QVariant::Quaternion); + offset = 0; + suffixes = (QVector() << 'W' << 'X' << 'Y' << 'Z'); + expectedResults = (QVector() << 0 << 1 << 2 << 3); + + QTest::newRow("quaternion Rotation, offset = 0") + << channel << dataType << offset << suffixes << expectedResults; + + expectedResults.clear(); + + offset = 10; + expectedResults = (QVector() << 10 << 11 << 12 << 13); + QTest::newRow("quaternion Rotation, offset = 10") + << channel << dataType << offset << suffixes << expectedResults; + + suffixes.clear(); + expectedResults.clear(); + } + + // quaternion with and without offset, randomized + { + channel = Channel(); + channel.name = QLatin1String("Rotation"); + channel.channelComponents.resize(4); + channel.channelComponents[0].name = QLatin1String("Rotation X"); + channel.channelComponents[1].name = QLatin1String("Rotation W"); + channel.channelComponents[2].name = QLatin1String("Rotation Z"); + channel.channelComponents[3].name = QLatin1String("Rotation Y"); + + dataType = static_cast(QVariant::Quaternion); + offset = 0; + suffixes = (QVector() << 'W' << 'X' << 'Y' << 'Z'); + expectedResults = (QVector() << 1 << 0 << 3 << 2); + + QTest::newRow("quaternion Rotation, offset = 0, randomized") + << channel << dataType << offset << suffixes << expectedResults; + + expectedResults.clear(); + + offset = 10; + expectedResults = (QVector() << 11 << 10 << 13 << 12); + QTest::newRow("quaternion Rotation, offset = 10, randomized") + << channel << dataType << offset << suffixes << expectedResults; + + suffixes.clear(); + expectedResults.clear(); + } + } + + void checkChannelComponentsToIndicesHelper() + { + // GIVEN + QFETCH(Channel, channel); + QFETCH(int, dataType); + QFETCH(int, offset); + QFETCH(QVector, suffixes); + QFETCH(QVector, expectedResults); + + // WHEN + QVector actualResults + = channelComponentsToIndicesHelper(channel, dataType, offset, suffixes); + + // THEN + QCOMPARE(actualResults.size(), expectedResults.size()); + for (int i = 0; i < actualResults.size(); ++i) { + QCOMPARE(actualResults[i], expectedResults[i]); + } + } }; QTEST_MAIN(tst_AnimationUtils) -- cgit v1.2.3 From 107bd8891152738da8ab8831eba2ffef19505548 Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Fri, 3 Mar 2017 16:59:32 +0000 Subject: Rename channelGroup -> channel For consistency with new animation naming scheme. Change-Id: Ia250f233678149cac8ca40188f5043f2a1fca965 Reviewed-by: Mike Krus --- src/animation/backend/animationutils.cpp | 7 +++---- src/animation/backend/animationutils_p.h | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/animation/backend/animationutils.cpp b/src/animation/backend/animationutils.cpp index 18c340b15..beac147a1 100644 --- a/src/animation/backend/animationutils.cpp +++ b/src/animation/backend/animationutils.cpp @@ -103,7 +103,7 @@ double localTimeFromGlobalTime(double t_global, return t_local; } -QVector channelComponentsToIndices(const Channel &channelGroup, int dataType, int offset) +QVector channelComponentsToIndices(const Channel &channel, int dataType, int offset) { #if defined Q_COMPILER_UNIFORM_INIT static const QVector standardSuffixes = { 'X', 'Y', 'Z', 'W' }; @@ -114,10 +114,9 @@ QVector channelComponentsToIndices(const Channel &channelGroup, int dataTyp #endif if (dataType != QVariant::Quaternion) - return channelComponentsToIndicesHelper(channelGroup, dataType, offset, standardSuffixes); + return channelComponentsToIndicesHelper(channel, dataType, offset, standardSuffixes); else - return channelComponentsToIndicesHelper(channelGroup, dataType, offset, quaternionSuffixes); - + return channelComponentsToIndicesHelper(channel, dataType, offset, quaternionSuffixes); } QVector channelComponentsToIndicesHelper(const Channel &channel, diff --git a/src/animation/backend/animationutils_p.h b/src/animation/backend/animationutils_p.h index 26dc047eb..c1d13554a 100644 --- a/src/animation/backend/animationutils_p.h +++ b/src/animation/backend/animationutils_p.h @@ -114,7 +114,7 @@ ClipEvaluationData evaluationDataForClip(AnimationClipLoader *clip, const AnimatorEvaluationData &animatorData); Q_AUTOTEST_EXPORT -QVector channelComponentsToIndices(const Channel &channelGroup, +QVector channelComponentsToIndices(const Channel &channel, int dataType, int offset = 0); -- cgit v1.2.3 From 76c7862ec26cad41aa6d30dca684ea09a8423e98 Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Fri, 3 Mar 2017 17:00:01 +0000 Subject: Extend animation utils test to cover channelComponentsToIndices Change-Id: Iacccdfc052b6739fcc0b8825d7f55b7ce70e6a40 Reviewed-by: Mike Krus --- .../animationutils/tst_animationutils.cpp | 84 ++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/tests/auto/animation/animationutils/tst_animationutils.cpp b/tests/auto/animation/animationutils/tst_animationutils.cpp index a69e1114b..ac113b9ab 100644 --- a/tests/auto/animation/animationutils/tst_animationutils.cpp +++ b/tests/auto/animation/animationutils/tst_animationutils.cpp @@ -895,6 +895,90 @@ private Q_SLOTS: QCOMPARE(actualResults[i], expectedResults[i]); } } + + void checkChannelComponentsToIndices_data() + { + QTest::addColumn("channel"); + QTest::addColumn("dataType"); + QTest::addColumn("offset"); + QTest::addColumn>("expectedResults"); + + Channel channel; + int dataType; + int offset; + QVector expectedResults; + + // Quaternion + { + channel = Channel(); + channel.name = QLatin1String("Rotation"); + channel.channelComponents.resize(4); + channel.channelComponents[0].name = QLatin1String("Rotation W"); + channel.channelComponents[1].name = QLatin1String("Rotation X"); + channel.channelComponents[2].name = QLatin1String("Rotation Y"); + channel.channelComponents[3].name = QLatin1String("Rotation Z"); + + dataType = static_cast(QVariant::Quaternion); + offset = 0; + expectedResults = (QVector() << 0 << 1 << 2 << 3); + + QTest::newRow("quaternion Rotation, offset = 0") + << channel << dataType << offset << expectedResults; + + expectedResults.clear(); + + offset = 10; + expectedResults = (QVector() << 10 << 11 << 12 << 13); + QTest::newRow("quaternion Rotation, offset = 10") + << channel << dataType << offset << expectedResults; + + expectedResults.clear(); + } + + // vec3 with and without offset + { + channel = Channel(); + channel.name = QLatin1String("Location"); + channel.channelComponents.resize(3); + channel.channelComponents[0].name = QLatin1String("Location X"); + channel.channelComponents[1].name = QLatin1String("Location Y"); + channel.channelComponents[2].name = QLatin1String("Location Z"); + + dataType = static_cast(QVariant::Vector3D); + offset = 0; + expectedResults = (QVector() << 0 << 1 << 2); + + QTest::newRow("vec3 location, offset = 0") + << channel << dataType << offset << expectedResults; + + expectedResults.clear(); + + offset = 4; + expectedResults = (QVector() << 4 << 5 << 6); + QTest::newRow("vec3 location, offset = 4") + << channel << dataType << offset << expectedResults; + + expectedResults.clear(); + } + } + + void checkChannelComponentsToIndices() + { + QFETCH(Channel, channel); + QFETCH(int, dataType); + QFETCH(int, offset); + QFETCH(QVector, expectedResults); + + // WHEN + QVector actualResults + = channelComponentsToIndices(channel, dataType, offset); + + // THEN + QCOMPARE(actualResults.size(), expectedResults.size()); + for (int i = 0; i < actualResults.size(); ++i) { + QCOMPARE(actualResults[i], expectedResults[i]); + } + } }; QTEST_MAIN(tst_AnimationUtils) -- cgit v1.2.3 From bb8bd77fbbb70be9237fbe8ac127087162ca0b65 Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Fri, 3 Mar 2017 19:25:16 +0000 Subject: Add ClipAnimator::setLoops() for testing purposes Change-Id: I6e491509b438954e526e1c958a7565a7704f0eac Reviewed-by: Mike Krus --- src/animation/backend/clipanimator_p.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/animation/backend/clipanimator_p.h b/src/animation/backend/clipanimator_p.h index 8c1ea393d..a616ac9cd 100644 --- a/src/animation/backend/clipanimator_p.h +++ b/src/animation/backend/clipanimator_p.h @@ -73,6 +73,7 @@ public: void setRunning(bool running); bool isRunning() const { return m_running; } + void setLoops(int loops) { m_loops = loops; } int loops() const { return m_loops; } void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_OVERRIDE; -- cgit v1.2.3 From 983f66c0a043e0f94b699c5119b7dc2ac91194aa Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Fri, 3 Mar 2017 19:26:10 +0000 Subject: Extend animation utils test to cover evaluationDataForClip() Change-Id: I1bdf856404ee20ddd9500e66ae48ed622801bd2e Reviewed-by: Mike Krus --- .../animationutils/tst_animationutils.cpp | 131 +++++++++++++++++++++ 1 file changed, 131 insertions(+) diff --git a/tests/auto/animation/animationutils/tst_animationutils.cpp b/tests/auto/animation/animationutils/tst_animationutils.cpp index ac113b9ab..dd9734edf 100644 --- a/tests/auto/animation/animationutils/tst_animationutils.cpp +++ b/tests/auto/animation/animationutils/tst_animationutils.cpp @@ -51,6 +51,8 @@ Q_DECLARE_METATYPE(AnimationClipLoader *) Q_DECLARE_METATYPE(QVector) Q_DECLARE_METATYPE(QVector) Q_DECLARE_METATYPE(Channel) +Q_DECLARE_METATYPE(AnimatorEvaluationData) +Q_DECLARE_METATYPE(ClipEvaluationData) bool fuzzyCompare(float x1, float x2) { @@ -108,6 +110,18 @@ public: return clip; } + ClipAnimator *createClipAnimator(Handler *handler, + qint64 globalStartTimeNS, + int loops) + { + auto animatorId = Qt3DCore::QNodeId::createId(); + ClipAnimator *animator = handler->clipAnimatorManager()->getOrCreateResource(animatorId); + setPeerId(animator, animatorId); + animator->setStartTime(globalStartTimeNS); + animator->setLoops(loops); + return animator; + } + private Q_SLOTS: void checkBuildPropertyMappings_data() { @@ -979,6 +993,123 @@ private Q_SLOTS: QCOMPARE(actualResults[i], expectedResults[i]); } } + + void checkEvaluationDataForClip_data() + { + QTest::addColumn("handler"); + QTest::addColumn("clip"); + QTest::addColumn("animatorData"); + QTest::addColumn("expectedClipData"); + + Handler *handler; + AnimationClipLoader *clip; + AnimatorEvaluationData animatorData; + ClipEvaluationData clipData; + + { + handler = new Handler(); + clip = createAnimationClipLoader(handler, QUrl("qrc:/clip1.json")); + const qint64 globalStartTimeNS = 0; + const int loops = 1; + auto animator = createClipAnimator(handler, globalStartTimeNS, loops); + const qint64 globalTimeNS = 0; + animatorData = evaluationDataForAnimator(animator, globalTimeNS); // Tested elsewhere + + clipData.localTime = localTimeFromGlobalTime(animatorData.globalTime, + animatorData.startTime, + animatorData.playbackRate, + clip->duration(), + animatorData.loopCount, + clipData.currentLoop); // Tested elsewhere + clipData.isFinalFrame = false; + + QTest::newRow("clip1.json, globalTime = 0") + << handler << clip << animatorData << clipData; + } + + { + handler = new Handler(); + clip = createAnimationClipLoader(handler, QUrl("qrc:/clip1.json")); + const qint64 globalStartTimeNS = 0; + const int loops = 1; + auto animator = createClipAnimator(handler, globalStartTimeNS, loops); + const qint64 globalTimeNS = (clip->duration() + 1.0) * 1.0e9; // +1 to ensure beyond end of clip + animatorData = evaluationDataForAnimator(animator, globalTimeNS); // Tested elsewhere + + clipData.localTime = localTimeFromGlobalTime(animatorData.globalTime, + animatorData.startTime, + animatorData.playbackRate, + clip->duration(), + animatorData.loopCount, + clipData.currentLoop); // Tested elsewhere + clipData.isFinalFrame = true; + + QTest::newRow("clip1.json, globalTime = duration") + << handler << clip << animatorData << clipData; + } + + { + handler = new Handler(); + clip = createAnimationClipLoader(handler, QUrl("qrc:/clip1.json")); + const qint64 globalStartTimeNS = 0; + const int loops = 0; // Infinite loops + auto animator = createClipAnimator(handler, globalStartTimeNS, loops); + const qint64 globalTimeNS = 2.0 * clip->duration() * 1.0e9; + animatorData = evaluationDataForAnimator(animator, globalTimeNS); // Tested elsewhere + + clipData.localTime = localTimeFromGlobalTime(animatorData.globalTime, + animatorData.startTime, + animatorData.playbackRate, + clip->duration(), + animatorData.loopCount, + clipData.currentLoop); // Tested elsewhere + clipData.isFinalFrame = false; + + QTest::newRow("clip1.json, globalTime = 2 * duration, loops = infinite") + << handler << clip << animatorData << clipData; + } + + { + handler = new Handler(); + clip = createAnimationClipLoader(handler, QUrl("qrc:/clip1.json")); + const qint64 globalStartTimeNS = 0; + const int loops = 2; + auto animator = createClipAnimator(handler, globalStartTimeNS, loops); + const qint64 globalTimeNS = (2.0 * clip->duration() + 1.0) * 1.0e9; // +1 to ensure beyond end of clip + animatorData = evaluationDataForAnimator(animator, globalTimeNS); // Tested elsewhere + + clipData.localTime = localTimeFromGlobalTime(animatorData.globalTime, + animatorData.startTime, + animatorData.playbackRate, + clip->duration(), + animatorData.loopCount, + clipData.currentLoop); // Tested elsewhere + clipData.isFinalFrame = true; + + QTest::newRow("clip1.json, globalTime = 2 * duration + 1, loops = 2") + << handler << clip << animatorData << clipData; + } + } + + void checkEvaluationDataForClip() + { + // GIVEN + QFETCH(Handler *, handler); + QFETCH(AnimationClipLoader *, clip); + QFETCH(AnimatorEvaluationData, animatorData); + QFETCH(ClipEvaluationData, expectedClipData); + + // WHEN + ClipEvaluationData actualClipData = evaluationDataForClip(clip, animatorData); + + // THEN + QCOMPARE(actualClipData.currentLoop, expectedClipData.currentLoop); + QVERIFY(fuzzyCompare(actualClipData.localTime, expectedClipData.localTime) == true); + QCOMPARE(actualClipData.isFinalFrame, expectedClipData.isFinalFrame); + + // Cleanup + delete handler; + } }; QTEST_MAIN(tst_AnimationUtils) -- cgit v1.2.3 From e76fabc8f1349d0eddf725453fc188d2ae0bf77e Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Fri, 3 Mar 2017 19:56:02 +0000 Subject: Extend animation utils test to cover evaluationDataForAnimator() Change-Id: I537185cb10499562b7d578cd83ff28e2faba78b4 Reviewed-by: Mike Krus --- .../animationutils/tst_animationutils.cpp | 99 ++++++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/tests/auto/animation/animationutils/tst_animationutils.cpp b/tests/auto/animation/animationutils/tst_animationutils.cpp index dd9734edf..1f91aedf1 100644 --- a/tests/auto/animation/animationutils/tst_animationutils.cpp +++ b/tests/auto/animation/animationutils/tst_animationutils.cpp @@ -53,6 +53,7 @@ Q_DECLARE_METATYPE(QVector) Q_DECLARE_METATYPE(Channel) Q_DECLARE_METATYPE(AnimatorEvaluationData) Q_DECLARE_METATYPE(ClipEvaluationData) +Q_DECLARE_METATYPE(ClipAnimator *) bool fuzzyCompare(float x1, float x2) { @@ -1110,6 +1111,104 @@ private Q_SLOTS: // Cleanup delete handler; } + + void checkEvaluationDataForAnimator_data() + { + QTest::addColumn("handler"); + QTest::addColumn("animator"); + QTest::addColumn("globalTimeNS"); + QTest::addColumn("expectedAnimatorData"); + + Handler *handler; + ClipAnimator *animator; + qint64 globalTimeNS; + AnimatorEvaluationData expectedAnimatorData; + + { + handler = new Handler(); + const qint64 globalStartTimeNS = 0; + const int loops = 1; + animator = createClipAnimator(handler, globalStartTimeNS, loops); + globalTimeNS = 0; + + expectedAnimatorData.loopCount = loops; + expectedAnimatorData.playbackRate = 1.0; // hard-wired for now + expectedAnimatorData.startTime = 0.0; + expectedAnimatorData.globalTime = 0.0; + + QTest::newRow("globalStartTime = 0, globalTime = 0, loops = 1") + << handler << animator << globalTimeNS << expectedAnimatorData; + } + + { + handler = new Handler(); + const qint64 globalStartTimeNS = 0; + const int loops = 5; + animator = createClipAnimator(handler, globalStartTimeNS, loops); + globalTimeNS = 0; + + expectedAnimatorData.loopCount = loops; + expectedAnimatorData.playbackRate = 1.0; // hard-wired for now + expectedAnimatorData.startTime = 0.0; + expectedAnimatorData.globalTime = 0.0; + + QTest::newRow("globalStartTime = 0, globalTime = 0, loops = 5") + << handler << animator << globalTimeNS << expectedAnimatorData; + } + + { + handler = new Handler(); + const qint64 globalStartTimeNS = 0; + const int loops = 1; + animator = createClipAnimator(handler, globalStartTimeNS, loops); + globalTimeNS = 5000000000; + + expectedAnimatorData.loopCount = loops; + expectedAnimatorData.playbackRate = 1.0; // hard-wired for now + expectedAnimatorData.startTime = 0.0; + expectedAnimatorData.globalTime = 5.0; + + QTest::newRow("globalStartTime = 0, globalTime = 5, loops = 1") + << handler << animator << globalTimeNS << expectedAnimatorData; + } + + { + handler = new Handler(); + const qint64 globalStartTimeNS = 3000000000; + const int loops = 1; + animator = createClipAnimator(handler, globalStartTimeNS, loops); + globalTimeNS = 5000000000; + + expectedAnimatorData.loopCount = loops; + expectedAnimatorData.playbackRate = 1.0; // hard-wired for now + expectedAnimatorData.startTime = 3.0; + expectedAnimatorData.globalTime = 5.0; + + QTest::newRow("globalStartTime = 3, globalTime = 5, loops = 1") + << handler << animator << globalTimeNS << expectedAnimatorData; + } + } + + void checkEvaluationDataForAnimator() + { + // GIVEN + QFETCH(Handler *, handler); + QFETCH(ClipAnimator *, animator); + QFETCH(qint64, globalTimeNS); + QFETCH(AnimatorEvaluationData, expectedAnimatorData); + + // WHEN + AnimatorEvaluationData actualAnimatorData = evaluationDataForAnimator(animator, globalTimeNS); + + // THEN + QCOMPARE(actualAnimatorData.loopCount, expectedAnimatorData.loopCount); + QVERIFY(fuzzyCompare(actualAnimatorData.playbackRate, expectedAnimatorData.playbackRate) == true); + QVERIFY(fuzzyCompare(actualAnimatorData.startTime, expectedAnimatorData.startTime) == true); + QVERIFY(fuzzyCompare(actualAnimatorData.globalTime, expectedAnimatorData.globalTime) == true); + + // Cleanup + delete handler; + } }; QTEST_MAIN(tst_AnimationUtils) -- cgit v1.2.3 From 3cd55c54dbf66a320438d743fbd223952043cd39 Mon Sep 17 00:00:00 2001 From: Andy Maloney Date: Wed, 7 Dec 2016 19:33:08 -0500 Subject: Update assimp lib to 3.3.1 The currently included assimp lib is v3.0 from 2012. This updates assimp lib to the latest released version (3.3.1). Change-Id: I15a60e3150c0b268422f23137107b34e4c5c4342 Reviewed-by: Sean Harmer --- src/3rdparty/assimp/CHANGES | 109 +- src/3rdparty/assimp/CREDITS | 14 +- src/3rdparty/assimp/LICENSE | 30 +- src/3rdparty/assimp/Readme.md | 119 +- src/3rdparty/assimp/assimp.pri | 239 +- src/3rdparty/assimp/code/3DSConverter.cpp | 1518 +-- src/3rdparty/assimp/code/3DSExporter.cpp | 565 + src/3rdparty/assimp/code/3DSExporter.h | 98 + src/3rdparty/assimp/code/3DSHelper.h | 906 +- src/3rdparty/assimp/code/3DSLoader.cpp | 2397 ++--- src/3rdparty/assimp/code/3DSLoader.h | 410 +- src/3rdparty/assimp/code/ACLoader.cpp | 1539 +-- src/3rdparty/assimp/code/ACLoader.h | 353 +- src/3rdparty/assimp/code/ASELoader.cpp | 2317 ++--- src/3rdparty/assimp/code/ASELoader.h | 218 +- src/3rdparty/assimp/code/ASEParser.cpp | 3789 +++---- src/3rdparty/assimp/code/ASEParser.h | 945 +- src/3rdparty/assimp/code/AssbinExporter.cpp | 768 ++ src/3rdparty/assimp/code/AssbinExporter.h | 49 + src/3rdparty/assimp/code/AssbinLoader.cpp | 686 ++ src/3rdparty/assimp/code/AssbinLoader.h | 105 + src/3rdparty/assimp/code/Assimp.cpp | 741 +- src/3rdparty/assimp/code/AssimpCExport.cpp | 105 +- src/3rdparty/assimp/code/AssimpPCH.cpp | 135 - src/3rdparty/assimp/code/AssimpPCH.h | 166 - src/3rdparty/assimp/code/AssxmlExporter.cpp | 648 ++ src/3rdparty/assimp/code/AssxmlExporter.h | 49 + src/3rdparty/assimp/code/B3DImporter.cpp | 979 +- src/3rdparty/assimp/code/B3DImporter.h | 146 +- src/3rdparty/assimp/code/BVHLoader.cpp | 779 +- src/3rdparty/assimp/code/BVHLoader.h | 164 +- src/3rdparty/assimp/code/BaseImporter.cpp | 865 +- src/3rdparty/assimp/code/BaseImporter.h | 586 +- src/3rdparty/assimp/code/BaseProcess.cpp | 62 +- src/3rdparty/assimp/code/BaseProcess.h | 380 +- src/3rdparty/assimp/code/Bitmap.cpp | 191 +- src/3rdparty/assimp/code/Bitmap.h | 107 +- src/3rdparty/assimp/code/BlenderBMesh.cpp | 164 +- src/3rdparty/assimp/code/BlenderBMesh.h | 97 +- src/3rdparty/assimp/code/BlenderDNA.cpp | 519 +- src/3rdparty/assimp/code/BlenderDNA.h | 933 +- src/3rdparty/assimp/code/BlenderDNA.inl | 1018 +- src/3rdparty/assimp/code/BlenderIntermediate.h | 264 +- src/3rdparty/assimp/code/BlenderLoader.cpp | 2066 ++-- src/3rdparty/assimp/code/BlenderLoader.h | 306 +- src/3rdparty/assimp/code/BlenderModifier.cpp | 438 +- src/3rdparty/assimp/code/BlenderModifier.h | 125 +- src/3rdparty/assimp/code/BlenderScene.cpp | 303 +- src/3rdparty/assimp/code/BlenderScene.h | 964 +- src/3rdparty/assimp/code/BlenderSceneGen.h | 28 +- src/3rdparty/assimp/code/BlenderTessellator.cpp | 530 +- src/3rdparty/assimp/code/BlenderTessellator.h | 272 +- src/3rdparty/assimp/code/BlobIOSystem.h | 434 +- .../code/BoostWorkaround/boost/LICENSE_1_0.txt | 23 - .../assimp/code/BoostWorkaround/boost/foreach.hpp | 99 - .../assimp/code/BoostWorkaround/boost/format.hpp | 81 - .../code/BoostWorkaround/boost/lexical_cast.hpp | 26 - .../code/BoostWorkaround/boost/make_shared.hpp | 57 - .../boost/math/common_factor_rt.hpp | 37 - .../code/BoostWorkaround/boost/noncopyable.hpp | 36 - .../code/BoostWorkaround/boost/pointer_cast.hpp | 45 - .../code/BoostWorkaround/boost/scoped_array.hpp | 79 - .../code/BoostWorkaround/boost/scoped_ptr.hpp | 79 - .../code/BoostWorkaround/boost/shared_array.hpp | 228 - .../code/BoostWorkaround/boost/shared_ptr.hpp | 257 - .../code/BoostWorkaround/boost/static_assert.hpp | 20 - .../assimp/code/BoostWorkaround/boost/timer.hpp | 72 - .../code/BoostWorkaround/boost/tuple/tuple.hpp | 283 - src/3rdparty/assimp/code/ByteSwap.h | 285 - src/3rdparty/assimp/code/ByteSwapper.h | 286 + src/3rdparty/assimp/code/C4DImporter.cpp | 650 ++ src/3rdparty/assimp/code/C4DImporter.h | 123 + src/3rdparty/assimp/code/CInterfaceIOWrapper.h | 194 +- src/3rdparty/assimp/code/CMakeLists.txt | 1284 +-- src/3rdparty/assimp/code/COBLoader.cpp | 2007 ++-- src/3rdparty/assimp/code/COBLoader.h | 178 +- src/3rdparty/assimp/code/COBScene.h | 257 +- src/3rdparty/assimp/code/CSMLoader.cpp | 443 +- src/3rdparty/assimp/code/CSMLoader.h | 51 +- src/3rdparty/assimp/code/CalcTangentsProcess.cpp | 395 +- src/3rdparty/assimp/code/CalcTangentsProcess.h | 100 +- src/3rdparty/assimp/code/ColladaExporter.cpp | 1287 ++- src/3rdparty/assimp/code/ColladaExporter.h | 155 +- src/3rdparty/assimp/code/ColladaHelper.h | 722 +- src/3rdparty/assimp/code/ColladaLoader.cpp | 1598 +-- src/3rdparty/assimp/code/ColladaLoader.h | 163 +- src/3rdparty/assimp/code/ColladaParser.cpp | 4929 ++++----- src/3rdparty/assimp/code/ColladaParser.h | 519 +- .../assimp/code/ComputeUVMappingProcess.cpp | 798 +- src/3rdparty/assimp/code/ComputeUVMappingProcess.h | 170 +- src/3rdparty/assimp/code/ConvertToLHProcess.cpp | 347 +- src/3rdparty/assimp/code/ConvertToLHProcess.h | 140 +- src/3rdparty/assimp/code/D3MFImporter.cpp | 388 + src/3rdparty/assimp/code/D3MFImporter.h | 68 + src/3rdparty/assimp/code/D3MFOpcPackage.cpp | 591 ++ src/3rdparty/assimp/code/D3MFOpcPackage.h | 76 + src/3rdparty/assimp/code/DXFHelper.h | 257 +- src/3rdparty/assimp/code/DXFLoader.cpp | 1509 +-- src/3rdparty/assimp/code/DXFLoader.h | 152 +- src/3rdparty/assimp/code/DeboneProcess.cpp | 743 +- src/3rdparty/assimp/code/DeboneProcess.h | 130 +- src/3rdparty/assimp/code/DefaultIOStream.cpp | 121 +- src/3rdparty/assimp/code/DefaultIOStream.h | 125 +- src/3rdparty/assimp/code/DefaultIOSystem.cpp | 152 +- src/3rdparty/assimp/code/DefaultIOSystem.h | 75 +- src/3rdparty/assimp/code/DefaultLogger.cpp | 498 +- src/3rdparty/assimp/code/DefaultProgressHandler.h | 39 +- src/3rdparty/assimp/code/Defines.h | 49 + src/3rdparty/assimp/code/Exceptional.h | 93 +- src/3rdparty/assimp/code/Exporter.cpp | 688 +- src/3rdparty/assimp/code/FBXAnimation.cpp | 391 +- src/3rdparty/assimp/code/FBXBinaryTokenizer.cpp | 527 +- src/3rdparty/assimp/code/FBXCompileConfig.h | 44 +- src/3rdparty/assimp/code/FBXConverter.cpp | 6066 +++++------ src/3rdparty/assimp/code/FBXConverter.h | 35 +- src/3rdparty/assimp/code/FBXDeformer.cpp | 147 +- src/3rdparty/assimp/code/FBXDocument.cpp | 934 +- src/3rdparty/assimp/code/FBXDocument.h | 1776 ++-- src/3rdparty/assimp/code/FBXDocumentUtil.cpp | 110 +- src/3rdparty/assimp/code/FBXDocumentUtil.h | 108 +- src/3rdparty/assimp/code/FBXImportSettings.h | 190 +- src/3rdparty/assimp/code/FBXImporter.cpp | 193 +- src/3rdparty/assimp/code/FBXImporter.h | 75 +- src/3rdparty/assimp/code/FBXMaterial.cpp | 406 +- src/3rdparty/assimp/code/FBXMeshGeometry.cpp | 901 +- src/3rdparty/assimp/code/FBXMeshGeometry.h | 180 + src/3rdparty/assimp/code/FBXModel.cpp | 154 +- src/3rdparty/assimp/code/FBXNodeAttribute.cpp | 74 +- src/3rdparty/assimp/code/FBXParser.cpp | 1834 ++-- src/3rdparty/assimp/code/FBXParser.h | 153 +- src/3rdparty/assimp/code/FBXProperties.cpp | 238 +- src/3rdparty/assimp/code/FBXProperties.h | 170 +- src/3rdparty/assimp/code/FBXTokenizer.cpp | 322 +- src/3rdparty/assimp/code/FBXTokenizer.h | 144 +- src/3rdparty/assimp/code/FBXUtil.cpp | 86 +- src/3rdparty/assimp/code/FBXUtil.h | 32 +- src/3rdparty/assimp/code/FileLogStream.h | 61 +- src/3rdparty/assimp/code/FileSystemFilter.h | 480 +- src/3rdparty/assimp/code/FindDegenerates.cpp | 277 +- src/3rdparty/assimp/code/FindDegenerates.h | 98 +- src/3rdparty/assimp/code/FindInstancesProcess.cpp | 396 +- src/3rdparty/assimp/code/FindInstancesProcess.h | 94 +- .../assimp/code/FindInvalidDataProcess.cpp | 566 +- src/3rdparty/assimp/code/FindInvalidDataProcess.h | 75 +- src/3rdparty/assimp/code/FixNormalsStep.cpp | 178 +- src/3rdparty/assimp/code/FixNormalsStep.h | 64 +- src/3rdparty/assimp/code/GenFaceNormalsProcess.cpp | 143 +- src/3rdparty/assimp/code/GenFaceNormalsProcess.h | 56 +- .../assimp/code/GenVertexNormalsProcess.cpp | 319 +- src/3rdparty/assimp/code/GenVertexNormalsProcess.h | 106 +- src/3rdparty/assimp/code/GenericProperty.h | 129 +- src/3rdparty/assimp/code/HMPFileData.h | 129 +- src/3rdparty/assimp/code/HMPLoader.cpp | 806 +- src/3rdparty/assimp/code/HMPLoader.h | 164 +- src/3rdparty/assimp/code/HalfLifeFileData.h | 179 +- src/3rdparty/assimp/code/Hash.h | 27 +- src/3rdparty/assimp/code/IFCBoolean.cpp | 1347 +-- src/3rdparty/assimp/code/IFCCurve.cpp | 850 +- src/3rdparty/assimp/code/IFCGeometry.cpp | 1473 +-- src/3rdparty/assimp/code/IFCLoader.cpp | 1508 +-- src/3rdparty/assimp/code/IFCLoader.h | 112 +- src/3rdparty/assimp/code/IFCMaterial.cpp | 269 +- src/3rdparty/assimp/code/IFCOpenings.cpp | 2980 +++--- src/3rdparty/assimp/code/IFCProfile.cpp | 232 +- src/3rdparty/assimp/code/IFCReaderGen.h | 6578 ++++++------ src/3rdparty/assimp/code/IFCReaderGen1.cpp | 4604 +++++---- src/3rdparty/assimp/code/IFCReaderGen2.cpp | 2150 ++-- src/3rdparty/assimp/code/IFCUtil.cpp | 903 +- src/3rdparty/assimp/code/IFCUtil.h | 442 +- src/3rdparty/assimp/code/IFF.h | 88 +- src/3rdparty/assimp/code/IRRLoader.cpp | 2699 ++--- src/3rdparty/assimp/code/IRRLoader.h | 471 +- src/3rdparty/assimp/code/IRRMeshLoader.cpp | 894 +- src/3rdparty/assimp/code/IRRMeshLoader.h | 66 +- src/3rdparty/assimp/code/IRRShared.cpp | 805 +- src/3rdparty/assimp/code/IRRShared.h | 117 +- src/3rdparty/assimp/code/Importer.cpp | 1487 +-- src/3rdparty/assimp/code/Importer.h | 247 +- src/3rdparty/assimp/code/ImporterRegistry.cpp | 228 +- src/3rdparty/assimp/code/ImproveCacheLocality.cpp | 608 +- src/3rdparty/assimp/code/ImproveCacheLocality.h | 64 +- src/3rdparty/assimp/code/JoinVerticesProcess.cpp | 684 +- src/3rdparty/assimp/code/JoinVerticesProcess.h | 80 +- src/3rdparty/assimp/code/LWOAnimation.cpp | 985 +- src/3rdparty/assimp/code/LWOAnimation.h | 418 +- src/3rdparty/assimp/code/LWOBLoader.cpp | 664 +- src/3rdparty/assimp/code/LWOFileData.h | 672 +- src/3rdparty/assimp/code/LWOLoader.cpp | 2481 ++--- src/3rdparty/assimp/code/LWOLoader.h | 714 +- src/3rdparty/assimp/code/LWOMaterial.cpp | 1569 ++- src/3rdparty/assimp/code/LWSLoader.cpp | 1510 +-- src/3rdparty/assimp/code/LWSLoader.h | 254 +- .../assimp/code/LimitBoneWeightsProcess.cpp | 259 +- src/3rdparty/assimp/code/LimitBoneWeightsProcess.h | 122 +- src/3rdparty/assimp/code/LineSplitter.h | 342 +- src/3rdparty/assimp/code/LogAux.h | 150 +- src/3rdparty/assimp/code/MD2FileData.h | 123 +- src/3rdparty/assimp/code/MD2Loader.cpp | 661 +- src/3rdparty/assimp/code/MD2Loader.h | 100 +- src/3rdparty/assimp/code/MD2NormalTable.h | 346 +- src/3rdparty/assimp/code/MD3FileData.h | 297 +- src/3rdparty/assimp/code/MD3Loader.cpp | 1801 ++-- src/3rdparty/assimp/code/MD3Loader.h | 320 +- src/3rdparty/assimp/code/MD4FileData.h | 182 +- src/3rdparty/assimp/code/MD5Loader.cpp | 1223 +-- src/3rdparty/assimp/code/MD5Loader.h | 247 +- src/3rdparty/assimp/code/MD5Parser.cpp | 752 +- src/3rdparty/assimp/code/MD5Parser.h | 469 +- src/3rdparty/assimp/code/MDCFileData.h | 175 +- src/3rdparty/assimp/code/MDCLoader.cpp | 762 +- src/3rdparty/assimp/code/MDCLoader.h | 110 +- src/3rdparty/assimp/code/MDCNormalTable.h | 516 +- src/3rdparty/assimp/code/MDLDefaultColorMap.h | 146 +- src/3rdparty/assimp/code/MDLFileData.h | 894 +- src/3rdparty/assimp/code/MDLLoader.cpp | 3389 +++--- src/3rdparty/assimp/code/MDLLoader.h | 719 +- src/3rdparty/assimp/code/MDLMaterialLoader.cpp | 1438 +-- src/3rdparty/assimp/code/MS3DLoader.cpp | 1066 +- src/3rdparty/assimp/code/MS3DLoader.h | 183 +- src/3rdparty/assimp/code/Macros.h | 49 + src/3rdparty/assimp/code/MakeVerboseFormat.cpp | 318 +- src/3rdparty/assimp/code/MakeVerboseFormat.h | 80 +- src/3rdparty/assimp/code/MaterialSystem.cpp | 942 +- src/3rdparty/assimp/code/MaterialSystem.h | 30 +- src/3rdparty/assimp/code/MathFunctions.h | 77 + src/3rdparty/assimp/code/MemoryIOWrapper.h | 265 +- src/3rdparty/assimp/code/NDOLoader.cpp | 461 +- src/3rdparty/assimp/code/NDOLoader.h | 119 +- src/3rdparty/assimp/code/NFFLoader.cpp | 2351 ++--- src/3rdparty/assimp/code/NFFLoader.h | 291 +- src/3rdparty/assimp/code/OFFLoader.cpp | 335 +- src/3rdparty/assimp/code/OFFLoader.h | 64 +- src/3rdparty/assimp/code/ObjExporter.cpp | 520 +- src/3rdparty/assimp/code/ObjExporter.h | 150 +- src/3rdparty/assimp/code/ObjFileData.h | 562 +- src/3rdparty/assimp/code/ObjFileImporter.cpp | 1198 +-- src/3rdparty/assimp/code/ObjFileImporter.h | 115 +- src/3rdparty/assimp/code/ObjFileMtlImporter.cpp | 671 +- src/3rdparty/assimp/code/ObjFileMtlImporter.h | 114 +- src/3rdparty/assimp/code/ObjFileParser.cpp | 1258 +-- src/3rdparty/assimp/code/ObjFileParser.h | 192 +- src/3rdparty/assimp/code/ObjTools.h | 335 +- src/3rdparty/assimp/code/OgreBinarySerializer.cpp | 1675 ++- src/3rdparty/assimp/code/OgreBinarySerializer.h | 693 +- src/3rdparty/assimp/code/OgreImporter.cpp | 166 +- src/3rdparty/assimp/code/OgreImporter.h | 86 +- src/3rdparty/assimp/code/OgreMaterial.cpp | 1023 +- src/3rdparty/assimp/code/OgreParsingUtils.h | 110 +- src/3rdparty/assimp/code/OgreStructs.cpp | 1639 +-- src/3rdparty/assimp/code/OgreStructs.h | 895 +- src/3rdparty/assimp/code/OgreXmlSerializer.cpp | 1511 +-- src/3rdparty/assimp/code/OgreXmlSerializer.h | 118 +- src/3rdparty/assimp/code/OpenGEXExporter.cpp | 56 + src/3rdparty/assimp/code/OpenGEXExporter.h | 66 + src/3rdparty/assimp/code/OpenGEXImporter.cpp | 1190 +++ src/3rdparty/assimp/code/OpenGEXImporter.h | 209 + src/3rdparty/assimp/code/OpenGEXStructs.h | 265 + src/3rdparty/assimp/code/OptimizeGraph.cpp | 519 +- src/3rdparty/assimp/code/OptimizeGraph.h | 133 +- src/3rdparty/assimp/code/OptimizeMeshes.cpp | 334 +- src/3rdparty/assimp/code/OptimizeMeshes.h | 212 +- src/3rdparty/assimp/code/ParsingUtils.h | 180 +- src/3rdparty/assimp/code/PlyExporter.cpp | 503 +- src/3rdparty/assimp/code/PlyExporter.h | 55 +- src/3rdparty/assimp/code/PlyLoader.cpp | 1924 ++-- src/3rdparty/assimp/code/PlyLoader.h | 208 +- src/3rdparty/assimp/code/PlyParser.cpp | 1538 +-- src/3rdparty/assimp/code/PlyParser.h | 594 +- src/3rdparty/assimp/code/PolyTools.h | 245 +- src/3rdparty/assimp/code/PostStepRegistry.cpp | 153 +- src/3rdparty/assimp/code/PretransformVertices.cpp | 1160 +-- src/3rdparty/assimp/code/PretransformVertices.h | 201 +- src/3rdparty/assimp/code/ProcessHelper.cpp | 622 +- src/3rdparty/assimp/code/ProcessHelper.h | 355 +- src/3rdparty/assimp/code/Profiler.h | 74 +- src/3rdparty/assimp/code/Q3BSPFileData.h | 230 +- src/3rdparty/assimp/code/Q3BSPFileImporter.cpp | 1181 +-- src/3rdparty/assimp/code/Q3BSPFileImporter.h | 98 +- src/3rdparty/assimp/code/Q3BSPFileParser.cpp | 302 +- src/3rdparty/assimp/code/Q3BSPFileParser.h | 54 +- src/3rdparty/assimp/code/Q3BSPZipArchive.cpp | 342 +- src/3rdparty/assimp/code/Q3BSPZipArchive.h | 124 +- src/3rdparty/assimp/code/Q3DLoader.cpp | 1073 +- src/3rdparty/assimp/code/Q3DLoader.h | 139 +- src/3rdparty/assimp/code/RawLoader.cpp | 510 +- src/3rdparty/assimp/code/RawLoader.h | 114 +- src/3rdparty/assimp/code/RemoveComments.cpp | 113 +- src/3rdparty/assimp/code/RemoveComments.h | 69 +- .../assimp/code/RemoveRedundantMaterials.cpp | 291 +- .../assimp/code/RemoveRedundantMaterials.h | 92 +- src/3rdparty/assimp/code/RemoveVCProcess.cpp | 488 +- src/3rdparty/assimp/code/RemoveVCProcess.h | 118 +- src/3rdparty/assimp/code/SGSpatialSort.cpp | 215 +- src/3rdparty/assimp/code/SGSpatialSort.h | 171 +- src/3rdparty/assimp/code/SIBImporter.cpp | 926 ++ src/3rdparty/assimp/code/SIBImporter.h | 119 + src/3rdparty/assimp/code/SMDLoader.cpp | 1875 ++-- src/3rdparty/assimp/code/SMDLoader.h | 577 +- src/3rdparty/assimp/code/STEPFile.h | 1824 ++-- src/3rdparty/assimp/code/STEPFileEncoding.cpp | 772 +- src/3rdparty/assimp/code/STEPFileEncoding.h | 38 +- src/3rdparty/assimp/code/STEPFileReader.cpp | 879 +- src/3rdparty/assimp/code/STEPFileReader.h | 44 +- src/3rdparty/assimp/code/STLExporter.cpp | 218 +- src/3rdparty/assimp/code/STLExporter.h | 42 +- src/3rdparty/assimp/code/STLLoader.cpp | 777 +- src/3rdparty/assimp/code/STLLoader.h | 98 +- src/3rdparty/assimp/code/SceneCombiner.cpp | 2014 ++-- src/3rdparty/assimp/code/SceneCombiner.h | 541 +- src/3rdparty/assimp/code/ScenePreprocessor.cpp | 401 +- src/3rdparty/assimp/code/ScenePreprocessor.h | 117 +- src/3rdparty/assimp/code/ScenePrivate.h | 69 +- src/3rdparty/assimp/code/SkeletonMeshBuilder.cpp | 413 +- src/3rdparty/assimp/code/SkeletonMeshBuilder.h | 111 +- src/3rdparty/assimp/code/SmoothingGroups.h | 79 +- src/3rdparty/assimp/code/SmoothingGroups.inl | 154 +- src/3rdparty/assimp/code/SortByPTypeProcess.cpp | 657 +- src/3rdparty/assimp/code/SortByPTypeProcess.h | 46 +- src/3rdparty/assimp/code/SpatialSort.cpp | 484 +- src/3rdparty/assimp/code/SpatialSort.h | 216 +- .../assimp/code/SplitByBoneCountProcess.cpp | 646 +- src/3rdparty/assimp/code/SplitByBoneCountProcess.h | 86 +- src/3rdparty/assimp/code/SplitLargeMeshes.cpp | 1120 +- src/3rdparty/assimp/code/SplitLargeMeshes.h | 191 +- src/3rdparty/assimp/code/StandardShapes.cpp | 687 +- src/3rdparty/assimp/code/StandardShapes.h | 286 +- src/3rdparty/assimp/code/StdOStreamLogStream.h | 84 +- src/3rdparty/assimp/code/StepExporter.cpp | 370 + src/3rdparty/assimp/code/StepExporter.h | 109 + src/3rdparty/assimp/code/StreamReader.h | 550 +- src/3rdparty/assimp/code/StreamWriter.h | 239 + src/3rdparty/assimp/code/StringComparison.h | 166 +- src/3rdparty/assimp/code/StringUtils.h | 111 + src/3rdparty/assimp/code/Subdivision.cpp | 970 +- src/3rdparty/assimp/code/Subdivision.h | 138 +- src/3rdparty/assimp/code/TargetAnimation.cpp | 350 +- src/3rdparty/assimp/code/TargetAnimation.h | 186 +- src/3rdparty/assimp/code/TerragenLoader.cpp | 395 +- src/3rdparty/assimp/code/TerragenLoader.h | 50 +- src/3rdparty/assimp/code/TextureTransform.cpp | 972 +- src/3rdparty/assimp/code/TextureTransform.h | 276 +- src/3rdparty/assimp/code/TinyFormatter.h | 164 +- src/3rdparty/assimp/code/TriangulateProcess.cpp | 793 +- src/3rdparty/assimp/code/TriangulateProcess.h | 64 +- src/3rdparty/assimp/code/UnrealLoader.cpp | 713 +- src/3rdparty/assimp/code/UnrealLoader.h | 216 +- src/3rdparty/assimp/code/ValidateDataStructure.cpp | 1617 +-- src/3rdparty/assimp/code/ValidateDataStructure.h | 223 +- src/3rdparty/assimp/code/Version.cpp | 169 + src/3rdparty/assimp/code/Vertex.h | 381 +- .../assimp/code/VertexTriangleAdjacency.cpp | 176 +- src/3rdparty/assimp/code/VertexTriangleAdjacency.h | 116 +- src/3rdparty/assimp/code/Win32DebugLogStream.h | 36 +- src/3rdparty/assimp/code/XFileExporter.cpp | 532 + src/3rdparty/assimp/code/XFileExporter.h | 135 + src/3rdparty/assimp/code/XFileHelper.h | 205 +- src/3rdparty/assimp/code/XFileImporter.cpp | 1145 ++- src/3rdparty/assimp/code/XFileImporter.h | 164 +- src/3rdparty/assimp/code/XFileParser.cpp | 2355 ++--- src/3rdparty/assimp/code/XFileParser.h | 194 +- src/3rdparty/assimp/code/XGLLoader.cpp | 1503 +-- src/3rdparty/assimp/code/XGLLoader.h | 265 +- src/3rdparty/assimp/code/XMLTools.h | 81 + src/3rdparty/assimp/code/assbin_chunks.h | 118 +- src/3rdparty/assimp/code/fast_atof.h | 469 +- src/3rdparty/assimp/code/glTFAsset.h | 964 ++ src/3rdparty/assimp/code/glTFAsset.inl | 1269 +++ src/3rdparty/assimp/code/glTFAssetWriter.h | 89 + src/3rdparty/assimp/code/glTFAssetWriter.inl | 492 + src/3rdparty/assimp/code/glTFExporter.cpp | 366 + src/3rdparty/assimp/code/glTFExporter.h | 108 + src/3rdparty/assimp/code/glTFImporter.cpp | 654 ++ src/3rdparty/assimp/code/glTFImporter.h | 90 + src/3rdparty/assimp/code/irrXMLWrapper.h | 155 +- src/3rdparty/assimp/code/qnan.h | 74 +- src/3rdparty/assimp/contrib/clipper/clipper.cpp | 2 +- src/3rdparty/assimp/contrib/clipper/clipper.hpp | 2 +- src/3rdparty/assimp/contrib/irrXML/irrXML.cpp | 1 - .../assimp/contrib/openddlparser/CMakeLists.txt | 64 + src/3rdparty/assimp/contrib/openddlparser/CREDITS | 16 + src/3rdparty/assimp/contrib/openddlparser/LICENSE | 22 + .../assimp/contrib/openddlparser/README.md | 136 + .../assimp/contrib/openddlparser/code/DDLNode.cpp | 209 + .../contrib/openddlparser/code/OpenDDLCommon.cpp | 186 + .../contrib/openddlparser/code/OpenDDLExport.cpp | 439 + .../contrib/openddlparser/code/OpenDDLParser.cpp | 1008 ++ .../assimp/contrib/openddlparser/code/Value.cpp | 440 + .../openddlparser/include/openddlparser/DDLNode.h | 164 + .../include/openddlparser/OpenDDLCommon.h | 247 + .../include/openddlparser/OpenDDLExport.h | 104 + .../include/openddlparser/OpenDDLParser.h | 187 + .../include/openddlparser/OpenDDLParserUtils.h | 254 + .../openddlparser/include/openddlparser/Value.h | 269 + .../contrib/poly2tri/poly2tri/common/shapes.h | 2 +- .../contrib/poly2tri/poly2tri/common/utils.h | 60 +- .../contrib/poly2tri/poly2tri/sweep/sweep.cc | 18 +- .../poly2tri/poly2tri/sweep/sweep_context.cc | 2 +- .../rapidjson/include/rapidjson/allocators.h | 261 + .../contrib/rapidjson/include/rapidjson/document.h | 2136 ++++ .../rapidjson/include/rapidjson/encodedstream.h | 261 + .../rapidjson/include/rapidjson/encodings.h | 625 ++ .../contrib/rapidjson/include/rapidjson/error/en.h | 65 + .../rapidjson/include/rapidjson/error/error.h | 146 + .../rapidjson/include/rapidjson/filereadstream.h | 88 + .../rapidjson/include/rapidjson/filewritestream.h | 95 + .../include/rapidjson/internal/biginteger.h | 290 + .../rapidjson/include/rapidjson/internal/diyfp.h | 248 + .../rapidjson/include/rapidjson/internal/dtoa.h | 217 + .../rapidjson/include/rapidjson/internal/ieee754.h | 77 + .../rapidjson/include/rapidjson/internal/itoa.h | 304 + .../rapidjson/include/rapidjson/internal/meta.h | 181 + .../rapidjson/include/rapidjson/internal/pow10.h | 55 + .../rapidjson/include/rapidjson/internal/stack.h | 196 + .../rapidjson/include/rapidjson/internal/strfunc.h | 39 + .../rapidjson/include/rapidjson/internal/strtod.h | 270 + .../rapidjson/include/rapidjson/internal/swap.h | 37 + .../rapidjson/include/rapidjson/memorybuffer.h | 70 + .../rapidjson/include/rapidjson/memorystream.h | 61 + .../include/rapidjson/msinttypes/inttypes.h | 316 + .../include/rapidjson/msinttypes/stdint.h | 300 + .../contrib/rapidjson/include/rapidjson/pointer.h | 1313 +++ .../rapidjson/include/rapidjson/prettywriter.h | 207 + .../rapidjson/include/rapidjson/rapidjson.h | 654 ++ .../contrib/rapidjson/include/rapidjson/reader.h | 1510 +++ .../rapidjson/include/rapidjson/stringbuffer.h | 93 + .../contrib/rapidjson/include/rapidjson/writer.h | 395 + src/3rdparty/assimp/contrib/rapidjson/license.txt | 57 + src/3rdparty/assimp/contrib/rapidjson/readme.md | 129 + src/3rdparty/assimp/contrib/unzip/unzip.c | 2 +- src/3rdparty/assimp/contrib/zlib_note.txt | 11 - .../assimp/include/assimp/Compiler/pstdint.h | 259 +- .../assimp/include/assimp/Compiler/pushpack1.h | 4 +- .../assimp/include/assimp/DefaultLogger.hpp | 214 +- src/3rdparty/assimp/include/assimp/Exporter.hpp | 639 +- src/3rdparty/assimp/include/assimp/IOStream.hpp | 130 +- src/3rdparty/assimp/include/assimp/IOSystem.hpp | 323 +- src/3rdparty/assimp/include/assimp/Importer.hpp | 1130 +- src/3rdparty/assimp/include/assimp/LogStream.hpp | 78 +- src/3rdparty/assimp/include/assimp/Logger.hpp | 314 +- src/3rdparty/assimp/include/assimp/NullLogger.hpp | 92 +- .../assimp/include/assimp/ProgressHandler.hpp | 110 +- src/3rdparty/assimp/include/assimp/ai_assert.h | 50 +- src/3rdparty/assimp/include/assimp/anim.h | 556 +- src/3rdparty/assimp/include/assimp/camera.h | 250 +- src/3rdparty/assimp/include/assimp/cexport.h | 154 +- src/3rdparty/assimp/include/assimp/cfileio.h | 102 +- src/3rdparty/assimp/include/assimp/cimport.h | 348 +- src/3rdparty/assimp/include/assimp/color4.h | 70 +- src/3rdparty/assimp/include/assimp/color4.inl | 128 +- src/3rdparty/assimp/include/assimp/config.h | 410 +- src/3rdparty/assimp/include/assimp/defs.h | 357 +- src/3rdparty/assimp/include/assimp/importerdesc.h | 171 +- src/3rdparty/assimp/include/assimp/light.h | 327 +- src/3rdparty/assimp/include/assimp/material.h | 1442 ++- src/3rdparty/assimp/include/assimp/material.inl | 342 +- src/3rdparty/assimp/include/assimp/matrix3x3.h | 197 +- src/3rdparty/assimp/include/assimp/matrix3x3.inl | 338 +- src/3rdparty/assimp/include/assimp/matrix4x4.h | 329 +- src/3rdparty/assimp/include/assimp/matrix4x4.inl | 555 +- src/3rdparty/assimp/include/assimp/mesh.h | 1055 +- src/3rdparty/assimp/include/assimp/metadata.h | 230 +- .../assimp/port/AndroidJNI/AndroidJNIIOSystem.h | 92 + src/3rdparty/assimp/include/assimp/postprocess.h | 1006 +- src/3rdparty/assimp/include/assimp/quaternion.h | 90 +- src/3rdparty/assimp/include/assimp/quaternion.inl | 271 +- src/3rdparty/assimp/include/assimp/scene.h | 536 +- src/3rdparty/assimp/include/assimp/texture.h | 206 +- src/3rdparty/assimp/include/assimp/types.h | 597 +- src/3rdparty/assimp/include/assimp/vector2.h | 70 +- src/3rdparty/assimp/include/assimp/vector2.inl | 94 +- src/3rdparty/assimp/include/assimp/vector3.h | 113 +- src/3rdparty/assimp/include/assimp/vector3.inl | 130 +- src/3rdparty/assimp/include/assimp/version.h | 30 +- src/3rdparty/assimp/qt_attribution.json | 2 +- src/3rdparty/assimp/revision.h | 2 +- .../0001-Fix-ambiguous-if-else-in-assimp.patch | 31 - .../patches/0001-assimp-Fix-type-warnings.patch | 48 + .../patches/0002-assimp-Add-license-header.patch | 39 + ...mp-Fix-building-with-mingw-older-than-4.9.patch | 10174 ------------------- .../0003-assimp-Add-missing-case-option.patch | 11 + ...move-usage-of-deprecated-keyword-register.patch | 382 - .../0004-assimp-Remove-register-keyword.patch | 12 + ...se-std-namespace-for-most-cmath-functions.patch | 1281 --- ...ed-copy-ctor-calls-when-calling-getAiType.patch | 31 + .../0005-assimp-Fix-build-FBXConverter.patch | 35 - src/plugins/sceneparsers/assimp/assimpimporter.cpp | 5 +- 486 files changed, 133258 insertions(+), 113453 deletions(-) create mode 100644 src/3rdparty/assimp/code/3DSExporter.cpp create mode 100644 src/3rdparty/assimp/code/3DSExporter.h create mode 100644 src/3rdparty/assimp/code/AssbinExporter.cpp create mode 100644 src/3rdparty/assimp/code/AssbinExporter.h create mode 100644 src/3rdparty/assimp/code/AssbinLoader.cpp create mode 100644 src/3rdparty/assimp/code/AssbinLoader.h delete mode 100644 src/3rdparty/assimp/code/AssimpPCH.cpp delete mode 100644 src/3rdparty/assimp/code/AssimpPCH.h create mode 100644 src/3rdparty/assimp/code/AssxmlExporter.cpp create mode 100644 src/3rdparty/assimp/code/AssxmlExporter.h delete mode 100644 src/3rdparty/assimp/code/BoostWorkaround/boost/LICENSE_1_0.txt delete mode 100644 src/3rdparty/assimp/code/BoostWorkaround/boost/foreach.hpp delete mode 100644 src/3rdparty/assimp/code/BoostWorkaround/boost/format.hpp delete mode 100644 src/3rdparty/assimp/code/BoostWorkaround/boost/lexical_cast.hpp delete mode 100644 src/3rdparty/assimp/code/BoostWorkaround/boost/make_shared.hpp delete mode 100644 src/3rdparty/assimp/code/BoostWorkaround/boost/math/common_factor_rt.hpp delete mode 100644 src/3rdparty/assimp/code/BoostWorkaround/boost/noncopyable.hpp delete mode 100644 src/3rdparty/assimp/code/BoostWorkaround/boost/pointer_cast.hpp delete mode 100644 src/3rdparty/assimp/code/BoostWorkaround/boost/scoped_array.hpp delete mode 100644 src/3rdparty/assimp/code/BoostWorkaround/boost/scoped_ptr.hpp delete mode 100644 src/3rdparty/assimp/code/BoostWorkaround/boost/shared_array.hpp delete mode 100644 src/3rdparty/assimp/code/BoostWorkaround/boost/shared_ptr.hpp delete mode 100644 src/3rdparty/assimp/code/BoostWorkaround/boost/static_assert.hpp delete mode 100644 src/3rdparty/assimp/code/BoostWorkaround/boost/timer.hpp delete mode 100644 src/3rdparty/assimp/code/BoostWorkaround/boost/tuple/tuple.hpp delete mode 100644 src/3rdparty/assimp/code/ByteSwap.h create mode 100644 src/3rdparty/assimp/code/ByteSwapper.h create mode 100644 src/3rdparty/assimp/code/C4DImporter.cpp create mode 100644 src/3rdparty/assimp/code/C4DImporter.h create mode 100644 src/3rdparty/assimp/code/D3MFImporter.cpp create mode 100644 src/3rdparty/assimp/code/D3MFImporter.h create mode 100644 src/3rdparty/assimp/code/D3MFOpcPackage.cpp create mode 100644 src/3rdparty/assimp/code/D3MFOpcPackage.h create mode 100644 src/3rdparty/assimp/code/Defines.h create mode 100644 src/3rdparty/assimp/code/FBXMeshGeometry.h create mode 100644 src/3rdparty/assimp/code/Macros.h create mode 100644 src/3rdparty/assimp/code/MathFunctions.h create mode 100644 src/3rdparty/assimp/code/OpenGEXExporter.cpp create mode 100644 src/3rdparty/assimp/code/OpenGEXExporter.h create mode 100644 src/3rdparty/assimp/code/OpenGEXImporter.cpp create mode 100644 src/3rdparty/assimp/code/OpenGEXImporter.h create mode 100644 src/3rdparty/assimp/code/OpenGEXStructs.h create mode 100644 src/3rdparty/assimp/code/SIBImporter.cpp create mode 100644 src/3rdparty/assimp/code/SIBImporter.h create mode 100644 src/3rdparty/assimp/code/StepExporter.cpp create mode 100644 src/3rdparty/assimp/code/StepExporter.h create mode 100644 src/3rdparty/assimp/code/StreamWriter.h create mode 100644 src/3rdparty/assimp/code/StringUtils.h create mode 100644 src/3rdparty/assimp/code/Version.cpp create mode 100644 src/3rdparty/assimp/code/XFileExporter.cpp create mode 100644 src/3rdparty/assimp/code/XFileExporter.h create mode 100644 src/3rdparty/assimp/code/XMLTools.h create mode 100644 src/3rdparty/assimp/code/glTFAsset.h create mode 100644 src/3rdparty/assimp/code/glTFAsset.inl create mode 100644 src/3rdparty/assimp/code/glTFAssetWriter.h create mode 100644 src/3rdparty/assimp/code/glTFAssetWriter.inl create mode 100644 src/3rdparty/assimp/code/glTFExporter.cpp create mode 100644 src/3rdparty/assimp/code/glTFExporter.h create mode 100644 src/3rdparty/assimp/code/glTFImporter.cpp create mode 100644 src/3rdparty/assimp/code/glTFImporter.h create mode 100644 src/3rdparty/assimp/contrib/openddlparser/CMakeLists.txt create mode 100644 src/3rdparty/assimp/contrib/openddlparser/CREDITS create mode 100644 src/3rdparty/assimp/contrib/openddlparser/LICENSE create mode 100644 src/3rdparty/assimp/contrib/openddlparser/README.md create mode 100644 src/3rdparty/assimp/contrib/openddlparser/code/DDLNode.cpp create mode 100644 src/3rdparty/assimp/contrib/openddlparser/code/OpenDDLCommon.cpp create mode 100644 src/3rdparty/assimp/contrib/openddlparser/code/OpenDDLExport.cpp create mode 100644 src/3rdparty/assimp/contrib/openddlparser/code/OpenDDLParser.cpp create mode 100644 src/3rdparty/assimp/contrib/openddlparser/code/Value.cpp create mode 100644 src/3rdparty/assimp/contrib/openddlparser/include/openddlparser/DDLNode.h create mode 100644 src/3rdparty/assimp/contrib/openddlparser/include/openddlparser/OpenDDLCommon.h create mode 100644 src/3rdparty/assimp/contrib/openddlparser/include/openddlparser/OpenDDLExport.h create mode 100644 src/3rdparty/assimp/contrib/openddlparser/include/openddlparser/OpenDDLParser.h create mode 100644 src/3rdparty/assimp/contrib/openddlparser/include/openddlparser/OpenDDLParserUtils.h create mode 100644 src/3rdparty/assimp/contrib/openddlparser/include/openddlparser/Value.h create mode 100644 src/3rdparty/assimp/contrib/rapidjson/include/rapidjson/allocators.h create mode 100644 src/3rdparty/assimp/contrib/rapidjson/include/rapidjson/document.h create mode 100644 src/3rdparty/assimp/contrib/rapidjson/include/rapidjson/encodedstream.h create mode 100644 src/3rdparty/assimp/contrib/rapidjson/include/rapidjson/encodings.h create mode 100644 src/3rdparty/assimp/contrib/rapidjson/include/rapidjson/error/en.h create mode 100644 src/3rdparty/assimp/contrib/rapidjson/include/rapidjson/error/error.h create mode 100644 src/3rdparty/assimp/contrib/rapidjson/include/rapidjson/filereadstream.h create mode 100644 src/3rdparty/assimp/contrib/rapidjson/include/rapidjson/filewritestream.h create mode 100644 src/3rdparty/assimp/contrib/rapidjson/include/rapidjson/internal/biginteger.h create mode 100644 src/3rdparty/assimp/contrib/rapidjson/include/rapidjson/internal/diyfp.h create mode 100644 src/3rdparty/assimp/contrib/rapidjson/include/rapidjson/internal/dtoa.h create mode 100644 src/3rdparty/assimp/contrib/rapidjson/include/rapidjson/internal/ieee754.h create mode 100644 src/3rdparty/assimp/contrib/rapidjson/include/rapidjson/internal/itoa.h create mode 100644 src/3rdparty/assimp/contrib/rapidjson/include/rapidjson/internal/meta.h create mode 100644 src/3rdparty/assimp/contrib/rapidjson/include/rapidjson/internal/pow10.h create mode 100644 src/3rdparty/assimp/contrib/rapidjson/include/rapidjson/internal/stack.h create mode 100644 src/3rdparty/assimp/contrib/rapidjson/include/rapidjson/internal/strfunc.h create mode 100644 src/3rdparty/assimp/contrib/rapidjson/include/rapidjson/internal/strtod.h create mode 100644 src/3rdparty/assimp/contrib/rapidjson/include/rapidjson/internal/swap.h create mode 100644 src/3rdparty/assimp/contrib/rapidjson/include/rapidjson/memorybuffer.h create mode 100644 src/3rdparty/assimp/contrib/rapidjson/include/rapidjson/memorystream.h create mode 100644 src/3rdparty/assimp/contrib/rapidjson/include/rapidjson/msinttypes/inttypes.h create mode 100644 src/3rdparty/assimp/contrib/rapidjson/include/rapidjson/msinttypes/stdint.h create mode 100644 src/3rdparty/assimp/contrib/rapidjson/include/rapidjson/pointer.h create mode 100644 src/3rdparty/assimp/contrib/rapidjson/include/rapidjson/prettywriter.h create mode 100644 src/3rdparty/assimp/contrib/rapidjson/include/rapidjson/rapidjson.h create mode 100644 src/3rdparty/assimp/contrib/rapidjson/include/rapidjson/reader.h create mode 100644 src/3rdparty/assimp/contrib/rapidjson/include/rapidjson/stringbuffer.h create mode 100644 src/3rdparty/assimp/contrib/rapidjson/include/rapidjson/writer.h create mode 100644 src/3rdparty/assimp/contrib/rapidjson/license.txt create mode 100644 src/3rdparty/assimp/contrib/rapidjson/readme.md delete mode 100644 src/3rdparty/assimp/contrib/zlib_note.txt create mode 100644 src/3rdparty/assimp/include/assimp/port/AndroidJNI/AndroidJNIIOSystem.h delete mode 100644 src/3rdparty/patches/0001-Fix-ambiguous-if-else-in-assimp.patch create mode 100644 src/3rdparty/patches/0001-assimp-Fix-type-warnings.patch create mode 100644 src/3rdparty/patches/0002-assimp-Add-license-header.patch delete mode 100644 src/3rdparty/patches/0002-assimp-Fix-building-with-mingw-older-than-4.9.patch create mode 100644 src/3rdparty/patches/0003-assimp-Add-missing-case-option.patch delete mode 100644 src/3rdparty/patches/0003-assimp-Remove-usage-of-deprecated-keyword-register.patch create mode 100644 src/3rdparty/patches/0004-assimp-Remove-register-keyword.patch delete mode 100644 src/3rdparty/patches/0004-assimp-Use-std-namespace-for-most-cmath-functions.patch create mode 100644 src/3rdparty/patches/0005-assimp-Avoid-unneeded-copy-ctor-calls-when-calling-getAiType.patch delete mode 100644 src/3rdparty/patches/0005-assimp-Fix-build-FBXConverter.patch diff --git a/src/3rdparty/assimp/CHANGES b/src/3rdparty/assimp/CHANGES index 7fa999a95..1d98700f8 100644 --- a/src/3rdparty/assimp/CHANGES +++ b/src/3rdparty/assimp/CHANGES @@ -2,11 +2,100 @@ CHANGELOG ---------------------------------------------------------------------- +3.3.1 (2016-07-08) + +FIXES/HOUSEKEEPING: + - Setup of default precision for 17 exporters + - Fix xcode project files + - Fix BlenderTesselator: offsetof operator + - Invalid version in cmake file + - Update pstdint.h to latest greatest + + +3.3.0 (2016-07-05) + +FEATURES: + - C++11 support enabled + - New regression-test-UI + - Experimental glTF-importer support + - OpenGEX: add support for cameras and lights + - C4D: update to latest Melange-SDK + - Add a gitter channel + - Coverity check enabled + - Switch to <...> include brackets for public headers + - Enable export by pyAssimp + - CI: check windows build + - Add functionality to perform a singlepost-processing step + - many more, just check the history + +FIXES/HOUSEKEEPING: + - Fix of many resource leaks in unittests and main lib + - Fix iOS-buildfor X64 + - Choosing zlib manually for cmake + - many more, just check the history + + +3.2.1 (2016-010-10) + +FEATURES: + - Updated glTF exporter to meet 1.0 specification. + +FIXES/HOUSEKEEPING: + - Fixed glTF Validator errors for exported glTF format. + +ISSUES: + - Hard coded sampler setting for + - magFilter + - minFilter + - void* in ExportData for accessor max and min. + + +3.2.0 (2015-11-03) + +FEATURES: + - OpenDDL-Parser is part of contrib-source. + - Experimental OpenGEX-support + - CI-check for linux and windows + - Coverity check added + - New regression testsuite. + +FIXES/HOUSEKEEPING: + - Hundreds of bugfixes in all parts of the library + - Unified line endings + + +API COMPATIBILITY: + - Removed precompiled header to increase build speed for linux + + +3.1.1 (2014-06-15) + +FEATURES: + - Support for FBX 2013 and newer, binary and ASCII (this is partly + work from Google Summer of Code 2012) + - Support for OGRE binary mesh and skeleton format + - Updated BLEND support for newer Blender versions + - Support for arbitrary meta data, used to hold FBX and DAE metadata + - OBJ Export now produces smaller files + - Meshes can now have names, this is supported by the major importers + - Improved IFC geometry generation + - M3 support has been removed + +FIXES/HOUSEKEEPING: + - Hundreds of bugfixes in all parts of the library + - CMake is now the primary build system + +API COMPATIBILITY: + - 3.1.1 is not binary compatible to 3.0 due to aiNode::mMetaData + and aiMesh::mName + - Export interface has been cleaned up and unified + - Other than that no relevant changes + 3.0 (2012-07-07) FEATURES: - - new export interface similar to the import API. + - new export interface similar to the import API. - Supported export formats: Collada, OBJ, PLY and STL - added new import formats: XGL/ZGL, M3 (experimental) - new postprocessing steps: Debone @@ -23,11 +112,11 @@ FIXES/HOUSEKEEPING: - improved CMake build system - templatized math library - reduce dependency on boost.thread, only remaining spot - is synchronization for the C logging API + is synchronization for the C logging API API COMPATIBILITY: - renamed headers, export interface, C API properties and meta data - prevent compatibility with code written for 2.0, but in + prevent compatibility with code written for 2.0, but in most cases these can be easily resolved - Note: 3.0 is not binary compatible with 2.0 @@ -45,9 +134,9 @@ FEATURES: spatial structure) in some expensive postprocessing steps - AssimpView now uses a reworked layout which leaves more space to the scene hierarchy window - + - Add C# bindings ('Assimp.NET') - - Keep BSD-licensed and otherwise free test files in separate + - Keep BSD-licensed and otherwise free test files in separate folders (./test/models and ./test/models-nonbsd). FIXES: @@ -57,20 +146,20 @@ FIXES: - OpenGL-sample now works with MinGW - Fix Importer::FindLoader failing on uppercase file extensions - Fix flawed path handling when locating external files - - Limit the maximum number of vertices, faces, face indices and + - Limit the maximum number of vertices, faces, face indices and weights that Assimp is able to handle. This is to avoid crashes due to overflowing counters. - + - Updated XCode project files - Further CMAKE build improvements - + API CHANGES: - Add data structures for vertex-based animations (These are not currently used, however ...) - Some Assimp::Importer methods are const now. - - + + diff --git a/src/3rdparty/assimp/CREDITS b/src/3rdparty/assimp/CREDITS index 070a15431..16096cd1d 100644 --- a/src/3rdparty/assimp/CREDITS +++ b/src/3rdparty/assimp/CREDITS @@ -30,7 +30,7 @@ Ogre Loader, VC2010 fixes and CMake fixes. - Sebastian Hempel, PyAssimp (first version) -Compile-Bugfixes for mingw, add enviroment for static library support in make. +Compile-Bugfixes for mingw, add environment for static library support in make. - Jonathan Pokrass Supplied a bugfix concerning the scaling in the md3 loader. @@ -114,7 +114,7 @@ Contributes a fix for the configure script environment. Contributed AssimpDelphi (/port/AssimpDelphi). - rdb -Contributes a bundle of fixes and improvments for the bsp-importer. +Contributes a bundle of fixes and improvements for the bsp-importer. - Mick P For contributing the De-bone postprocessing step and filing various bug reports. @@ -148,3 +148,13 @@ Bugfixes for uv-tanget calculation. - Jonne Nauha Ogre Binary format support + +- Filip Wasil, Tieto Poland Sp. z o.o. +Android JNI asset extraction support + +- Richard Steffen +Contributed ExportProperties interface +Contributed X File exporter +Contributed Step (stp) exporter + + diff --git a/src/3rdparty/assimp/LICENSE b/src/3rdparty/assimp/LICENSE index 44f91785f..262606aff 100644 --- a/src/3rdparty/assimp/LICENSE +++ b/src/3rdparty/assimp/LICENSE @@ -1,10 +1,10 @@ Open Asset Import Library (assimp) -Copyright (c) 2006-2012, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above @@ -21,16 +21,16 @@ following conditions are met: derived from this software without specific prior written permission of the assimp team. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. @@ -41,9 +41,9 @@ AN EXCEPTION applies to all files in the ./test/models-nonbsd folder. These are 3d models for testing purposes, from various free sources on the internet. They are - unless otherwise stated - copyright of their respective creators, which may impose additional requirements -on the use of their work. For any of these models, see +on the use of their work. For any of these models, see .source.txt for more legal information. Contact us if you -are a copyright holder and believe that we credited you inproperly or +are a copyright holder and believe that we credited you inproperly or if you don't want your files to appear in the repository. @@ -76,9 +76,3 @@ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - - - - - diff --git a/src/3rdparty/assimp/Readme.md b/src/3rdparty/assimp/Readme.md index 214417798..e4fe07b02 100644 --- a/src/3rdparty/assimp/Readme.md +++ b/src/3rdparty/assimp/Readme.md @@ -1,39 +1,54 @@ -Open Asset Import Library (assimp) -======== +Open Asset Import Library (assimp) +================================== -Open Asset Import Library is a Open Source library designed to load various __3d file formats and convert them into a shared, in-memory format__. It supports more than __30 file formats__ for import and a growing selection of file formats for export. Additionally, assimp features various __post processing tools__ to refine the imported data: _normals and tangent space generation, triangulation, vertex cache locality optimization, removal of degenerate primitives and duplicate vertices, sorting by primitive type, merging of redundant materials_ and many more. +APIs are provided for C and C++. There are various bindings to other languages (C#, Java, Python, Delphi, D). Assimp also runs on Android and iOS. -This is the development trunk of assimp containing the latest features and bugfixes. For productive use though, we recommend one of the stable releases available from [assimp.sf.net](http://assimp.sf.net) or from *nix package repositories. According to [Travis-CI] (https://travis-ci.org/), the current build status of the trunk is [![Build Status](https://travis-ci.org/assimp/assimp.png)](https://travis-ci.org/assimp/assimp) +Additionally, assimp features various __mesh post processing tools__: normals and tangent space generation, triangulation, vertex cache locality optimization, removal of degenerate primitives and duplicate vertices, sorting by primitive type, merging of redundant materials and many more. + +This is the development trunk containing the latest features and bugfixes. For productive use though, we recommend one of the stable releases available from [assimp.sf.net](http://assimp.sf.net) or from *nix package repositories. +The current build status is: + +Linux [![Linux Build Status](https://travis-ci.org/assimp/assimp.png)](https://travis-ci.org/assimp/assimp) +Windows [![Windows Build Status](https://ci.appveyor.com/api/projects/status/tmo433wax6u6cjp4?svg=true)](https://ci.appveyor.com/project/kimkulling/assimp) +Coverity + Coverity Scan Build Status + +Gitter [![Join the chat at https://gitter.im/assimp/assimp](https://badges.gitter.im/assimp/assimp.svg)](https://gitter.im/assimp/assimp?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +
+__[open3mod](https://github.com/acgessler/open3mod) is a powerful 3D model viewer based on Assimp's import and export abilities.__ #### Supported file formats #### -The library provides importers for a lot of file formats, including: +A full list [is here](http://assimp.sourceforge.net/main_features_formats.html). +__Importers__: - 3DS -- BLEND (Blender 3D) +- BLEND (Blender) - DAE/Collada - FBX -- IFC-STEP +- IFC-STEP - ASE - DXF - HMP - MD2 -- MD3 +- MD3 - MD5 - MDC - MDL - NFF - PLY - STL -- X -- OBJ +- X +- OBJ +- OpenGEX - SMD -- LWO -- LXO +- LWO +- LXO - LWS -- TER -- AC3D -- MS3D +- TER +- AC3D +- MS3D - COB - Q3BSP - XGL @@ -44,77 +59,81 @@ The library provides importers for a lot of file formats, including: - Ogre Binary - Ogre XML - Q3D - -Additionally, the following formats are also supported, but not part of the core library as they depend on proprietary libraries. +- ASSBIN (Assimp custom format) +- glTF (partial) +- 3MF + +Additionally, some formats are supported by dependency on non-free code or external SDKs (not built by default): - C4D (https://github.com/acgessler/assimp-cinema4d) -Exporters include: +__Exporters__: - DAE (Collada) - STL - OBJ - PLY +- X +- 3DS - JSON (for WebGl, via https://github.com/acgessler/assimp2json) - -See [the full list here](http://assimp.sourceforge.net/main_features_formats.html). +- ASSBIN +- STEP +- glTF (partial) +### Building ### +Take a look into the `INSTALL` file. Our build system is CMake, if you used CMake before there is a good chance you know what to do. +### Ports ### +* [Android](port/AndroidJNI/README.md) +* [Python](port/PyAssimp/README.md) +* [.NET](port/AssimpNET/Readme.md) +* [Pascal](port/AssimpPascal/Readme.md) #### Repository structure #### +Open Asset Import Library is implemented in C++. The directory structure is: - -Open Asset Import Library is implemented in C++ (but provides both a C and a -C++ish interface). The directory structure is: - - /bin Folder for binaries, only used on Windows /code Source code /contrib Third-party libraries /doc Documentation (doxysource and pre-compiled docs) /include Public header C and C++ header files - /lib Static library location for Windows - /obj Object file location for Windows /scripts Scripts used to generate the loading code for some formats /port Ports to other languages and scripts to maintain those. /test Unit- and regression tests, test suite of models - /tools Tools (viewer, command line `assimp`) - /samples A small number of samples to illustrate possible + /tools Tools (old assimp viewer, command line `assimp`) + /samples A small number of samples to illustrate possible use cases for Assimp - /workspaces Build enviroments for vc,xcode,... (deprecated, + /workspaces Build environments for vc,xcode,... (deprecated, CMake has superseeded all legacy build options!) - -### Building ### - - -Take a look into the `INSTALL` file. Our build system is CMake, if you already used CMake before there is a good chance you know what to do. - - ### Where to get help ### - - For more information, visit [our website](http://assimp.sourceforge.net/). Or check out the `./doc`- folder, which contains the official documentation in HTML format. (CHMs for Windows are included in some release packages and should be located right here in the root folder). -If the documentation doesn't solve your problems, -[try our forums at SF.net](http://sourceforge.net/p/assimp/discussion/817654) or ask on -[StackOverflow](http://stackoverflow.com/questions/tagged/assimp?sort=newest). +If the docs don't solve your problem, ask on [StackOverflow](http://stackoverflow.com/questions/tagged/assimp?sort=newest). If you think you found a bug, please open an issue on Github. -For development discussions, there is also a mailing list, _assimp-discussions_ - [(subscribe here)]( https://lists.sourceforge.net/lists/listinfo/assimp-discussions) +For development discussions, there is also a (very low-volume) mailing list, _assimp-discussions_ + [(subscribe here)]( https://lists.sourceforge.net/lists/listinfo/assimp-discussions) -### Contributing ### +Open Asset Import Library is a library to load various 3d file formats into a shared, in-memory format. It supports more than __40 file formats__ for import and a growing selection of file formats for export. + +And we also have an IRC-channel at freenode: #assetimporterlib . You can easily join us via: [KiwiIRC/freenote](https://kiwiirc.com/client/irc.freenode.net), choose your nickname and type +> /join #assetimporterlib -Contributions to assimp are highly appreciated. The easiest way to get involved is to submit +### Contributing ### +Contributions to assimp are highly appreciated. The easiest way to get involved is to submit a pull request with your changes against the main repository's `master` branch. +### Donate ### +If you like assimp, consider buying us a beer (or two): +[Donate](http://sourceforge.net/donate/index.php?group_id=226462) ### License ### +Our license is based on the modified, __3-clause BSD__-License. -Our license is based on the modified, __3-clause BSD__-License, which is very liberal. - -An _informal_ summary is: do whatever you want, but include Assimp's license text with your product - +An _informal_ summary is: do whatever you want, but include Assimp's license text with your product - and don't sue us if our code doesn't work. Note that, unlike LGPLed code, you may link statically to Assimp. -For the legal details, see the `LICENSE` file. +For the legal details, see the `LICENSE` file. +### Why this name ### +Sorry, we're germans :-), no english native speakers ... diff --git a/src/3rdparty/assimp/assimp.pri b/src/3rdparty/assimp/assimp.pri index e3eabe4ca..8167b66a3 100644 --- a/src/3rdparty/assimp/assimp.pri +++ b/src/3rdparty/assimp/assimp.pri @@ -15,7 +15,13 @@ qtConfig(system-zlib):!if(cross_compile:host_build): \ else: \ QT_PRIVATE += zlib-private -DEFINES += ASSIMP_BUILD_NO_OWN_ZLIB ASSIMP_BUILD_NO_COMPRESSED_IFC ASSIMP_BUILD_NO_Q3BSP_IMPORTER +DEFINES += \ + ASSIMP_BUILD_NO_OWN_ZLIB \ + ASSIMP_BUILD_NO_COMPRESSED_IFC \ + ASSIMP_BUILD_NO_Q3BSP_IMPORTER \ + ASSIMP_BUILD_NO_C4D_IMPORTER \ + ASSIMP_BUILD_NO_3MF_IMPORTER \ + OPENDDL_STATIC_LIBARY intel_icc: { # warning #310: old-style parameter list (anachronism) @@ -58,35 +64,40 @@ VPATH += \ $$PWD/contrib/clipper \ $$PWD/contrib/ConvertUTF \ $$PWD/contrib/irrXML \ - $$PWD/contrib/unzip \ + $$PWD/contrib/unzip INCLUDEPATH += \ $$PWD \ $$PWD/code \ - $$PWD/code/BoostWorkaround \ $$PWD/include \ $$PWD/include/assimp/Compiler \ + $$PWD/contrib/clipper \ $$PWD/contrib/ConvertUTF \ $$PWD/contrib/irrXML \ + $$PWD/contrib/openddlparser/include \ $$PWD/contrib/poly2tri/poly2tri \ - $$PWD/contrib/clipper \ + $$PWD/contrib/rapidjson/include \ $$PWD/contrib/unzip # Input HEADERS += revision.h \ + code/3DSExporter.h \ code/3DSHelper.h \ code/3DSLoader.h \ code/ACLoader.h \ code/ASELoader.h \ code/ASEParser.h \ code/assbin_chunks.h \ - code/AssimpPCH.h \ + code/AssbinExporter.h \ + code/AssbinLoader.h \ + code/AssxmlExporter.h \ code/B3DImporter.h \ code/BaseImporter.h \ + code/BaseProcess.h \ code/Bitmap.h \ code/BlenderBMesh.h \ - code/BaseProcess.h \ code/BlenderDNA.h \ + code/BlenderDNA.inl \ code/BlenderIntermediate.h \ code/BlenderLoader.h \ code/BlenderModifier.h \ @@ -95,7 +106,8 @@ HEADERS += revision.h \ code/BlenderTessellator.h \ code/BlobIOSystem.h \ code/BVHLoader.h \ - code/ByteSwap.h \ + code/ByteSwapper.h \ + code/C4DImporter.h \ code/CalcTangentsProcess.h \ code/CInterfaceIOWrapper.h \ code/COBLoader.h \ @@ -106,15 +118,30 @@ HEADERS += revision.h \ code/ColladaParser.h \ code/ComputeUVMappingProcess.h \ code/ConvertToLHProcess.h \ + code/CreateAnimMesh.h \ code/CSMLoader.h \ + code/D3MFImporter.h \ + code/D3MFOpcPackage.h \ code/DeboneProcess.h \ code/DefaultIOStream.h \ code/DefaultIOSystem.h \ code/DefaultProgressHandler.h \ + code/Defines.h \ code/DXFHelper.h \ code/DXFLoader.h \ code/Exceptional.h \ code/fast_atof.h \ + code/FBXCompileConfig.h \ + code/FBXConverter.h \ + code/FBXDocument.h \ + code/FBXDocumentUtil.h \ + code/FBXImporter.h \ + code/FBXImportSettings.h \ + code/FBXMeshGeometry.h \ + code/FBXParser.h \ + code/FBXProperties.h \ + code/FBXTokenizer.h \ + code/FBXUtil.h \ code/FileLogStream.h \ code/FileSystemFilter.h \ code/FindDegenerates.h \ @@ -124,6 +151,12 @@ HEADERS += revision.h \ code/GenericProperty.h \ code/GenFaceNormalsProcess.h \ code/GenVertexNormalsProcess.h \ + code/glTFAsset.h \ + code/glTFAsset.inl \ + code/glTFAssetWriter.h \ + code/glTFAssetWriter.inl \ + code/glTFExporter.h \ + code/glTFImporter.h \ code/HalfLifeFileData.h \ code/Hash.h \ code/HMPFileData.h \ @@ -146,8 +179,10 @@ HEADERS += revision.h \ code/LWOFileData.h \ code/LWOLoader.h \ code/LWSLoader.h \ + code/Macros.h \ code/MakeVerboseFormat.h \ code/MaterialSystem.h \ + code/MathFunctions.h \ code/MD2FileData.h \ code/MD2Loader.h \ code/MD2NormalTable.h \ @@ -173,6 +208,14 @@ HEADERS += revision.h \ code/ObjFileParser.h \ code/ObjTools.h \ code/OFFLoader.h \ + code/OgreBinarySerializer.h \ + code/OgreImporter.h \ + code/OgreParsingUtils.h \ + code/OgreStructs.h \ + code/OgreXmlSerializer.h \ + code/OpenGEXExporter.h \ + code/OpenGEXImporter.h \ + code/OpenGEXStructs.h \ code/OptimizeGraph.h \ code/OptimizeMeshes.h \ code/ParsingUtils.h \ @@ -197,21 +240,27 @@ HEADERS += revision.h \ code/ScenePreprocessor.h \ code/ScenePrivate.h \ code/SGSpatialSort.h \ + code/SIBImporter.h \ code/SkeletonMeshBuilder.h \ code/SMDLoader.h \ code/SmoothingGroups.h \ + code/SmoothingGroups.inl \ code/SortByPTypeProcess.h \ code/SpatialSort.h \ code/SplitByBoneCountProcess.h \ code/SplitLargeMeshes.h \ code/StandardShapes.h \ code/StdOStreamLogStream.h \ + code/STEPExporter.h \ code/STEPFile.h \ + code/STEPFileEncoding.h \ code/STEPFileReader.h \ code/STLExporter.h \ code/STLLoader.h \ code/StreamReader.h \ + code/StreamWriter.h \ code/StringComparison.h \ + code/StringUtils.h \ code/Subdivision.h \ code/TargetAnimation.h \ code/TerragenLoader.h \ @@ -223,10 +272,12 @@ HEADERS += revision.h \ code/Vertex.h \ code/VertexTriangleAdjacency.h \ code/Win32DebugLogStream.h \ + code/XFileExporter.h \ code/XFileHelper.h \ code/XFileImporter.h \ code/XFileParser.h \ code/XGLLoader.h \ + code/XMLTools.h \ code/res/resource.h \ contrib/clipper/clipper.hpp \ contrib/ConvertUTF/ConvertUTF.h \ @@ -236,6 +287,48 @@ HEADERS += revision.h \ contrib/irrXML/irrString.h \ contrib/irrXML/irrTypes.h \ contrib/irrXML/irrXML.h \ + contrib/openddlparser/include/openddlparser/DDLNode.h \ + contrib/openddlparser/include/openddlparser/OpenDDLCommon.h \ + contrib/openddlparser/include/openddlparser/OpenDDLExport.h \ + contrib/openddlparser/include/openddlparser/OpenDDLParser.h \ + contrib/openddlparser/include/openddlparser/OpenDDLParserUtils.h \ + contrib/openddlparser/include/openddlparser/Value.h \ + contrib/poly2tri/poly2tri/poly2tri.h \ + contrib/poly2tri/poly2tri/common/shapes.h \ + contrib/poly2tri/poly2tri/common/utils.h \ + contrib/poly2tri/poly2tri/sweep/advancing_front.h \ + contrib/poly2tri/poly2tri/sweep/cdt.h \ + contrib/poly2tri/poly2tri/sweep/sweep.h \ + contrib/poly2tri/poly2tri/sweep/sweep_context.h \ + contrib/rapidjson/include/rapidjson/allocators.h \ + contrib/rapidjson/include/rapidjson/document.h \ + contrib/rapidjson/include/rapidjson/encodedstream.h \ + contrib/rapidjson/include/rapidjson/encodings.h \ + contrib/rapidjson/include/rapidjson/error/en.h \ + contrib/rapidjson/include/rapidjson/error/error.h \ + contrib/rapidjson/include/rapidjson/filereadstream.h \ + contrib/rapidjson/include/rapidjson/filewritestream.h \ + contrib/rapidjson/include/rapidjson/internal/biginteger.h \ + contrib/rapidjson/include/rapidjson/internal/diyfp.h \ + contrib/rapidjson/include/rapidjson/internal/dtoa.h \ + contrib/rapidjson/include/rapidjson/internal/ieee754.h \ + contrib/rapidjson/include/rapidjson/internal/itoa.h \ + contrib/rapidjson/include/rapidjson/internal/meta.h \ + contrib/rapidjson/include/rapidjson/internal/pow10.h \ + contrib/rapidjson/include/rapidjson/internal/stack.h \ + contrib/rapidjson/include/rapidjson/internal/strfunc.h \ + contrib/rapidjson/include/rapidjson/internal/strtod.h \ + contrib/rapidjson/include/rapidjson/internal/swap.h \ + contrib/rapidjson/include/rapidjson/memorybuffer.h \ + contrib/rapidjson/include/rapidjson/memorystream.h \ + contrib/rapidjson/include/rapidjson/msinttypes/inttypes.h \ + contrib/rapidjson/include/rapidjson/msinttypes/stdint.h \ + contrib/rapidjson/include/rapidjson/pointer.h \ + contrib/rapidjson/include/rapidjson/prettywriter.h \ + contrib/rapidjson/include/rapidjson/rapidjson.h \ + contrib/rapidjson/include/rapidjson/reader.h \ + contrib/rapidjson/include/rapidjson/stringbuffer.h \ + contrib/rapidjson/include/rapidjson/writer.h \ contrib/unzip/crypt.h \ contrib/unzip/ioapi.h \ contrib/unzip/unzip.h \ @@ -246,6 +339,7 @@ HEADERS += revision.h \ include/assimp/cfileio.h \ include/assimp/cimport.h \ include/assimp/color4.h \ + include/assimp/color4.inl \ include/assimp/config.h \ include/assimp/DefaultLogger.hpp \ include/assimp/defs.h \ @@ -258,90 +352,53 @@ HEADERS += revision.h \ include/assimp/Logger.hpp \ include/assimp/LogStream.hpp \ include/assimp/material.h \ + include/assimp/material.inl \ include/assimp/matrix3x3.h \ + include/assimp/matrix3x3.inl \ include/assimp/matrix4x4.h \ + include/assimp/matrix4x4.inl \ include/assimp/mesh.h \ + include/assimp/metadata.h \ include/assimp/NullLogger.hpp \ include/assimp/postprocess.h \ include/assimp/ProgressHandler.hpp \ include/assimp/quaternion.h \ + include/assimp/quaternion.inl \ include/assimp/scene.h \ include/assimp/texture.h \ include/assimp/types.h \ include/assimp/vector2.h \ - include/assimp/vector3.h \ - include/assimp/version.h \ include/assimp/vector2.inl \ + include/assimp/vector3.h \ include/assimp/vector3.inl \ - include/assimp/color4.inl \ - include/assimp/quaternion.inl \ - include/assimp/matrix3x3.inl \ - include/assimp/matrix4x4.inl \ - include/assimp/material.inl \ - include/assimp/metadata.h \ + include/assimp/version.h \ include/assimp/Compiler/poppack1.h \ include/assimp/Compiler/pushpack1.h \ - include/assimp/Compiler/pstdint.h \ - code/BoostWorkaround/boost/foreach.hpp \ - code/BoostWorkaround/boost/format.hpp \ - code/BoostWorkaround/boost/lexical_cast.hpp \ - code/BoostWorkaround/boost/make_shared.hpp \ - code/BoostWorkaround/boost/noncopyable.hpp \ - code/BoostWorkaround/boost/pointer_cast.hpp \ - code/BoostWorkaround/boost/scoped_array.hpp \ - code/BoostWorkaround/boost/scoped_ptr.hpp \ - code/BoostWorkaround/boost/shared_array.hpp \ - code/BoostWorkaround/boost/shared_ptr.hpp \ - code/BoostWorkaround/boost/static_assert.hpp \ - code/BoostWorkaround/boost/timer.hpp \ - contrib/poly2tri/poly2tri/poly2tri.h \ - code/BoostWorkaround/boost/math/common_factor_rt.hpp \ - code/BoostWorkaround/boost/tuple/tuple.hpp \ - contrib/poly2tri/poly2tri/common/shapes.h \ - contrib/poly2tri/poly2tri/common/utils.h \ - contrib/poly2tri/poly2tri/sweep/advancing_front.h \ - contrib/poly2tri/poly2tri/sweep/cdt.h \ - contrib/poly2tri/poly2tri/sweep/sweep.h \ - contrib/poly2tri/poly2tri/sweep/sweep_context.h \ - code/SmoothingGroups.inl \ - code/BlenderDNA.inl \ - code/FBXConverter.h \ - code/FBXDocument.h \ - code/FBXDocumentUtil.h \ - code/FBXImporter.h \ - code/FBXImportSettings.h \ - code/FBXParser.h \ - code/FBXProperties.h \ - code/FBXTokenizer.h \ - code/FBXUtil.h \ - code/OgreImporter.h \ - code/OgreParsingUtils.h \ - code/FBXCompileConfig.h \ - code/STEPFileEncoding.h \ - code/OgreBinarySerializer.h \ - code/OgreStructs.h \ - code/OgreXmlSerializer.h \ - code/CreateAnimMesh.h + include/assimp/Compiler/pstdint.h SOURCES += code/3DSConverter.cpp \ + code/3DSExporter.cpp \ code/3DSLoader.cpp \ code/ACLoader.cpp \ code/ASELoader.cpp \ code/ASEParser.cpp \ + code/AssbinExporter.cpp \ + code/AssbinLoader.cpp \ code/Assimp.cpp \ code/AssimpCExport.cpp \ - code/AssimpPCH.cpp \ + code/AssxmlExporter.cpp \ code/B3DImporter.cpp \ code/BaseImporter.cpp \ + code/BaseProcess.cpp \ code/Bitmap.cpp \ code/BlenderBMesh.cpp \ - code/BaseProcess.cpp \ code/BlenderDNA.cpp \ code/BlenderLoader.cpp \ code/BlenderModifier.cpp \ code/BlenderScene.cpp \ code/BlenderTessellator.cpp \ code/BVHLoader.cpp \ + code/C4DImporter.cpp \ code/CalcTangentsProcess.cpp \ code/COBLoader.cpp \ code/ColladaExporter.cpp \ @@ -349,24 +406,46 @@ SOURCES += code/3DSConverter.cpp \ code/ColladaParser.cpp \ code/ComputeUVMappingProcess.cpp \ code/ConvertToLHProcess.cpp \ + code/CreateAnimMesh.cpp \ code/CSMLoader.cpp \ + code/D3MFImporter.cpp \ + code/D3MFOpcPackage.cpp \ code/DeboneProcess.cpp \ code/DefaultIOStream.cpp \ code/DefaultIOSystem.cpp \ code/DefaultLogger.cpp \ code/DXFLoader.cpp \ code/Exporter.cpp \ + code/FBXAnimation.cpp \ + code/FBXBinaryTokenizer.cpp \ + code/FBXConverter.cpp \ + code/FBXDeformer.cpp \ + code/FBXDocument.cpp \ + code/FBXDocumentUtil.cpp \ + code/FBXImporter.cpp \ + code/FBXMaterial.cpp \ + code/FBXMeshGeometry.cpp \ + code/FBXModel.cpp \ + code/FBXNodeAttribute.cpp \ + code/FBXParser.cpp \ + code/FBXProperties.cpp \ + code/FBXTokenizer.cpp \ + code/FBXUtil.cpp \ code/FindDegenerates.cpp \ code/FindInstancesProcess.cpp \ code/FindInvalidDataProcess.cpp \ code/FixNormalsStep.cpp \ code/GenFaceNormalsProcess.cpp \ code/GenVertexNormalsProcess.cpp \ + code/glTFExporter.cpp \ + code/glTFImporter.cpp \ code/HMPLoader.cpp \ + code/IFCBoolean.cpp \ code/IFCCurve.cpp \ code/IFCGeometry.cpp \ code/IFCLoader.cpp \ code/IFCMaterial.cpp \ + code/IFCOpenings.cpp \ code/IFCProfile.cpp \ code/IFCReaderGen1.cpp \ code/IFCReaderGen2.cpp \ @@ -401,8 +480,13 @@ SOURCES += code/3DSConverter.cpp \ code/ObjFileMtlImporter.cpp \ code/ObjFileParser.cpp \ code/OFFLoader.cpp \ + code/OgreBinarySerializer.cpp \ code/OgreImporter.cpp \ code/OgreMaterial.cpp \ + code/OgreStructs.cpp \ + code/OgreXmlSerializer.cpp \ + code/OpenGEXExporter.cpp \ + code/OpenGEXImporter.cpp \ code/OptimizeGraph.cpp \ code/OptimizeMeshes.cpp \ code/PlyExporter.cpp \ @@ -422,6 +506,7 @@ SOURCES += code/3DSConverter.cpp \ code/SceneCombiner.cpp \ code/ScenePreprocessor.cpp \ code/SGSpatialSort.cpp \ + code/SIBImporter.cpp \ code/SkeletonMeshBuilder.cpp \ code/SMDLoader.cpp \ code/SortByPTypeProcess.cpp \ @@ -429,6 +514,8 @@ SOURCES += code/3DSConverter.cpp \ code/SplitByBoneCountProcess.cpp \ code/SplitLargeMeshes.cpp \ code/StandardShapes.cpp \ + code/StepExporter.cpp \ + code/STEPFileEncoding.cpp \ code/STEPFileReader.cpp \ code/STLExporter.cpp \ code/STLLoader.cpp \ @@ -439,42 +526,24 @@ SOURCES += code/3DSConverter.cpp \ code/TriangulateProcess.cpp \ code/UnrealLoader.cpp \ code/ValidateDataStructure.cpp \ + code/Version.cpp \ code/VertexTriangleAdjacency.cpp \ + code/XFileExporter.cpp \ code/XFileImporter.cpp \ code/XFileParser.cpp \ code/XGLLoader.cpp \ contrib/clipper/clipper.cpp \ contrib/ConvertUTF/ConvertUTF.c \ contrib/irrXML/irrXML.cpp \ - contrib/unzip/ioapi.c \ - contrib/unzip/unzip.c \ + contrib/openddlparser/code/DDLNode.cpp \ + contrib/openddlparser/code/OpenDDLCommon.cpp \ + contrib/openddlparser/code/OpenDDLExport.cpp \ + contrib/openddlparser/code/OpenDDLParser.cpp \ + contrib/openddlparser/code/Value.cpp \ contrib/poly2tri/poly2tri/common/shapes.cc \ contrib/poly2tri/poly2tri/sweep/advancing_front.cc \ contrib/poly2tri/poly2tri/sweep/cdt.cc \ contrib/poly2tri/poly2tri/sweep/sweep.cc \ contrib/poly2tri/poly2tri/sweep/sweep_context.cc \ - code/FBXAnimation.cpp \ - code/FBXBinaryTokenizer.cpp \ - code/FBXDeformer.cpp \ - code/FBXDocument.cpp \ - code/FBXDocumentUtil.cpp \ - code/FBXImporter.cpp \ - code/FBXMaterial.cpp \ - code/FBXMeshGeometry.cpp \ - code/FBXModel.cpp \ - code/FBXNodeAttribute.cpp \ - code/FBXParser.cpp \ - code/FBXProperties.cpp \ - code/FBXTokenizer.cpp \ - code/FBXUtil.cpp \ - code/IFCBoolean.cpp \ - code/IFCOpenings.cpp \ - code/FBXConverter.cpp \ - code/STEPFileEncoding.cpp \ - code/OgreBinarySerializer.cpp \ - code/OgreStructs.cpp \ - code/OgreXmlSerializer.cpp \ - code/CreateAnimMesh.cpp - - - + contrib/unzip/ioapi.c \ + contrib/unzip/unzip.c diff --git a/src/3rdparty/assimp/code/3DSConverter.cpp b/src/3rdparty/assimp/code/3DSConverter.cpp index 3498a4b21..cb6fd9077 100644 --- a/src/3rdparty/assimp/code/3DSConverter.cpp +++ b/src/3rdparty/assimp/code/3DSConverter.cpp @@ -3,12 +3,12 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2012, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above @@ -25,28 +25,33 @@ conditions are met: derived from this software without specific prior written permission of the assimp team. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --------------------------------------------------------------------------- */ /** @file Implementation of the 3ds importer class */ -#include "AssimpPCH.h" + #ifndef ASSIMP_BUILD_NO_3DS_IMPORTER // internal headers #include "3DSLoader.h" #include "TargetAnimation.h" +#include +#include +#include "StringComparison.h" +#include +#include using namespace Assimp; @@ -54,808 +59,809 @@ using namespace Assimp; // Setup final material indices, generae a default material if necessary void Discreet3DSImporter::ReplaceDefaultMaterial() { - - // Try to find an existing material that matches the - // typical default material setting: - // - no textures - // - diffuse color (in grey!) - // NOTE: This is here to workaround the fact that some - // exporters are writing a default material, too. - unsigned int idx = 0xcdcdcdcd; - for (unsigned int i = 0; i < mScene->mMaterials.size();++i) - { - std::string s = mScene->mMaterials[i].mName; - for (std::string::iterator it = s.begin(); it != s.end(); ++it) - *it = ::tolower(*it); - - if (std::string::npos == s.find("default"))continue; - - if (mScene->mMaterials[i].mDiffuse.r != - mScene->mMaterials[i].mDiffuse.g || - mScene->mMaterials[i].mDiffuse.r != - mScene->mMaterials[i].mDiffuse.b)continue; - - if (mScene->mMaterials[i].sTexDiffuse.mMapName.length() != 0 || - mScene->mMaterials[i].sTexBump.mMapName.length() != 0 || - mScene->mMaterials[i].sTexOpacity.mMapName.length() != 0 || - mScene->mMaterials[i].sTexEmissive.mMapName.length() != 0 || - mScene->mMaterials[i].sTexSpecular.mMapName.length() != 0 || - mScene->mMaterials[i].sTexShininess.mMapName.length() != 0 ) - { - continue; - } - idx = i; - } - if (0xcdcdcdcd == idx)idx = (unsigned int)mScene->mMaterials.size(); - - // now iterate through all meshes and through all faces and - // find all faces that are using the default material - unsigned int cnt = 0; - for (std::vector::iterator - i = mScene->mMeshes.begin(); - i != mScene->mMeshes.end();++i) - { - for (std::vector::iterator - a = (*i).mFaceMaterials.begin(); - a != (*i).mFaceMaterials.end();++a) - { - // NOTE: The additional check seems to be necessary, - // some exporters seem to generate invalid data here - if (0xcdcdcdcd == (*a)) - { - (*a) = idx; - ++cnt; - } - else if ( (*a) >= mScene->mMaterials.size()) - { - (*a) = idx; - DefaultLogger::get()->warn("Material index overflow in 3DS file. Using default material"); - ++cnt; - } - } - } - if (cnt && idx == mScene->mMaterials.size()) - { - // We need to create our own default material - D3DS::Material sMat; - sMat.mDiffuse = aiColor3D(0.3f,0.3f,0.3f); - sMat.mName = "%%%DEFAULT"; - mScene->mMaterials.push_back(sMat); - - DefaultLogger::get()->info("3DS: Generating default material"); - } + + // Try to find an existing material that matches the + // typical default material setting: + // - no textures + // - diffuse color (in grey!) + // NOTE: This is here to workaround the fact that some + // exporters are writing a default material, too. + unsigned int idx = 0xcdcdcdcd; + for (unsigned int i = 0; i < mScene->mMaterials.size();++i) + { + std::string s = mScene->mMaterials[i].mName; + for ( std::string::iterator it = s.begin(); it != s.end(); ++it ) { + *it = static_cast< char >( ::tolower( *it ) ); + } + + if (std::string::npos == s.find("default"))continue; + + if (mScene->mMaterials[i].mDiffuse.r != + mScene->mMaterials[i].mDiffuse.g || + mScene->mMaterials[i].mDiffuse.r != + mScene->mMaterials[i].mDiffuse.b)continue; + + if (mScene->mMaterials[i].sTexDiffuse.mMapName.length() != 0 || + mScene->mMaterials[i].sTexBump.mMapName.length() != 0 || + mScene->mMaterials[i].sTexOpacity.mMapName.length() != 0 || + mScene->mMaterials[i].sTexEmissive.mMapName.length() != 0 || + mScene->mMaterials[i].sTexSpecular.mMapName.length() != 0 || + mScene->mMaterials[i].sTexShininess.mMapName.length() != 0 ) + { + continue; + } + idx = i; + } + if (0xcdcdcdcd == idx)idx = (unsigned int)mScene->mMaterials.size(); + + // now iterate through all meshes and through all faces and + // find all faces that are using the default material + unsigned int cnt = 0; + for (std::vector::iterator + i = mScene->mMeshes.begin(); + i != mScene->mMeshes.end();++i) + { + for (std::vector::iterator + a = (*i).mFaceMaterials.begin(); + a != (*i).mFaceMaterials.end();++a) + { + // NOTE: The additional check seems to be necessary, + // some exporters seem to generate invalid data here + if (0xcdcdcdcd == (*a)) + { + (*a) = idx; + ++cnt; + } + else if ( (*a) >= mScene->mMaterials.size()) + { + (*a) = idx; + DefaultLogger::get()->warn("Material index overflow in 3DS file. Using default material"); + ++cnt; + } + } + } + if (cnt && idx == mScene->mMaterials.size()) + { + // We need to create our own default material + D3DS::Material sMat; + sMat.mDiffuse = aiColor3D(0.3f,0.3f,0.3f); + sMat.mName = "%%%DEFAULT"; + mScene->mMaterials.push_back(sMat); + + DefaultLogger::get()->info("3DS: Generating default material"); + } } // ------------------------------------------------------------------------------------------------ // Check whether all indices are valid. Otherwise we'd crash before the validation step is reached void Discreet3DSImporter::CheckIndices(D3DS::Mesh& sMesh) { - for (std::vector< D3DS::Face >::iterator i = sMesh.mFaces.begin(); i != sMesh.mFaces.end();++i) - { - // check whether all indices are in range - for (unsigned int a = 0; a < 3;++a) - { - if ((*i).mIndices[a] >= sMesh.mPositions.size()) - { - DefaultLogger::get()->warn("3DS: Vertex index overflow)"); - (*i).mIndices[a] = (uint32_t)sMesh.mPositions.size()-1; - } - if ( !sMesh.mTexCoords.empty() && (*i).mIndices[a] >= sMesh.mTexCoords.size()) - { - DefaultLogger::get()->warn("3DS: Texture coordinate index overflow)"); - (*i).mIndices[a] = (uint32_t)sMesh.mTexCoords.size()-1; - } - } - } + for (std::vector< D3DS::Face >::iterator i = sMesh.mFaces.begin(); i != sMesh.mFaces.end();++i) + { + // check whether all indices are in range + for (unsigned int a = 0; a < 3;++a) + { + if ((*i).mIndices[a] >= sMesh.mPositions.size()) + { + DefaultLogger::get()->warn("3DS: Vertex index overflow)"); + (*i).mIndices[a] = (uint32_t)sMesh.mPositions.size()-1; + } + if ( !sMesh.mTexCoords.empty() && (*i).mIndices[a] >= sMesh.mTexCoords.size()) + { + DefaultLogger::get()->warn("3DS: Texture coordinate index overflow)"); + (*i).mIndices[a] = (uint32_t)sMesh.mTexCoords.size()-1; + } + } + } } // ------------------------------------------------------------------------------------------------ // Generate out unique verbose format representation void Discreet3DSImporter::MakeUnique(D3DS::Mesh& sMesh) { - // TODO: really necessary? I don't think. Just a waste of memory and time - // to do it now in a separate buffer. - - // Allocate output storage - std::vector vNew (sMesh.mFaces.size() * 3); - std::vector vNew2; - if (sMesh.mTexCoords.size()) - vNew2.resize(sMesh.mFaces.size() * 3); - - for (unsigned int i = 0, base = 0; i < sMesh.mFaces.size();++i) - { - D3DS::Face& face = sMesh.mFaces[i]; - - // Positions - for (unsigned int a = 0; a < 3;++a,++base) - { - vNew[base] = sMesh.mPositions[face.mIndices[a]]; - if (sMesh.mTexCoords.size()) - vNew2[base] = sMesh.mTexCoords[face.mIndices[a]]; - - face.mIndices[a] = base; - } - } - sMesh.mPositions = vNew; - sMesh.mTexCoords = vNew2; + // TODO: really necessary? I don't think. Just a waste of memory and time + // to do it now in a separate buffer. + + // Allocate output storage + std::vector vNew (sMesh.mFaces.size() * 3); + std::vector vNew2; + if (sMesh.mTexCoords.size()) + vNew2.resize(sMesh.mFaces.size() * 3); + + for (unsigned int i = 0, base = 0; i < sMesh.mFaces.size();++i) + { + D3DS::Face& face = sMesh.mFaces[i]; + + // Positions + for (unsigned int a = 0; a < 3;++a,++base) + { + vNew[base] = sMesh.mPositions[face.mIndices[a]]; + if (sMesh.mTexCoords.size()) + vNew2[base] = sMesh.mTexCoords[face.mIndices[a]]; + + face.mIndices[a] = base; + } + } + sMesh.mPositions = vNew; + sMesh.mTexCoords = vNew2; } // ------------------------------------------------------------------------------------------------ // Convert a 3DS texture to texture keys in an aiMaterial void CopyTexture(aiMaterial& mat, D3DS::Texture& texture, aiTextureType type) { - // Setup the texture name - aiString tex; - tex.Set( texture.mMapName); - mat.AddProperty( &tex, AI_MATKEY_TEXTURE(type,0)); - - // Setup the texture blend factor - if (is_not_qnan(texture.mTextureBlend)) - mat.AddProperty( &texture.mTextureBlend, 1, AI_MATKEY_TEXBLEND(type,0)); - - // Setup the texture mapping mode - mat.AddProperty((int*)&texture.mMapMode,1,AI_MATKEY_MAPPINGMODE_U(type,0)); - mat.AddProperty((int*)&texture.mMapMode,1,AI_MATKEY_MAPPINGMODE_V(type,0)); - - // Mirroring - double the scaling values - // FIXME: this is not really correct ... - if (texture.mMapMode == aiTextureMapMode_Mirror) - { - texture.mScaleU *= 2.f; - texture.mScaleV *= 2.f; - texture.mOffsetU /= 2.f; - texture.mOffsetV /= 2.f; - } - - // Setup texture UV transformations - mat.AddProperty(&texture.mOffsetU,5,AI_MATKEY_UVTRANSFORM(type,0)); + // Setup the texture name + aiString tex; + tex.Set( texture.mMapName); + mat.AddProperty( &tex, AI_MATKEY_TEXTURE(type,0)); + + // Setup the texture blend factor + if (is_not_qnan(texture.mTextureBlend)) + mat.AddProperty( &texture.mTextureBlend, 1, AI_MATKEY_TEXBLEND(type,0)); + + // Setup the texture mapping mode + mat.AddProperty((int*)&texture.mMapMode,1,AI_MATKEY_MAPPINGMODE_U(type,0)); + mat.AddProperty((int*)&texture.mMapMode,1,AI_MATKEY_MAPPINGMODE_V(type,0)); + + // Mirroring - double the scaling values + // FIXME: this is not really correct ... + if (texture.mMapMode == aiTextureMapMode_Mirror) + { + texture.mScaleU *= 2.f; + texture.mScaleV *= 2.f; + texture.mOffsetU /= 2.f; + texture.mOffsetV /= 2.f; + } + + // Setup texture UV transformations + mat.AddProperty(&texture.mOffsetU,5,AI_MATKEY_UVTRANSFORM(type,0)); } // ------------------------------------------------------------------------------------------------ // Convert a 3DS material to an aiMaterial void Discreet3DSImporter::ConvertMaterial(D3DS::Material& oldMat, - aiMaterial& mat) + aiMaterial& mat) { - // NOTE: Pass the background image to the viewer by bypassing the - // material system. This is an evil hack, never do it again! - if (0 != mBackgroundImage.length() && bHasBG) - { - aiString tex; - tex.Set( mBackgroundImage); - mat.AddProperty( &tex, AI_MATKEY_GLOBAL_BACKGROUND_IMAGE); - - // Be sure this is only done for the first material - mBackgroundImage = std::string(""); - } - - // At first add the base ambient color of the scene to the material - oldMat.mAmbient.r += mClrAmbient.r; - oldMat.mAmbient.g += mClrAmbient.g; - oldMat.mAmbient.b += mClrAmbient.b; - - aiString name; - name.Set( oldMat.mName); - mat.AddProperty( &name, AI_MATKEY_NAME); - - // Material colors - mat.AddProperty( &oldMat.mAmbient, 1, AI_MATKEY_COLOR_AMBIENT); - mat.AddProperty( &oldMat.mDiffuse, 1, AI_MATKEY_COLOR_DIFFUSE); - mat.AddProperty( &oldMat.mSpecular, 1, AI_MATKEY_COLOR_SPECULAR); - mat.AddProperty( &oldMat.mEmissive, 1, AI_MATKEY_COLOR_EMISSIVE); - - // Phong shininess and shininess strength - if (D3DS::Discreet3DS::Phong == oldMat.mShading || - D3DS::Discreet3DS::Metal == oldMat.mShading) - { - if (!oldMat.mSpecularExponent || !oldMat.mShininessStrength) - { - oldMat.mShading = D3DS::Discreet3DS::Gouraud; - } - else - { - mat.AddProperty( &oldMat.mSpecularExponent, 1, AI_MATKEY_SHININESS); - mat.AddProperty( &oldMat.mShininessStrength, 1, AI_MATKEY_SHININESS_STRENGTH); - } - } - - // Opacity - mat.AddProperty( &oldMat.mTransparency,1,AI_MATKEY_OPACITY); - - // Bump height scaling - mat.AddProperty( &oldMat.mBumpHeight,1,AI_MATKEY_BUMPSCALING); - - // Two sided rendering? - if (oldMat.mTwoSided) - { - int i = 1; - mat.AddProperty(&i,1,AI_MATKEY_TWOSIDED); - } - - // Shading mode - aiShadingMode eShading = aiShadingMode_NoShading; - switch (oldMat.mShading) - { - case D3DS::Discreet3DS::Flat: - eShading = aiShadingMode_Flat; break; - - // I don't know what "Wire" shading should be, - // assume it is simple lambertian diffuse shading - case D3DS::Discreet3DS::Wire: - { - // Set the wireframe flag - unsigned int iWire = 1; - mat.AddProperty( (int*)&iWire,1,AI_MATKEY_ENABLE_WIREFRAME); - } - - case D3DS::Discreet3DS::Gouraud: - eShading = aiShadingMode_Gouraud; break; - - // assume cook-torrance shading for metals. - case D3DS::Discreet3DS::Phong : - eShading = aiShadingMode_Phong; break; - - case D3DS::Discreet3DS::Metal : - eShading = aiShadingMode_CookTorrance; break; - - // FIX to workaround a warning with GCC 4 who complained - // about a missing case Blinn: here - Blinn isn't a valid - // value in the 3DS Loader, it is just needed for ASE - case D3DS::Discreet3DS::Blinn : - eShading = aiShadingMode_Blinn; break; - } - mat.AddProperty( (int*)&eShading,1,AI_MATKEY_SHADING_MODEL); - - // DIFFUSE texture - if( oldMat.sTexDiffuse.mMapName.length() > 0) - CopyTexture(mat,oldMat.sTexDiffuse, aiTextureType_DIFFUSE); - - // SPECULAR texture - if( oldMat.sTexSpecular.mMapName.length() > 0) - CopyTexture(mat,oldMat.sTexSpecular, aiTextureType_SPECULAR); - - // OPACITY texture - if( oldMat.sTexOpacity.mMapName.length() > 0) - CopyTexture(mat,oldMat.sTexOpacity, aiTextureType_OPACITY); - - // EMISSIVE texture - if( oldMat.sTexEmissive.mMapName.length() > 0) - CopyTexture(mat,oldMat.sTexEmissive, aiTextureType_EMISSIVE); - - // BUMP texture - if( oldMat.sTexBump.mMapName.length() > 0) - CopyTexture(mat,oldMat.sTexBump, aiTextureType_HEIGHT); - - // SHININESS texture - if( oldMat.sTexShininess.mMapName.length() > 0) - CopyTexture(mat,oldMat.sTexShininess, aiTextureType_SHININESS); - - // REFLECTION texture - if( oldMat.sTexReflective.mMapName.length() > 0) - CopyTexture(mat,oldMat.sTexReflective, aiTextureType_REFLECTION); - - // Store the name of the material itself, too - if( oldMat.mName.length()) { - aiString tex; - tex.Set( oldMat.mName); - mat.AddProperty( &tex, AI_MATKEY_NAME); - } + // NOTE: Pass the background image to the viewer by bypassing the + // material system. This is an evil hack, never do it again! + if (0 != mBackgroundImage.length() && bHasBG) + { + aiString tex; + tex.Set( mBackgroundImage); + mat.AddProperty( &tex, AI_MATKEY_GLOBAL_BACKGROUND_IMAGE); + + // Be sure this is only done for the first material + mBackgroundImage = std::string(""); + } + + // At first add the base ambient color of the scene to the material + oldMat.mAmbient.r += mClrAmbient.r; + oldMat.mAmbient.g += mClrAmbient.g; + oldMat.mAmbient.b += mClrAmbient.b; + + aiString name; + name.Set( oldMat.mName); + mat.AddProperty( &name, AI_MATKEY_NAME); + + // Material colors + mat.AddProperty( &oldMat.mAmbient, 1, AI_MATKEY_COLOR_AMBIENT); + mat.AddProperty( &oldMat.mDiffuse, 1, AI_MATKEY_COLOR_DIFFUSE); + mat.AddProperty( &oldMat.mSpecular, 1, AI_MATKEY_COLOR_SPECULAR); + mat.AddProperty( &oldMat.mEmissive, 1, AI_MATKEY_COLOR_EMISSIVE); + + // Phong shininess and shininess strength + if (D3DS::Discreet3DS::Phong == oldMat.mShading || + D3DS::Discreet3DS::Metal == oldMat.mShading) + { + if (!oldMat.mSpecularExponent || !oldMat.mShininessStrength) + { + oldMat.mShading = D3DS::Discreet3DS::Gouraud; + } + else + { + mat.AddProperty( &oldMat.mSpecularExponent, 1, AI_MATKEY_SHININESS); + mat.AddProperty( &oldMat.mShininessStrength, 1, AI_MATKEY_SHININESS_STRENGTH); + } + } + + // Opacity + mat.AddProperty( &oldMat.mTransparency,1,AI_MATKEY_OPACITY); + + // Bump height scaling + mat.AddProperty( &oldMat.mBumpHeight,1,AI_MATKEY_BUMPSCALING); + + // Two sided rendering? + if (oldMat.mTwoSided) + { + int i = 1; + mat.AddProperty(&i,1,AI_MATKEY_TWOSIDED); + } + + // Shading mode + aiShadingMode eShading = aiShadingMode_NoShading; + switch (oldMat.mShading) + { + case D3DS::Discreet3DS::Flat: + eShading = aiShadingMode_Flat; break; + + // I don't know what "Wire" shading should be, + // assume it is simple lambertian diffuse shading + case D3DS::Discreet3DS::Wire: + { + // Set the wireframe flag + unsigned int iWire = 1; + mat.AddProperty( (int*)&iWire,1,AI_MATKEY_ENABLE_WIREFRAME); + } + + case D3DS::Discreet3DS::Gouraud: + eShading = aiShadingMode_Gouraud; break; + + // assume cook-torrance shading for metals. + case D3DS::Discreet3DS::Phong : + eShading = aiShadingMode_Phong; break; + + case D3DS::Discreet3DS::Metal : + eShading = aiShadingMode_CookTorrance; break; + + // FIX to workaround a warning with GCC 4 who complained + // about a missing case Blinn: here - Blinn isn't a valid + // value in the 3DS Loader, it is just needed for ASE + case D3DS::Discreet3DS::Blinn : + eShading = aiShadingMode_Blinn; break; + } + mat.AddProperty( (int*)&eShading,1,AI_MATKEY_SHADING_MODEL); + + // DIFFUSE texture + if( oldMat.sTexDiffuse.mMapName.length() > 0) + CopyTexture(mat,oldMat.sTexDiffuse, aiTextureType_DIFFUSE); + + // SPECULAR texture + if( oldMat.sTexSpecular.mMapName.length() > 0) + CopyTexture(mat,oldMat.sTexSpecular, aiTextureType_SPECULAR); + + // OPACITY texture + if( oldMat.sTexOpacity.mMapName.length() > 0) + CopyTexture(mat,oldMat.sTexOpacity, aiTextureType_OPACITY); + + // EMISSIVE texture + if( oldMat.sTexEmissive.mMapName.length() > 0) + CopyTexture(mat,oldMat.sTexEmissive, aiTextureType_EMISSIVE); + + // BUMP texture + if( oldMat.sTexBump.mMapName.length() > 0) + CopyTexture(mat,oldMat.sTexBump, aiTextureType_HEIGHT); + + // SHININESS texture + if( oldMat.sTexShininess.mMapName.length() > 0) + CopyTexture(mat,oldMat.sTexShininess, aiTextureType_SHININESS); + + // REFLECTION texture + if( oldMat.sTexReflective.mMapName.length() > 0) + CopyTexture(mat,oldMat.sTexReflective, aiTextureType_REFLECTION); + + // Store the name of the material itself, too + if( oldMat.mName.length()) { + aiString tex; + tex.Set( oldMat.mName); + mat.AddProperty( &tex, AI_MATKEY_NAME); + } } // ------------------------------------------------------------------------------------------------ // Split meshes by their materials and generate output aiMesh'es void Discreet3DSImporter::ConvertMeshes(aiScene* pcOut) { - std::vector avOutMeshes; - avOutMeshes.reserve(mScene->mMeshes.size() * 2); - - unsigned int iFaceCnt = 0,num = 0; - aiString name; - - // we need to split all meshes by their materials - for (std::vector::iterator i = mScene->mMeshes.begin(); i != mScene->mMeshes.end();++i) { - boost::scoped_array< std::vector > aiSplit(new std::vector[mScene->mMaterials.size()]); - - name.length = ASSIMP_itoa10(name.data,num++); - - unsigned int iNum = 0; - for (std::vector::const_iterator a = (*i).mFaceMaterials.begin(); - a != (*i).mFaceMaterials.end();++a,++iNum) - { - aiSplit[*a].push_back(iNum); - } - // now generate submeshes - for (unsigned int p = 0; p < mScene->mMaterials.size();++p) - { - if (aiSplit[p].empty()) { - continue; - } - aiMesh* meshOut = new aiMesh(); - meshOut->mName = name; - meshOut->mPrimitiveTypes = aiPrimitiveType_TRIANGLE; - - // be sure to setup the correct material index - meshOut->mMaterialIndex = p; - - // use the color data as temporary storage - meshOut->mColors[0] = (aiColor4D*)(&*i); - avOutMeshes.push_back(meshOut); - - // convert vertices - meshOut->mNumFaces = (unsigned int)aiSplit[p].size(); - meshOut->mNumVertices = meshOut->mNumFaces*3; - - // allocate enough storage for faces - meshOut->mFaces = new aiFace[meshOut->mNumFaces]; - iFaceCnt += meshOut->mNumFaces; - - meshOut->mVertices = new aiVector3D[meshOut->mNumVertices]; - meshOut->mNormals = new aiVector3D[meshOut->mNumVertices]; - if ((*i).mTexCoords.size()) - { - meshOut->mTextureCoords[0] = new aiVector3D[meshOut->mNumVertices]; - } - for (unsigned int q = 0, base = 0; q < aiSplit[p].size();++q) - { - unsigned int index = aiSplit[p][q]; - aiFace& face = meshOut->mFaces[q]; - - face.mIndices = new unsigned int[3]; - face.mNumIndices = 3; - - for (unsigned int a = 0; a < 3;++a,++base) - { - unsigned int idx = (*i).mFaces[index].mIndices[a]; - meshOut->mVertices[base] = (*i).mPositions[idx]; - meshOut->mNormals [base] = (*i).mNormals[idx]; - - if ((*i).mTexCoords.size()) - meshOut->mTextureCoords[0][base] = (*i).mTexCoords[idx]; - - face.mIndices[a] = base; - } - } - } - } - - // Copy them to the output array - pcOut->mNumMeshes = (unsigned int)avOutMeshes.size(); - pcOut->mMeshes = new aiMesh*[pcOut->mNumMeshes](); - for (unsigned int a = 0; a < pcOut->mNumMeshes;++a) { - pcOut->mMeshes[a] = avOutMeshes[a]; - } - - // We should have at least one face here - if (!iFaceCnt) { - throw DeadlyImportError("No faces loaded. The mesh is empty"); - } + std::vector avOutMeshes; + avOutMeshes.reserve(mScene->mMeshes.size() * 2); + + unsigned int iFaceCnt = 0,num = 0; + aiString name; + + // we need to split all meshes by their materials + for (std::vector::iterator i = mScene->mMeshes.begin(); i != mScene->mMeshes.end();++i) { + std::unique_ptr< std::vector[] > aiSplit(new std::vector[mScene->mMaterials.size()]); + + name.length = ASSIMP_itoa10(name.data,num++); + + unsigned int iNum = 0; + for (std::vector::const_iterator a = (*i).mFaceMaterials.begin(); + a != (*i).mFaceMaterials.end();++a,++iNum) + { + aiSplit[*a].push_back(iNum); + } + // now generate submeshes + for (unsigned int p = 0; p < mScene->mMaterials.size();++p) + { + if (aiSplit[p].empty()) { + continue; + } + aiMesh* meshOut = new aiMesh(); + meshOut->mName = name; + meshOut->mPrimitiveTypes = aiPrimitiveType_TRIANGLE; + + // be sure to setup the correct material index + meshOut->mMaterialIndex = p; + + // use the color data as temporary storage + meshOut->mColors[0] = (aiColor4D*)(&*i); + avOutMeshes.push_back(meshOut); + + // convert vertices + meshOut->mNumFaces = (unsigned int)aiSplit[p].size(); + meshOut->mNumVertices = meshOut->mNumFaces*3; + + // allocate enough storage for faces + meshOut->mFaces = new aiFace[meshOut->mNumFaces]; + iFaceCnt += meshOut->mNumFaces; + + meshOut->mVertices = new aiVector3D[meshOut->mNumVertices]; + meshOut->mNormals = new aiVector3D[meshOut->mNumVertices]; + if ((*i).mTexCoords.size()) + { + meshOut->mTextureCoords[0] = new aiVector3D[meshOut->mNumVertices]; + } + for (unsigned int q = 0, base = 0; q < aiSplit[p].size();++q) + { + unsigned int index = aiSplit[p][q]; + aiFace& face = meshOut->mFaces[q]; + + face.mIndices = new unsigned int[3]; + face.mNumIndices = 3; + + for (unsigned int a = 0; a < 3;++a,++base) + { + unsigned int idx = (*i).mFaces[index].mIndices[a]; + meshOut->mVertices[base] = (*i).mPositions[idx]; + meshOut->mNormals [base] = (*i).mNormals[idx]; + + if ((*i).mTexCoords.size()) + meshOut->mTextureCoords[0][base] = (*i).mTexCoords[idx]; + + face.mIndices[a] = base; + } + } + } + } + + // Copy them to the output array + pcOut->mNumMeshes = (unsigned int)avOutMeshes.size(); + pcOut->mMeshes = new aiMesh*[pcOut->mNumMeshes](); + for (unsigned int a = 0; a < pcOut->mNumMeshes;++a) { + pcOut->mMeshes[a] = avOutMeshes[a]; + } + + // We should have at least one face here + if (!iFaceCnt) { + throw DeadlyImportError("No faces loaded. The mesh is empty"); + } } // ------------------------------------------------------------------------------------------------ // Add a node to the scenegraph and setup its final transformation void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut, - D3DS::Node* pcIn, aiMatrix4x4& /*absTrafo*/) + D3DS::Node* pcIn, aiMatrix4x4& /*absTrafo*/) { - std::vector iArray; - iArray.reserve(3); - - aiMatrix4x4 abs; - - // Find all meshes with the same name as the node - for (unsigned int a = 0; a < pcSOut->mNumMeshes;++a) - { - const D3DS::Mesh* pcMesh = (const D3DS::Mesh*)pcSOut->mMeshes[a]->mColors[0]; - ai_assert(NULL != pcMesh); - - if (pcIn->mName == pcMesh->mName) - iArray.push_back(a); - } - if (!iArray.empty()) - { - // The matrix should be identical for all meshes with the - // same name. It HAS to be identical for all meshes ..... - D3DS::Mesh* imesh = ((D3DS::Mesh*)pcSOut->mMeshes[iArray[0]]->mColors[0]); - - // Compute the inverse of the transformation matrix to move the - // vertices back to their relative and local space - aiMatrix4x4 mInv = imesh->mMat, mInvTransposed = imesh->mMat; - mInv.Inverse();mInvTransposed.Transpose(); - aiVector3D pivot = pcIn->vPivot; - - pcOut->mNumMeshes = (unsigned int)iArray.size(); - pcOut->mMeshes = new unsigned int[iArray.size()]; - for (unsigned int i = 0;i < iArray.size();++i) { - const unsigned int iIndex = iArray[i]; - aiMesh* const mesh = pcSOut->mMeshes[iIndex]; - - if (mesh->mColors[1] == NULL) - { - // Transform the vertices back into their local space - // fixme: consider computing normals after this, so we don't need to transform them - const aiVector3D* const pvEnd = mesh->mVertices + mesh->mNumVertices; - aiVector3D* pvCurrent = mesh->mVertices, *t2 = mesh->mNormals; - - for (; pvCurrent != pvEnd; ++pvCurrent, ++t2) { - *pvCurrent = mInv * (*pvCurrent); - *t2 = mInvTransposed * (*t2); - } - - // Handle negative transformation matrix determinant -> invert vertex x - if (imesh->mMat.Determinant() < 0.0f) - { - /* we *must* have normals */ - for (pvCurrent = mesh->mVertices, t2 = mesh->mNormals; pvCurrent != pvEnd; ++pvCurrent, ++t2) { - pvCurrent->x *= -1.f; - t2->x *= -1.f; - } - DefaultLogger::get()->info("3DS: Flipping mesh X-Axis"); - } - - // Handle pivot point - if (pivot.x || pivot.y || pivot.z) - { - for (pvCurrent = mesh->mVertices; pvCurrent != pvEnd; ++pvCurrent) { - *pvCurrent -= pivot; - } - } - - mesh->mColors[1] = (aiColor4D*)1; - } - else - mesh->mColors[1] = (aiColor4D*)1; - - // Setup the mesh index - pcOut->mMeshes[i] = iIndex; - } - } - - // Setup the name of the node - // First instance keeps its name otherwise something might break, all others will be postfixed with their instance number - if (pcIn->mInstanceNumber > 1) - { - char tmp[12]; - ASSIMP_itoa10(tmp, pcIn->mInstanceNumber); - std::string tempStr = pcIn->mName + "_inst_"; - tempStr += tmp; - pcOut->mName.Set(tempStr); - } - else - pcOut->mName.Set(pcIn->mName); - - // Now build the transformation matrix of the node - // ROTATION - if (pcIn->aRotationKeys.size()){ - - // FIX to get to Assimp's quaternion conventions - for (std::vector::iterator it = pcIn->aRotationKeys.begin(); it != pcIn->aRotationKeys.end(); ++it) { - (*it).mValue.w *= -1.f; - } - - pcOut->mTransformation = aiMatrix4x4( pcIn->aRotationKeys[0].mValue.GetMatrix() ); - } - else if (pcIn->aCameraRollKeys.size()) - { - aiMatrix4x4::RotationZ(AI_DEG_TO_RAD(- pcIn->aCameraRollKeys[0].mValue), - pcOut->mTransformation); - } - - // SCALING - aiMatrix4x4& m = pcOut->mTransformation; - if (pcIn->aScalingKeys.size()) - { - const aiVector3D& v = pcIn->aScalingKeys[0].mValue; - m.a1 *= v.x; m.b1 *= v.x; m.c1 *= v.x; - m.a2 *= v.y; m.b2 *= v.y; m.c2 *= v.y; - m.a3 *= v.z; m.b3 *= v.z; m.c3 *= v.z; - } - - // TRANSLATION - if (pcIn->aPositionKeys.size()) - { - const aiVector3D& v = pcIn->aPositionKeys[0].mValue; - m.a4 += v.x; - m.b4 += v.y; - m.c4 += v.z; - } - - // Generate animation channels for the node - if (pcIn->aPositionKeys.size() > 1 || pcIn->aRotationKeys.size() > 1 || - pcIn->aScalingKeys.size() > 1 || pcIn->aCameraRollKeys.size() > 1 || - pcIn->aTargetPositionKeys.size() > 1) - { - aiAnimation* anim = pcSOut->mAnimations[0]; - ai_assert(NULL != anim); - - if (pcIn->aCameraRollKeys.size() > 1) - { - DefaultLogger::get()->debug("3DS: Converting camera roll track ..."); - - // Camera roll keys - in fact they're just rotations - // around the camera's z axis. The angles are given - // in degrees (and they're clockwise). - pcIn->aRotationKeys.resize(pcIn->aCameraRollKeys.size()); - for (unsigned int i = 0; i < pcIn->aCameraRollKeys.size();++i) - { - aiQuatKey& q = pcIn->aRotationKeys[i]; - aiFloatKey& f = pcIn->aCameraRollKeys[i]; - - q.mTime = f.mTime; - - // FIX to get to Assimp quaternion conventions - q.mValue = aiQuaternion(0.f,0.f,AI_DEG_TO_RAD( /*-*/ f.mValue)); - } - } + std::vector iArray; + iArray.reserve(3); + + aiMatrix4x4 abs; + + // Find all meshes with the same name as the node + for (unsigned int a = 0; a < pcSOut->mNumMeshes;++a) + { + const D3DS::Mesh* pcMesh = (const D3DS::Mesh*)pcSOut->mMeshes[a]->mColors[0]; + ai_assert(NULL != pcMesh); + + if (pcIn->mName == pcMesh->mName) + iArray.push_back(a); + } + if (!iArray.empty()) + { + // The matrix should be identical for all meshes with the + // same name. It HAS to be identical for all meshes ..... + D3DS::Mesh* imesh = ((D3DS::Mesh*)pcSOut->mMeshes[iArray[0]]->mColors[0]); + + // Compute the inverse of the transformation matrix to move the + // vertices back to their relative and local space + aiMatrix4x4 mInv = imesh->mMat, mInvTransposed = imesh->mMat; + mInv.Inverse();mInvTransposed.Transpose(); + aiVector3D pivot = pcIn->vPivot; + + pcOut->mNumMeshes = (unsigned int)iArray.size(); + pcOut->mMeshes = new unsigned int[iArray.size()]; + for (unsigned int i = 0;i < iArray.size();++i) { + const unsigned int iIndex = iArray[i]; + aiMesh* const mesh = pcSOut->mMeshes[iIndex]; + + if (mesh->mColors[1] == NULL) + { + // Transform the vertices back into their local space + // fixme: consider computing normals after this, so we don't need to transform them + const aiVector3D* const pvEnd = mesh->mVertices + mesh->mNumVertices; + aiVector3D* pvCurrent = mesh->mVertices, *t2 = mesh->mNormals; + + for (; pvCurrent != pvEnd; ++pvCurrent, ++t2) { + *pvCurrent = mInv * (*pvCurrent); + *t2 = mInvTransposed * (*t2); + } + + // Handle negative transformation matrix determinant -> invert vertex x + if (imesh->mMat.Determinant() < 0.0f) + { + /* we *must* have normals */ + for (pvCurrent = mesh->mVertices, t2 = mesh->mNormals; pvCurrent != pvEnd; ++pvCurrent, ++t2) { + pvCurrent->x *= -1.f; + t2->x *= -1.f; + } + DefaultLogger::get()->info("3DS: Flipping mesh X-Axis"); + } + + // Handle pivot point + if (pivot.x || pivot.y || pivot.z) + { + for (pvCurrent = mesh->mVertices; pvCurrent != pvEnd; ++pvCurrent) { + *pvCurrent -= pivot; + } + } + + mesh->mColors[1] = (aiColor4D*)1; + } + else + mesh->mColors[1] = (aiColor4D*)1; + + // Setup the mesh index + pcOut->mMeshes[i] = iIndex; + } + } + + // Setup the name of the node + // First instance keeps its name otherwise something might break, all others will be postfixed with their instance number + if (pcIn->mInstanceNumber > 1) + { + char tmp[12]; + ASSIMP_itoa10(tmp, pcIn->mInstanceNumber); + std::string tempStr = pcIn->mName + "_inst_"; + tempStr += tmp; + pcOut->mName.Set(tempStr); + } + else + pcOut->mName.Set(pcIn->mName); + + // Now build the transformation matrix of the node + // ROTATION + if (pcIn->aRotationKeys.size()){ + + // FIX to get to Assimp's quaternion conventions + for (std::vector::iterator it = pcIn->aRotationKeys.begin(); it != pcIn->aRotationKeys.end(); ++it) { + (*it).mValue.w *= -1.f; + } + + pcOut->mTransformation = aiMatrix4x4( pcIn->aRotationKeys[0].mValue.GetMatrix() ); + } + else if (pcIn->aCameraRollKeys.size()) + { + aiMatrix4x4::RotationZ(AI_DEG_TO_RAD(- pcIn->aCameraRollKeys[0].mValue), + pcOut->mTransformation); + } + + // SCALING + aiMatrix4x4& m = pcOut->mTransformation; + if (pcIn->aScalingKeys.size()) + { + const aiVector3D& v = pcIn->aScalingKeys[0].mValue; + m.a1 *= v.x; m.b1 *= v.x; m.c1 *= v.x; + m.a2 *= v.y; m.b2 *= v.y; m.c2 *= v.y; + m.a3 *= v.z; m.b3 *= v.z; m.c3 *= v.z; + } + + // TRANSLATION + if (pcIn->aPositionKeys.size()) + { + const aiVector3D& v = pcIn->aPositionKeys[0].mValue; + m.a4 += v.x; + m.b4 += v.y; + m.c4 += v.z; + } + + // Generate animation channels for the node + if (pcIn->aPositionKeys.size() > 1 || pcIn->aRotationKeys.size() > 1 || + pcIn->aScalingKeys.size() > 1 || pcIn->aCameraRollKeys.size() > 1 || + pcIn->aTargetPositionKeys.size() > 1) + { + aiAnimation* anim = pcSOut->mAnimations[0]; + ai_assert(NULL != anim); + + if (pcIn->aCameraRollKeys.size() > 1) + { + DefaultLogger::get()->debug("3DS: Converting camera roll track ..."); + + // Camera roll keys - in fact they're just rotations + // around the camera's z axis. The angles are given + // in degrees (and they're clockwise). + pcIn->aRotationKeys.resize(pcIn->aCameraRollKeys.size()); + for (unsigned int i = 0; i < pcIn->aCameraRollKeys.size();++i) + { + aiQuatKey& q = pcIn->aRotationKeys[i]; + aiFloatKey& f = pcIn->aCameraRollKeys[i]; + + q.mTime = f.mTime; + + // FIX to get to Assimp quaternion conventions + q.mValue = aiQuaternion(0.f,0.f,AI_DEG_TO_RAD( /*-*/ f.mValue)); + } + } #if 0 - if (pcIn->aTargetPositionKeys.size() > 1) - { - DefaultLogger::get()->debug("3DS: Converting target track ..."); - - // Camera or spot light - need to convert the separate - // target position channel to our representation - TargetAnimationHelper helper; - - if (pcIn->aPositionKeys.empty()) - { - // We can just pass zero here ... - helper.SetFixedMainAnimationChannel(aiVector3D()); - } - else helper.SetMainAnimationChannel(&pcIn->aPositionKeys); - helper.SetTargetAnimationChannel(&pcIn->aTargetPositionKeys); - - // Do the conversion - std::vector distanceTrack; - helper.Process(&distanceTrack); - - // Now add a new node as child, name it .Target - // and assign the distance track to it. This is that the - // information where the target is and how it moves is - // not lost - D3DS::Node* nd = new D3DS::Node(); - pcIn->push_back(nd); - - nd->mName = pcIn->mName + ".Target"; - - aiNodeAnim* nda = anim->mChannels[anim->mNumChannels++] = new aiNodeAnim(); - nda->mNodeName.Set(nd->mName); - - nda->mNumPositionKeys = (unsigned int)distanceTrack.size(); - nda->mPositionKeys = new aiVectorKey[nda->mNumPositionKeys]; - ::memcpy(nda->mPositionKeys,&distanceTrack[0], - sizeof(aiVectorKey)*nda->mNumPositionKeys); - } + if (pcIn->aTargetPositionKeys.size() > 1) + { + DefaultLogger::get()->debug("3DS: Converting target track ..."); + + // Camera or spot light - need to convert the separate + // target position channel to our representation + TargetAnimationHelper helper; + + if (pcIn->aPositionKeys.empty()) + { + // We can just pass zero here ... + helper.SetFixedMainAnimationChannel(aiVector3D()); + } + else helper.SetMainAnimationChannel(&pcIn->aPositionKeys); + helper.SetTargetAnimationChannel(&pcIn->aTargetPositionKeys); + + // Do the conversion + std::vector distanceTrack; + helper.Process(&distanceTrack); + + // Now add a new node as child, name it .Target + // and assign the distance track to it. This is that the + // information where the target is and how it moves is + // not lost + D3DS::Node* nd = new D3DS::Node(); + pcIn->push_back(nd); + + nd->mName = pcIn->mName + ".Target"; + + aiNodeAnim* nda = anim->mChannels[anim->mNumChannels++] = new aiNodeAnim(); + nda->mNodeName.Set(nd->mName); + + nda->mNumPositionKeys = (unsigned int)distanceTrack.size(); + nda->mPositionKeys = new aiVectorKey[nda->mNumPositionKeys]; + ::memcpy(nda->mPositionKeys,&distanceTrack[0], + sizeof(aiVectorKey)*nda->mNumPositionKeys); + } #endif - // Cameras or lights define their transformation in their parent node and in the - // corresponding light or camera chunks. However, we read and process the latter - // to to be able to return valid cameras/lights even if no scenegraph is given. - for (unsigned int n = 0; n < pcSOut->mNumCameras;++n) { - if (pcSOut->mCameras[n]->mName == pcOut->mName) { - pcSOut->mCameras[n]->mLookAt = aiVector3D(0.f,0.f,1.f); - } - } - for (unsigned int n = 0; n < pcSOut->mNumLights;++n) { - if (pcSOut->mLights[n]->mName == pcOut->mName) { - pcSOut->mLights[n]->mDirection = aiVector3D(0.f,0.f,1.f); - } - } - - // Allocate a new node anim and setup its name - aiNodeAnim* nda = anim->mChannels[anim->mNumChannels++] = new aiNodeAnim(); - nda->mNodeName.Set(pcIn->mName); - - // POSITION keys - if (pcIn->aPositionKeys.size() > 0) - { - nda->mNumPositionKeys = (unsigned int)pcIn->aPositionKeys.size(); - nda->mPositionKeys = new aiVectorKey[nda->mNumPositionKeys]; - ::memcpy(nda->mPositionKeys,&pcIn->aPositionKeys[0], - sizeof(aiVectorKey)*nda->mNumPositionKeys); - } - - // ROTATION keys - if (pcIn->aRotationKeys.size() > 0) - { - nda->mNumRotationKeys = (unsigned int)pcIn->aRotationKeys.size(); - nda->mRotationKeys = new aiQuatKey[nda->mNumRotationKeys]; - - // Rotations are quaternion offsets - aiQuaternion abs; - for (unsigned int n = 0; n < nda->mNumRotationKeys;++n) - { - const aiQuatKey& q = pcIn->aRotationKeys[n]; - - abs = (n ? abs * q.mValue : q.mValue); - nda->mRotationKeys[n].mTime = q.mTime; - nda->mRotationKeys[n].mValue = abs.Normalize(); - } - } - - // SCALING keys - if (pcIn->aScalingKeys.size() > 0) - { - nda->mNumScalingKeys = (unsigned int)pcIn->aScalingKeys.size(); - nda->mScalingKeys = new aiVectorKey[nda->mNumScalingKeys]; - ::memcpy(nda->mScalingKeys,&pcIn->aScalingKeys[0], - sizeof(aiVectorKey)*nda->mNumScalingKeys); - } - } - - // Allocate storage for children - pcOut->mNumChildren = (unsigned int)pcIn->mChildren.size(); - pcOut->mChildren = new aiNode*[pcIn->mChildren.size()]; - - // Recursively process all children - const unsigned int size = pcIn->mChildren.size(); - for (unsigned int i = 0; i < size;++i) - { - pcOut->mChildren[i] = new aiNode(); - pcOut->mChildren[i]->mParent = pcOut; - AddNodeToGraph(pcSOut,pcOut->mChildren[i],pcIn->mChildren[i],abs); - } + // Cameras or lights define their transformation in their parent node and in the + // corresponding light or camera chunks. However, we read and process the latter + // to to be able to return valid cameras/lights even if no scenegraph is given. + for (unsigned int n = 0; n < pcSOut->mNumCameras;++n) { + if (pcSOut->mCameras[n]->mName == pcOut->mName) { + pcSOut->mCameras[n]->mLookAt = aiVector3D(0.f,0.f,1.f); + } + } + for (unsigned int n = 0; n < pcSOut->mNumLights;++n) { + if (pcSOut->mLights[n]->mName == pcOut->mName) { + pcSOut->mLights[n]->mDirection = aiVector3D(0.f,0.f,1.f); + } + } + + // Allocate a new node anim and setup its name + aiNodeAnim* nda = anim->mChannels[anim->mNumChannels++] = new aiNodeAnim(); + nda->mNodeName.Set(pcIn->mName); + + // POSITION keys + if (pcIn->aPositionKeys.size() > 0) + { + nda->mNumPositionKeys = (unsigned int)pcIn->aPositionKeys.size(); + nda->mPositionKeys = new aiVectorKey[nda->mNumPositionKeys]; + ::memcpy(nda->mPositionKeys,&pcIn->aPositionKeys[0], + sizeof(aiVectorKey)*nda->mNumPositionKeys); + } + + // ROTATION keys + if (pcIn->aRotationKeys.size() > 0) + { + nda->mNumRotationKeys = (unsigned int)pcIn->aRotationKeys.size(); + nda->mRotationKeys = new aiQuatKey[nda->mNumRotationKeys]; + + // Rotations are quaternion offsets + aiQuaternion abs1; + for (unsigned int n = 0; n < nda->mNumRotationKeys;++n) + { + const aiQuatKey& q = pcIn->aRotationKeys[n]; + + abs1 = (n ? abs1 * q.mValue : q.mValue); + nda->mRotationKeys[n].mTime = q.mTime; + nda->mRotationKeys[n].mValue = abs1.Normalize(); + } + } + + // SCALING keys + if (pcIn->aScalingKeys.size() > 0) + { + nda->mNumScalingKeys = (unsigned int)pcIn->aScalingKeys.size(); + nda->mScalingKeys = new aiVectorKey[nda->mNumScalingKeys]; + ::memcpy(nda->mScalingKeys,&pcIn->aScalingKeys[0], + sizeof(aiVectorKey)*nda->mNumScalingKeys); + } + } + + // Allocate storage for children + pcOut->mNumChildren = (unsigned int)pcIn->mChildren.size(); + pcOut->mChildren = new aiNode*[pcIn->mChildren.size()]; + + // Recursively process all children + const unsigned int size = pcIn->mChildren.size(); + for (unsigned int i = 0; i < size;++i) + { + pcOut->mChildren[i] = new aiNode(); + pcOut->mChildren[i]->mParent = pcOut; + AddNodeToGraph(pcSOut,pcOut->mChildren[i],pcIn->mChildren[i],abs); + } } // ------------------------------------------------------------------------------------------------ // Find out how many node animation channels we'll have finally void CountTracks(D3DS::Node* node, unsigned int& cnt) { - ////////////////////////////////////////////////////////////////////////////// - // We will never generate more than one channel for a node, so - // this is rather easy here. - - if (node->aPositionKeys.size() > 1 || node->aRotationKeys.size() > 1 || - node->aScalingKeys.size() > 1 || node->aCameraRollKeys.size() > 1 || - node->aTargetPositionKeys.size() > 1) - { - ++cnt; - - // account for the additional channel for the camera/spotlight target position - if (node->aTargetPositionKeys.size() > 1)++cnt; - } - - // Recursively process all children - for (unsigned int i = 0; i < node->mChildren.size();++i) - CountTracks(node->mChildren[i],cnt); + ////////////////////////////////////////////////////////////////////////////// + // We will never generate more than one channel for a node, so + // this is rather easy here. + + if (node->aPositionKeys.size() > 1 || node->aRotationKeys.size() > 1 || + node->aScalingKeys.size() > 1 || node->aCameraRollKeys.size() > 1 || + node->aTargetPositionKeys.size() > 1) + { + ++cnt; + + // account for the additional channel for the camera/spotlight target position + if (node->aTargetPositionKeys.size() > 1)++cnt; + } + + // Recursively process all children + for (unsigned int i = 0; i < node->mChildren.size();++i) + CountTracks(node->mChildren[i],cnt); } // ------------------------------------------------------------------------------------------------ // Generate the output node graph void Discreet3DSImporter::GenerateNodeGraph(aiScene* pcOut) { - pcOut->mRootNode = new aiNode(); - if (0 == mRootNode->mChildren.size()) - { - ////////////////////////////////////////////////////////////////////////////// - // It seems the file is so messed up that it has not even a hierarchy. - // generate a flat hiearachy which looks like this: - // - // ROOT_NODE - // | - // ---------------------------------------- - // | | | | | - // MESH_0 MESH_1 MESH_2 ... MESH_N CAMERA_0 .... - // - DefaultLogger::get()->warn("No hierarchy information has been found in the file. "); - - pcOut->mRootNode->mNumChildren = pcOut->mNumMeshes + - mScene->mCameras.size() + mScene->mLights.size(); - - pcOut->mRootNode->mChildren = new aiNode* [ pcOut->mRootNode->mNumChildren ]; - pcOut->mRootNode->mName.Set("<3DSDummyRoot>"); - - // Build dummy nodes for all meshes - unsigned int a = 0; - for (unsigned int i = 0; i < pcOut->mNumMeshes;++i,++a) - { - aiNode* pcNode = pcOut->mRootNode->mChildren[a] = new aiNode(); - pcNode->mParent = pcOut->mRootNode; - pcNode->mMeshes = new unsigned int[1]; - pcNode->mMeshes[0] = i; - pcNode->mNumMeshes = 1; - - // Build a name for the node - pcNode->mName.length = sprintf(pcNode->mName.data,"3DSMesh_%i",i); - } - - // Build dummy nodes for all cameras - for (unsigned int i = 0; i < (unsigned int )mScene->mCameras.size();++i,++a) - { - aiNode* pcNode = pcOut->mRootNode->mChildren[a] = new aiNode(); - pcNode->mParent = pcOut->mRootNode; - - // Build a name for the node - pcNode->mName = mScene->mCameras[i]->mName; - } - - // Build dummy nodes for all lights - for (unsigned int i = 0; i < (unsigned int )mScene->mLights.size();++i,++a) - { - aiNode* pcNode = pcOut->mRootNode->mChildren[a] = new aiNode(); - pcNode->mParent = pcOut->mRootNode; - - // Build a name for the node - pcNode->mName = mScene->mLights[i]->mName; - } - } - else - { - // First of all: find out how many scaling, rotation and translation - // animation tracks we'll have afterwards - unsigned int numChannel = 0; - CountTracks(mRootNode,numChannel); - - if (numChannel) - { - // Allocate a primary animation channel - pcOut->mNumAnimations = 1; - pcOut->mAnimations = new aiAnimation*[1]; - aiAnimation* anim = pcOut->mAnimations[0] = new aiAnimation(); - - anim->mName.Set("3DSMasterAnim"); - - // Allocate enough storage for all node animation channels, - // but don't set the mNumChannels member - we'll use it to - // index into the array - anim->mChannels = new aiNodeAnim*[numChannel]; - } - - aiMatrix4x4 m; - AddNodeToGraph(pcOut, pcOut->mRootNode, mRootNode,m); - } - - // We used the first and second vertex color set to store some temporary values so we need to cleanup here - for (unsigned int a = 0; a < pcOut->mNumMeshes; ++a) - { - pcOut->mMeshes[a]->mColors[0] = NULL; - pcOut->mMeshes[a]->mColors[1] = NULL; - } - - pcOut->mRootNode->mTransformation = aiMatrix4x4( - 1.f,0.f,0.f,0.f, - 0.f,0.f,1.f,0.f, - 0.f,-1.f,0.f,0.f, - 0.f,0.f,0.f,1.f) * pcOut->mRootNode->mTransformation; - - // If the root node is unnamed name it "<3DSRoot>" - if (::strstr( pcOut->mRootNode->mName.data, "UNNAMED" ) || - (pcOut->mRootNode->mName.data[0] == '$' && pcOut->mRootNode->mName.data[1] == '$') ) - { - pcOut->mRootNode->mName.Set("<3DSRoot>"); - } + pcOut->mRootNode = new aiNode(); + if (0 == mRootNode->mChildren.size()) + { + ////////////////////////////////////////////////////////////////////////////// + // It seems the file is so messed up that it has not even a hierarchy. + // generate a flat hiearachy which looks like this: + // + // ROOT_NODE + // | + // ---------------------------------------- + // | | | | | + // MESH_0 MESH_1 MESH_2 ... MESH_N CAMERA_0 .... + // + DefaultLogger::get()->warn("No hierarchy information has been found in the file. "); + + pcOut->mRootNode->mNumChildren = pcOut->mNumMeshes + + mScene->mCameras.size() + mScene->mLights.size(); + + pcOut->mRootNode->mChildren = new aiNode* [ pcOut->mRootNode->mNumChildren ]; + pcOut->mRootNode->mName.Set("<3DSDummyRoot>"); + + // Build dummy nodes for all meshes + unsigned int a = 0; + for (unsigned int i = 0; i < pcOut->mNumMeshes;++i,++a) + { + aiNode* pcNode = pcOut->mRootNode->mChildren[a] = new aiNode(); + pcNode->mParent = pcOut->mRootNode; + pcNode->mMeshes = new unsigned int[1]; + pcNode->mMeshes[0] = i; + pcNode->mNumMeshes = 1; + + // Build a name for the node + pcNode->mName.length = ai_snprintf(pcNode->mName.data, MAXLEN, "3DSMesh_%u",i); + } + + // Build dummy nodes for all cameras + for (unsigned int i = 0; i < (unsigned int )mScene->mCameras.size();++i,++a) + { + aiNode* pcNode = pcOut->mRootNode->mChildren[a] = new aiNode(); + pcNode->mParent = pcOut->mRootNode; + + // Build a name for the node + pcNode->mName = mScene->mCameras[i]->mName; + } + + // Build dummy nodes for all lights + for (unsigned int i = 0; i < (unsigned int )mScene->mLights.size();++i,++a) + { + aiNode* pcNode = pcOut->mRootNode->mChildren[a] = new aiNode(); + pcNode->mParent = pcOut->mRootNode; + + // Build a name for the node + pcNode->mName = mScene->mLights[i]->mName; + } + } + else + { + // First of all: find out how many scaling, rotation and translation + // animation tracks we'll have afterwards + unsigned int numChannel = 0; + CountTracks(mRootNode,numChannel); + + if (numChannel) + { + // Allocate a primary animation channel + pcOut->mNumAnimations = 1; + pcOut->mAnimations = new aiAnimation*[1]; + aiAnimation* anim = pcOut->mAnimations[0] = new aiAnimation(); + + anim->mName.Set("3DSMasterAnim"); + + // Allocate enough storage for all node animation channels, + // but don't set the mNumChannels member - we'll use it to + // index into the array + anim->mChannels = new aiNodeAnim*[numChannel]; + } + + aiMatrix4x4 m; + AddNodeToGraph(pcOut, pcOut->mRootNode, mRootNode,m); + } + + // We used the first and second vertex color set to store some temporary values so we need to cleanup here + for (unsigned int a = 0; a < pcOut->mNumMeshes; ++a) + { + pcOut->mMeshes[a]->mColors[0] = NULL; + pcOut->mMeshes[a]->mColors[1] = NULL; + } + + pcOut->mRootNode->mTransformation = aiMatrix4x4( + 1.f,0.f,0.f,0.f, + 0.f,0.f,1.f,0.f, + 0.f,-1.f,0.f,0.f, + 0.f,0.f,0.f,1.f) * pcOut->mRootNode->mTransformation; + + // If the root node is unnamed name it "<3DSRoot>" + if (::strstr( pcOut->mRootNode->mName.data, "UNNAMED" ) || + (pcOut->mRootNode->mName.data[0] == '$' && pcOut->mRootNode->mName.data[1] == '$') ) + { + pcOut->mRootNode->mName.Set("<3DSRoot>"); + } } // ------------------------------------------------------------------------------------------------ // Convert all meshes in the scene and generate the final output scene. void Discreet3DSImporter::ConvertScene(aiScene* pcOut) { - // Allocate enough storage for all output materials - pcOut->mNumMaterials = (unsigned int)mScene->mMaterials.size(); - pcOut->mMaterials = new aiMaterial*[pcOut->mNumMaterials]; - - // ... and convert the 3DS materials to aiMaterial's - for (unsigned int i = 0; i < pcOut->mNumMaterials;++i) - { - aiMaterial* pcNew = new aiMaterial(); - ConvertMaterial(mScene->mMaterials[i],*pcNew); - pcOut->mMaterials[i] = pcNew; - } - - // Generate the output mesh list - ConvertMeshes(pcOut); - - // Now copy all light sources to the output scene - pcOut->mNumLights = (unsigned int)mScene->mLights.size(); - if (pcOut->mNumLights) - { - pcOut->mLights = new aiLight*[pcOut->mNumLights]; - ::memcpy(pcOut->mLights,&mScene->mLights[0],sizeof(void*)*pcOut->mNumLights); - } - - // Now copy all cameras to the output scene - pcOut->mNumCameras = (unsigned int)mScene->mCameras.size(); - if (pcOut->mNumCameras) - { - pcOut->mCameras = new aiCamera*[pcOut->mNumCameras]; - ::memcpy(pcOut->mCameras,&mScene->mCameras[0],sizeof(void*)*pcOut->mNumCameras); - } + // Allocate enough storage for all output materials + pcOut->mNumMaterials = (unsigned int)mScene->mMaterials.size(); + pcOut->mMaterials = new aiMaterial*[pcOut->mNumMaterials]; + + // ... and convert the 3DS materials to aiMaterial's + for (unsigned int i = 0; i < pcOut->mNumMaterials;++i) + { + aiMaterial* pcNew = new aiMaterial(); + ConvertMaterial(mScene->mMaterials[i],*pcNew); + pcOut->mMaterials[i] = pcNew; + } + + // Generate the output mesh list + ConvertMeshes(pcOut); + + // Now copy all light sources to the output scene + pcOut->mNumLights = (unsigned int)mScene->mLights.size(); + if (pcOut->mNumLights) + { + pcOut->mLights = new aiLight*[pcOut->mNumLights]; + ::memcpy(pcOut->mLights,&mScene->mLights[0],sizeof(void*)*pcOut->mNumLights); + } + + // Now copy all cameras to the output scene + pcOut->mNumCameras = (unsigned int)mScene->mCameras.size(); + if (pcOut->mNumCameras) + { + pcOut->mCameras = new aiCamera*[pcOut->mNumCameras]; + ::memcpy(pcOut->mCameras,&mScene->mCameras[0],sizeof(void*)*pcOut->mNumCameras); + } } #endif // !! ASSIMP_BUILD_NO_3DS_IMPORTER diff --git a/src/3rdparty/assimp/code/3DSExporter.cpp b/src/3rdparty/assimp/code/3DSExporter.cpp new file mode 100644 index 000000000..5bb79408f --- /dev/null +++ b/src/3rdparty/assimp/code/3DSExporter.cpp @@ -0,0 +1,565 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2016, assimp team +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the +following conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +---------------------------------------------------------------------- +*/ + + +#ifndef ASSIMP_BUILD_NO_EXPORT +#ifndef ASSIMP_BUILD_NO_3DS_EXPORTER + +#include "3DSExporter.h" +#include "3DSLoader.h" +#include "SceneCombiner.h" +#include "SplitLargeMeshes.h" +#include "StringComparison.h" +#include +#include +#include +#include + +using namespace Assimp; +namespace Assimp { + +namespace { + + ////////////////////////////////////////////////////////////////////////////////////// + // Scope utility to write a 3DS file chunk. + // + // Upon construction, the chunk header is written with the chunk type (flags) + // filled out, but the chunk size left empty. Upon destruction, the correct chunk + // size based on the then-position of the output stream cursor is filled in. + class ChunkWriter { + enum { + CHUNK_SIZE_NOT_SET = 0xdeadbeef + , SIZE_OFFSET = 2 + }; + public: + + ChunkWriter(StreamWriterLE& writer, uint16_t chunk_type) + : writer(writer) + { + chunk_start_pos = writer.GetCurrentPos(); + writer.PutU2(chunk_type); + writer.PutU4(CHUNK_SIZE_NOT_SET); + } + + ~ChunkWriter() { + std::size_t head_pos = writer.GetCurrentPos(); + + ai_assert(head_pos > chunk_start_pos); + const std::size_t chunk_size = head_pos - chunk_start_pos; + + writer.SetCurrentPos(chunk_start_pos + SIZE_OFFSET); + writer.PutU4(chunk_size); + writer.SetCurrentPos(head_pos); + } + + private: + StreamWriterLE& writer; + std::size_t chunk_start_pos; + }; + + + // Return an unique name for a given |mesh| attached to |node| that + // preserves the mesh's given name if it has one. |index| is the index + // of the mesh in |aiScene::mMeshes|. + std::string GetMeshName(const aiMesh& mesh, unsigned int index, const aiNode& node) { + static const std::string underscore = "_"; + char postfix[10] = {0}; + ASSIMP_itoa10(postfix, index); + + std::string result = node.mName.C_Str(); + if (mesh.mName.length > 0) { + result += underscore + mesh.mName.C_Str(); + } + return result + underscore + postfix; + } + + // Return an unique name for a given |mat| with original position |index| + // in |aiScene::mMaterials|. The name preserves the original material + // name if possible. + std::string GetMaterialName(const aiMaterial& mat, unsigned int index) { + static const std::string underscore = "_"; + char postfix[10] = {0}; + ASSIMP_itoa10(postfix, index); + + aiString mat_name; + if (AI_SUCCESS == mat.Get(AI_MATKEY_NAME, mat_name)) { + return mat_name.C_Str() + underscore + postfix; + } + + return "Material" + underscore + postfix; + } + + // Collect world transformations for each node + void CollectTrafos(const aiNode* node, std::map& trafos) { + const aiMatrix4x4& parent = node->mParent ? trafos[node->mParent] : aiMatrix4x4(); + trafos[node] = parent * node->mTransformation; + for (unsigned int i = 0; i < node->mNumChildren; ++i) { + CollectTrafos(node->mChildren[i], trafos); + } + } + + // Generate a flat list of the meshes (by index) assigned to each node + void CollectMeshes(const aiNode* node, std::multimap& meshes) { + for (unsigned int i = 0; i < node->mNumMeshes; ++i) { + meshes.insert(std::make_pair(node, node->mMeshes[i])); + } + for (unsigned int i = 0; i < node->mNumChildren; ++i) { + CollectMeshes(node->mChildren[i], meshes); + } + } +} + +// ------------------------------------------------------------------------------------------------ +// Worker function for exporting a scene to 3DS. Prototyped and registered in Exporter.cpp +void ExportScene3DS(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* pProperties) +{ + std::shared_ptr outfile (pIOSystem->Open(pFile, "wb")); + if(!outfile) { + throw DeadlyExportError("Could not open output .3ds file: " + std::string(pFile)); + } + + // TODO: This extra copy should be avoided and all of this made a preprocess + // requirement of the 3DS exporter. + // + // 3DS meshes can be max 0xffff (16 Bit) vertices and faces, respectively. + // SplitLargeMeshes can do this, but it requires the correct limit to be set + // which is not possible with the current way of specifying preprocess steps + // in |Exporter::ExportFormatEntry|. + aiScene* scenecopy_tmp; + SceneCombiner::CopyScene(&scenecopy_tmp,pScene); + std::unique_ptr scenecopy(scenecopy_tmp); + + SplitLargeMeshesProcess_Triangle tri_splitter; + tri_splitter.SetLimit(0xffff); + tri_splitter.Execute(scenecopy.get()); + + SplitLargeMeshesProcess_Vertex vert_splitter; + vert_splitter.SetLimit(0xffff); + vert_splitter.Execute(scenecopy.get()); + + // Invoke the actual exporter + Discreet3DSExporter exporter(outfile, scenecopy.get()); +} + +} // end of namespace Assimp + +// ------------------------------------------------------------------------------------------------ +Discreet3DSExporter:: Discreet3DSExporter(std::shared_ptr outfile, const aiScene* scene) +: scene(scene) +, writer(outfile) +{ + CollectTrafos(scene->mRootNode, trafos); + CollectMeshes(scene->mRootNode, meshes); + + ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAIN); + + { + ChunkWriter chunk(writer, Discreet3DS::CHUNK_OBJMESH); + WriteMaterials(); + WriteMeshes(); + + { + ChunkWriter chunk(writer, Discreet3DS::CHUNK_MASTER_SCALE); + writer.PutF4(1.0f); + } + } + + { + ChunkWriter chunk(writer, Discreet3DS::CHUNK_KEYFRAMER); + WriteHierarchy(*scene->mRootNode, -1, -1); + } +} + +// ------------------------------------------------------------------------------------------------ +int Discreet3DSExporter::WriteHierarchy(const aiNode& node, int seq, int sibling_level) +{ + // 3DS scene hierarchy is serialized as in http://www.martinreddy.net/gfx/3d/3DS.spec + { + ChunkWriter chunk(writer, Discreet3DS::CHUNK_TRACKINFO); + { + ChunkWriter chunk(writer, Discreet3DS::CHUNK_TRACKOBJNAME); + + // Assimp node names are unique and distinct from all mesh-node + // names we generate; thus we can use them as-is + WriteString(node.mName); + + // Two unknown int16 values - it is even unclear if 0 is a safe value + // but luckily importers do not know better either. + writer.PutI4(0); + + int16_t hierarchy_pos = static_cast(seq); + if (sibling_level != -1) { + hierarchy_pos = sibling_level; + } + + // Write the hierarchy position + writer.PutI2(hierarchy_pos); + } + } + + // TODO: write transformation chunks + + ++seq; + sibling_level = seq; + + // Write all children + for (unsigned int i = 0; i < node.mNumChildren; ++i) { + seq = WriteHierarchy(*node.mChildren[i], seq, i == 0 ? -1 : sibling_level); + } + + // Write all meshes as separate nodes to be able to reference the meshes by name + for (unsigned int i = 0; i < node.mNumMeshes; ++i) { + const bool first_child = node.mNumChildren == 0 && i == 0; + + const unsigned int mesh_idx = node.mMeshes[i]; + const aiMesh& mesh = *scene->mMeshes[mesh_idx]; + + ChunkWriter chunk(writer, Discreet3DS::CHUNK_TRACKINFO); + { + ChunkWriter chunk(writer, Discreet3DS::CHUNK_TRACKOBJNAME); + WriteString(GetMeshName(mesh, mesh_idx, node)); + + writer.PutI4(0); + writer.PutI2(static_cast(first_child ? seq : sibling_level)); + ++seq; + } + } + return seq; +} + +// ------------------------------------------------------------------------------------------------ +void Discreet3DSExporter::WriteMaterials() +{ + for (unsigned int i = 0; i < scene->mNumMaterials; ++i) { + ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_MATERIAL); + const aiMaterial& mat = *scene->mMaterials[i]; + + { + ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_MATNAME); + const std::string& name = GetMaterialName(mat, i); + WriteString(name); + } + + aiColor3D color; + if (mat.Get(AI_MATKEY_COLOR_DIFFUSE, color) == AI_SUCCESS) { + ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_DIFFUSE); + WriteColor(color); + } + + if (mat.Get(AI_MATKEY_COLOR_SPECULAR, color) == AI_SUCCESS) { + ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_SPECULAR); + WriteColor(color); + } + + if (mat.Get(AI_MATKEY_COLOR_AMBIENT, color) == AI_SUCCESS) { + ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_AMBIENT); + WriteColor(color); + } + + if (mat.Get(AI_MATKEY_COLOR_EMISSIVE, color) == AI_SUCCESS) { + ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_SELF_ILLUM); + WriteColor(color); + } + + aiShadingMode shading_mode = aiShadingMode_Flat; + if (mat.Get(AI_MATKEY_SHADING_MODEL, shading_mode) == AI_SUCCESS) { + ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_SHADING); + + Discreet3DS::shadetype3ds shading_mode_out; + switch(shading_mode) { + case aiShadingMode_Flat: + case aiShadingMode_NoShading: + shading_mode_out = Discreet3DS::Flat; + break; + + case aiShadingMode_Gouraud: + case aiShadingMode_Toon: + case aiShadingMode_OrenNayar: + case aiShadingMode_Minnaert: + shading_mode_out = Discreet3DS::Gouraud; + break; + + case aiShadingMode_Phong: + case aiShadingMode_Blinn: + case aiShadingMode_CookTorrance: + case aiShadingMode_Fresnel: + shading_mode_out = Discreet3DS::Phong; + break; + + default: + shading_mode_out = Discreet3DS::Flat; + ai_assert(false); + }; + writer.PutU2(static_cast(shading_mode_out)); + } + + + float f; + if (mat.Get(AI_MATKEY_SHININESS, f) == AI_SUCCESS) { + ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_SHININESS); + WritePercentChunk(f); + } + + if (mat.Get(AI_MATKEY_SHININESS_STRENGTH, f) == AI_SUCCESS) { + ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_SHININESS_PERCENT); + WritePercentChunk(f); + } + + int twosided; + if (mat.Get(AI_MATKEY_TWOSIDED, twosided) == AI_SUCCESS && twosided != 0) { + ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_TWO_SIDE); + writer.PutI2(1); + } + + WriteTexture(mat, aiTextureType_DIFFUSE, Discreet3DS::CHUNK_MAT_TEXTURE); + WriteTexture(mat, aiTextureType_HEIGHT, Discreet3DS::CHUNK_MAT_BUMPMAP); + WriteTexture(mat, aiTextureType_OPACITY, Discreet3DS::CHUNK_MAT_OPACMAP); + WriteTexture(mat, aiTextureType_SHININESS, Discreet3DS::CHUNK_MAT_MAT_SHINMAP); + WriteTexture(mat, aiTextureType_SPECULAR, Discreet3DS::CHUNK_MAT_SPECMAP); + WriteTexture(mat, aiTextureType_EMISSIVE, Discreet3DS::CHUNK_MAT_SELFIMAP); + WriteTexture(mat, aiTextureType_REFLECTION, Discreet3DS::CHUNK_MAT_REFLMAP); + } +} + +// ------------------------------------------------------------------------------------------------ +void Discreet3DSExporter::WriteTexture(const aiMaterial& mat, aiTextureType type, uint16_t chunk_flags) +{ + aiString path; + aiTextureMapMode map_mode[2] = { + aiTextureMapMode_Wrap, aiTextureMapMode_Wrap + }; + float blend = 1.0f; + if (mat.GetTexture(type, 0, &path, NULL, NULL, &blend, NULL, map_mode) != AI_SUCCESS || !path.length) { + return; + } + + // TODO: handle embedded textures properly + if (path.data[0] == '*') { + DefaultLogger::get()->error("Ignoring embedded texture for export: " + std::string(path.C_Str())); + return; + } + + ChunkWriter chunk(writer, chunk_flags); + { + ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAPFILE); + WriteString(path); + } + + WritePercentChunk(blend); + + { + ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_MAP_TILING); + uint16_t val = 0; // WRAP + if (map_mode[0] == aiTextureMapMode_Mirror) { + val = 0x2; + } + else if (map_mode[0] == aiTextureMapMode_Decal) { + val = 0x10; + } + writer.PutU2(val); + } + // TODO: export texture transformation (i.e. UV offset, scale, rotation) +} + +// ------------------------------------------------------------------------------------------------ +void Discreet3DSExporter::WriteMeshes() +{ + // NOTE: 3DS allows for instances. However: + // i) not all importers support reading them + // ii) instances are not as flexible as they are in assimp, in particular, + // nodes can carry (and instance) only one mesh. + // + // This exporter currently deep clones all instanced meshes, i.e. for each mesh + // attached to a node a full TRIMESH chunk is written to the file. + // + // Furthermore, the TRIMESH is transformed into world space so that it will + // appear correctly if importers don't read the scene hierarchy at all. + for (MeshesByNodeMap::const_iterator it = meshes.begin(); it != meshes.end(); ++it) { + const aiNode& node = *(*it).first; + const unsigned int mesh_idx = (*it).second; + + const aiMesh& mesh = *scene->mMeshes[mesh_idx]; + + // This should not happen if the SLM step is correctly executed + // before the scene is handed to the exporter + ai_assert(mesh.mNumVertices <= 0xffff); + ai_assert(mesh.mNumFaces <= 0xffff); + + const aiMatrix4x4& trafo = trafos[&node]; + + ChunkWriter chunk(writer, Discreet3DS::CHUNK_OBJBLOCK); + + // Mesh name is tied to the node it is attached to so it can later be referenced + const std::string& name = GetMeshName(mesh, mesh_idx, node); + WriteString(name); + + + // TRIMESH chunk + ChunkWriter chunk2(writer, Discreet3DS::CHUNK_TRIMESH); + + // Vertices in world space + { + ChunkWriter chunk(writer, Discreet3DS::CHUNK_VERTLIST); + + const uint16_t count = static_cast(mesh.mNumVertices); + writer.PutU2(count); + for (unsigned int i = 0; i < mesh.mNumVertices; ++i) { + const aiVector3D& v = trafo * mesh.mVertices[i]; + writer.PutF4(v.x); + writer.PutF4(v.y); + writer.PutF4(v.z); + } + } + + // UV coordinates + if (mesh.HasTextureCoords(0)) { + ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAPLIST); + const uint16_t count = static_cast(mesh.mNumVertices); + writer.PutU2(count); + + for (unsigned int i = 0; i < mesh.mNumVertices; ++i) { + const aiVector3D& v = mesh.mTextureCoords[0][i]; + writer.PutF4(v.x); + writer.PutF4(v.y); + } + } + + // Faces (indices) + { + ChunkWriter chunk(writer, Discreet3DS::CHUNK_FACELIST); + + ai_assert(mesh.mNumFaces <= 0xffff); + + // Count triangles, discard lines and points + uint16_t count = 0; + for (unsigned int i = 0; i < mesh.mNumFaces; ++i) { + const aiFace& f = mesh.mFaces[i]; + if (f.mNumIndices < 3) { + continue; + } + // TRIANGULATE step is a pre-requisite so we should not see polys here + ai_assert(f.mNumIndices == 3); + ++count; + } + + writer.PutU2(count); + for (unsigned int i = 0; i < mesh.mNumFaces; ++i) { + const aiFace& f = mesh.mFaces[i]; + if (f.mNumIndices < 3) { + continue; + } + + for (unsigned int j = 0; j < 3; ++j) { + ai_assert(f.mIndices[j] <= 0xffff); + writer.PutI2(static_cast(f.mIndices[j])); + } + + // Edge visibility flag + writer.PutI2(0x0); + } + + // TODO: write smoothing groups (CHUNK_SMOOLIST) + + WriteFaceMaterialChunk(mesh); + } + + // Transformation matrix by which the mesh vertices have been pre-transformed with. + { + ChunkWriter chunk(writer, Discreet3DS::CHUNK_TRMATRIX); + for (unsigned int r = 0; r < 4; ++r) { + for (unsigned int c = 0; c < 3; ++c) { + writer.PutF4(trafo[r][c]); + } + } + } + } +} + +// ------------------------------------------------------------------------------------------------ +void Discreet3DSExporter::WriteFaceMaterialChunk(const aiMesh& mesh) +{ + ChunkWriter chunk(writer, Discreet3DS::CHUNK_FACEMAT); + const std::string& name = GetMaterialName(*scene->mMaterials[mesh.mMaterialIndex], mesh.mMaterialIndex); + WriteString(name); + + // Because assimp splits meshes by material, only a single + // FACEMAT chunk needs to be written + ai_assert(mesh.mNumFaces <= 0xffff); + const uint16_t count = static_cast(mesh.mNumFaces); + writer.PutU2(count); + + for (unsigned int i = 0; i < mesh.mNumFaces; ++i) { + writer.PutU2(static_cast(i)); + } +} + +// ------------------------------------------------------------------------------------------------ +void Discreet3DSExporter::WriteString(const std::string& s) { + for (std::string::const_iterator it = s.begin(); it != s.end(); ++it) { + writer.PutI1(*it); + } + writer.PutI1('\0'); +} + +// ------------------------------------------------------------------------------------------------ +void Discreet3DSExporter::WriteString(const aiString& s) { + for (std::size_t i = 0; i < s.length; ++i) { + writer.PutI1(s.data[i]); + } + writer.PutI1('\0'); +} + +// ------------------------------------------------------------------------------------------------ +void Discreet3DSExporter::WriteColor(const aiColor3D& color) { + ChunkWriter chunk(writer, Discreet3DS::CHUNK_RGBF); + writer.PutF4(color.r); + writer.PutF4(color.g); + writer.PutF4(color.b); +} + +// ------------------------------------------------------------------------------------------------ +void Discreet3DSExporter::WritePercentChunk(float f) { + ChunkWriter chunk(writer, Discreet3DS::CHUNK_PERCENTF); + writer.PutF4(f); +} + + +#endif // ASSIMP_BUILD_NO_3DS_EXPORTER +#endif // ASSIMP_BUILD_NO_EXPORT diff --git a/src/3rdparty/assimp/code/3DSExporter.h b/src/3rdparty/assimp/code/3DSExporter.h new file mode 100644 index 000000000..321539cff --- /dev/null +++ b/src/3rdparty/assimp/code/3DSExporter.h @@ -0,0 +1,98 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2016, assimp team +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the +following conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +---------------------------------------------------------------------- +*/ + +/** @file 3DSExporter.h + * 3DS Exporter Main Header + */ +#ifndef AI_3DSEXPORTER_H_INC +#define AI_3DSEXPORTER_H_INC + +#include +#include + +#include "StreamWriter.h" +#include "./../include/assimp/material.h" + +struct aiScene; +struct aiNode; +struct aiMaterial; +struct aiMesh; + +namespace Assimp +{ + +// ------------------------------------------------------------------------------------------------ +/** Helper class to export a given scene to a 3DS file. */ +// ------------------------------------------------------------------------------------------------ +class Discreet3DSExporter +{ +public: + Discreet3DSExporter(std::shared_ptr outfile, const aiScene* pScene); + +private: + + void WriteMeshes(); + void WriteMaterials(); + void WriteTexture(const aiMaterial& mat, aiTextureType type, uint16_t chunk_flags); + + void WriteFaceMaterialChunk(const aiMesh& mesh); + + int WriteHierarchy(const aiNode& node, int level, int sibling_level); + + void WriteString(const std::string& s); + void WriteString(const aiString& s); + void WriteColor(const aiColor3D& color); + void WritePercentChunk(float f); + +private: + + const aiScene* const scene; + StreamWriterLE writer; + + std::map trafos; + + typedef std::multimap MeshesByNodeMap; + MeshesByNodeMap meshes; + +}; + +} + +#endif diff --git a/src/3rdparty/assimp/code/3DSHelper.h b/src/3rdparty/assimp/code/3DSHelper.h index 8da7f0838..5911b9d47 100644 --- a/src/3rdparty/assimp/code/3DSHelper.h +++ b/src/3rdparty/assimp/code/3DSHelper.h @@ -2,11 +2,11 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2012, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above @@ -23,16 +23,16 @@ following conditions are met: derived from this software without specific prior written permission of the assimp team. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- @@ -46,9 +46,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "SpatialSort.h" #include "SmoothingGroups.h" +#include "StringUtils.h" +#include "qnan.h" +#include "./../include/assimp/material.h" +#include "./../include/assimp/camera.h" +#include "./../include/assimp/light.h" +#include "./../include/assimp/anim.h" +#include //sprintf -namespace Assimp { -namespace D3DS { +namespace Assimp { +namespace D3DS { #include "./../include/assimp/Compiler/pushpack1.h" @@ -59,253 +66,253 @@ namespace D3DS { class Discreet3DS { private: - inline Discreet3DS() {} + inline Discreet3DS() {} public: - //! data structure for a single chunk in a .3ds file - struct Chunk - { - uint16_t Flag; - uint32_t Size; - } PACK_STRUCT; - - - //! Used for shading field in material3ds structure - //! From AutoDesk 3ds SDK - typedef enum - { - // translated to gouraud shading with wireframe active - Wire = 0x0, - - // if this material is set, no vertex normals will - // be calculated for the model. Face normals + gouraud - Flat = 0x1, - - // standard gouraud shading - Gouraud = 0x2, - - // phong shading - Phong = 0x3, - - // cooktorrance or anistropic phong shading ... - // the exact meaning is unknown, if you know it - // feel free to tell me ;-) - Metal = 0x4, - - // required by the ASE loader - Blinn = 0x5 - } shadetype3ds; - - // Flags for animated keys - enum - { - KEY_USE_TENS = 0x1, - KEY_USE_CONT = 0x2, - KEY_USE_BIAS = 0x4, - KEY_USE_EASE_TO = 0x8, - KEY_USE_EASE_FROM = 0x10 - } ; - - enum - { - - // ******************************************************************** - // Basic chunks which can be found everywhere in the file - CHUNK_VERSION = 0x0002, - CHUNK_RGBF = 0x0010, // float4 R; float4 G; float4 B - CHUNK_RGBB = 0x0011, // int1 R; int1 G; int B - - // Linear color values (gamma = 2.2?) - CHUNK_LINRGBF = 0x0013, // float4 R; float4 G; float4 B - CHUNK_LINRGBB = 0x0012, // int1 R; int1 G; int B - - CHUNK_PERCENTW = 0x0030, // int2 percentage - CHUNK_PERCENTF = 0x0031, // float4 percentage - // ******************************************************************** - - // Prj master chunk - CHUNK_PRJ = 0xC23D, - - // MDLI master chunk - CHUNK_MLI = 0x3DAA, - - // Primary main chunk of the .3ds file - CHUNK_MAIN = 0x4D4D, - - // Mesh main chunk - CHUNK_OBJMESH = 0x3D3D, - - // Specifies the background color of the .3ds file - // This is passed through the material system for - // viewing purposes. - CHUNK_BKGCOLOR = 0x1200, - - // Specifies the ambient base color of the scene. - // This is added to all materials in the file - CHUNK_AMBCOLOR = 0x2100, - - // Specifies the background image for the whole scene - // This value is passed through the material system - // to the viewer - CHUNK_BIT_MAP = 0x1100, - CHUNK_BIT_MAP_EXISTS = 0x1101, - - // ******************************************************************** - // Viewport related stuff. Ignored - CHUNK_DEFAULT_VIEW = 0x3000, - CHUNK_VIEW_TOP = 0x3010, - CHUNK_VIEW_BOTTOM = 0x3020, - CHUNK_VIEW_LEFT = 0x3030, - CHUNK_VIEW_RIGHT = 0x3040, - CHUNK_VIEW_FRONT = 0x3050, - CHUNK_VIEW_BACK = 0x3060, - CHUNK_VIEW_USER = 0x3070, - CHUNK_VIEW_CAMERA = 0x3080, - // ******************************************************************** - - // Mesh chunks - CHUNK_OBJBLOCK = 0x4000, - CHUNK_TRIMESH = 0x4100, - CHUNK_VERTLIST = 0x4110, - CHUNK_VERTFLAGS = 0x4111, - CHUNK_FACELIST = 0x4120, - CHUNK_FACEMAT = 0x4130, - CHUNK_MAPLIST = 0x4140, - CHUNK_SMOOLIST = 0x4150, - CHUNK_TRMATRIX = 0x4160, - CHUNK_MESHCOLOR = 0x4165, - CHUNK_TXTINFO = 0x4170, - CHUNK_LIGHT = 0x4600, - CHUNK_CAMERA = 0x4700, - CHUNK_HIERARCHY = 0x4F00, - - // Specifies the global scaling factor. This is applied - // to the root node's transformation matrix - CHUNK_MASTER_SCALE = 0x0100, - - // ******************************************************************** - // Material chunks - CHUNK_MAT_MATERIAL = 0xAFFF, - - // asciiz containing the name of the material - CHUNK_MAT_MATNAME = 0xA000, - CHUNK_MAT_AMBIENT = 0xA010, // followed by color chunk - CHUNK_MAT_DIFFUSE = 0xA020, // followed by color chunk - CHUNK_MAT_SPECULAR = 0xA030, // followed by color chunk - - // Specifies the shininess of the material - // followed by percentage chunk - CHUNK_MAT_SHININESS = 0xA040, - CHUNK_MAT_SHININESS_PERCENT = 0xA041 , - - // Specifies the shading mode to be used - // followed by a short - CHUNK_MAT_SHADING = 0xA100, - - // NOTE: Emissive color (self illumination) seems not - // to be a color but a single value, type is unknown. - // Make the parser accept both of them. - // followed by percentage chunk (?) - CHUNK_MAT_SELF_ILLUM = 0xA080, - - // Always followed by percentage chunk (?) - CHUNK_MAT_SELF_ILPCT = 0xA084, - - // Always followed by percentage chunk - CHUNK_MAT_TRANSPARENCY = 0xA050, - - // Diffuse texture channel 0 - CHUNK_MAT_TEXTURE = 0xA200, - - // Contains opacity information for each texel - CHUNK_MAT_OPACMAP = 0xA210, - - // Contains a reflection map to be used to reflect - // the environment. This is partially supported. - CHUNK_MAT_REFLMAP = 0xA220, - - // Self Illumination map (emissive colors) - CHUNK_MAT_SELFIMAP = 0xA33d, - - // Bumpmap. Not specified whether it is a heightmap - // or a normal map. Assme it is a heightmap since - // artist normally prefer this format. - CHUNK_MAT_BUMPMAP = 0xA230, - - // Specular map. Seems to influence the specular color - CHUNK_MAT_SPECMAP = 0xA204, - - // Holds shininess data. - CHUNK_MAT_MAT_SHINMAP = 0xA33C, - - // Scaling in U/V direction. - // (need to gen separate UV coordinate set - // and do this by hand) - CHUNK_MAT_MAP_USCALE = 0xA354, - CHUNK_MAT_MAP_VSCALE = 0xA356, - - // Translation in U/V direction. - // (need to gen separate UV coordinate set - // and do this by hand) - CHUNK_MAT_MAP_UOFFSET = 0xA358, - CHUNK_MAT_MAP_VOFFSET = 0xA35a, - - // UV-coordinates rotation around the z-axis - // Assumed to be in radians. - CHUNK_MAT_MAP_ANG = 0xA35C, - - // Tiling flags for 3DS files - CHUNK_MAT_MAP_TILING = 0xa351, - - // Specifies the file name of a texture - CHUNK_MAPFILE = 0xA300, - - // Specifies whether a materail requires two-sided rendering - CHUNK_MAT_TWO_SIDE = 0xA081, - // ******************************************************************** - - // Main keyframer chunk. Contains translation/rotation/scaling data - CHUNK_KEYFRAMER = 0xB000, - - // Supported sub chunks - CHUNK_TRACKINFO = 0xB002, - CHUNK_TRACKOBJNAME = 0xB010, - CHUNK_TRACKDUMMYOBJNAME = 0xB011, - CHUNK_TRACKPIVOT = 0xB013, - CHUNK_TRACKPOS = 0xB020, - CHUNK_TRACKROTATE = 0xB021, - CHUNK_TRACKSCALE = 0xB022, - - // ******************************************************************** - // Keyframes for various other stuff in the file - // Partially ignored - CHUNK_AMBIENTKEY = 0xB001, - CHUNK_TRACKMORPH = 0xB026, - CHUNK_TRACKHIDE = 0xB029, - CHUNK_OBJNUMBER = 0xB030, - CHUNK_TRACKCAMERA = 0xB003, - CHUNK_TRACKFOV = 0xB023, - CHUNK_TRACKROLL = 0xB024, - CHUNK_TRACKCAMTGT = 0xB004, - CHUNK_TRACKLIGHT = 0xB005, - CHUNK_TRACKLIGTGT = 0xB006, - CHUNK_TRACKSPOTL = 0xB007, - CHUNK_FRAMES = 0xB008, - // ******************************************************************** - - // light sub-chunks - CHUNK_DL_OFF = 0x4620, - CHUNK_DL_OUTER_RANGE = 0x465A, - CHUNK_DL_INNER_RANGE = 0x4659, - CHUNK_DL_MULTIPLIER = 0x465B, - CHUNK_DL_EXCLUDE = 0x4654, - CHUNK_DL_ATTENUATE = 0x4625, - CHUNK_DL_SPOTLIGHT = 0x4610, - - // camera sub-chunks - CHUNK_CAM_RANGES = 0x4720 - }; + //! data structure for a single chunk in a .3ds file + struct Chunk + { + uint16_t Flag; + uint32_t Size; + } PACK_STRUCT; + + + //! Used for shading field in material3ds structure + //! From AutoDesk 3ds SDK + typedef enum + { + // translated to gouraud shading with wireframe active + Wire = 0x0, + + // if this material is set, no vertex normals will + // be calculated for the model. Face normals + gouraud + Flat = 0x1, + + // standard gouraud shading + Gouraud = 0x2, + + // phong shading + Phong = 0x3, + + // cooktorrance or anistropic phong shading ... + // the exact meaning is unknown, if you know it + // feel free to tell me ;-) + Metal = 0x4, + + // required by the ASE loader + Blinn = 0x5 + } shadetype3ds; + + // Flags for animated keys + enum + { + KEY_USE_TENS = 0x1, + KEY_USE_CONT = 0x2, + KEY_USE_BIAS = 0x4, + KEY_USE_EASE_TO = 0x8, + KEY_USE_EASE_FROM = 0x10 + } ; + + enum + { + + // ******************************************************************** + // Basic chunks which can be found everywhere in the file + CHUNK_VERSION = 0x0002, + CHUNK_RGBF = 0x0010, // float4 R; float4 G; float4 B + CHUNK_RGBB = 0x0011, // int1 R; int1 G; int B + + // Linear color values (gamma = 2.2?) + CHUNK_LINRGBF = 0x0013, // float4 R; float4 G; float4 B + CHUNK_LINRGBB = 0x0012, // int1 R; int1 G; int B + + CHUNK_PERCENTW = 0x0030, // int2 percentage + CHUNK_PERCENTF = 0x0031, // float4 percentage + // ******************************************************************** + + // Prj master chunk + CHUNK_PRJ = 0xC23D, + + // MDLI master chunk + CHUNK_MLI = 0x3DAA, + + // Primary main chunk of the .3ds file + CHUNK_MAIN = 0x4D4D, + + // Mesh main chunk + CHUNK_OBJMESH = 0x3D3D, + + // Specifies the background color of the .3ds file + // This is passed through the material system for + // viewing purposes. + CHUNK_BKGCOLOR = 0x1200, + + // Specifies the ambient base color of the scene. + // This is added to all materials in the file + CHUNK_AMBCOLOR = 0x2100, + + // Specifies the background image for the whole scene + // This value is passed through the material system + // to the viewer + CHUNK_BIT_MAP = 0x1100, + CHUNK_BIT_MAP_EXISTS = 0x1101, + + // ******************************************************************** + // Viewport related stuff. Ignored + CHUNK_DEFAULT_VIEW = 0x3000, + CHUNK_VIEW_TOP = 0x3010, + CHUNK_VIEW_BOTTOM = 0x3020, + CHUNK_VIEW_LEFT = 0x3030, + CHUNK_VIEW_RIGHT = 0x3040, + CHUNK_VIEW_FRONT = 0x3050, + CHUNK_VIEW_BACK = 0x3060, + CHUNK_VIEW_USER = 0x3070, + CHUNK_VIEW_CAMERA = 0x3080, + // ******************************************************************** + + // Mesh chunks + CHUNK_OBJBLOCK = 0x4000, + CHUNK_TRIMESH = 0x4100, + CHUNK_VERTLIST = 0x4110, + CHUNK_VERTFLAGS = 0x4111, + CHUNK_FACELIST = 0x4120, + CHUNK_FACEMAT = 0x4130, + CHUNK_MAPLIST = 0x4140, + CHUNK_SMOOLIST = 0x4150, + CHUNK_TRMATRIX = 0x4160, + CHUNK_MESHCOLOR = 0x4165, + CHUNK_TXTINFO = 0x4170, + CHUNK_LIGHT = 0x4600, + CHUNK_CAMERA = 0x4700, + CHUNK_HIERARCHY = 0x4F00, + + // Specifies the global scaling factor. This is applied + // to the root node's transformation matrix + CHUNK_MASTER_SCALE = 0x0100, + + // ******************************************************************** + // Material chunks + CHUNK_MAT_MATERIAL = 0xAFFF, + + // asciiz containing the name of the material + CHUNK_MAT_MATNAME = 0xA000, + CHUNK_MAT_AMBIENT = 0xA010, // followed by color chunk + CHUNK_MAT_DIFFUSE = 0xA020, // followed by color chunk + CHUNK_MAT_SPECULAR = 0xA030, // followed by color chunk + + // Specifies the shininess of the material + // followed by percentage chunk + CHUNK_MAT_SHININESS = 0xA040, + CHUNK_MAT_SHININESS_PERCENT = 0xA041 , + + // Specifies the shading mode to be used + // followed by a short + CHUNK_MAT_SHADING = 0xA100, + + // NOTE: Emissive color (self illumination) seems not + // to be a color but a single value, type is unknown. + // Make the parser accept both of them. + // followed by percentage chunk (?) + CHUNK_MAT_SELF_ILLUM = 0xA080, + + // Always followed by percentage chunk (?) + CHUNK_MAT_SELF_ILPCT = 0xA084, + + // Always followed by percentage chunk + CHUNK_MAT_TRANSPARENCY = 0xA050, + + // Diffuse texture channel 0 + CHUNK_MAT_TEXTURE = 0xA200, + + // Contains opacity information for each texel + CHUNK_MAT_OPACMAP = 0xA210, + + // Contains a reflection map to be used to reflect + // the environment. This is partially supported. + CHUNK_MAT_REFLMAP = 0xA220, + + // Self Illumination map (emissive colors) + CHUNK_MAT_SELFIMAP = 0xA33d, + + // Bumpmap. Not specified whether it is a heightmap + // or a normal map. Assme it is a heightmap since + // artist normally prefer this format. + CHUNK_MAT_BUMPMAP = 0xA230, + + // Specular map. Seems to influence the specular color + CHUNK_MAT_SPECMAP = 0xA204, + + // Holds shininess data. + CHUNK_MAT_MAT_SHINMAP = 0xA33C, + + // Scaling in U/V direction. + // (need to gen separate UV coordinate set + // and do this by hand) + CHUNK_MAT_MAP_USCALE = 0xA354, + CHUNK_MAT_MAP_VSCALE = 0xA356, + + // Translation in U/V direction. + // (need to gen separate UV coordinate set + // and do this by hand) + CHUNK_MAT_MAP_UOFFSET = 0xA358, + CHUNK_MAT_MAP_VOFFSET = 0xA35a, + + // UV-coordinates rotation around the z-axis + // Assumed to be in radians. + CHUNK_MAT_MAP_ANG = 0xA35C, + + // Tiling flags for 3DS files + CHUNK_MAT_MAP_TILING = 0xa351, + + // Specifies the file name of a texture + CHUNK_MAPFILE = 0xA300, + + // Specifies whether a materail requires two-sided rendering + CHUNK_MAT_TWO_SIDE = 0xA081, + // ******************************************************************** + + // Main keyframer chunk. Contains translation/rotation/scaling data + CHUNK_KEYFRAMER = 0xB000, + + // Supported sub chunks + CHUNK_TRACKINFO = 0xB002, + CHUNK_TRACKOBJNAME = 0xB010, + CHUNK_TRACKDUMMYOBJNAME = 0xB011, + CHUNK_TRACKPIVOT = 0xB013, + CHUNK_TRACKPOS = 0xB020, + CHUNK_TRACKROTATE = 0xB021, + CHUNK_TRACKSCALE = 0xB022, + + // ******************************************************************** + // Keyframes for various other stuff in the file + // Partially ignored + CHUNK_AMBIENTKEY = 0xB001, + CHUNK_TRACKMORPH = 0xB026, + CHUNK_TRACKHIDE = 0xB029, + CHUNK_OBJNUMBER = 0xB030, + CHUNK_TRACKCAMERA = 0xB003, + CHUNK_TRACKFOV = 0xB023, + CHUNK_TRACKROLL = 0xB024, + CHUNK_TRACKCAMTGT = 0xB004, + CHUNK_TRACKLIGHT = 0xB005, + CHUNK_TRACKLIGTGT = 0xB006, + CHUNK_TRACKSPOTL = 0xB007, + CHUNK_FRAMES = 0xB008, + // ******************************************************************** + + // light sub-chunks + CHUNK_DL_OFF = 0x4620, + CHUNK_DL_OUTER_RANGE = 0x465A, + CHUNK_DL_INNER_RANGE = 0x4659, + CHUNK_DL_MULTIPLIER = 0x465B, + CHUNK_DL_EXCLUDE = 0x4654, + CHUNK_DL_ATTENUATE = 0x4625, + CHUNK_DL_SPOTLIGHT = 0x4610, + + // camera sub-chunks + CHUNK_CAM_RANGES = 0x4720 + }; }; // --------------------------------------------------------------------------- @@ -318,38 +325,39 @@ struct Face : public FaceWithSmoothingGroup /** Helper structure representing a texture */ struct Texture { - //! Default constructor - Texture() - : mOffsetU (0.0f) - , mOffsetV (0.0f) - , mScaleU (1.0f) - , mScaleV (1.0f) - , mRotation (0.0f) - , mMapMode (aiTextureMapMode_Wrap) - , iUVSrc (0) - { - mTextureBlend = get_qnan(); - } - - //! Specifies the blend factor for the texture - float mTextureBlend; - - //! Specifies the filename of the texture - std::string mMapName; - - //! Specifies texture coordinate offsets/scaling/rotations - float mOffsetU; - float mOffsetV; - float mScaleU; - float mScaleV; - float mRotation; - - //! Specifies the mapping mode to be used for the texture - aiTextureMapMode mMapMode; - - //! Used internally - bool bPrivate; - int iUVSrc; + //! Default constructor + Texture() + : mOffsetU (0.0f) + , mOffsetV (0.0f) + , mScaleU (1.0f) + , mScaleV (1.0f) + , mRotation (0.0f) + , mMapMode (aiTextureMapMode_Wrap) + , bPrivate() + , iUVSrc (0) + { + mTextureBlend = get_qnan(); + } + + //! Specifies the blend factor for the texture + float mTextureBlend; + + //! Specifies the filename of the texture + std::string mMapName; + + //! Specifies texture coordinate offsets/scaling/rotations + float mOffsetU; + float mOffsetV; + float mScaleU; + float mScaleV; + float mRotation; + + //! Specifies the mapping mode to be used for the texture + aiTextureMapMode mMapMode; + + //! Used internally + bool bPrivate; + int iUVSrc; }; #include "./../include/assimp/Compiler/poppack1.h" @@ -358,117 +366,117 @@ struct Texture /** Helper structure representing a 3ds material */ struct Material { - //! Default constructor. Builds a default name for the material - Material() - : - mDiffuse (0.6f,0.6f,0.6f), // FIX ... we won't want object to be black - mSpecularExponent (0.0f), - mShininessStrength (1.0f), - mShading(Discreet3DS::Gouraud), - mTransparency (1.0f), - mBumpHeight (1.0f), - mTwoSided (false) - { - static int iCnt = 0; - - char szTemp[128]; - sprintf(szTemp,"UNNAMED_%i",iCnt++); - mName = szTemp; - } - - //! Name of the material - std::string mName; - //! Diffuse color of the material - aiColor3D mDiffuse; - //! Specular exponent - float mSpecularExponent; - //! Shininess strength, in percent - float mShininessStrength; - //! Specular color of the material - aiColor3D mSpecular; - //! Ambient color of the material - aiColor3D mAmbient; - //! Shading type to be used - Discreet3DS::shadetype3ds mShading; - //! Opacity of the material - float mTransparency; - //! Diffuse texture channel - Texture sTexDiffuse; - //! Opacity texture channel - Texture sTexOpacity; - //! Specular texture channel - Texture sTexSpecular; - //! Reflective texture channel - Texture sTexReflective; - //! Bump texture channel - Texture sTexBump; - //! Emissive texture channel - Texture sTexEmissive; - //! Shininess texture channel - Texture sTexShininess; - //! Scaling factor for the bump values - float mBumpHeight; - //! Emissive color - aiColor3D mEmissive; - //! Ambient texture channel - //! (used by the ASE format) - Texture sTexAmbient; - //! True if the material must be rendered from two sides - bool mTwoSided; + //! Default constructor. Builds a default name for the material + Material() + : + mDiffuse (0.6f,0.6f,0.6f), // FIX ... we won't want object to be black + mSpecularExponent (0.0f), + mShininessStrength (1.0f), + mShading(Discreet3DS::Gouraud), + mTransparency (1.0f), + mBumpHeight (1.0f), + mTwoSided (false) + { + static int iCnt = 0; + + char szTemp[128]; + ai_snprintf(szTemp, 128, "UNNAMED_%i",iCnt++); + mName = szTemp; + } + + //! Name of the material + std::string mName; + //! Diffuse color of the material + aiColor3D mDiffuse; + //! Specular exponent + float mSpecularExponent; + //! Shininess strength, in percent + float mShininessStrength; + //! Specular color of the material + aiColor3D mSpecular; + //! Ambient color of the material + aiColor3D mAmbient; + //! Shading type to be used + Discreet3DS::shadetype3ds mShading; + //! Opacity of the material + float mTransparency; + //! Diffuse texture channel + Texture sTexDiffuse; + //! Opacity texture channel + Texture sTexOpacity; + //! Specular texture channel + Texture sTexSpecular; + //! Reflective texture channel + Texture sTexReflective; + //! Bump texture channel + Texture sTexBump; + //! Emissive texture channel + Texture sTexEmissive; + //! Shininess texture channel + Texture sTexShininess; + //! Scaling factor for the bump values + float mBumpHeight; + //! Emissive color + aiColor3D mEmissive; + //! Ambient texture channel + //! (used by the ASE format) + Texture sTexAmbient; + //! True if the material must be rendered from two sides + bool mTwoSided; }; // --------------------------------------------------------------------------- /** Helper structure to represent a 3ds file mesh */ struct Mesh : public MeshWithSmoothingGroups { - //! Default constructor - Mesh() - { - static int iCnt = 0; - - // Generate a default name for the mesh - char szTemp[128]; - ::sprintf(szTemp,"UNNAMED_%i",iCnt++); - mName = szTemp; - } - - //! Name of the mesh - std::string mName; - - //! Texture coordinates - std::vector mTexCoords; - - //! Face materials - std::vector mFaceMaterials; - - //! Local transformation matrix - aiMatrix4x4 mMat; + //! Default constructor + Mesh() + { + static int iCnt = 0; + + // Generate a default name for the mesh + char szTemp[128]; + ai_snprintf(szTemp, 128, "UNNAMED_%i",iCnt++); + mName = szTemp; + } + + //! Name of the mesh + std::string mName; + + //! Texture coordinates + std::vector mTexCoords; + + //! Face materials + std::vector mFaceMaterials; + + //! Local transformation matrix + aiMatrix4x4 mMat; }; // --------------------------------------------------------------------------- /** Float key - quite similar to aiVectorKey and aiQuatKey. Both are in the C-API, so it would be difficult to make them a template. */ -struct aiFloatKey +struct aiFloatKey { - double mTime; ///< The time of this key - float mValue; ///< The value of this key + double mTime; ///< The time of this key + float mValue; ///< The value of this key #ifdef __cplusplus - // time is not compared - bool operator == (const aiFloatKey& o) const - {return o.mValue == this->mValue;} + // time is not compared + bool operator == (const aiFloatKey& o) const + {return o.mValue == this->mValue;} - bool operator != (const aiFloatKey& o) const - {return o.mValue != this->mValue;} + bool operator != (const aiFloatKey& o) const + {return o.mValue != this->mValue;} - // Only time is compared. This operator is defined - // for use with std::sort - bool operator < (const aiFloatKey& o) const - {return mTime < o.mTime;} + // Only time is compared. This operator is defined + // for use with std::sort + bool operator < (const aiFloatKey& o) const + {return mTime < o.mTime;} - bool operator > (const aiFloatKey& o) const - {return mTime < o.mTime;} + bool operator > (const aiFloatKey& o) const + {return mTime > o.mTime;} #endif }; @@ -477,104 +485,104 @@ struct aiFloatKey /** Helper structure to represent a 3ds file node */ struct Node { - Node() - - : mHierarchyPos (0) + Node(): + mParent(NULL) + , mInstanceNumber(0) + , mHierarchyPos (0) , mHierarchyIndex (0) , mInstanceCount (1) + { + static int iCnt = 0; - { - static int iCnt = 0; - - // Generate a default name for the node - char szTemp[128]; - ::sprintf(szTemp,"UNNAMED_%i",iCnt++); - mName = szTemp; + // Generate a default name for the node + char szTemp[128]; + ::ai_snprintf(szTemp, 128, "UNNAMED_%i",iCnt++); + mName = szTemp; - aRotationKeys.reserve (20); - aPositionKeys.reserve (20); - aScalingKeys.reserve (20); - } + aRotationKeys.reserve (20); + aPositionKeys.reserve (20); + aScalingKeys.reserve (20); + } - ~Node() - { - for (unsigned int i = 0; i < mChildren.size();++i) - delete mChildren[i]; - } + ~Node() + { + for (unsigned int i = 0; i < mChildren.size();++i) + delete mChildren[i]; + } - //! Pointer to the parent node - Node* mParent; + //! Pointer to the parent node + Node* mParent; - //! Holds all child nodes - std::vector mChildren; + //! Holds all child nodes + std::vector mChildren; - //! Name of the node - std::string mName; + //! Name of the node + std::string mName; - //! InstanceNumber of the node - int32_t mInstanceNumber; + //! InstanceNumber of the node + int32_t mInstanceNumber; - //! Dummy nodes: real name to be combined with the $$$DUMMY - std::string mDummyName; + //! Dummy nodes: real name to be combined with the $$$DUMMY + std::string mDummyName; - //! Position of the node in the hierarchy (tree depth) - int16_t mHierarchyPos; + //! Position of the node in the hierarchy (tree depth) + int16_t mHierarchyPos; - //! Index of the node - int16_t mHierarchyIndex; + //! Index of the node + int16_t mHierarchyIndex; - //! Rotation keys loaded from the file - std::vector aRotationKeys; + //! Rotation keys loaded from the file + std::vector aRotationKeys; - //! Position keys loaded from the file - std::vector aPositionKeys; + //! Position keys loaded from the file + std::vector aPositionKeys; - //! Scaling keys loaded from the file - std::vector aScalingKeys; + //! Scaling keys loaded from the file + std::vector aScalingKeys; - // For target lights (spot lights and directional lights): - // The position of the target - std::vector< aiVectorKey > aTargetPositionKeys; + // For target lights (spot lights and directional lights): + // The position of the target + std::vector< aiVectorKey > aTargetPositionKeys; - // For cameras: the camera roll angle - std::vector< aiFloatKey > aCameraRollKeys; + // For cameras: the camera roll angle + std::vector< aiFloatKey > aCameraRollKeys; - //! Pivot position loaded from the file - aiVector3D vPivot; + //! Pivot position loaded from the file + aiVector3D vPivot; - //instance count, will be kept only for the first node - int32_t mInstanceCount; + //instance count, will be kept only for the first node + int32_t mInstanceCount; - //! Add a child node, setup the right parent node for it - //! \param pc Node to be 'adopted' - inline Node& push_back(Node* pc) - { - mChildren.push_back(pc); - pc->mParent = this; - return *this; - } + //! Add a child node, setup the right parent node for it + //! \param pc Node to be 'adopted' + inline Node& push_back(Node* pc) + { + mChildren.push_back(pc); + pc->mParent = this; + return *this; + } }; // --------------------------------------------------------------------------- /** Helper structure analogue to aiScene */ struct Scene { - //! List of all materials loaded - //! NOTE: 3ds references materials globally - std::vector mMaterials; + //! List of all materials loaded + //! NOTE: 3ds references materials globally + std::vector mMaterials; - //! List of all meshes loaded - std::vector mMeshes; + //! List of all meshes loaded + std::vector mMeshes; - //! List of all cameras loaded - std::vector mCameras; + //! List of all cameras loaded + std::vector mCameras; - //! List of all lights loaded - std::vector mLights; + //! List of all lights loaded + std::vector mLights; - //! Pointer to the root node of the scene - // --- moved to main class - // Node* pcRootNode; + //! Pointer to the root node of the scene + // --- moved to main class + // Node* pcRootNode; }; diff --git a/src/3rdparty/assimp/code/3DSLoader.cpp b/src/3rdparty/assimp/code/3DSLoader.cpp index 137cceb1f..a2b73b2cb 100644 --- a/src/3rdparty/assimp/code/3DSLoader.cpp +++ b/src/3rdparty/assimp/code/3DSLoader.cpp @@ -3,12 +3,12 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2012, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above @@ -25,16 +25,16 @@ conditions are met: derived from this software without specific prior written permission of the assimp team. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --------------------------------------------------------------------------- */ @@ -45,554 +45,570 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * http://www.the-labs.com/Blender/3DS-details.html */ -#include "AssimpPCH.h" + #ifndef ASSIMP_BUILD_NO_3DS_IMPORTER // internal headers #include "3DSLoader.h" +#include "Macros.h" +#include +#include +#include +#include "StringComparison.h" using namespace Assimp; static const aiImporterDesc desc = { - "Discreet 3DS Importer", - "", - "", - "Limited animation support", - aiImporterFlags_SupportBinaryFlavour, - 0, - 0, - 0, - 0, - "3ds prj" + "Discreet 3DS Importer", + "", + "", + "Limited animation support", + aiImporterFlags_SupportBinaryFlavour, + 0, + 0, + 0, + 0, + "3ds prj" }; - + // ------------------------------------------------------------------------------------------------ // Begins a new parsing block // - Reads the current chunk and validates it // - computes its length #define ASSIMP_3DS_BEGIN_CHUNK() \ - while (true) { \ - if (stream->GetRemainingSizeToLimit() < sizeof(Discreet3DS::Chunk)){ \ - return; \ - } \ - Discreet3DS::Chunk chunk; \ - ReadChunk(&chunk); \ - int chunkSize = chunk.Size-sizeof(Discreet3DS::Chunk); \ + while (true) { \ + if (stream->GetRemainingSizeToLimit() < sizeof(Discreet3DS::Chunk)){ \ + return; \ + } \ + Discreet3DS::Chunk chunk; \ + ReadChunk(&chunk); \ + int chunkSize = chunk.Size-sizeof(Discreet3DS::Chunk); \ if(chunkSize <= 0) \ continue; \ - const int oldReadLimit = stream->GetReadLimit(); \ - stream->SetReadLimit(stream->GetCurrentPos() + chunkSize); \ - + const unsigned int oldReadLimit = stream->SetReadLimit( \ + stream->GetCurrentPos() + chunkSize); \ + // ------------------------------------------------------------------------------------------------ // End a parsing block // Must follow at the end of each parsing block, reset chunk end marker to previous value #define ASSIMP_3DS_END_CHUNK() \ - stream->SkipToReadLimit(); \ - stream->SetReadLimit(oldReadLimit); \ - if (stream->GetRemainingSizeToLimit() == 0) \ - return; \ - } + stream->SkipToReadLimit(); \ + stream->SetReadLimit(oldReadLimit); \ + if (stream->GetRemainingSizeToLimit() == 0) \ + return; \ + } // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer Discreet3DSImporter::Discreet3DSImporter() + : stream(), + mLastNodeIndex(), + mCurrentNode(), + mRootNode(), + mScene(), + mMasterScale(), + bHasBG(), + bIsPrj() {} // ------------------------------------------------------------------------------------------------ -// Destructor, private as well +// Destructor, private as well Discreet3DSImporter::~Discreet3DSImporter() {} // ------------------------------------------------------------------------------------------------ -// Returns whether the class can handle the format of the given file. +// Returns whether the class can handle the format of the given file. bool Discreet3DSImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const { - std::string extension = GetExtension(pFile); - if(extension == "3ds" || extension == "prj" ) { - return true; - } - if (!extension.length() || checkSig) { - uint16_t token[3]; - token[0] = 0x4d4d; - token[1] = 0x3dc2; - //token[2] = 0x3daa; - return CheckMagicToken(pIOHandler,pFile,token,2,0,2); - } - return false; + std::string extension = GetExtension(pFile); + if(extension == "3ds" || extension == "prj" ) { + return true; + } + if (!extension.length() || checkSig) { + uint16_t token[3]; + token[0] = 0x4d4d; + token[1] = 0x3dc2; + //token[2] = 0x3daa; + return CheckMagicToken(pIOHandler,pFile,token,2,0,2); + } + return false; } // ------------------------------------------------------------------------------------------------ // Loader registry entry const aiImporterDesc* Discreet3DSImporter::GetInfo () const { - return &desc; + return &desc; } // ------------------------------------------------------------------------------------------------ // Setup configuration properties void Discreet3DSImporter::SetupProperties(const Importer* /*pImp*/) { - // nothing to be done for the moment + // nothing to be done for the moment } // ------------------------------------------------------------------------------------------------ -// Imports the given file into the given scene structure. -void Discreet3DSImporter::InternReadFile( const std::string& pFile, - aiScene* pScene, IOSystem* pIOHandler) +// Imports the given file into the given scene structure. +void Discreet3DSImporter::InternReadFile( const std::string& pFile, + aiScene* pScene, IOSystem* pIOHandler) { - StreamReaderLE stream(pIOHandler->Open(pFile,"rb")); - this->stream = &stream; - - // We should have at least one chunk - if (stream.GetRemainingSize() < 16) { - throw DeadlyImportError("3DS file is either empty or corrupt: " + pFile); - } - - // Allocate our temporary 3DS representation - mScene = new D3DS::Scene(); - - // Initialize members - mLastNodeIndex = -1; - mCurrentNode = new D3DS::Node(); - mRootNode = mCurrentNode; - mRootNode->mHierarchyPos = -1; - mRootNode->mHierarchyIndex = -1; - mRootNode->mParent = NULL; - mMasterScale = 1.0f; - mBackgroundImage = ""; - bHasBG = false; - bIsPrj = false; - - // Parse the file - ParseMainChunk(); - - // Process all meshes in the file. First check whether all - // face indices haev valid values. The generate our - // internal verbose representation. Finally compute normal - // vectors from the smoothing groups we read from the - // file. - for (std::vector::iterator i = mScene->mMeshes.begin(), - end = mScene->mMeshes.end(); i != end;++i) { - CheckIndices(*i); - MakeUnique (*i); - ComputeNormalsWithSmoothingsGroups(*i); - } - - // Replace all occurences of the default material with a - // valid material. Generate it if no material containing - // DEFAULT in its name has been found in the file - ReplaceDefaultMaterial(); - - // Convert the scene from our internal representation to an - // aiScene object. This involves copying all meshes, lights - // and cameras to the scene - ConvertScene(pScene); - - // Generate the node graph for the scene. This is a little bit - // tricky since we'll need to split some meshes into submeshes - GenerateNodeGraph(pScene); - - // Now apply the master scaling factor to the scene - ApplyMasterScale(pScene); - - // Delete our internal scene representation and the root - // node, so the whole hierarchy will follow - delete mRootNode; - delete mScene; - - AI_DEBUG_INVALIDATE_PTR(mRootNode); - AI_DEBUG_INVALIDATE_PTR(mScene); - AI_DEBUG_INVALIDATE_PTR(this->stream); + StreamReaderLE stream(pIOHandler->Open(pFile,"rb")); + this->stream = &stream; + + // We should have at least one chunk + if (stream.GetRemainingSize() < 16) { + throw DeadlyImportError("3DS file is either empty or corrupt: " + pFile); + } + + // Allocate our temporary 3DS representation + mScene = new D3DS::Scene(); + + // Initialize members + mLastNodeIndex = -1; + mCurrentNode = new D3DS::Node(); + mRootNode = mCurrentNode; + mRootNode->mHierarchyPos = -1; + mRootNode->mHierarchyIndex = -1; + mRootNode->mParent = NULL; + mMasterScale = 1.0f; + mBackgroundImage = ""; + bHasBG = false; + bIsPrj = false; + + // Parse the file + ParseMainChunk(); + + // Process all meshes in the file. First check whether all + // face indices haev valid values. The generate our + // internal verbose representation. Finally compute normal + // vectors from the smoothing groups we read from the + // file. + for (auto &mesh : mScene->mMeshes) { + if (mesh.mFaces.size() > 0 && mesh.mPositions.size() == 0) { + delete mScene; + throw DeadlyImportError("3DS file contains faces but no vertices: " + pFile); + } + CheckIndices(mesh); + MakeUnique (mesh); + ComputeNormalsWithSmoothingsGroups(mesh); + } + + // Replace all occurrences of the default material with a + // valid material. Generate it if no material containing + // DEFAULT in its name has been found in the file + ReplaceDefaultMaterial(); + + // Convert the scene from our internal representation to an + // aiScene object. This involves copying all meshes, lights + // and cameras to the scene + ConvertScene(pScene); + + // Generate the node graph for the scene. This is a little bit + // tricky since we'll need to split some meshes into submeshes + GenerateNodeGraph(pScene); + + // Now apply the master scaling factor to the scene + ApplyMasterScale(pScene); + + // Delete our internal scene representation and the root + // node, so the whole hierarchy will follow + delete mRootNode; + delete mScene; + + AI_DEBUG_INVALIDATE_PTR(mRootNode); + AI_DEBUG_INVALIDATE_PTR(mScene); + AI_DEBUG_INVALIDATE_PTR(this->stream); } // ------------------------------------------------------------------------------------------------ // Applies a master-scaling factor to the imported scene void Discreet3DSImporter::ApplyMasterScale(aiScene* pScene) { - // There are some 3DS files with a zero scaling factor - if (!mMasterScale)mMasterScale = 1.0f; - else mMasterScale = 1.0f / mMasterScale; - - // Construct an uniform scaling matrix and multiply with it - pScene->mRootNode->mTransformation *= aiMatrix4x4( - mMasterScale,0.0f, 0.0f, 0.0f, - 0.0f, mMasterScale,0.0f, 0.0f, - 0.0f, 0.0f, mMasterScale,0.0f, - 0.0f, 0.0f, 0.0f, 1.0f); - - // Check whether a scaling track is assigned to the root node. + // There are some 3DS files with a zero scaling factor + if (!mMasterScale)mMasterScale = 1.0f; + else mMasterScale = 1.0f / mMasterScale; + + // Construct an uniform scaling matrix and multiply with it + pScene->mRootNode->mTransformation *= aiMatrix4x4( + mMasterScale,0.0f, 0.0f, 0.0f, + 0.0f, mMasterScale,0.0f, 0.0f, + 0.0f, 0.0f, mMasterScale,0.0f, + 0.0f, 0.0f, 0.0f, 1.0f); + + // Check whether a scaling track is assigned to the root node. } // ------------------------------------------------------------------------------------------------ // Reads a new chunk from the file void Discreet3DSImporter::ReadChunk(Discreet3DS::Chunk* pcOut) { - ai_assert(pcOut != NULL); + ai_assert(pcOut != NULL); - pcOut->Flag = stream->GetI2(); - pcOut->Size = stream->GetI4(); + pcOut->Flag = stream->GetI2(); + pcOut->Size = stream->GetI4(); - if (pcOut->Size - sizeof(Discreet3DS::Chunk) > stream->GetRemainingSize()) - throw DeadlyImportError("Chunk is too large"); - - if (pcOut->Size - sizeof(Discreet3DS::Chunk) > stream->GetRemainingSizeToLimit()) - DefaultLogger::get()->error("3DS: Chunk overflow"); + if (pcOut->Size - sizeof(Discreet3DS::Chunk) > stream->GetRemainingSize()) + throw DeadlyImportError("Chunk is too large"); + + if (pcOut->Size - sizeof(Discreet3DS::Chunk) > stream->GetRemainingSizeToLimit()) + DefaultLogger::get()->error("3DS: Chunk overflow"); } // ------------------------------------------------------------------------------------------------ // Skip a chunk void Discreet3DSImporter::SkipChunk() { - Discreet3DS::Chunk psChunk; - ReadChunk(&psChunk); - - stream->IncPtr(psChunk.Size-sizeof(Discreet3DS::Chunk)); - return; + Discreet3DS::Chunk psChunk; + ReadChunk(&psChunk); + + stream->IncPtr(psChunk.Size-sizeof(Discreet3DS::Chunk)); + return; } // ------------------------------------------------------------------------------------------------ // Process the primary chunk of the file void Discreet3DSImporter::ParseMainChunk() { - ASSIMP_3DS_BEGIN_CHUNK(); - - // get chunk type - switch (chunk.Flag) - { - - case Discreet3DS::CHUNK_PRJ: - bIsPrj = true; - case Discreet3DS::CHUNK_MAIN: - ParseEditorChunk(); - break; - }; - - ASSIMP_3DS_END_CHUNK(); - // recursively continue processing this hierarchy level - return ParseMainChunk(); + ASSIMP_3DS_BEGIN_CHUNK(); + + // get chunk type + switch (chunk.Flag) + { + + case Discreet3DS::CHUNK_PRJ: + bIsPrj = true; + case Discreet3DS::CHUNK_MAIN: + ParseEditorChunk(); + break; + }; + + ASSIMP_3DS_END_CHUNK(); + // recursively continue processing this hierarchy level + return ParseMainChunk(); } // ------------------------------------------------------------------------------------------------ void Discreet3DSImporter::ParseEditorChunk() { - ASSIMP_3DS_BEGIN_CHUNK(); - - // get chunk type - switch (chunk.Flag) - { - case Discreet3DS::CHUNK_OBJMESH: - - ParseObjectChunk(); - break; - - // NOTE: In several documentations in the internet this - // chunk appears at different locations - case Discreet3DS::CHUNK_KEYFRAMER: - - ParseKeyframeChunk(); - break; - - case Discreet3DS::CHUNK_VERSION: - { - // print the version number - char buff[10]; - ASSIMP_itoa10(buff,stream->GetI2()); - DefaultLogger::get()->info(std::string("3DS file format version: ") + buff); - } - break; - }; - ASSIMP_3DS_END_CHUNK(); + ASSIMP_3DS_BEGIN_CHUNK(); + + // get chunk type + switch (chunk.Flag) + { + case Discreet3DS::CHUNK_OBJMESH: + + ParseObjectChunk(); + break; + + // NOTE: In several documentations in the internet this + // chunk appears at different locations + case Discreet3DS::CHUNK_KEYFRAMER: + + ParseKeyframeChunk(); + break; + + case Discreet3DS::CHUNK_VERSION: + { + // print the version number + char buff[10]; + ASSIMP_itoa10(buff,stream->GetI2()); + DefaultLogger::get()->info(std::string("3DS file format version: ") + buff); + } + break; + }; + ASSIMP_3DS_END_CHUNK(); } // ------------------------------------------------------------------------------------------------ void Discreet3DSImporter::ParseObjectChunk() { - ASSIMP_3DS_BEGIN_CHUNK(); - - // get chunk type - switch (chunk.Flag) - { - case Discreet3DS::CHUNK_OBJBLOCK: - { - unsigned int cnt = 0; - const char* sz = (const char*)stream->GetPtr(); - - // Get the name of the geometry object - while (stream->GetI1())++cnt; - ParseChunk(sz,cnt); - } - break; - - case Discreet3DS::CHUNK_MAT_MATERIAL: - - // Add a new material to the list - mScene->mMaterials.push_back(D3DS::Material()); - ParseMaterialChunk(); - break; - - case Discreet3DS::CHUNK_AMBCOLOR: - - // This is the ambient base color of the scene. - // We add it to the ambient color of all materials - ParseColorChunk(&mClrAmbient,true); - if (is_qnan(mClrAmbient.r)) - { - // We failed to read the ambient base color. - DefaultLogger::get()->error("3DS: Failed to read ambient base color"); - mClrAmbient.r = mClrAmbient.g = mClrAmbient.b = 0.0f; - } - break; - - case Discreet3DS::CHUNK_BIT_MAP: - { - // Specifies the background image. The string should already be - // properly 0 terminated but we need to be sure - unsigned int cnt = 0; - const char* sz = (const char*)stream->GetPtr(); - while (stream->GetI1())++cnt; - mBackgroundImage = std::string(sz,cnt); - } - break; - - case Discreet3DS::CHUNK_BIT_MAP_EXISTS: - bHasBG = true; - break; - - case Discreet3DS::CHUNK_MASTER_SCALE: - // Scene master scaling factor - mMasterScale = stream->GetF4(); - break; - }; - ASSIMP_3DS_END_CHUNK(); + ASSIMP_3DS_BEGIN_CHUNK(); + + // get chunk type + switch (chunk.Flag) + { + case Discreet3DS::CHUNK_OBJBLOCK: + { + unsigned int cnt = 0; + const char* sz = (const char*)stream->GetPtr(); + + // Get the name of the geometry object + while (stream->GetI1())++cnt; + ParseChunk(sz,cnt); + } + break; + + case Discreet3DS::CHUNK_MAT_MATERIAL: + + // Add a new material to the list + mScene->mMaterials.push_back(D3DS::Material()); + ParseMaterialChunk(); + break; + + case Discreet3DS::CHUNK_AMBCOLOR: + + // This is the ambient base color of the scene. + // We add it to the ambient color of all materials + ParseColorChunk(&mClrAmbient,true); + if (is_qnan(mClrAmbient.r)) + { + // We failed to read the ambient base color. + DefaultLogger::get()->error("3DS: Failed to read ambient base color"); + mClrAmbient.r = mClrAmbient.g = mClrAmbient.b = 0.0f; + } + break; + + case Discreet3DS::CHUNK_BIT_MAP: + { + // Specifies the background image. The string should already be + // properly 0 terminated but we need to be sure + unsigned int cnt = 0; + const char* sz = (const char*)stream->GetPtr(); + while (stream->GetI1())++cnt; + mBackgroundImage = std::string(sz,cnt); + } + break; + + case Discreet3DS::CHUNK_BIT_MAP_EXISTS: + bHasBG = true; + break; + + case Discreet3DS::CHUNK_MASTER_SCALE: + // Scene master scaling factor + mMasterScale = stream->GetF4(); + break; + }; + ASSIMP_3DS_END_CHUNK(); } // ------------------------------------------------------------------------------------------------ void Discreet3DSImporter::ParseChunk(const char* name, unsigned int num) { - ASSIMP_3DS_BEGIN_CHUNK(); - - // IMPLEMENTATION NOTE; - // Cameras or lights define their transformation in their parent node and in the - // corresponding light or camera chunks. However, we read and process the latter - // to to be able to return valid cameras/lights even if no scenegraph is given. - - // get chunk type - switch (chunk.Flag) - { - case Discreet3DS::CHUNK_TRIMESH: - { - // this starts a new triangle mesh - mScene->mMeshes.push_back(D3DS::Mesh()); - D3DS::Mesh& m = mScene->mMeshes.back(); - - // Setup the name of the mesh - m.mName = std::string(name, num); - - // Read mesh chunks - ParseMeshChunk(); - } - break; - - case Discreet3DS::CHUNK_LIGHT: - { - // This starts a new light - aiLight* light = new aiLight(); - mScene->mLights.push_back(light); - - light->mName.Set(std::string(name, num)); - - // First read the position of the light - light->mPosition.x = stream->GetF4(); - light->mPosition.y = stream->GetF4(); - light->mPosition.z = stream->GetF4(); - - light->mColorDiffuse = aiColor3D(1.f,1.f,1.f); - - // Now check for further subchunks - if (!bIsPrj) /* fixme */ - ParseLightChunk(); - - // The specular light color is identical the the diffuse light color. The ambient light color - // is equal to the ambient base color of the whole scene. - light->mColorSpecular = light->mColorDiffuse; - light->mColorAmbient = mClrAmbient; - - if (light->mType == aiLightSource_UNDEFINED) - { - // It must be a point light - light->mType = aiLightSource_POINT; - }} - break; - - case Discreet3DS::CHUNK_CAMERA: - { - // This starts a new camera - aiCamera* camera = new aiCamera(); - mScene->mCameras.push_back(camera); - camera->mName.Set(std::string(name, num)); - - // First read the position of the camera - camera->mPosition.x = stream->GetF4(); - camera->mPosition.y = stream->GetF4(); - camera->mPosition.z = stream->GetF4(); - - // Then the camera target - camera->mLookAt.x = stream->GetF4() - camera->mPosition.x; - camera->mLookAt.y = stream->GetF4() - camera->mPosition.y; - camera->mLookAt.z = stream->GetF4() - camera->mPosition.z; - float len = camera->mLookAt.Length(); - if (len < 1e-5f) { - - // There are some files with lookat == position. Don't know why or whether it's ok or not. - DefaultLogger::get()->error("3DS: Unable to read proper camera look-at vector"); - camera->mLookAt = aiVector3D(0.f,1.f,0.f); - - } - else camera->mLookAt /= len; - - // And finally - the camera rotation angle, in counter clockwise direction - const float angle = AI_DEG_TO_RAD( stream->GetF4() ); - aiQuaternion quat(camera->mLookAt,angle); - camera->mUp = quat.GetMatrix() * aiVector3D(0.f,1.f,0.f); - - // Read the lense angle - camera->mHorizontalFOV = AI_DEG_TO_RAD ( stream->GetF4() ); - if (camera->mHorizontalFOV < 0.001f) { - camera->mHorizontalFOV = AI_DEG_TO_RAD(45.f); - } - - // Now check for further subchunks - if (!bIsPrj) /* fixme */ { - ParseCameraChunk(); - }} - break; - }; - ASSIMP_3DS_END_CHUNK(); + ASSIMP_3DS_BEGIN_CHUNK(); + + // IMPLEMENTATION NOTE; + // Cameras or lights define their transformation in their parent node and in the + // corresponding light or camera chunks. However, we read and process the latter + // to to be able to return valid cameras/lights even if no scenegraph is given. + + // get chunk type + switch (chunk.Flag) + { + case Discreet3DS::CHUNK_TRIMESH: + { + // this starts a new triangle mesh + mScene->mMeshes.push_back(D3DS::Mesh()); + D3DS::Mesh& m = mScene->mMeshes.back(); + + // Setup the name of the mesh + m.mName = std::string(name, num); + + // Read mesh chunks + ParseMeshChunk(); + } + break; + + case Discreet3DS::CHUNK_LIGHT: + { + // This starts a new light + aiLight* light = new aiLight(); + mScene->mLights.push_back(light); + + light->mName.Set(std::string(name, num)); + + // First read the position of the light + light->mPosition.x = stream->GetF4(); + light->mPosition.y = stream->GetF4(); + light->mPosition.z = stream->GetF4(); + + light->mColorDiffuse = aiColor3D(1.f,1.f,1.f); + + // Now check for further subchunks + if (!bIsPrj) /* fixme */ + ParseLightChunk(); + + // The specular light color is identical the the diffuse light color. The ambient light color + // is equal to the ambient base color of the whole scene. + light->mColorSpecular = light->mColorDiffuse; + light->mColorAmbient = mClrAmbient; + + if (light->mType == aiLightSource_UNDEFINED) + { + // It must be a point light + light->mType = aiLightSource_POINT; + }} + break; + + case Discreet3DS::CHUNK_CAMERA: + { + // This starts a new camera + aiCamera* camera = new aiCamera(); + mScene->mCameras.push_back(camera); + camera->mName.Set(std::string(name, num)); + + // First read the position of the camera + camera->mPosition.x = stream->GetF4(); + camera->mPosition.y = stream->GetF4(); + camera->mPosition.z = stream->GetF4(); + + // Then the camera target + camera->mLookAt.x = stream->GetF4() - camera->mPosition.x; + camera->mLookAt.y = stream->GetF4() - camera->mPosition.y; + camera->mLookAt.z = stream->GetF4() - camera->mPosition.z; + float len = camera->mLookAt.Length(); + if (len < 1e-5f) { + + // There are some files with lookat == position. Don't know why or whether it's ok or not. + DefaultLogger::get()->error("3DS: Unable to read proper camera look-at vector"); + camera->mLookAt = aiVector3D(0.f,1.f,0.f); + + } + else camera->mLookAt /= len; + + // And finally - the camera rotation angle, in counter clockwise direction + const float angle = AI_DEG_TO_RAD( stream->GetF4() ); + aiQuaternion quat(camera->mLookAt,angle); + camera->mUp = quat.GetMatrix() * aiVector3D(0.f,1.f,0.f); + + // Read the lense angle + camera->mHorizontalFOV = AI_DEG_TO_RAD ( stream->GetF4() ); + if (camera->mHorizontalFOV < 0.001f) { + camera->mHorizontalFOV = AI_DEG_TO_RAD(45.f); + } + + // Now check for further subchunks + if (!bIsPrj) /* fixme */ { + ParseCameraChunk(); + }} + break; + }; + ASSIMP_3DS_END_CHUNK(); } // ------------------------------------------------------------------------------------------------ void Discreet3DSImporter::ParseLightChunk() { - ASSIMP_3DS_BEGIN_CHUNK(); - aiLight* light = mScene->mLights.back(); - - // get chunk type - switch (chunk.Flag) - { - case Discreet3DS::CHUNK_DL_SPOTLIGHT: - // Now we can be sure that the light is a spot light - light->mType = aiLightSource_SPOT; - - // We wouldn't need to normalize here, but we do it - light->mDirection.x = stream->GetF4() - light->mPosition.x; - light->mDirection.y = stream->GetF4() - light->mPosition.y; - light->mDirection.z = stream->GetF4() - light->mPosition.z; - light->mDirection.Normalize(); - - // Now the hotspot and falloff angles - in degrees - light->mAngleInnerCone = AI_DEG_TO_RAD( stream->GetF4() ); - - // FIX: the falloff angle is just an offset - light->mAngleOuterCone = light->mAngleInnerCone+AI_DEG_TO_RAD( stream->GetF4() ); - break; - - // intensity multiplier - case Discreet3DS::CHUNK_DL_MULTIPLIER: - light->mColorDiffuse = light->mColorDiffuse * stream->GetF4(); - break; - - // light color - case Discreet3DS::CHUNK_RGBF: - case Discreet3DS::CHUNK_LINRGBF: - light->mColorDiffuse.r *= stream->GetF4(); - light->mColorDiffuse.g *= stream->GetF4(); - light->mColorDiffuse.b *= stream->GetF4(); - break; - - // light attenuation - case Discreet3DS::CHUNK_DL_ATTENUATE: - light->mAttenuationLinear = stream->GetF4(); - break; - }; - - ASSIMP_3DS_END_CHUNK(); + ASSIMP_3DS_BEGIN_CHUNK(); + aiLight* light = mScene->mLights.back(); + + // get chunk type + switch (chunk.Flag) + { + case Discreet3DS::CHUNK_DL_SPOTLIGHT: + // Now we can be sure that the light is a spot light + light->mType = aiLightSource_SPOT; + + // We wouldn't need to normalize here, but we do it + light->mDirection.x = stream->GetF4() - light->mPosition.x; + light->mDirection.y = stream->GetF4() - light->mPosition.y; + light->mDirection.z = stream->GetF4() - light->mPosition.z; + light->mDirection.Normalize(); + + // Now the hotspot and falloff angles - in degrees + light->mAngleInnerCone = AI_DEG_TO_RAD( stream->GetF4() ); + + // FIX: the falloff angle is just an offset + light->mAngleOuterCone = light->mAngleInnerCone+AI_DEG_TO_RAD( stream->GetF4() ); + break; + + // intensity multiplier + case Discreet3DS::CHUNK_DL_MULTIPLIER: + light->mColorDiffuse = light->mColorDiffuse * stream->GetF4(); + break; + + // light color + case Discreet3DS::CHUNK_RGBF: + case Discreet3DS::CHUNK_LINRGBF: + light->mColorDiffuse.r *= stream->GetF4(); + light->mColorDiffuse.g *= stream->GetF4(); + light->mColorDiffuse.b *= stream->GetF4(); + break; + + // light attenuation + case Discreet3DS::CHUNK_DL_ATTENUATE: + light->mAttenuationLinear = stream->GetF4(); + break; + }; + + ASSIMP_3DS_END_CHUNK(); } // ------------------------------------------------------------------------------------------------ void Discreet3DSImporter::ParseCameraChunk() { - ASSIMP_3DS_BEGIN_CHUNK(); - aiCamera* camera = mScene->mCameras.back(); - - // get chunk type - switch (chunk.Flag) - { - // near and far clip plane - case Discreet3DS::CHUNK_CAM_RANGES: - camera->mClipPlaneNear = stream->GetF4(); - camera->mClipPlaneFar = stream->GetF4(); - break; - } - - ASSIMP_3DS_END_CHUNK(); + ASSIMP_3DS_BEGIN_CHUNK(); + aiCamera* camera = mScene->mCameras.back(); + + // get chunk type + switch (chunk.Flag) + { + // near and far clip plane + case Discreet3DS::CHUNK_CAM_RANGES: + camera->mClipPlaneNear = stream->GetF4(); + camera->mClipPlaneFar = stream->GetF4(); + break; + } + + ASSIMP_3DS_END_CHUNK(); } // ------------------------------------------------------------------------------------------------ void Discreet3DSImporter::ParseKeyframeChunk() { - ASSIMP_3DS_BEGIN_CHUNK(); - - // get chunk type - switch (chunk.Flag) - { - case Discreet3DS::CHUNK_TRACKCAMTGT: - case Discreet3DS::CHUNK_TRACKSPOTL: - case Discreet3DS::CHUNK_TRACKCAMERA: - case Discreet3DS::CHUNK_TRACKINFO: - case Discreet3DS::CHUNK_TRACKLIGHT: - case Discreet3DS::CHUNK_TRACKLIGTGT: - - // this starts a new mesh hierarchy chunk - ParseHierarchyChunk(chunk.Flag); - break; - }; - - ASSIMP_3DS_END_CHUNK(); + ASSIMP_3DS_BEGIN_CHUNK(); + + // get chunk type + switch (chunk.Flag) + { + case Discreet3DS::CHUNK_TRACKCAMTGT: + case Discreet3DS::CHUNK_TRACKSPOTL: + case Discreet3DS::CHUNK_TRACKCAMERA: + case Discreet3DS::CHUNK_TRACKINFO: + case Discreet3DS::CHUNK_TRACKLIGHT: + case Discreet3DS::CHUNK_TRACKLIGTGT: + + // this starts a new mesh hierarchy chunk + ParseHierarchyChunk(chunk.Flag); + break; + }; + + ASSIMP_3DS_END_CHUNK(); } // ------------------------------------------------------------------------------------------------ // Little helper function for ParseHierarchyChunk void Discreet3DSImporter::InverseNodeSearch(D3DS::Node* pcNode,D3DS::Node* pcCurrent) { - if (!pcCurrent) { - mRootNode->push_back(pcNode); - return; - } - - if (pcCurrent->mHierarchyPos == pcNode->mHierarchyPos) { - if(pcCurrent->mParent) { - pcCurrent->mParent->push_back(pcNode); - } - else pcCurrent->push_back(pcNode); - return; - } - return InverseNodeSearch(pcNode,pcCurrent->mParent); + if (!pcCurrent) { + mRootNode->push_back(pcNode); + return; + } + + if (pcCurrent->mHierarchyPos == pcNode->mHierarchyPos) { + if(pcCurrent->mParent) { + pcCurrent->mParent->push_back(pcNode); + } + else pcCurrent->push_back(pcNode); + return; + } + return InverseNodeSearch(pcNode,pcCurrent->mParent); } // ------------------------------------------------------------------------------------------------ // Find a node with a specific name in the import hierarchy D3DS::Node* FindNode(D3DS::Node* root, const std::string& name) { - if (root->mName == name) - return root; - for (std::vector::iterator it = root->mChildren.begin();it != root->mChildren.end(); ++it) { - D3DS::Node* nd; - if (( nd = FindNode(*it,name))) - return nd; - } - return NULL; + if (root->mName == name) + return root; + for (std::vector::iterator it = root->mChildren.begin();it != root->mChildren.end(); ++it) { + D3DS::Node* nd; + if (( nd = FindNode(*it,name))) + return nd; + } + return NULL; } // ------------------------------------------------------------------------------------------------ @@ -600,803 +616,806 @@ D3DS::Node* FindNode(D3DS::Node* root, const std::string& name) template bool KeyUniqueCompare(const T& first, const T& second) { - return first.mTime == second.mTime; + return first.mTime == second.mTime; } // ------------------------------------------------------------------------------------------------ // Skip some additional import data. void Discreet3DSImporter::SkipTCBInfo() { - unsigned int flags = stream->GetI2(); - - if (!flags) { - // Currently we can't do anything with these values. They occur - // quite rare, so it wouldn't be worth the effort implementing - // them. 3DS ist not really suitable for complex animations, - // so full support is not required. - DefaultLogger::get()->warn("3DS: Skipping TCB animation info"); - } - - if (flags & Discreet3DS::KEY_USE_TENS) { - stream->IncPtr(4); - } - if (flags & Discreet3DS::KEY_USE_BIAS) { - stream->IncPtr(4); - } - if (flags & Discreet3DS::KEY_USE_CONT) { - stream->IncPtr(4); - } - if (flags & Discreet3DS::KEY_USE_EASE_FROM) { - stream->IncPtr(4); - } - if (flags & Discreet3DS::KEY_USE_EASE_TO) { - stream->IncPtr(4); - } + unsigned int flags = stream->GetI2(); + + if (!flags) { + // Currently we can't do anything with these values. They occur + // quite rare, so it wouldn't be worth the effort implementing + // them. 3DS ist not really suitable for complex animations, + // so full support is not required. + DefaultLogger::get()->warn("3DS: Skipping TCB animation info"); + } + + if (flags & Discreet3DS::KEY_USE_TENS) { + stream->IncPtr(4); + } + if (flags & Discreet3DS::KEY_USE_BIAS) { + stream->IncPtr(4); + } + if (flags & Discreet3DS::KEY_USE_CONT) { + stream->IncPtr(4); + } + if (flags & Discreet3DS::KEY_USE_EASE_FROM) { + stream->IncPtr(4); + } + if (flags & Discreet3DS::KEY_USE_EASE_TO) { + stream->IncPtr(4); + } } // ------------------------------------------------------------------------------------------------ // Read hierarchy and keyframe info void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent) { - ASSIMP_3DS_BEGIN_CHUNK(); - - // get chunk type - switch (chunk.Flag) - { - case Discreet3DS::CHUNK_TRACKOBJNAME: - - // This is the name of the object to which the track applies. The chunk also - // defines the position of this object in the hierarchy. - { - - // First of all: get the name of the object - unsigned int cnt = 0; - const char* sz = (const char*)stream->GetPtr(); - - while (stream->GetI1())++cnt; - std::string name = std::string(sz,cnt); - - // Now find out whether we have this node already (target animation channels - // are stored with a separate object ID) - D3DS::Node* pcNode = FindNode(mRootNode,name); - int instanceNumber = 1; - - if ( pcNode) - { - // if the source is not a CHUNK_TRACKINFO block it wont be an object instance - if (parent != Discreet3DS::CHUNK_TRACKINFO) - { - mCurrentNode = pcNode; - break; - } - pcNode->mInstanceCount++; - instanceNumber = pcNode->mInstanceCount; - } - pcNode = new D3DS::Node(); - pcNode->mName = name; - pcNode->mInstanceNumber = instanceNumber; - - // There are two unknown values which we can safely ignore - stream->IncPtr(4); - - // Now read the hierarchy position of the object - uint16_t hierarchy = stream->GetI2() + 1; - pcNode->mHierarchyPos = hierarchy; - pcNode->mHierarchyIndex = mLastNodeIndex; - - // And find a proper position in the graph for it - if (mCurrentNode && mCurrentNode->mHierarchyPos == hierarchy) { - - // add to the parent of the last touched node - mCurrentNode->mParent->push_back(pcNode); - mLastNodeIndex++; - } - else if(hierarchy >= mLastNodeIndex) { - - // place it at the current position in the hierarchy - mCurrentNode->push_back(pcNode); - mLastNodeIndex = hierarchy; - } - else { - // need to go back to the specified position in the hierarchy. - InverseNodeSearch(pcNode,mCurrentNode); - mLastNodeIndex++; - } - // Make this node the current node - mCurrentNode = pcNode; - } - break; - - case Discreet3DS::CHUNK_TRACKDUMMYOBJNAME: - - // This is the "real" name of a $$$DUMMY object - { - const char* sz = (const char*) stream->GetPtr(); - while (stream->GetI1()); - - // If object name is DUMMY, take this one instead - if (mCurrentNode->mName == "$$$DUMMY") { - //DefaultLogger::get()->warn("3DS: Skipping dummy object name for non-dummy object"); - mCurrentNode->mName = std::string(sz); - break; - } - } - break; - - case Discreet3DS::CHUNK_TRACKPIVOT: - - if ( Discreet3DS::CHUNK_TRACKINFO != parent) - { - DefaultLogger::get()->warn("3DS: Skipping pivot subchunk for non usual object"); - break; - } - - // Pivot = origin of rotation and scaling - mCurrentNode->vPivot.x = stream->GetF4(); - mCurrentNode->vPivot.y = stream->GetF4(); - mCurrentNode->vPivot.z = stream->GetF4(); - break; - - - // //////////////////////////////////////////////////////////////////// - // POSITION KEYFRAME - case Discreet3DS::CHUNK_TRACKPOS: - { - stream->IncPtr(10); - const unsigned int numFrames = stream->GetI4(); - bool sortKeys = false; - - // This could also be meant as the target position for - // (targeted) lights and cameras - std::vector* l; - if ( Discreet3DS::CHUNK_TRACKCAMTGT == parent || Discreet3DS::CHUNK_TRACKLIGTGT == parent) { - l = & mCurrentNode->aTargetPositionKeys; - } - else l = & mCurrentNode->aPositionKeys; - - l->reserve(numFrames); - for (unsigned int i = 0; i < numFrames;++i) { - const unsigned int fidx = stream->GetI4(); - - // Setup a new position key - aiVectorKey v; - v.mTime = (double)fidx; - - SkipTCBInfo(); - v.mValue.x = stream->GetF4(); - v.mValue.y = stream->GetF4(); - v.mValue.z = stream->GetF4(); - - // check whether we'll need to sort the keys - if (!l->empty() && v.mTime <= l->back().mTime) - sortKeys = true; - - // Add the new keyframe to the list - l->push_back(v); - } - - // Sort all keys with ascending time values and remove duplicates? - if (sortKeys) { - std::stable_sort(l->begin(),l->end()); - l->erase ( std::unique (l->begin(),l->end(),&KeyUniqueCompare), l->end() ); - }} - - break; - - // //////////////////////////////////////////////////////////////////// - // CAMERA ROLL KEYFRAME - case Discreet3DS::CHUNK_TRACKROLL: - { - // roll keys are accepted for cameras only - if (parent != Discreet3DS::CHUNK_TRACKCAMERA) { - DefaultLogger::get()->warn("3DS: Ignoring roll track for non-camera object"); - break; - } - bool sortKeys = false; - std::vector* l = &mCurrentNode->aCameraRollKeys; - - stream->IncPtr(10); - const unsigned int numFrames = stream->GetI4(); - l->reserve(numFrames); - for (unsigned int i = 0; i < numFrames;++i) { - const unsigned int fidx = stream->GetI4(); - - // Setup a new position key - aiFloatKey v; - v.mTime = (double)fidx; - - // This is just a single float - SkipTCBInfo(); - v.mValue = stream->GetF4(); - - // Check whether we'll need to sort the keys - if (!l->empty() && v.mTime <= l->back().mTime) - sortKeys = true; - - // Add the new keyframe to the list - l->push_back(v); - } - - // Sort all keys with ascending time values and remove duplicates? - if (sortKeys) { - std::stable_sort(l->begin(),l->end()); - l->erase ( std::unique (l->begin(),l->end(),&KeyUniqueCompare), l->end() ); - }} - break; - - - // //////////////////////////////////////////////////////////////////// - // CAMERA FOV KEYFRAME - case Discreet3DS::CHUNK_TRACKFOV: - { - DefaultLogger::get()->error("3DS: Skipping FOV animation track. " - "This is not supported"); - } - break; - - - // //////////////////////////////////////////////////////////////////// - // ROTATION KEYFRAME - case Discreet3DS::CHUNK_TRACKROTATE: - { - stream->IncPtr(10); - const unsigned int numFrames = stream->GetI4(); - - bool sortKeys = false; - std::vector* l = &mCurrentNode->aRotationKeys; - l->reserve(numFrames); - - for (unsigned int i = 0; i < numFrames;++i) { - const unsigned int fidx = stream->GetI4(); - SkipTCBInfo(); - - aiQuatKey v; - v.mTime = (double)fidx; - - // The rotation keyframe is given as an axis-angle pair - const float rad = stream->GetF4(); - aiVector3D axis; - axis.x = stream->GetF4(); - axis.y = stream->GetF4(); - axis.z = stream->GetF4(); - - if (!axis.x && !axis.y && !axis.z) - axis.y = 1.f; - - // Construct a rotation quaternion from the axis-angle pair - v.mValue = aiQuaternion(axis,rad); - - // Check whether we'll need to sort the keys - if (!l->empty() && v.mTime <= l->back().mTime) - sortKeys = true; - - // add the new keyframe to the list - l->push_back(v); - } - // Sort all keys with ascending time values and remove duplicates? - if (sortKeys) { - std::stable_sort(l->begin(),l->end()); - l->erase ( std::unique (l->begin(),l->end(),&KeyUniqueCompare), l->end() ); - }} - break; - - // //////////////////////////////////////////////////////////////////// - // SCALING KEYFRAME - case Discreet3DS::CHUNK_TRACKSCALE: - { - stream->IncPtr(10); - const unsigned int numFrames = stream->GetI2(); - stream->IncPtr(2); - - bool sortKeys = false; - std::vector* l = &mCurrentNode->aScalingKeys; - l->reserve(numFrames); - - for (unsigned int i = 0; i < numFrames;++i) { - const unsigned int fidx = stream->GetI4(); - SkipTCBInfo(); - - // Setup a new key - aiVectorKey v; - v.mTime = (double)fidx; - - // ... and read its value - v.mValue.x = stream->GetF4(); - v.mValue.y = stream->GetF4(); - v.mValue.z = stream->GetF4(); - - // check whether we'll need to sort the keys - if (!l->empty() && v.mTime <= l->back().mTime) - sortKeys = true; - - // Remove zero-scalings on singular axes - they've been reported to be there erroneously in some strange files - if (!v.mValue.x) v.mValue.x = 1.f; - if (!v.mValue.y) v.mValue.y = 1.f; - if (!v.mValue.z) v.mValue.z = 1.f; - - l->push_back(v); - } - // Sort all keys with ascending time values and remove duplicates? - if (sortKeys) { - std::stable_sort(l->begin(),l->end()); - l->erase ( std::unique (l->begin(),l->end(),&KeyUniqueCompare), l->end() ); - }} - break; - }; - - ASSIMP_3DS_END_CHUNK(); + ASSIMP_3DS_BEGIN_CHUNK(); + + // get chunk type + switch (chunk.Flag) + { + case Discreet3DS::CHUNK_TRACKOBJNAME: + + // This is the name of the object to which the track applies. The chunk also + // defines the position of this object in the hierarchy. + { + + // First of all: get the name of the object + unsigned int cnt = 0; + const char* sz = (const char*)stream->GetPtr(); + + while (stream->GetI1())++cnt; + std::string name = std::string(sz,cnt); + + // Now find out whether we have this node already (target animation channels + // are stored with a separate object ID) + D3DS::Node* pcNode = FindNode(mRootNode,name); + int instanceNumber = 1; + + if ( pcNode) + { + // if the source is not a CHUNK_TRACKINFO block it wont be an object instance + if (parent != Discreet3DS::CHUNK_TRACKINFO) + { + mCurrentNode = pcNode; + break; + } + pcNode->mInstanceCount++; + instanceNumber = pcNode->mInstanceCount; + } + pcNode = new D3DS::Node(); + pcNode->mName = name; + pcNode->mInstanceNumber = instanceNumber; + + // There are two unknown values which we can safely ignore + stream->IncPtr(4); + + // Now read the hierarchy position of the object + uint16_t hierarchy = stream->GetI2() + 1; + pcNode->mHierarchyPos = hierarchy; + pcNode->mHierarchyIndex = mLastNodeIndex; + + // And find a proper position in the graph for it + if (mCurrentNode && mCurrentNode->mHierarchyPos == hierarchy) { + + // add to the parent of the last touched node + mCurrentNode->mParent->push_back(pcNode); + mLastNodeIndex++; + } + else if(hierarchy >= mLastNodeIndex) { + + // place it at the current position in the hierarchy + mCurrentNode->push_back(pcNode); + mLastNodeIndex = hierarchy; + } + else { + // need to go back to the specified position in the hierarchy. + InverseNodeSearch(pcNode,mCurrentNode); + mLastNodeIndex++; + } + // Make this node the current node + mCurrentNode = pcNode; + } + break; + + case Discreet3DS::CHUNK_TRACKDUMMYOBJNAME: + + // This is the "real" name of a $$$DUMMY object + { + const char* sz = (const char*) stream->GetPtr(); + while (stream->GetI1()); + + // If object name is DUMMY, take this one instead + if (mCurrentNode->mName == "$$$DUMMY") { + //DefaultLogger::get()->warn("3DS: Skipping dummy object name for non-dummy object"); + mCurrentNode->mName = std::string(sz); + break; + } + } + break; + + case Discreet3DS::CHUNK_TRACKPIVOT: + + if ( Discreet3DS::CHUNK_TRACKINFO != parent) + { + DefaultLogger::get()->warn("3DS: Skipping pivot subchunk for non usual object"); + break; + } + + // Pivot = origin of rotation and scaling + mCurrentNode->vPivot.x = stream->GetF4(); + mCurrentNode->vPivot.y = stream->GetF4(); + mCurrentNode->vPivot.z = stream->GetF4(); + break; + + + // //////////////////////////////////////////////////////////////////// + // POSITION KEYFRAME + case Discreet3DS::CHUNK_TRACKPOS: + { + stream->IncPtr(10); + const unsigned int numFrames = stream->GetI4(); + bool sortKeys = false; + + // This could also be meant as the target position for + // (targeted) lights and cameras + std::vector* l; + if ( Discreet3DS::CHUNK_TRACKCAMTGT == parent || Discreet3DS::CHUNK_TRACKLIGTGT == parent) { + l = & mCurrentNode->aTargetPositionKeys; + } + else l = & mCurrentNode->aPositionKeys; + + l->reserve(numFrames); + for (unsigned int i = 0; i < numFrames;++i) { + const unsigned int fidx = stream->GetI4(); + + // Setup a new position key + aiVectorKey v; + v.mTime = (double)fidx; + + SkipTCBInfo(); + v.mValue.x = stream->GetF4(); + v.mValue.y = stream->GetF4(); + v.mValue.z = stream->GetF4(); + + // check whether we'll need to sort the keys + if (!l->empty() && v.mTime <= l->back().mTime) + sortKeys = true; + + // Add the new keyframe to the list + l->push_back(v); + } + + // Sort all keys with ascending time values and remove duplicates? + if (sortKeys) { + std::stable_sort(l->begin(),l->end()); + l->erase ( std::unique (l->begin(),l->end(),&KeyUniqueCompare), l->end() ); + }} + + break; + + // //////////////////////////////////////////////////////////////////// + // CAMERA ROLL KEYFRAME + case Discreet3DS::CHUNK_TRACKROLL: + { + // roll keys are accepted for cameras only + if (parent != Discreet3DS::CHUNK_TRACKCAMERA) { + DefaultLogger::get()->warn("3DS: Ignoring roll track for non-camera object"); + break; + } + bool sortKeys = false; + std::vector* l = &mCurrentNode->aCameraRollKeys; + + stream->IncPtr(10); + const unsigned int numFrames = stream->GetI4(); + l->reserve(numFrames); + for (unsigned int i = 0; i < numFrames;++i) { + const unsigned int fidx = stream->GetI4(); + + // Setup a new position key + aiFloatKey v; + v.mTime = (double)fidx; + + // This is just a single float + SkipTCBInfo(); + v.mValue = stream->GetF4(); + + // Check whether we'll need to sort the keys + if (!l->empty() && v.mTime <= l->back().mTime) + sortKeys = true; + + // Add the new keyframe to the list + l->push_back(v); + } + + // Sort all keys with ascending time values and remove duplicates? + if (sortKeys) { + std::stable_sort(l->begin(),l->end()); + l->erase ( std::unique (l->begin(),l->end(),&KeyUniqueCompare), l->end() ); + }} + break; + + + // //////////////////////////////////////////////////////////////////// + // CAMERA FOV KEYFRAME + case Discreet3DS::CHUNK_TRACKFOV: + { + DefaultLogger::get()->error("3DS: Skipping FOV animation track. " + "This is not supported"); + } + break; + + + // //////////////////////////////////////////////////////////////////// + // ROTATION KEYFRAME + case Discreet3DS::CHUNK_TRACKROTATE: + { + stream->IncPtr(10); + const unsigned int numFrames = stream->GetI4(); + + bool sortKeys = false; + std::vector* l = &mCurrentNode->aRotationKeys; + l->reserve(numFrames); + + for (unsigned int i = 0; i < numFrames;++i) { + const unsigned int fidx = stream->GetI4(); + SkipTCBInfo(); + + aiQuatKey v; + v.mTime = (double)fidx; + + // The rotation keyframe is given as an axis-angle pair + const float rad = stream->GetF4(); + aiVector3D axis; + axis.x = stream->GetF4(); + axis.y = stream->GetF4(); + axis.z = stream->GetF4(); + + if (!axis.x && !axis.y && !axis.z) + axis.y = 1.f; + + // Construct a rotation quaternion from the axis-angle pair + v.mValue = aiQuaternion(axis,rad); + + // Check whether we'll need to sort the keys + if (!l->empty() && v.mTime <= l->back().mTime) + sortKeys = true; + + // add the new keyframe to the list + l->push_back(v); + } + // Sort all keys with ascending time values and remove duplicates? + if (sortKeys) { + std::stable_sort(l->begin(),l->end()); + l->erase ( std::unique (l->begin(),l->end(),&KeyUniqueCompare), l->end() ); + }} + break; + + // //////////////////////////////////////////////////////////////////// + // SCALING KEYFRAME + case Discreet3DS::CHUNK_TRACKSCALE: + { + stream->IncPtr(10); + const unsigned int numFrames = stream->GetI2(); + stream->IncPtr(2); + + bool sortKeys = false; + std::vector* l = &mCurrentNode->aScalingKeys; + l->reserve(numFrames); + + for (unsigned int i = 0; i < numFrames;++i) { + const unsigned int fidx = stream->GetI4(); + SkipTCBInfo(); + + // Setup a new key + aiVectorKey v; + v.mTime = (double)fidx; + + // ... and read its value + v.mValue.x = stream->GetF4(); + v.mValue.y = stream->GetF4(); + v.mValue.z = stream->GetF4(); + + // check whether we'll need to sort the keys + if (!l->empty() && v.mTime <= l->back().mTime) + sortKeys = true; + + // Remove zero-scalings on singular axes - they've been reported to be there erroneously in some strange files + if (!v.mValue.x) v.mValue.x = 1.f; + if (!v.mValue.y) v.mValue.y = 1.f; + if (!v.mValue.z) v.mValue.z = 1.f; + + l->push_back(v); + } + // Sort all keys with ascending time values and remove duplicates? + if (sortKeys) { + std::stable_sort(l->begin(),l->end()); + l->erase ( std::unique (l->begin(),l->end(),&KeyUniqueCompare), l->end() ); + }} + break; + }; + + ASSIMP_3DS_END_CHUNK(); } // ------------------------------------------------------------------------------------------------ // Read a face chunk - it contains smoothing groups and material assignments void Discreet3DSImporter::ParseFaceChunk() { - ASSIMP_3DS_BEGIN_CHUNK(); - - // Get the mesh we're currently working on - D3DS::Mesh& mMesh = mScene->mMeshes.back(); - - // Get chunk type - switch (chunk.Flag) - { - case Discreet3DS::CHUNK_SMOOLIST: - { - // This is the list of smoothing groups - a bitfield for every face. - // Up to 32 smoothing groups assigned to a single face. - unsigned int num = chunkSize/4, m = 0; - for (std::vector::iterator i = mMesh.mFaces.begin(); m != num;++i, ++m) { - // nth bit is set for nth smoothing group - (*i).iSmoothGroup = stream->GetI4(); - }} - break; - - case Discreet3DS::CHUNK_FACEMAT: - { - // at fist an asciiz with the material name - const char* sz = (const char*)stream->GetPtr(); - while (stream->GetI1()); - - // find the index of the material - unsigned int idx = 0xcdcdcdcd, cnt = 0; - for (std::vector::const_iterator i = mScene->mMaterials.begin();i != mScene->mMaterials.end();++i,++cnt) { - // use case independent comparisons. hopefully it will work. - if ((*i).mName.length() && !ASSIMP_stricmp(sz, (*i).mName.c_str())) { - idx = cnt; - break; - } - } - if (0xcdcdcdcd == idx) { - DefaultLogger::get()->error(std::string("3DS: Unknown material: ") + sz); - } - - // Now continue and read all material indices - cnt = (uint16_t)stream->GetI2(); - for (unsigned int i = 0; i < cnt;++i) { - unsigned int fidx = (uint16_t)stream->GetI2(); - - // check range - if (fidx >= mMesh.mFaceMaterials.size()) { - DefaultLogger::get()->error("3DS: Invalid face index in face material list"); - } - else mMesh.mFaceMaterials[fidx] = idx; - }} - break; - }; - ASSIMP_3DS_END_CHUNK(); + ASSIMP_3DS_BEGIN_CHUNK(); + + // Get the mesh we're currently working on + D3DS::Mesh& mMesh = mScene->mMeshes.back(); + + // Get chunk type + switch (chunk.Flag) + { + case Discreet3DS::CHUNK_SMOOLIST: + { + // This is the list of smoothing groups - a bitfield for every face. + // Up to 32 smoothing groups assigned to a single face. + unsigned int num = chunkSize/4, m = 0; + if (num > mMesh.mFaces.size()) { + throw DeadlyImportError("3DS: More smoothing groups than faces"); + } + for (std::vector::iterator i = mMesh.mFaces.begin(); m != num;++i, ++m) { + // nth bit is set for nth smoothing group + (*i).iSmoothGroup = stream->GetI4(); + }} + break; + + case Discreet3DS::CHUNK_FACEMAT: + { + // at fist an asciiz with the material name + const char* sz = (const char*)stream->GetPtr(); + while (stream->GetI1()); + + // find the index of the material + unsigned int idx = 0xcdcdcdcd, cnt = 0; + for (std::vector::const_iterator i = mScene->mMaterials.begin();i != mScene->mMaterials.end();++i,++cnt) { + // use case independent comparisons. hopefully it will work. + if ((*i).mName.length() && !ASSIMP_stricmp(sz, (*i).mName.c_str())) { + idx = cnt; + break; + } + } + if (0xcdcdcdcd == idx) { + DefaultLogger::get()->error(std::string("3DS: Unknown material: ") + sz); + } + + // Now continue and read all material indices + cnt = (uint16_t)stream->GetI2(); + for (unsigned int i = 0; i < cnt;++i) { + unsigned int fidx = (uint16_t)stream->GetI2(); + + // check range + if (fidx >= mMesh.mFaceMaterials.size()) { + DefaultLogger::get()->error("3DS: Invalid face index in face material list"); + } + else mMesh.mFaceMaterials[fidx] = idx; + }} + break; + }; + ASSIMP_3DS_END_CHUNK(); } // ------------------------------------------------------------------------------------------------ // Read a mesh chunk. Here's the actual mesh data void Discreet3DSImporter::ParseMeshChunk() { - ASSIMP_3DS_BEGIN_CHUNK(); - - // Get the mesh we're currently working on - D3DS::Mesh& mMesh = mScene->mMeshes.back(); - - // get chunk type - switch (chunk.Flag) - { - case Discreet3DS::CHUNK_VERTLIST: - { - // This is the list of all vertices in the current mesh - int num = (int)(uint16_t)stream->GetI2(); - mMesh.mPositions.reserve(num); - while (num-- > 0) { - aiVector3D v; - v.x = stream->GetF4(); - v.y = stream->GetF4(); - v.z = stream->GetF4(); - mMesh.mPositions.push_back(v); - }} - break; - case Discreet3DS::CHUNK_TRMATRIX: - { - // This is the RLEATIVE transformation matrix of the current mesh. Vertices are - // pretransformed by this matrix wonder. - mMesh.mMat.a1 = stream->GetF4(); - mMesh.mMat.b1 = stream->GetF4(); - mMesh.mMat.c1 = stream->GetF4(); - mMesh.mMat.a2 = stream->GetF4(); - mMesh.mMat.b2 = stream->GetF4(); - mMesh.mMat.c2 = stream->GetF4(); - mMesh.mMat.a3 = stream->GetF4(); - mMesh.mMat.b3 = stream->GetF4(); - mMesh.mMat.c3 = stream->GetF4(); - mMesh.mMat.a4 = stream->GetF4(); - mMesh.mMat.b4 = stream->GetF4(); - mMesh.mMat.c4 = stream->GetF4(); - } - break; - - case Discreet3DS::CHUNK_MAPLIST: - { - // This is the list of all UV coords in the current mesh - int num = (int)(uint16_t)stream->GetI2(); - mMesh.mTexCoords.reserve(num); - while (num-- > 0) { - aiVector3D v; - v.x = stream->GetF4(); - v.y = stream->GetF4(); - mMesh.mTexCoords.push_back(v); - }} - break; - - case Discreet3DS::CHUNK_FACELIST: - { - // This is the list of all faces in the current mesh - int num = (int)(uint16_t)stream->GetI2(); - mMesh.mFaces.reserve(num); - while (num-- > 0) { - // 3DS faces are ALWAYS triangles - mMesh.mFaces.push_back(D3DS::Face()); - D3DS::Face& sFace = mMesh.mFaces.back(); - - sFace.mIndices[0] = (uint16_t)stream->GetI2(); - sFace.mIndices[1] = (uint16_t)stream->GetI2(); - sFace.mIndices[2] = (uint16_t)stream->GetI2(); - - stream->IncPtr(2); // skip edge visibility flag - } - - // Resize the material array (0xcdcdcdcd marks the default material; so if a face is - // not referenced by a material, $$DEFAULT will be assigned to it) - mMesh.mFaceMaterials.resize(mMesh.mFaces.size(),0xcdcdcdcd); - - // Larger 3DS files could have multiple FACE chunks here - chunkSize = stream->GetRemainingSizeToLimit(); - if ( chunkSize > (int) sizeof(Discreet3DS::Chunk ) ) - ParseFaceChunk(); - } - break; - }; - ASSIMP_3DS_END_CHUNK(); + ASSIMP_3DS_BEGIN_CHUNK(); + + // Get the mesh we're currently working on + D3DS::Mesh& mMesh = mScene->mMeshes.back(); + + // get chunk type + switch (chunk.Flag) + { + case Discreet3DS::CHUNK_VERTLIST: + { + // This is the list of all vertices in the current mesh + int num = (int)(uint16_t)stream->GetI2(); + mMesh.mPositions.reserve(num); + while (num-- > 0) { + aiVector3D v; + v.x = stream->GetF4(); + v.y = stream->GetF4(); + v.z = stream->GetF4(); + mMesh.mPositions.push_back(v); + }} + break; + case Discreet3DS::CHUNK_TRMATRIX: + { + // This is the RLEATIVE transformation matrix of the current mesh. Vertices are + // pretransformed by this matrix wonder. + mMesh.mMat.a1 = stream->GetF4(); + mMesh.mMat.b1 = stream->GetF4(); + mMesh.mMat.c1 = stream->GetF4(); + mMesh.mMat.a2 = stream->GetF4(); + mMesh.mMat.b2 = stream->GetF4(); + mMesh.mMat.c2 = stream->GetF4(); + mMesh.mMat.a3 = stream->GetF4(); + mMesh.mMat.b3 = stream->GetF4(); + mMesh.mMat.c3 = stream->GetF4(); + mMesh.mMat.a4 = stream->GetF4(); + mMesh.mMat.b4 = stream->GetF4(); + mMesh.mMat.c4 = stream->GetF4(); + } + break; + + case Discreet3DS::CHUNK_MAPLIST: + { + // This is the list of all UV coords in the current mesh + int num = (int)(uint16_t)stream->GetI2(); + mMesh.mTexCoords.reserve(num); + while (num-- > 0) { + aiVector3D v; + v.x = stream->GetF4(); + v.y = stream->GetF4(); + mMesh.mTexCoords.push_back(v); + }} + break; + + case Discreet3DS::CHUNK_FACELIST: + { + // This is the list of all faces in the current mesh + int num = (int)(uint16_t)stream->GetI2(); + mMesh.mFaces.reserve(num); + while (num-- > 0) { + // 3DS faces are ALWAYS triangles + mMesh.mFaces.push_back(D3DS::Face()); + D3DS::Face& sFace = mMesh.mFaces.back(); + + sFace.mIndices[0] = (uint16_t)stream->GetI2(); + sFace.mIndices[1] = (uint16_t)stream->GetI2(); + sFace.mIndices[2] = (uint16_t)stream->GetI2(); + + stream->IncPtr(2); // skip edge visibility flag + } + + // Resize the material array (0xcdcdcdcd marks the default material; so if a face is + // not referenced by a material, $$DEFAULT will be assigned to it) + mMesh.mFaceMaterials.resize(mMesh.mFaces.size(),0xcdcdcdcd); + + // Larger 3DS files could have multiple FACE chunks here + chunkSize = stream->GetRemainingSizeToLimit(); + if ( chunkSize > (int) sizeof(Discreet3DS::Chunk ) ) + ParseFaceChunk(); + } + break; + }; + ASSIMP_3DS_END_CHUNK(); } // ------------------------------------------------------------------------------------------------ // Read a 3DS material chunk void Discreet3DSImporter::ParseMaterialChunk() { - ASSIMP_3DS_BEGIN_CHUNK(); - switch (chunk.Flag) - { - case Discreet3DS::CHUNK_MAT_MATNAME: - - { - // The material name string is already zero-terminated, but we need to be sure ... - const char* sz = (const char*)stream->GetPtr(); - unsigned int cnt = 0; - while (stream->GetI1()) - ++cnt; - - if (!cnt) { - // This may not be, we use the default name instead - DefaultLogger::get()->error("3DS: Empty material name"); - } - else mScene->mMaterials.back().mName = std::string(sz,cnt); - } - break; - - case Discreet3DS::CHUNK_MAT_DIFFUSE: - { - // This is the diffuse material color - aiColor3D* pc = &mScene->mMaterials.back().mDiffuse; - ParseColorChunk(pc); - if (is_qnan(pc->r)) { - // color chunk is invalid. Simply ignore it - DefaultLogger::get()->error("3DS: Unable to read DIFFUSE chunk"); - pc->r = pc->g = pc->b = 1.0f; - }} - break; - - case Discreet3DS::CHUNK_MAT_SPECULAR: - { - // This is the specular material color - aiColor3D* pc = &mScene->mMaterials.back().mSpecular; - ParseColorChunk(pc); - if (is_qnan(pc->r)) { - // color chunk is invalid. Simply ignore it - DefaultLogger::get()->error("3DS: Unable to read SPECULAR chunk"); - pc->r = pc->g = pc->b = 1.0f; - }} - break; - - case Discreet3DS::CHUNK_MAT_AMBIENT: - { - // This is the ambient material color - aiColor3D* pc = &mScene->mMaterials.back().mAmbient; - ParseColorChunk(pc); - if (is_qnan(pc->r)) { - // color chunk is invalid. Simply ignore it - DefaultLogger::get()->error("3DS: Unable to read AMBIENT chunk"); - pc->r = pc->g = pc->b = 0.0f; - }} - break; - - case Discreet3DS::CHUNK_MAT_SELF_ILLUM: - { - // This is the emissive material color - aiColor3D* pc = &mScene->mMaterials.back().mEmissive; - ParseColorChunk(pc); - if (is_qnan(pc->r)) { - // color chunk is invalid. Simply ignore it - DefaultLogger::get()->error("3DS: Unable to read EMISSIVE chunk"); - pc->r = pc->g = pc->b = 0.0f; - }} - break; - - case Discreet3DS::CHUNK_MAT_TRANSPARENCY: - { - // This is the material's transparency - float* pcf = &mScene->mMaterials.back().mTransparency; - *pcf = ParsePercentageChunk(); - - // NOTE: transparency, not opacity - if (is_qnan(*pcf)) - *pcf = 1.0f; - else *pcf = 1.0f - *pcf * (float)0xFFFF / 100.0f; - } - break; - - case Discreet3DS::CHUNK_MAT_SHADING: - // This is the material shading mode - mScene->mMaterials.back().mShading = (D3DS::Discreet3DS::shadetype3ds)stream->GetI2(); - break; - - case Discreet3DS::CHUNK_MAT_TWO_SIDE: - // This is the two-sided flag - mScene->mMaterials.back().mTwoSided = true; - break; - - case Discreet3DS::CHUNK_MAT_SHININESS: - { // This is the shininess of the material - float* pcf = &mScene->mMaterials.back().mSpecularExponent; - *pcf = ParsePercentageChunk(); - if (is_qnan(*pcf)) - *pcf = 0.0f; - else *pcf *= (float)0xFFFF; - } - break; - - case Discreet3DS::CHUNK_MAT_SHININESS_PERCENT: - { // This is the shininess strength of the material - float* pcf = &mScene->mMaterials.back().mShininessStrength; - *pcf = ParsePercentageChunk(); - if (is_qnan(*pcf)) - *pcf = 0.0f; - else *pcf *= (float)0xffff / 100.0f; - } - break; - - case Discreet3DS::CHUNK_MAT_SELF_ILPCT: - { // This is the self illumination strength of the material - float f = ParsePercentageChunk(); - if (is_qnan(f)) - f = 0.0f; - else f *= (float)0xFFFF / 100.0f; - mScene->mMaterials.back().mEmissive = aiColor3D(f,f,f); - } - break; - - // Parse texture chunks - case Discreet3DS::CHUNK_MAT_TEXTURE: - // Diffuse texture - ParseTextureChunk(&mScene->mMaterials.back().sTexDiffuse); - break; - case Discreet3DS::CHUNK_MAT_BUMPMAP: - // Height map - ParseTextureChunk(&mScene->mMaterials.back().sTexBump); - break; - case Discreet3DS::CHUNK_MAT_OPACMAP: - // Opacity texture - ParseTextureChunk(&mScene->mMaterials.back().sTexOpacity); - break; - case Discreet3DS::CHUNK_MAT_MAT_SHINMAP: - // Shininess map - ParseTextureChunk(&mScene->mMaterials.back().sTexShininess); - break; - case Discreet3DS::CHUNK_MAT_SPECMAP: - // Specular map - ParseTextureChunk(&mScene->mMaterials.back().sTexSpecular); - break; - case Discreet3DS::CHUNK_MAT_SELFIMAP: - // Self-illumination (emissive) map - ParseTextureChunk(&mScene->mMaterials.back().sTexEmissive); - break; - case Discreet3DS::CHUNK_MAT_REFLMAP: - // Reflection map - ParseTextureChunk(&mScene->mMaterials.back().sTexReflective); - break; - }; - ASSIMP_3DS_END_CHUNK(); + ASSIMP_3DS_BEGIN_CHUNK(); + switch (chunk.Flag) + { + case Discreet3DS::CHUNK_MAT_MATNAME: + + { + // The material name string is already zero-terminated, but we need to be sure ... + const char* sz = (const char*)stream->GetPtr(); + unsigned int cnt = 0; + while (stream->GetI1()) + ++cnt; + + if (!cnt) { + // This may not be, we use the default name instead + DefaultLogger::get()->error("3DS: Empty material name"); + } + else mScene->mMaterials.back().mName = std::string(sz,cnt); + } + break; + + case Discreet3DS::CHUNK_MAT_DIFFUSE: + { + // This is the diffuse material color + aiColor3D* pc = &mScene->mMaterials.back().mDiffuse; + ParseColorChunk(pc); + if (is_qnan(pc->r)) { + // color chunk is invalid. Simply ignore it + DefaultLogger::get()->error("3DS: Unable to read DIFFUSE chunk"); + pc->r = pc->g = pc->b = 1.0f; + }} + break; + + case Discreet3DS::CHUNK_MAT_SPECULAR: + { + // This is the specular material color + aiColor3D* pc = &mScene->mMaterials.back().mSpecular; + ParseColorChunk(pc); + if (is_qnan(pc->r)) { + // color chunk is invalid. Simply ignore it + DefaultLogger::get()->error("3DS: Unable to read SPECULAR chunk"); + pc->r = pc->g = pc->b = 1.0f; + }} + break; + + case Discreet3DS::CHUNK_MAT_AMBIENT: + { + // This is the ambient material color + aiColor3D* pc = &mScene->mMaterials.back().mAmbient; + ParseColorChunk(pc); + if (is_qnan(pc->r)) { + // color chunk is invalid. Simply ignore it + DefaultLogger::get()->error("3DS: Unable to read AMBIENT chunk"); + pc->r = pc->g = pc->b = 0.0f; + }} + break; + + case Discreet3DS::CHUNK_MAT_SELF_ILLUM: + { + // This is the emissive material color + aiColor3D* pc = &mScene->mMaterials.back().mEmissive; + ParseColorChunk(pc); + if (is_qnan(pc->r)) { + // color chunk is invalid. Simply ignore it + DefaultLogger::get()->error("3DS: Unable to read EMISSIVE chunk"); + pc->r = pc->g = pc->b = 0.0f; + }} + break; + + case Discreet3DS::CHUNK_MAT_TRANSPARENCY: + { + // This is the material's transparency + float* pcf = &mScene->mMaterials.back().mTransparency; + *pcf = ParsePercentageChunk(); + + // NOTE: transparency, not opacity + if (is_qnan(*pcf)) + *pcf = 1.0f; + else *pcf = 1.0f - *pcf * (float)0xFFFF / 100.0f; + } + break; + + case Discreet3DS::CHUNK_MAT_SHADING: + // This is the material shading mode + mScene->mMaterials.back().mShading = (D3DS::Discreet3DS::shadetype3ds)stream->GetI2(); + break; + + case Discreet3DS::CHUNK_MAT_TWO_SIDE: + // This is the two-sided flag + mScene->mMaterials.back().mTwoSided = true; + break; + + case Discreet3DS::CHUNK_MAT_SHININESS: + { // This is the shininess of the material + float* pcf = &mScene->mMaterials.back().mSpecularExponent; + *pcf = ParsePercentageChunk(); + if (is_qnan(*pcf)) + *pcf = 0.0f; + else *pcf *= (float)0xFFFF; + } + break; + + case Discreet3DS::CHUNK_MAT_SHININESS_PERCENT: + { // This is the shininess strength of the material + float* pcf = &mScene->mMaterials.back().mShininessStrength; + *pcf = ParsePercentageChunk(); + if (is_qnan(*pcf)) + *pcf = 0.0f; + else *pcf *= (float)0xffff / 100.0f; + } + break; + + case Discreet3DS::CHUNK_MAT_SELF_ILPCT: + { // This is the self illumination strength of the material + float f = ParsePercentageChunk(); + if (is_qnan(f)) + f = 0.0f; + else f *= (float)0xFFFF / 100.0f; + mScene->mMaterials.back().mEmissive = aiColor3D(f,f,f); + } + break; + + // Parse texture chunks + case Discreet3DS::CHUNK_MAT_TEXTURE: + // Diffuse texture + ParseTextureChunk(&mScene->mMaterials.back().sTexDiffuse); + break; + case Discreet3DS::CHUNK_MAT_BUMPMAP: + // Height map + ParseTextureChunk(&mScene->mMaterials.back().sTexBump); + break; + case Discreet3DS::CHUNK_MAT_OPACMAP: + // Opacity texture + ParseTextureChunk(&mScene->mMaterials.back().sTexOpacity); + break; + case Discreet3DS::CHUNK_MAT_MAT_SHINMAP: + // Shininess map + ParseTextureChunk(&mScene->mMaterials.back().sTexShininess); + break; + case Discreet3DS::CHUNK_MAT_SPECMAP: + // Specular map + ParseTextureChunk(&mScene->mMaterials.back().sTexSpecular); + break; + case Discreet3DS::CHUNK_MAT_SELFIMAP: + // Self-illumination (emissive) map + ParseTextureChunk(&mScene->mMaterials.back().sTexEmissive); + break; + case Discreet3DS::CHUNK_MAT_REFLMAP: + // Reflection map + ParseTextureChunk(&mScene->mMaterials.back().sTexReflective); + break; + }; + ASSIMP_3DS_END_CHUNK(); } // ------------------------------------------------------------------------------------------------ void Discreet3DSImporter::ParseTextureChunk(D3DS::Texture* pcOut) { - ASSIMP_3DS_BEGIN_CHUNK(); - - // get chunk type - switch (chunk.Flag) - { - case Discreet3DS::CHUNK_MAPFILE: - { - // The material name string is already zero-terminated, but we need to be sure ... - const char* sz = (const char*)stream->GetPtr(); - unsigned int cnt = 0; - while (stream->GetI1()) - ++cnt; - pcOut->mMapName = std::string(sz,cnt); - } - break; - - - case Discreet3DS::CHUNK_PERCENTF: - // Manually parse the blend factor - pcOut->mTextureBlend = stream->GetF4(); - break; - - case Discreet3DS::CHUNK_PERCENTW: - // Manually parse the blend factor - pcOut->mTextureBlend = (float)((uint16_t)stream->GetI2()) / 100.0f; - break; - - case Discreet3DS::CHUNK_MAT_MAP_USCALE: - // Texture coordinate scaling in the U direction - pcOut->mScaleU = stream->GetF4(); - if (0.0f == pcOut->mScaleU) - { - DefaultLogger::get()->warn("Texture coordinate scaling in the x direction is zero. Assuming 1."); - pcOut->mScaleU = 1.0f; - } - break; - case Discreet3DS::CHUNK_MAT_MAP_VSCALE: - // Texture coordinate scaling in the V direction - pcOut->mScaleV = stream->GetF4(); - if (0.0f == pcOut->mScaleV) - { - DefaultLogger::get()->warn("Texture coordinate scaling in the y direction is zero. Assuming 1."); - pcOut->mScaleV = 1.0f; - } - break; - - case Discreet3DS::CHUNK_MAT_MAP_UOFFSET: - // Texture coordinate offset in the U direction - pcOut->mOffsetU = -stream->GetF4(); - break; - - case Discreet3DS::CHUNK_MAT_MAP_VOFFSET: - // Texture coordinate offset in the V direction - pcOut->mOffsetV = stream->GetF4(); - break; - - case Discreet3DS::CHUNK_MAT_MAP_ANG: - // Texture coordinate rotation, CCW in DEGREES - pcOut->mRotation = -AI_DEG_TO_RAD( stream->GetF4() ); - break; - - case Discreet3DS::CHUNK_MAT_MAP_TILING: - { - const uint16_t iFlags = stream->GetI2(); - - // Get the mapping mode (for both axes) - if (iFlags & 0x2u) - pcOut->mMapMode = aiTextureMapMode_Mirror; - - else if (iFlags & 0x10u) - pcOut->mMapMode = aiTextureMapMode_Decal; - - // wrapping in all remaining cases - else pcOut->mMapMode = aiTextureMapMode_Wrap; - } - break; - }; - - ASSIMP_3DS_END_CHUNK(); + ASSIMP_3DS_BEGIN_CHUNK(); + + // get chunk type + switch (chunk.Flag) + { + case Discreet3DS::CHUNK_MAPFILE: + { + // The material name string is already zero-terminated, but we need to be sure ... + const char* sz = (const char*)stream->GetPtr(); + unsigned int cnt = 0; + while (stream->GetI1()) + ++cnt; + pcOut->mMapName = std::string(sz,cnt); + } + break; + + + case Discreet3DS::CHUNK_PERCENTF: + // Manually parse the blend factor + pcOut->mTextureBlend = stream->GetF4(); + break; + + case Discreet3DS::CHUNK_PERCENTW: + // Manually parse the blend factor + pcOut->mTextureBlend = (float)((uint16_t)stream->GetI2()) / 100.0f; + break; + + case Discreet3DS::CHUNK_MAT_MAP_USCALE: + // Texture coordinate scaling in the U direction + pcOut->mScaleU = stream->GetF4(); + if (0.0f == pcOut->mScaleU) + { + DefaultLogger::get()->warn("Texture coordinate scaling in the x direction is zero. Assuming 1."); + pcOut->mScaleU = 1.0f; + } + break; + case Discreet3DS::CHUNK_MAT_MAP_VSCALE: + // Texture coordinate scaling in the V direction + pcOut->mScaleV = stream->GetF4(); + if (0.0f == pcOut->mScaleV) + { + DefaultLogger::get()->warn("Texture coordinate scaling in the y direction is zero. Assuming 1."); + pcOut->mScaleV = 1.0f; + } + break; + + case Discreet3DS::CHUNK_MAT_MAP_UOFFSET: + // Texture coordinate offset in the U direction + pcOut->mOffsetU = -stream->GetF4(); + break; + + case Discreet3DS::CHUNK_MAT_MAP_VOFFSET: + // Texture coordinate offset in the V direction + pcOut->mOffsetV = stream->GetF4(); + break; + + case Discreet3DS::CHUNK_MAT_MAP_ANG: + // Texture coordinate rotation, CCW in DEGREES + pcOut->mRotation = -AI_DEG_TO_RAD( stream->GetF4() ); + break; + + case Discreet3DS::CHUNK_MAT_MAP_TILING: + { + const uint16_t iFlags = stream->GetI2(); + + // Get the mapping mode (for both axes) + if (iFlags & 0x2u) + pcOut->mMapMode = aiTextureMapMode_Mirror; + + else if (iFlags & 0x10u) + pcOut->mMapMode = aiTextureMapMode_Decal; + + // wrapping in all remaining cases + else pcOut->mMapMode = aiTextureMapMode_Wrap; + } + break; + }; + + ASSIMP_3DS_END_CHUNK(); } // ------------------------------------------------------------------------------------------------ // Read a percentage chunk float Discreet3DSImporter::ParsePercentageChunk() { - Discreet3DS::Chunk chunk; - ReadChunk(&chunk); - - if (Discreet3DS::CHUNK_PERCENTF == chunk.Flag) - return stream->GetF4(); - else if (Discreet3DS::CHUNK_PERCENTW == chunk.Flag) - return (float)((uint16_t)stream->GetI2()) / (float)0xFFFF; - return get_qnan(); + Discreet3DS::Chunk chunk; + ReadChunk(&chunk); + + if (Discreet3DS::CHUNK_PERCENTF == chunk.Flag) + return stream->GetF4(); + else if (Discreet3DS::CHUNK_PERCENTW == chunk.Flag) + return (float)((uint16_t)stream->GetI2()) / (float)0xFFFF; + return get_qnan(); } // ------------------------------------------------------------------------------------------------ // Read a color chunk. If a percentage chunk is found instead it is read as a grayscale color void Discreet3DSImporter::ParseColorChunk(aiColor3D* out, - bool acceptPercent) + bool acceptPercent) { - ai_assert(out != NULL); - - // error return value - const float qnan = get_qnan(); - static const aiColor3D clrError = aiColor3D(qnan,qnan,qnan); - - Discreet3DS::Chunk chunk; - ReadChunk(&chunk); - const unsigned int diff = chunk.Size - sizeof(Discreet3DS::Chunk); - - bool bGamma = false; - - // Get the type of the chunk - switch(chunk.Flag) - { - case Discreet3DS::CHUNK_LINRGBF: - bGamma = true; - - case Discreet3DS::CHUNK_RGBF: - if (sizeof(float) * 3 > diff) { - *out = clrError; - return; - } - out->r = stream->GetF4(); - out->g = stream->GetF4(); - out->b = stream->GetF4(); - break; - - case Discreet3DS::CHUNK_LINRGBB: - bGamma = true; - case Discreet3DS::CHUNK_RGBB: - if (sizeof(char) * 3 > diff) { - *out = clrError; - return; - } - out->r = (float)(uint8_t)stream->GetI1() / 255.0f; - out->g = (float)(uint8_t)stream->GetI1() / 255.0f; - out->b = (float)(uint8_t)stream->GetI1() / 255.0f; - break; - - // Percentage chunks are accepted, too. - case Discreet3DS::CHUNK_PERCENTF: - if (acceptPercent && 4 <= diff) { - out->g = out->b = out->r = stream->GetF4(); - break; - } - *out = clrError; - return; - - case Discreet3DS::CHUNK_PERCENTW: - if (acceptPercent && 1 <= diff) { - out->g = out->b = out->r = (float)(uint8_t)stream->GetI1() / 255.0f; - break; - } - *out = clrError; - return; - - default: - stream->IncPtr(diff); - // Skip unknown chunks, hope this won't cause any problems. - return ParseColorChunk(out,acceptPercent); - }; - (void)bGamma; + ai_assert(out != NULL); + + // error return value + const float qnan = get_qnan(); + static const aiColor3D clrError = aiColor3D(qnan,qnan,qnan); + + Discreet3DS::Chunk chunk; + ReadChunk(&chunk); + const unsigned int diff = chunk.Size - sizeof(Discreet3DS::Chunk); + + bool bGamma = false; + + // Get the type of the chunk + switch(chunk.Flag) + { + case Discreet3DS::CHUNK_LINRGBF: + bGamma = true; + + case Discreet3DS::CHUNK_RGBF: + if (sizeof(float) * 3 > diff) { + *out = clrError; + return; + } + out->r = stream->GetF4(); + out->g = stream->GetF4(); + out->b = stream->GetF4(); + break; + + case Discreet3DS::CHUNK_LINRGBB: + bGamma = true; + case Discreet3DS::CHUNK_RGBB: + if (sizeof(char) * 3 > diff) { + *out = clrError; + return; + } + out->r = (float)(uint8_t)stream->GetI1() / 255.0f; + out->g = (float)(uint8_t)stream->GetI1() / 255.0f; + out->b = (float)(uint8_t)stream->GetI1() / 255.0f; + break; + + // Percentage chunks are accepted, too. + case Discreet3DS::CHUNK_PERCENTF: + if (acceptPercent && 4 <= diff) { + out->g = out->b = out->r = stream->GetF4(); + break; + } + *out = clrError; + return; + + case Discreet3DS::CHUNK_PERCENTW: + if (acceptPercent && 1 <= diff) { + out->g = out->b = out->r = (float)(uint8_t)stream->GetI1() / 255.0f; + break; + } + *out = clrError; + return; + + default: + stream->IncPtr(diff); + // Skip unknown chunks, hope this won't cause any problems. + return ParseColorChunk(out,acceptPercent); + }; + (void)bGamma; } #endif // !! ASSIMP_BUILD_NO_3DS_IMPORTER diff --git a/src/3rdparty/assimp/code/3DSLoader.h b/src/3rdparty/assimp/code/3DSLoader.h index bee129cc1..437ec94b4 100644 --- a/src/3rdparty/assimp/code/3DSLoader.h +++ b/src/3rdparty/assimp/code/3DSLoader.h @@ -3,11 +3,11 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2012, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above @@ -24,16 +24,16 @@ following conditions are met: derived from this software without specific prior written permission of the assimp team. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- @@ -46,14 +46,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define AI_3DSIMPORTER_H_INC #include "BaseImporter.h" -#include "../include/assimp/types.h" +#include #ifndef ASSIMP_BUILD_NO_3DS_IMPORTER -struct aiNode; #include "3DSHelper.h" +#include "StreamReader.h" + +struct aiNode; -namespace Assimp { +namespace Assimp { using namespace D3DS; @@ -65,216 +67,216 @@ class Discreet3DSImporter : public BaseImporter { public: - Discreet3DSImporter(); - ~Discreet3DSImporter(); + Discreet3DSImporter(); + ~Discreet3DSImporter(); public: - // ------------------------------------------------------------------- - /** Returns whether the class can handle the format of the given file. - * See BaseImporter::CanRead() for details. - */ - bool CanRead( const std::string& pFile, IOSystem* pIOHandler, - bool checkSig) const; + // ------------------------------------------------------------------- + /** Returns whether the class can handle the format of the given file. + * See BaseImporter::CanRead() for details. + */ + bool CanRead( const std::string& pFile, IOSystem* pIOHandler, + bool checkSig) const; - // ------------------------------------------------------------------- - /** Called prior to ReadFile(). - * The function is a request to the importer to update its configuration - * basing on the Importer's configuration property list. - */ - void SetupProperties(const Importer* pImp); + // ------------------------------------------------------------------- + /** Called prior to ReadFile(). + * The function is a request to the importer to update its configuration + * basing on the Importer's configuration property list. + */ + void SetupProperties(const Importer* pImp); protected: - // ------------------------------------------------------------------- - /** Return importer meta information. - * See #BaseImporter::GetInfo for the details - */ - const aiImporterDesc* GetInfo () const; - - // ------------------------------------------------------------------- - /** Imports the given file into the given scene structure. - * See BaseImporter::InternReadFile() for details - */ - void InternReadFile( const std::string& pFile, aiScene* pScene, - IOSystem* pIOHandler); - - // ------------------------------------------------------------------- - /** Converts a temporary material to the outer representation - */ - void ConvertMaterial(D3DS::Material& p_cMat, - aiMaterial& p_pcOut); - - // ------------------------------------------------------------------- - /** Read a chunk - * - * @param pcOut Receives the current chunk - */ - void ReadChunk(Discreet3DS::Chunk* pcOut); - - // ------------------------------------------------------------------- - /** Parse a percentage chunk. mCurrent will point to the next - * chunk behind afterwards. If no percentage chunk is found - * QNAN is returned. - */ - float ParsePercentageChunk(); - - // ------------------------------------------------------------------- - /** Parse a color chunk. mCurrent will point to the next - * chunk behind afterwards. If no color chunk is found - * QNAN is returned in all members. - */ - void ParseColorChunk(aiColor3D* p_pcOut, - bool p_bAcceptPercent = true); - - - // ------------------------------------------------------------------- - /** Skip a chunk in the file - */ - void SkipChunk(); - - // ------------------------------------------------------------------- - /** Generate the nodegraph - */ - void GenerateNodeGraph(aiScene* pcOut); - - // ------------------------------------------------------------------- - /** Parse a main top-level chunk in the file - */ - void ParseMainChunk(); - - // ------------------------------------------------------------------- - /** Parse a top-level chunk in the file - */ - void ParseChunk(const char* name, unsigned int num); - - // ------------------------------------------------------------------- - /** Parse a top-level editor chunk in the file - */ - void ParseEditorChunk(); - - // ------------------------------------------------------------------- - /** Parse a top-level object chunk in the file - */ - void ParseObjectChunk(); - - // ------------------------------------------------------------------- - /** Parse a material chunk in the file - */ - void ParseMaterialChunk(); - - // ------------------------------------------------------------------- - /** Parse a mesh chunk in the file - */ - void ParseMeshChunk(); - - // ------------------------------------------------------------------- - /** Parse a light chunk in the file - */ - void ParseLightChunk(); - - // ------------------------------------------------------------------- - /** Parse a camera chunk in the file - */ - void ParseCameraChunk(); - - // ------------------------------------------------------------------- - /** Parse a face list chunk in the file - */ - void ParseFaceChunk(); - - // ------------------------------------------------------------------- - /** Parse a keyframe chunk in the file - */ - void ParseKeyframeChunk(); - - // ------------------------------------------------------------------- - /** Parse a hierarchy chunk in the file - */ - void ParseHierarchyChunk(uint16_t parent); - - // ------------------------------------------------------------------- - /** Parse a texture chunk in the file - */ - void ParseTextureChunk(D3DS::Texture* pcOut); - - // ------------------------------------------------------------------- - /** Convert the meshes in the file - */ - void ConvertMeshes(aiScene* pcOut); - - // ------------------------------------------------------------------- - /** Replace the default material in the scene - */ - void ReplaceDefaultMaterial(); - - // ------------------------------------------------------------------- - /** Convert the whole scene - */ - void ConvertScene(aiScene* pcOut); - - // ------------------------------------------------------------------- - /** generate unique vertices for a mesh - */ - void MakeUnique(D3DS::Mesh& sMesh); - - // ------------------------------------------------------------------- - /** Add a node to the node graph - */ - void AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,D3DS::Node* pcIn, - aiMatrix4x4& absTrafo); - - // ------------------------------------------------------------------- - /** Search for a node in the graph. - * Called recursively - */ - void InverseNodeSearch(D3DS::Node* pcNode,D3DS::Node* pcCurrent); - - // ------------------------------------------------------------------- - /** Apply the master scaling factor to the mesh - */ - void ApplyMasterScale(aiScene* pScene); - - // ------------------------------------------------------------------- - /** Clamp all indices in the file to a valid range - */ - void CheckIndices(D3DS::Mesh& sMesh); - - // ------------------------------------------------------------------- - /** Skip the TCB info in a track key - */ - void SkipTCBInfo(); + // ------------------------------------------------------------------- + /** Return importer meta information. + * See #BaseImporter::GetInfo for the details + */ + const aiImporterDesc* GetInfo () const; + + // ------------------------------------------------------------------- + /** Imports the given file into the given scene structure. + * See BaseImporter::InternReadFile() for details + */ + void InternReadFile( const std::string& pFile, aiScene* pScene, + IOSystem* pIOHandler); + + // ------------------------------------------------------------------- + /** Converts a temporary material to the outer representation + */ + void ConvertMaterial(D3DS::Material& p_cMat, + aiMaterial& p_pcOut); + + // ------------------------------------------------------------------- + /** Read a chunk + * + * @param pcOut Receives the current chunk + */ + void ReadChunk(Discreet3DS::Chunk* pcOut); + + // ------------------------------------------------------------------- + /** Parse a percentage chunk. mCurrent will point to the next + * chunk behind afterwards. If no percentage chunk is found + * QNAN is returned. + */ + float ParsePercentageChunk(); + + // ------------------------------------------------------------------- + /** Parse a color chunk. mCurrent will point to the next + * chunk behind afterwards. If no color chunk is found + * QNAN is returned in all members. + */ + void ParseColorChunk(aiColor3D* p_pcOut, + bool p_bAcceptPercent = true); + + + // ------------------------------------------------------------------- + /** Skip a chunk in the file + */ + void SkipChunk(); + + // ------------------------------------------------------------------- + /** Generate the nodegraph + */ + void GenerateNodeGraph(aiScene* pcOut); + + // ------------------------------------------------------------------- + /** Parse a main top-level chunk in the file + */ + void ParseMainChunk(); + + // ------------------------------------------------------------------- + /** Parse a top-level chunk in the file + */ + void ParseChunk(const char* name, unsigned int num); + + // ------------------------------------------------------------------- + /** Parse a top-level editor chunk in the file + */ + void ParseEditorChunk(); + + // ------------------------------------------------------------------- + /** Parse a top-level object chunk in the file + */ + void ParseObjectChunk(); + + // ------------------------------------------------------------------- + /** Parse a material chunk in the file + */ + void ParseMaterialChunk(); + + // ------------------------------------------------------------------- + /** Parse a mesh chunk in the file + */ + void ParseMeshChunk(); + + // ------------------------------------------------------------------- + /** Parse a light chunk in the file + */ + void ParseLightChunk(); + + // ------------------------------------------------------------------- + /** Parse a camera chunk in the file + */ + void ParseCameraChunk(); + + // ------------------------------------------------------------------- + /** Parse a face list chunk in the file + */ + void ParseFaceChunk(); + + // ------------------------------------------------------------------- + /** Parse a keyframe chunk in the file + */ + void ParseKeyframeChunk(); + + // ------------------------------------------------------------------- + /** Parse a hierarchy chunk in the file + */ + void ParseHierarchyChunk(uint16_t parent); + + // ------------------------------------------------------------------- + /** Parse a texture chunk in the file + */ + void ParseTextureChunk(D3DS::Texture* pcOut); + + // ------------------------------------------------------------------- + /** Convert the meshes in the file + */ + void ConvertMeshes(aiScene* pcOut); + + // ------------------------------------------------------------------- + /** Replace the default material in the scene + */ + void ReplaceDefaultMaterial(); + + // ------------------------------------------------------------------- + /** Convert the whole scene + */ + void ConvertScene(aiScene* pcOut); + + // ------------------------------------------------------------------- + /** generate unique vertices for a mesh + */ + void MakeUnique(D3DS::Mesh& sMesh); + + // ------------------------------------------------------------------- + /** Add a node to the node graph + */ + void AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,D3DS::Node* pcIn, + aiMatrix4x4& absTrafo); + + // ------------------------------------------------------------------- + /** Search for a node in the graph. + * Called recursively + */ + void InverseNodeSearch(D3DS::Node* pcNode,D3DS::Node* pcCurrent); + + // ------------------------------------------------------------------- + /** Apply the master scaling factor to the mesh + */ + void ApplyMasterScale(aiScene* pScene); + + // ------------------------------------------------------------------- + /** Clamp all indices in the file to a valid range + */ + void CheckIndices(D3DS::Mesh& sMesh); + + // ------------------------------------------------------------------- + /** Skip the TCB info in a track key + */ + void SkipTCBInfo(); protected: - /** Stream to read from */ - StreamReaderLE* stream; + /** Stream to read from */ + StreamReaderLE* stream; - /** Last touched node index */ - short mLastNodeIndex; + /** Last touched node index */ + short mLastNodeIndex; - /** Current node, root node */ - D3DS::Node* mCurrentNode, *mRootNode; + /** Current node, root node */ + D3DS::Node* mCurrentNode, *mRootNode; - /** Scene under construction */ - D3DS::Scene* mScene; + /** Scene under construction */ + D3DS::Scene* mScene; - /** Ambient base color of the scene */ - aiColor3D mClrAmbient; + /** Ambient base color of the scene */ + aiColor3D mClrAmbient; - /** Master scaling factor of the scene */ - float mMasterScale; + /** Master scaling factor of the scene */ + float mMasterScale; - /** Path to the background image of the scene */ - std::string mBackgroundImage; - bool bHasBG; + /** Path to the background image of the scene */ + std::string mBackgroundImage; + bool bHasBG; - /** true if PRJ file */ - bool bIsPrj; + /** true if PRJ file */ + bool bIsPrj; }; -#endif // !! ASSIMP_BUILD_NO_3DS_IMPORTER - } // end of namespace Assimp +#endif // !! ASSIMP_BUILD_NO_3DS_IMPORTER + #endif // AI_3DSIMPORTER_H_INC diff --git a/src/3rdparty/assimp/code/ACLoader.cpp b/src/3rdparty/assimp/code/ACLoader.cpp index 687e9acc4..c040d6bbd 100644 --- a/src/3rdparty/assimp/code/ACLoader.cpp +++ b/src/3rdparty/assimp/code/ACLoader.cpp @@ -4,12 +4,12 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2012, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above @@ -26,23 +26,23 @@ conditions are met: derived from this software without specific prior written permission of the assimp team. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --------------------------------------------------------------------------- */ /** @file Implementation of the AC3D importer class */ -#include "AssimpPCH.h" + #ifndef ASSIMP_BUILD_NO_AC_IMPORTER @@ -51,816 +51,857 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "ParsingUtils.h" #include "fast_atof.h" #include "Subdivision.h" +#include "Importer.h" +#include "BaseImporter.h" +#include +#include +#include +#include +#include +#include +#include +#include using namespace Assimp; static const aiImporterDesc desc = { - "AC3D Importer", - "", - "", - "", - aiImporterFlags_SupportTextFlavour, - 0, - 0, - 0, - 0, - "ac acc ac3d" + "AC3D Importer", + "", + "", + "", + aiImporterFlags_SupportTextFlavour, + 0, + 0, + 0, + 0, + "ac acc ac3d" }; // ------------------------------------------------------------------------------------------------ // skip to the next token #define AI_AC_SKIP_TO_NEXT_TOKEN() \ - if (!SkipSpaces(&buffer)) \ - { \ - DefaultLogger::get()->error("AC3D: Unexpected EOF/EOL"); \ - continue; \ - } + if (!SkipSpaces(&buffer)) \ + { \ + DefaultLogger::get()->error("AC3D: Unexpected EOF/EOL"); \ + continue; \ + } // ------------------------------------------------------------------------------------------------ // read a string (may be enclosed in double quotation marks). buffer must point to " #define AI_AC_GET_STRING(out) \ - ++buffer; \ - const char* sz = buffer; \ - while ('\"' != *buffer) \ - { \ - if (IsLineEnd( *buffer )) \ - { \ - DefaultLogger::get()->error("AC3D: Unexpected EOF/EOL in string"); \ - out = "ERROR"; \ - break; \ - } \ - ++buffer; \ - } \ - if (IsLineEnd( *buffer ))continue; \ - out = std::string(sz,(unsigned int)(buffer-sz)); \ - ++buffer; + if (*buffer == '\0') { \ + throw DeadlyImportError("AC3D: Unexpected EOF in string"); \ + } \ + ++buffer; \ + const char* sz = buffer; \ + while ('\"' != *buffer) \ + { \ + if (IsLineEnd( *buffer )) \ + { \ + DefaultLogger::get()->error("AC3D: Unexpected EOF/EOL in string"); \ + out = "ERROR"; \ + break; \ + } \ + ++buffer; \ + } \ + if (IsLineEnd( *buffer ))continue; \ + out = std::string(sz,(unsigned int)(buffer-sz)); \ + ++buffer; // ------------------------------------------------------------------------------------------------ -// read 1 to n floats prefixed with an optional predefined identifier +// read 1 to n floats prefixed with an optional predefined identifier #define AI_AC_CHECKED_LOAD_FLOAT_ARRAY(name,name_length,num,out) \ - AI_AC_SKIP_TO_NEXT_TOKEN(); \ - if (name_length) \ - { \ - if (strncmp(buffer,name,name_length) || !IsSpace(buffer[name_length])) \ - { \ - DefaultLogger::get()->error("AC3D: Unexpexted token. " name " was expected."); \ - continue; \ - } \ - buffer += name_length+1; \ - } \ - for (unsigned int i = 0; i < num;++i) \ - { \ - AI_AC_SKIP_TO_NEXT_TOKEN(); \ - buffer = fast_atoreal_move(buffer,((float*)out)[i]); \ - } + AI_AC_SKIP_TO_NEXT_TOKEN(); \ + if (name_length) \ + { \ + if (strncmp(buffer,name,name_length) || !IsSpace(buffer[name_length])) \ + { \ + DefaultLogger::get()->error("AC3D: Unexpexted token. " name " was expected."); \ + continue; \ + } \ + buffer += name_length+1; \ + } \ + for (unsigned int i = 0; i < num;++i) \ + { \ + AI_AC_SKIP_TO_NEXT_TOKEN(); \ + buffer = fast_atoreal_move(buffer,((float*)out)[i]); \ + } // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer AC3DImporter::AC3DImporter() + : buffer(), + configSplitBFCull(), + configEvalSubdivision(), + mNumMeshes(), + mLights(), + lights(), + groups(), + polys(), + worlds() { - // nothing to be done here + // nothing to be done here } // ------------------------------------------------------------------------------------------------ -// Destructor, private as well +// Destructor, private as well AC3DImporter::~AC3DImporter() { - // nothing to be done here + // nothing to be done here } // ------------------------------------------------------------------------------------------------ -// Returns whether the class can handle the format of the given file. +// Returns whether the class can handle the format of the given file. bool AC3DImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const { - std::string extension = GetExtension(pFile); - - // fixme: are acc and ac3d *really* used? Some sources say they are - if(extension == "ac" || extension == "ac3d" || extension == "acc") { - return true; - } - if (!extension.length() || checkSig) { - uint32_t token = AI_MAKE_MAGIC("AC3D"); - return CheckMagicToken(pIOHandler,pFile,&token,1,0); - } - return false; + std::string extension = GetExtension(pFile); + + // fixme: are acc and ac3d *really* used? Some sources say they are + if(extension == "ac" || extension == "ac3d" || extension == "acc") { + return true; + } + if (!extension.length() || checkSig) { + uint32_t token = AI_MAKE_MAGIC("AC3D"); + return CheckMagicToken(pIOHandler,pFile,&token,1,0); + } + return false; } // ------------------------------------------------------------------------------------------------ // Loader meta information const aiImporterDesc* AC3DImporter::GetInfo () const { - return &desc; + return &desc; } // ------------------------------------------------------------------------------------------------ // Get a pointer to the next line from the file bool AC3DImporter::GetNextLine( ) { - SkipLine(&buffer); - return SkipSpaces(&buffer); + SkipLine(&buffer); + return SkipSpaces(&buffer); } // ------------------------------------------------------------------------------------------------ // Parse an object section in an AC file void AC3DImporter::LoadObjectSection(std::vector& objects) { - if (!TokenMatch(buffer,"OBJECT",6)) - return; - - SkipSpaces(&buffer); - - ++mNumMeshes; - - objects.push_back(Object()); - Object& obj = objects.back(); - - aiLight* light = NULL; - if (!ASSIMP_strincmp(buffer,"light",5)) - { - // This is a light source. Add it to the list - mLights->push_back(light = new aiLight()); - - // Return a point light with no attenuation - light->mType = aiLightSource_POINT; - light->mColorDiffuse = light->mColorSpecular = aiColor3D(1.f,1.f,1.f); - light->mAttenuationConstant = 1.f; - - // Generate a default name for both the light source and the node - // FIXME - what's the right way to print a size_t? Is 'zu' universally available? stick with the safe version. - light->mName.length = ::sprintf(light->mName.data,"ACLight_%i",static_cast(mLights->size())-1); - obj.name = std::string( light->mName.data ); - - DefaultLogger::get()->debug("AC3D: Light source encountered"); - obj.type = Object::Light; - } - else if (!ASSIMP_strincmp(buffer,"group",5)) - { - obj.type = Object::Group; - } - else if (!ASSIMP_strincmp(buffer,"world",5)) - { - obj.type = Object::World; - } - else obj.type = Object::Poly; - while (GetNextLine()) - { - if (TokenMatch(buffer,"kids",4)) - { - SkipSpaces(&buffer); - unsigned int num = strtoul10(buffer,&buffer); - GetNextLine(); - if (num) - { - // load the children of this object recursively - obj.children.reserve(num); - for (unsigned int i = 0; i < num; ++i) - LoadObjectSection(obj.children); - } - return; - } - else if (TokenMatch(buffer,"name",4)) - { - SkipSpaces(&buffer); - AI_AC_GET_STRING(obj.name); - - // If this is a light source, we'll also need to store - // the name of the node in it. - if (light) - { - light->mName.Set(obj.name); - } - } - else if (TokenMatch(buffer,"texture",7)) - { - SkipSpaces(&buffer); - AI_AC_GET_STRING(obj.texture); - } - else if (TokenMatch(buffer,"texrep",6)) - { - SkipSpaces(&buffer); - AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,2,&obj.texRepeat); - if (!obj.texRepeat.x || !obj.texRepeat.y) - obj.texRepeat = aiVector2D (1.f,1.f); - } - else if (TokenMatch(buffer,"texoff",6)) - { - SkipSpaces(&buffer); - AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,2,&obj.texOffset); - } - else if (TokenMatch(buffer,"rot",3)) - { - SkipSpaces(&buffer); - AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,9,&obj.rotation); - } - else if (TokenMatch(buffer,"loc",3)) - { - SkipSpaces(&buffer); - AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,3,&obj.translation); - } - else if (TokenMatch(buffer,"subdiv",6)) - { - SkipSpaces(&buffer); - obj.subDiv = strtoul10(buffer,&buffer); - } - else if (TokenMatch(buffer,"crease",6)) - { - SkipSpaces(&buffer); - obj.crease = fast_atof(buffer); - } - else if (TokenMatch(buffer,"numvert",7)) - { - SkipSpaces(&buffer); - - unsigned int t = strtoul10(buffer,&buffer); - obj.vertices.reserve(t); - for (unsigned int i = 0; i < t;++i) - { - if (!GetNextLine()) - { - DefaultLogger::get()->error("AC3D: Unexpected EOF: not all vertices have been parsed yet"); - break; - } - else if (!IsNumeric(*buffer)) - { - DefaultLogger::get()->error("AC3D: Unexpected token: not all vertices have been parsed yet"); - --buffer; // make sure the line is processed a second time - break; - } - obj.vertices.push_back(aiVector3D()); - aiVector3D& v = obj.vertices.back(); - AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,3,&v.x); - } - } - else if (TokenMatch(buffer,"numsurf",7)) - { - SkipSpaces(&buffer); - - bool Q3DWorkAround = false; - - const unsigned int t = strtoul10(buffer,&buffer); - obj.surfaces.reserve(t); - for (unsigned int i = 0; i < t;++i) - { - GetNextLine(); - if (!TokenMatch(buffer,"SURF",4)) - { - // FIX: this can occur for some files - Quick 3D for - // example writes no surf chunks - if (!Q3DWorkAround) - { - DefaultLogger::get()->warn("AC3D: SURF token was expected"); - DefaultLogger::get()->debug("Continuing with Quick3D Workaround enabled"); - } - --buffer; // make sure the line is processed a second time - // break; --- see fix notes above - - Q3DWorkAround = true; - } - SkipSpaces(&buffer); - obj.surfaces.push_back(Surface()); - Surface& surf = obj.surfaces.back(); - surf.flags = strtoul_cppstyle(buffer); - - while (1) - { - if(!GetNextLine()) - { - DefaultLogger::get()->error("AC3D: Unexpected EOF: surface is incomplete"); - break; - } - if (TokenMatch(buffer,"mat",3)) - { - SkipSpaces(&buffer); - surf.mat = strtoul10(buffer); - } - else if (TokenMatch(buffer,"refs",4)) - { - // --- see fix notes above - if (Q3DWorkAround) - { - if (!surf.entries.empty()) - { - buffer -= 6; - break; - } - } - - SkipSpaces(&buffer); - const unsigned int m = strtoul10(buffer); - surf.entries.reserve(m); - - obj.numRefs += m; - - for (unsigned int k = 0; k < m; ++k) - { - if(!GetNextLine()) - { - DefaultLogger::get()->error("AC3D: Unexpected EOF: surface references are incomplete"); - break; - } - surf.entries.push_back(Surface::SurfaceEntry()); - Surface::SurfaceEntry& entry = surf.entries.back(); - - entry.first = strtoul10(buffer,&buffer); - SkipSpaces(&buffer); - AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,2,&entry.second); - } - } - else - { - - --buffer; // make sure the line is processed a second time - break; - } - } - } - } - } - DefaultLogger::get()->error("AC3D: Unexpected EOF: \'kids\' line was expected"); + if (!TokenMatch(buffer,"OBJECT",6)) + return; + + SkipSpaces(&buffer); + + ++mNumMeshes; + + objects.push_back(Object()); + Object& obj = objects.back(); + + aiLight* light = NULL; + if (!ASSIMP_strincmp(buffer,"light",5)) + { + // This is a light source. Add it to the list + mLights->push_back(light = new aiLight()); + + // Return a point light with no attenuation + light->mType = aiLightSource_POINT; + light->mColorDiffuse = light->mColorSpecular = aiColor3D(1.f,1.f,1.f); + light->mAttenuationConstant = 1.f; + + // Generate a default name for both the light source and the node + // FIXME - what's the right way to print a size_t? Is 'zu' universally available? stick with the safe version. + light->mName.length = ::ai_snprintf(light->mName.data, MAXLEN, "ACLight_%i",static_cast(mLights->size())-1); + obj.name = std::string( light->mName.data ); + + DefaultLogger::get()->debug("AC3D: Light source encountered"); + obj.type = Object::Light; + } + else if (!ASSIMP_strincmp(buffer,"group",5)) + { + obj.type = Object::Group; + } + else if (!ASSIMP_strincmp(buffer,"world",5)) + { + obj.type = Object::World; + } + else obj.type = Object::Poly; + while (GetNextLine()) + { + if (TokenMatch(buffer,"kids",4)) + { + SkipSpaces(&buffer); + unsigned int num = strtoul10(buffer,&buffer); + GetNextLine(); + if (num) + { + // load the children of this object recursively + obj.children.reserve(num); + for (unsigned int i = 0; i < num; ++i) + LoadObjectSection(obj.children); + } + return; + } + else if (TokenMatch(buffer,"name",4)) + { + SkipSpaces(&buffer); + AI_AC_GET_STRING(obj.name); + + // If this is a light source, we'll also need to store + // the name of the node in it. + if (light) + { + light->mName.Set(obj.name); + } + } + else if (TokenMatch(buffer,"texture",7)) + { + SkipSpaces(&buffer); + AI_AC_GET_STRING(obj.texture); + } + else if (TokenMatch(buffer,"texrep",6)) + { + SkipSpaces(&buffer); + AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,2,&obj.texRepeat); + if (!obj.texRepeat.x || !obj.texRepeat.y) + obj.texRepeat = aiVector2D (1.f,1.f); + } + else if (TokenMatch(buffer,"texoff",6)) + { + SkipSpaces(&buffer); + AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,2,&obj.texOffset); + } + else if (TokenMatch(buffer,"rot",3)) + { + SkipSpaces(&buffer); + AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,9,&obj.rotation); + } + else if (TokenMatch(buffer,"loc",3)) + { + SkipSpaces(&buffer); + AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,3,&obj.translation); + } + else if (TokenMatch(buffer,"subdiv",6)) + { + SkipSpaces(&buffer); + obj.subDiv = strtoul10(buffer,&buffer); + } + else if (TokenMatch(buffer,"crease",6)) + { + SkipSpaces(&buffer); + obj.crease = fast_atof(buffer); + } + else if (TokenMatch(buffer,"numvert",7)) + { + SkipSpaces(&buffer); + + unsigned int t = strtoul10(buffer,&buffer); + if (t >= AI_MAX_ALLOC(aiVector3D)) { + throw DeadlyImportError("AC3D: Too many vertices, would run out of memory"); + } + obj.vertices.reserve(t); + for (unsigned int i = 0; i < t;++i) + { + if (!GetNextLine()) + { + DefaultLogger::get()->error("AC3D: Unexpected EOF: not all vertices have been parsed yet"); + break; + } + else if (!IsNumeric(*buffer)) + { + DefaultLogger::get()->error("AC3D: Unexpected token: not all vertices have been parsed yet"); + --buffer; // make sure the line is processed a second time + break; + } + obj.vertices.push_back(aiVector3D()); + aiVector3D& v = obj.vertices.back(); + AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,3,&v.x); + } + } + else if (TokenMatch(buffer,"numsurf",7)) + { + SkipSpaces(&buffer); + + bool Q3DWorkAround = false; + + const unsigned int t = strtoul10(buffer,&buffer); + obj.surfaces.reserve(t); + for (unsigned int i = 0; i < t;++i) + { + GetNextLine(); + if (!TokenMatch(buffer,"SURF",4)) + { + // FIX: this can occur for some files - Quick 3D for + // example writes no surf chunks + if (!Q3DWorkAround) + { + DefaultLogger::get()->warn("AC3D: SURF token was expected"); + DefaultLogger::get()->debug("Continuing with Quick3D Workaround enabled"); + } + --buffer; // make sure the line is processed a second time + // break; --- see fix notes above + + Q3DWorkAround = true; + } + SkipSpaces(&buffer); + obj.surfaces.push_back(Surface()); + Surface& surf = obj.surfaces.back(); + surf.flags = strtoul_cppstyle(buffer); + + while (1) + { + if(!GetNextLine()) + { + throw DeadlyImportError("AC3D: Unexpected EOF: surface is incomplete"); + } + if (TokenMatch(buffer,"mat",3)) + { + SkipSpaces(&buffer); + surf.mat = strtoul10(buffer); + } + else if (TokenMatch(buffer,"refs",4)) + { + // --- see fix notes above + if (Q3DWorkAround) + { + if (!surf.entries.empty()) + { + buffer -= 6; + break; + } + } + + SkipSpaces(&buffer); + const unsigned int m = strtoul10(buffer); + surf.entries.reserve(m); + + obj.numRefs += m; + + for (unsigned int k = 0; k < m; ++k) + { + if(!GetNextLine()) + { + DefaultLogger::get()->error("AC3D: Unexpected EOF: surface references are incomplete"); + break; + } + surf.entries.push_back(Surface::SurfaceEntry()); + Surface::SurfaceEntry& entry = surf.entries.back(); + + entry.first = strtoul10(buffer,&buffer); + SkipSpaces(&buffer); + AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,2,&entry.second); + } + } + else + { + + --buffer; // make sure the line is processed a second time + break; + } + } + } + } + } + DefaultLogger::get()->error("AC3D: Unexpected EOF: \'kids\' line was expected"); } // ------------------------------------------------------------------------------------------------ // Convert a material from AC3DImporter::Material to aiMaterial void AC3DImporter::ConvertMaterial(const Object& object, - const Material& matSrc, - aiMaterial& matDest) + const Material& matSrc, + aiMaterial& matDest) { - aiString s; - - if (matSrc.name.length()) - { - s.Set(matSrc.name); - matDest.AddProperty(&s,AI_MATKEY_NAME); - } - if (object.texture.length()) - { - s.Set(object.texture); - matDest.AddProperty(&s,AI_MATKEY_TEXTURE_DIFFUSE(0)); - - // UV transformation - if (1.f != object.texRepeat.x || 1.f != object.texRepeat.y || - object.texOffset.x || object.texOffset.y) - { - aiUVTransform transform; - transform.mScaling = object.texRepeat; - transform.mTranslation = object.texOffset; - matDest.AddProperty(&transform,1,AI_MATKEY_UVTRANSFORM_DIFFUSE(0)); - } - } - - matDest.AddProperty(&matSrc.rgb,1, AI_MATKEY_COLOR_DIFFUSE); - matDest.AddProperty(&matSrc.amb,1, AI_MATKEY_COLOR_AMBIENT); - matDest.AddProperty(&matSrc.emis,1,AI_MATKEY_COLOR_EMISSIVE); - matDest.AddProperty(&matSrc.spec,1,AI_MATKEY_COLOR_SPECULAR); - - int n; - if (matSrc.shin) - { - n = aiShadingMode_Phong; - matDest.AddProperty(&matSrc.shin,1,AI_MATKEY_SHININESS); - } - else n = aiShadingMode_Gouraud; - matDest.AddProperty(&n,1,AI_MATKEY_SHADING_MODEL); - - float f = 1.f - matSrc.trans; - matDest.AddProperty(&f,1,AI_MATKEY_OPACITY); + aiString s; + + if (matSrc.name.length()) + { + s.Set(matSrc.name); + matDest.AddProperty(&s,AI_MATKEY_NAME); + } + if (object.texture.length()) + { + s.Set(object.texture); + matDest.AddProperty(&s,AI_MATKEY_TEXTURE_DIFFUSE(0)); + + // UV transformation + if (1.f != object.texRepeat.x || 1.f != object.texRepeat.y || + object.texOffset.x || object.texOffset.y) + { + aiUVTransform transform; + transform.mScaling = object.texRepeat; + transform.mTranslation = object.texOffset; + matDest.AddProperty(&transform,1,AI_MATKEY_UVTRANSFORM_DIFFUSE(0)); + } + } + + matDest.AddProperty(&matSrc.rgb,1, AI_MATKEY_COLOR_DIFFUSE); + matDest.AddProperty(&matSrc.amb,1, AI_MATKEY_COLOR_AMBIENT); + matDest.AddProperty(&matSrc.emis,1,AI_MATKEY_COLOR_EMISSIVE); + matDest.AddProperty(&matSrc.spec,1,AI_MATKEY_COLOR_SPECULAR); + + int n; + if (matSrc.shin) + { + n = aiShadingMode_Phong; + matDest.AddProperty(&matSrc.shin,1,AI_MATKEY_SHININESS); + } + else n = aiShadingMode_Gouraud; + matDest.AddProperty(&n,1,AI_MATKEY_SHADING_MODEL); + + float f = 1.f - matSrc.trans; + matDest.AddProperty(&f,1,AI_MATKEY_OPACITY); } // ------------------------------------------------------------------------------------------------ // Converts the loaded data to the internal verbose representation aiNode* AC3DImporter::ConvertObjectSection(Object& object, - std::vector& meshes, - std::vector& outMaterials, - const std::vector& materials, - aiNode* parent) + std::vector& meshes, + std::vector& outMaterials, + const std::vector& materials, + aiNode* parent) { - aiNode* node = new aiNode(); - node->mParent = parent; - if (object.vertices.size()) - { - if (!object.surfaces.size() || !object.numRefs) - { - /* " An object with 7 vertices (no surfaces, no materials defined). - This is a good way of getting point data into AC3D. - The Vertex->create convex-surface/object can be used on these - vertices to 'wrap' a 3d shape around them " - (http://www.opencity.info/html/ac3dfileformat.html) - - therefore: if no surfaces are defined return point data only - */ - - DefaultLogger::get()->info("AC3D: No surfaces defined in object definition, " - "a point list is returned"); - - meshes.push_back(new aiMesh()); - aiMesh* mesh = meshes.back(); - - mesh->mNumFaces = mesh->mNumVertices = (unsigned int)object.vertices.size(); - aiFace* faces = mesh->mFaces = new aiFace[mesh->mNumFaces]; - aiVector3D* verts = mesh->mVertices = new aiVector3D[mesh->mNumVertices]; - - for (unsigned int i = 0; i < mesh->mNumVertices;++i,++faces,++verts) - { - *verts = object.vertices[i]; - faces->mNumIndices = 1; - faces->mIndices = new unsigned int[1]; - faces->mIndices[0] = i; - } - - // use the primary material in this case. this should be the - // default material if all objects of the file contain points - // and no faces. - mesh->mMaterialIndex = 0; - outMaterials.push_back(new aiMaterial()); - ConvertMaterial(object, materials[0], *outMaterials.back()); - } - else - { - // need to generate one or more meshes for this object. - // find out how many different materials we have - typedef std::pair< unsigned int, unsigned int > IntPair; - typedef std::vector< IntPair > MatTable; - MatTable needMat(materials.size(),IntPair(0,0)); - - std::vector::iterator it,end = object.surfaces.end(); - std::vector::iterator it2,end2; - - for (it = object.surfaces.begin(); it != end; ++it) - { - unsigned int idx = (*it).mat; - if (idx >= needMat.size()) - { - DefaultLogger::get()->error("AC3D: material index is out of range"); - idx = 0; - } - if ((*it).entries.empty()) - { - DefaultLogger::get()->warn("AC3D: surface her zero vertex references"); - } - - // validate all vertex indices to make sure we won't crash here - for (it2 = (*it).entries.begin(), - end2 = (*it).entries.end(); it2 != end2; ++it2) - { - if ((*it2).first >= object.vertices.size()) - { - DefaultLogger::get()->warn("AC3D: Invalid vertex reference"); - (*it2).first = 0; - } - } - - if (!needMat[idx].first)++node->mNumMeshes; - - switch ((*it).flags & 0xf) - { - // closed line - case 0x1: - - needMat[idx].first += (unsigned int)(*it).entries.size(); - needMat[idx].second += (unsigned int)(*it).entries.size()<<1u; - break; - - // unclosed line - case 0x2: - - needMat[idx].first += (unsigned int)(*it).entries.size()-1; - needMat[idx].second += ((unsigned int)(*it).entries.size()-1)<<1u; - break; - - // 0 == polygon, else unknown - default: - - if ((*it).flags & 0xf) - { - DefaultLogger::get()->warn("AC3D: The type flag of a surface is unknown"); - (*it).flags &= ~(0xf); - } - - // the number of faces increments by one, the number - // of vertices by surface.numref. - needMat[idx].first++; - needMat[idx].second += (unsigned int)(*it).entries.size(); - }; - } - unsigned int* pip = node->mMeshes = new unsigned int[node->mNumMeshes]; - unsigned int mat = 0; - const size_t oldm = meshes.size(); - for (MatTable::const_iterator cit = needMat.begin(), cend = needMat.end(); - cit != cend; ++cit, ++mat) - { - if (!(*cit).first)continue; - - // allocate a new aiMesh object - *pip++ = (unsigned int)meshes.size(); - aiMesh* mesh = new aiMesh(); - meshes.push_back(mesh); - - mesh->mMaterialIndex = (unsigned int)outMaterials.size(); - outMaterials.push_back(new aiMaterial()); - ConvertMaterial(object, materials[mat], *outMaterials.back()); - - // allocate storage for vertices and normals - mesh->mNumFaces = (*cit).first; - aiFace* faces = mesh->mFaces = new aiFace[mesh->mNumFaces]; - - mesh->mNumVertices = (*cit).second; - aiVector3D* vertices = mesh->mVertices = new aiVector3D[mesh->mNumVertices]; - unsigned int cur = 0; - - // allocate UV coordinates, but only if the texture name for the - // surface is not empty - aiVector3D* uv = NULL; - if(object.texture.length()) - { - uv = mesh->mTextureCoords[0] = new aiVector3D[mesh->mNumVertices]; - mesh->mNumUVComponents[0] = 2; - } - - for (it = object.surfaces.begin(); it != end; ++it) - { - if (mat == (*it).mat) - { - const Surface& src = *it; - - // closed polygon - unsigned int type = (*it).flags & 0xf; - if (!type) - { - aiFace& face = *faces++; - if((face.mNumIndices = (unsigned int)src.entries.size())) - { - face.mIndices = new unsigned int[face.mNumIndices]; - for (unsigned int i = 0; i < face.mNumIndices;++i,++vertices) - { - const Surface::SurfaceEntry& entry = src.entries[i]; - face.mIndices[i] = cur++; - - // copy vertex positions - *vertices = object.vertices[entry.first] + object.translation; - - - // copy texture coordinates - if (uv) - { - uv->x = entry.second.x; - uv->y = entry.second.y; - ++uv; - } - } - } - } - else - { - - it2 = (*it).entries.begin(); - - // either a closed or an unclosed line - unsigned int tmp = (unsigned int)(*it).entries.size(); - if (0x2 == type)--tmp; - for (unsigned int m = 0; m < tmp;++m) - { - aiFace& face = *faces++; - - face.mNumIndices = 2; - face.mIndices = new unsigned int[2]; - face.mIndices[0] = cur++; - face.mIndices[1] = cur++; - - // copy vertex positions - *vertices++ = object.vertices[(*it2).first]; - - // copy texture coordinates - if (uv) - { - uv->x = (*it2).second.x; - uv->y = (*it2).second.y; - ++uv; - } - - - if (0x1 == type && tmp-1 == m) - { - // if this is a closed line repeat its beginning now - it2 = (*it).entries.begin(); - } - else ++it2; - - // second point - *vertices++ = object.vertices[(*it2).first]; - - if (uv) - { - uv->x = (*it2).second.x; - uv->y = (*it2).second.y; - ++uv; - } - } - } - } - } - } - - // Now apply catmull clark subdivision if necessary. We split meshes into - // materials which is not done by AC3D during smoothing, so we need to - // collect all meshes using the same material group. - if (object.subDiv) { - if (configEvalSubdivision) { - boost::scoped_ptr div(Subdivider::Create(Subdivider::CATMULL_CLARKE)); - DefaultLogger::get()->info("AC3D: Evaluating subdivision surface: "+object.name); - - std::vector cpy(meshes.size()-oldm,NULL); - div->Subdivide(&meshes[oldm],cpy.size(),&cpy.front(),object.subDiv,true); - std::copy(cpy.begin(),cpy.end(),meshes.begin()+oldm); - - // previous meshes are deleted vy Subdivide(). - } - else { - DefaultLogger::get()->info("AC3D: Letting the subdivision surface untouched due to my configuration: " - +object.name); - } - } - } - } - - if (object.name.length()) - node->mName.Set(object.name); - else - { - // generate a name depending on the type of the node - switch (object.type) - { - case Object::Group: - node->mName.length = ::sprintf(node->mName.data,"ACGroup_%i",groups++); - break; - case Object::Poly: - node->mName.length = ::sprintf(node->mName.data,"ACPoly_%i",polys++); - break; - case Object::Light: - node->mName.length = ::sprintf(node->mName.data,"ACLight_%i",lights++); - break; - - // there shouldn't be more than one world, but we don't care - case Object::World: - node->mName.length = ::sprintf(node->mName.data,"ACWorld_%i",worlds++); - break; - } - } - - - // setup the local transformation matrix of the object - // compute the transformation offset to the parent node - node->mTransformation = aiMatrix4x4 ( object.rotation ); - - if (object.type == Object::Group || !object.numRefs) - { - node->mTransformation.a4 = object.translation.x; - node->mTransformation.b4 = object.translation.y; - node->mTransformation.c4 = object.translation.z; - } - - // add children to the object - if (object.children.size()) - { - node->mNumChildren = (unsigned int)object.children.size(); - node->mChildren = new aiNode*[node->mNumChildren]; - for (unsigned int i = 0; i < node->mNumChildren;++i) - { - node->mChildren[i] = ConvertObjectSection(object.children[i],meshes,outMaterials,materials,node); - } - } - - return node; + aiNode* node = new aiNode(); + node->mParent = parent; + if (object.vertices.size()) + { + if (!object.surfaces.size() || !object.numRefs) + { + /* " An object with 7 vertices (no surfaces, no materials defined). + This is a good way of getting point data into AC3D. + The Vertex->create convex-surface/object can be used on these + vertices to 'wrap' a 3d shape around them " + (http://www.opencity.info/html/ac3dfileformat.html) + + therefore: if no surfaces are defined return point data only + */ + + DefaultLogger::get()->info("AC3D: No surfaces defined in object definition, " + "a point list is returned"); + + meshes.push_back(new aiMesh()); + aiMesh* mesh = meshes.back(); + + mesh->mNumFaces = mesh->mNumVertices = (unsigned int)object.vertices.size(); + aiFace* faces = mesh->mFaces = new aiFace[mesh->mNumFaces]; + aiVector3D* verts = mesh->mVertices = new aiVector3D[mesh->mNumVertices]; + + for (unsigned int i = 0; i < mesh->mNumVertices;++i,++faces,++verts) + { + *verts = object.vertices[i]; + faces->mNumIndices = 1; + faces->mIndices = new unsigned int[1]; + faces->mIndices[0] = i; + } + + // use the primary material in this case. this should be the + // default material if all objects of the file contain points + // and no faces. + mesh->mMaterialIndex = 0; + outMaterials.push_back(new aiMaterial()); + ConvertMaterial(object, materials[0], *outMaterials.back()); + } + else + { + // need to generate one or more meshes for this object. + // find out how many different materials we have + typedef std::pair< unsigned int, unsigned int > IntPair; + typedef std::vector< IntPair > MatTable; + MatTable needMat(materials.size(),IntPair(0,0)); + + std::vector::iterator it,end = object.surfaces.end(); + std::vector::iterator it2,end2; + + for (it = object.surfaces.begin(); it != end; ++it) + { + unsigned int idx = (*it).mat; + if (idx >= needMat.size()) + { + DefaultLogger::get()->error("AC3D: material index is out of range"); + idx = 0; + } + if ((*it).entries.empty()) + { + DefaultLogger::get()->warn("AC3D: surface her zero vertex references"); + } + + // validate all vertex indices to make sure we won't crash here + for (it2 = (*it).entries.begin(), + end2 = (*it).entries.end(); it2 != end2; ++it2) + { + if ((*it2).first >= object.vertices.size()) + { + DefaultLogger::get()->warn("AC3D: Invalid vertex reference"); + (*it2).first = 0; + } + } + + if (!needMat[idx].first)++node->mNumMeshes; + + switch ((*it).flags & 0xf) + { + // closed line + case 0x1: + + needMat[idx].first += (unsigned int)(*it).entries.size(); + needMat[idx].second += (unsigned int)(*it).entries.size()<<1u; + break; + + // unclosed line + case 0x2: + + needMat[idx].first += (unsigned int)(*it).entries.size()-1; + needMat[idx].second += ((unsigned int)(*it).entries.size()-1)<<1u; + break; + + // 0 == polygon, else unknown + default: + + if ((*it).flags & 0xf) + { + DefaultLogger::get()->warn("AC3D: The type flag of a surface is unknown"); + (*it).flags &= ~(0xf); + } + + // the number of faces increments by one, the number + // of vertices by surface.numref. + needMat[idx].first++; + needMat[idx].second += (unsigned int)(*it).entries.size(); + }; + } + unsigned int* pip = node->mMeshes = new unsigned int[node->mNumMeshes]; + unsigned int mat = 0; + const size_t oldm = meshes.size(); + for (MatTable::const_iterator cit = needMat.begin(), cend = needMat.end(); + cit != cend; ++cit, ++mat) + { + if (!(*cit).first)continue; + + // allocate a new aiMesh object + *pip++ = (unsigned int)meshes.size(); + aiMesh* mesh = new aiMesh(); + meshes.push_back(mesh); + + mesh->mMaterialIndex = (unsigned int)outMaterials.size(); + outMaterials.push_back(new aiMaterial()); + ConvertMaterial(object, materials[mat], *outMaterials.back()); + + // allocate storage for vertices and normals + mesh->mNumFaces = (*cit).first; + if (mesh->mNumFaces == 0) { + throw DeadlyImportError("AC3D: No faces"); + } else if (mesh->mNumFaces > AI_MAX_ALLOC(aiFace)) { + throw DeadlyImportError("AC3D: Too many faces, would run out of memory"); + } + aiFace* faces = mesh->mFaces = new aiFace[mesh->mNumFaces]; + + mesh->mNumVertices = (*cit).second; + if (mesh->mNumVertices == 0) { + throw DeadlyImportError("AC3D: No vertices"); + } else if (mesh->mNumVertices > AI_MAX_ALLOC(aiVector3D)) { + throw DeadlyImportError("AC3D: Too many vertices, would run out of memory"); + } + aiVector3D* vertices = mesh->mVertices = new aiVector3D[mesh->mNumVertices]; + unsigned int cur = 0; + + // allocate UV coordinates, but only if the texture name for the + // surface is not empty + aiVector3D* uv = NULL; + if(object.texture.length()) + { + uv = mesh->mTextureCoords[0] = new aiVector3D[mesh->mNumVertices]; + mesh->mNumUVComponents[0] = 2; + } + + for (it = object.surfaces.begin(); it != end; ++it) + { + if (mat == (*it).mat) + { + const Surface& src = *it; + + // closed polygon + unsigned int type = (*it).flags & 0xf; + if (!type) + { + aiFace& face = *faces++; + if((face.mNumIndices = (unsigned int)src.entries.size())) + { + face.mIndices = new unsigned int[face.mNumIndices]; + for (unsigned int i = 0; i < face.mNumIndices;++i,++vertices) + { + const Surface::SurfaceEntry& entry = src.entries[i]; + face.mIndices[i] = cur++; + + // copy vertex positions + if (static_cast(vertices - mesh->mVertices) >= mesh->mNumVertices) { + throw DeadlyImportError("AC3D: Invalid number of vertices"); + } + *vertices = object.vertices[entry.first] + object.translation; + + + // copy texture coordinates + if (uv) + { + uv->x = entry.second.x; + uv->y = entry.second.y; + ++uv; + } + } + } + } + else + { + + it2 = (*it).entries.begin(); + + // either a closed or an unclosed line + unsigned int tmp = (unsigned int)(*it).entries.size(); + if (0x2 == type)--tmp; + for (unsigned int m = 0; m < tmp;++m) + { + aiFace& face = *faces++; + + face.mNumIndices = 2; + face.mIndices = new unsigned int[2]; + face.mIndices[0] = cur++; + face.mIndices[1] = cur++; + + // copy vertex positions + if (it2 == (*it).entries.end() ) { + throw DeadlyImportError("AC3D: Bad line"); + } + ai_assert((*it2).first < object.vertices.size()); + *vertices++ = object.vertices[(*it2).first]; + + // copy texture coordinates + if (uv) + { + uv->x = (*it2).second.x; + uv->y = (*it2).second.y; + ++uv; + } + + + if (0x1 == type && tmp-1 == m) + { + // if this is a closed line repeat its beginning now + it2 = (*it).entries.begin(); + } + else ++it2; + + // second point + *vertices++ = object.vertices[(*it2).first]; + + if (uv) + { + uv->x = (*it2).second.x; + uv->y = (*it2).second.y; + ++uv; + } + } + } + } + } + } + + // Now apply catmull clark subdivision if necessary. We split meshes into + // materials which is not done by AC3D during smoothing, so we need to + // collect all meshes using the same material group. + if (object.subDiv) { + if (configEvalSubdivision) { + std::unique_ptr div(Subdivider::Create(Subdivider::CATMULL_CLARKE)); + DefaultLogger::get()->info("AC3D: Evaluating subdivision surface: "+object.name); + + std::vector cpy(meshes.size()-oldm,NULL); + div->Subdivide(&meshes[oldm],cpy.size(),&cpy.front(),object.subDiv,true); + std::copy(cpy.begin(),cpy.end(),meshes.begin()+oldm); + + // previous meshes are deleted vy Subdivide(). + } + else { + DefaultLogger::get()->info("AC3D: Letting the subdivision surface untouched due to my configuration: " + +object.name); + } + } + } + } + + if (object.name.length()) + node->mName.Set(object.name); + else + { + // generate a name depending on the type of the node + switch (object.type) + { + case Object::Group: + node->mName.length = ::ai_snprintf(node->mName.data, MAXLEN, "ACGroup_%i",groups++); + break; + case Object::Poly: + node->mName.length = ::ai_snprintf(node->mName.data, MAXLEN, "ACPoly_%i",polys++); + break; + case Object::Light: + node->mName.length = ::ai_snprintf(node->mName.data, MAXLEN, "ACLight_%i",lights++); + break; + + // there shouldn't be more than one world, but we don't care + case Object::World: + node->mName.length = ::ai_snprintf(node->mName.data, MAXLEN, "ACWorld_%i",worlds++); + break; + } + } + + + // setup the local transformation matrix of the object + // compute the transformation offset to the parent node + node->mTransformation = aiMatrix4x4 ( object.rotation ); + + if (object.type == Object::Group || !object.numRefs) + { + node->mTransformation.a4 = object.translation.x; + node->mTransformation.b4 = object.translation.y; + node->mTransformation.c4 = object.translation.z; + } + + // add children to the object + if (object.children.size()) + { + node->mNumChildren = (unsigned int)object.children.size(); + node->mChildren = new aiNode*[node->mNumChildren]; + for (unsigned int i = 0; i < node->mNumChildren;++i) + { + node->mChildren[i] = ConvertObjectSection(object.children[i],meshes,outMaterials,materials,node); + } + } + + return node; } // ------------------------------------------------------------------------------------------------ void AC3DImporter::SetupProperties(const Importer* pImp) { - configSplitBFCull = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_AC_SEPARATE_BFCULL,1) ? true : false; - configEvalSubdivision = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_AC_EVAL_SUBDIVISION,1) ? true : false; + configSplitBFCull = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_AC_SEPARATE_BFCULL,1) ? true : false; + configEvalSubdivision = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_AC_EVAL_SUBDIVISION,1) ? true : false; } // ------------------------------------------------------------------------------------------------ -// Imports the given file into the given scene structure. -void AC3DImporter::InternReadFile( const std::string& pFile, - aiScene* pScene, IOSystem* pIOHandler) +// Imports the given file into the given scene structure. +void AC3DImporter::InternReadFile( const std::string& pFile, + aiScene* pScene, IOSystem* pIOHandler) { - boost::scoped_ptr file( pIOHandler->Open( pFile, "rb")); - - // Check whether we can read from the file - if( file.get() == NULL) - throw DeadlyImportError( "Failed to open AC3D file " + pFile + "."); - - // allocate storage and copy the contents of the file to a memory buffer - std::vector mBuffer2; - TextFileToBuffer(file.get(),mBuffer2); - - buffer = &mBuffer2[0]; - mNumMeshes = 0; - - lights = polys = worlds = groups = 0; - - if (::strncmp(buffer,"AC3D",4)) { - throw DeadlyImportError("AC3D: No valid AC3D file, magic sequence not found"); - } - - // print the file format version to the console - unsigned int version = HexDigitToDecimal( buffer[4] ); - char msg[3]; - ASSIMP_itoa10(msg,3,version); - DefaultLogger::get()->info(std::string("AC3D file format version: ") + msg); - - std::vector materials; - materials.reserve(5); - - std::vector rootObjects; - rootObjects.reserve(5); - - std::vector lights; - mLights = & lights; - - while (GetNextLine()) - { - if (TokenMatch(buffer,"MATERIAL",8)) - { - materials.push_back(Material()); - Material& mat = materials.back(); - - // manually parse the material ... sscanf would use the buldin atof ... - // Format: (name) rgb %f %f %f amb %f %f %f emis %f %f %f spec %f %f %f shi %d trans %f - - AI_AC_SKIP_TO_NEXT_TOKEN(); - if ('\"' == *buffer) - { - AI_AC_GET_STRING(mat.name); - AI_AC_SKIP_TO_NEXT_TOKEN(); - } - - AI_AC_CHECKED_LOAD_FLOAT_ARRAY("rgb",3,3,&mat.rgb); - AI_AC_CHECKED_LOAD_FLOAT_ARRAY("amb",3,3,&mat.amb); - AI_AC_CHECKED_LOAD_FLOAT_ARRAY("emis",4,3,&mat.emis); - AI_AC_CHECKED_LOAD_FLOAT_ARRAY("spec",4,3,&mat.spec); - AI_AC_CHECKED_LOAD_FLOAT_ARRAY("shi",3,1,&mat.shin); - AI_AC_CHECKED_LOAD_FLOAT_ARRAY("trans",5,1,&mat.trans); - } - LoadObjectSection(rootObjects); - } - - if (rootObjects.empty() || !mNumMeshes) - { - throw DeadlyImportError("AC3D: No meshes have been loaded"); - } - if (materials.empty()) - { - DefaultLogger::get()->warn("AC3D: No material has been found"); - materials.push_back(Material()); - } - - mNumMeshes += (mNumMeshes>>2u) + 1; - std::vector meshes; - meshes.reserve(mNumMeshes); - - std::vector omaterials; - materials.reserve(mNumMeshes); - - // generate a dummy root if there are multiple objects on the top layer - Object* root; - if (1 == rootObjects.size()) - root = &rootObjects[0]; - else - { - root = new Object(); - } - - // now convert the imported stuff to our output data structure - pScene->mRootNode = ConvertObjectSection(*root,meshes,omaterials,materials); - if (1 != rootObjects.size())delete root; - - if (!::strncmp( pScene->mRootNode->mName.data, "Node", 4)) - pScene->mRootNode->mName.Set(""); - - // copy meshes - if (meshes.empty()) - { - throw DeadlyImportError("An unknown error occured during converting"); - } - pScene->mNumMeshes = (unsigned int)meshes.size(); - pScene->mMeshes = new aiMesh*[pScene->mNumMeshes]; - ::memcpy(pScene->mMeshes,&meshes[0],pScene->mNumMeshes*sizeof(void*)); - - // copy materials - pScene->mNumMaterials = (unsigned int)omaterials.size(); - pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials]; - ::memcpy(pScene->mMaterials,&omaterials[0],pScene->mNumMaterials*sizeof(void*)); - - // copy lights - pScene->mNumLights = (unsigned int)lights.size(); - if (lights.size()) - { - pScene->mLights = new aiLight*[lights.size()]; - ::memcpy(pScene->mLights,&lights[0],lights.size()*sizeof(void*)); - } + std::unique_ptr file( pIOHandler->Open( pFile, "rb")); + + // Check whether we can read from the file + if( file.get() == NULL) + throw DeadlyImportError( "Failed to open AC3D file " + pFile + "."); + + // allocate storage and copy the contents of the file to a memory buffer + std::vector mBuffer2; + TextFileToBuffer(file.get(),mBuffer2); + + buffer = &mBuffer2[0]; + mNumMeshes = 0; + + lights = polys = worlds = groups = 0; + + if (::strncmp(buffer,"AC3D",4)) { + throw DeadlyImportError("AC3D: No valid AC3D file, magic sequence not found"); + } + + // print the file format version to the console + unsigned int version = HexDigitToDecimal( buffer[4] ); + char msg[3]; + ASSIMP_itoa10(msg,3,version); + DefaultLogger::get()->info(std::string("AC3D file format version: ") + msg); + + std::vector materials; + materials.reserve(5); + + std::vector rootObjects; + rootObjects.reserve(5); + + std::vector lights; + mLights = & lights; + + while (GetNextLine()) + { + if (TokenMatch(buffer,"MATERIAL",8)) + { + materials.push_back(Material()); + Material& mat = materials.back(); + + // manually parse the material ... sscanf would use the buldin atof ... + // Format: (name) rgb %f %f %f amb %f %f %f emis %f %f %f spec %f %f %f shi %d trans %f + + AI_AC_SKIP_TO_NEXT_TOKEN(); + if ('\"' == *buffer) + { + AI_AC_GET_STRING(mat.name); + AI_AC_SKIP_TO_NEXT_TOKEN(); + } + + AI_AC_CHECKED_LOAD_FLOAT_ARRAY("rgb",3,3,&mat.rgb); + AI_AC_CHECKED_LOAD_FLOAT_ARRAY("amb",3,3,&mat.amb); + AI_AC_CHECKED_LOAD_FLOAT_ARRAY("emis",4,3,&mat.emis); + AI_AC_CHECKED_LOAD_FLOAT_ARRAY("spec",4,3,&mat.spec); + AI_AC_CHECKED_LOAD_FLOAT_ARRAY("shi",3,1,&mat.shin); + AI_AC_CHECKED_LOAD_FLOAT_ARRAY("trans",5,1,&mat.trans); + } + LoadObjectSection(rootObjects); + } + + if (rootObjects.empty() || !mNumMeshes) + { + throw DeadlyImportError("AC3D: No meshes have been loaded"); + } + if (materials.empty()) + { + DefaultLogger::get()->warn("AC3D: No material has been found"); + materials.push_back(Material()); + } + + mNumMeshes += (mNumMeshes>>2u) + 1; + std::vector meshes; + meshes.reserve(mNumMeshes); + + std::vector omaterials; + materials.reserve(mNumMeshes); + + // generate a dummy root if there are multiple objects on the top layer + Object* root; + if (1 == rootObjects.size()) + root = &rootObjects[0]; + else + { + root = new Object(); + } + + // now convert the imported stuff to our output data structure + pScene->mRootNode = ConvertObjectSection(*root,meshes,omaterials,materials); + if (1 != rootObjects.size())delete root; + + if (!::strncmp( pScene->mRootNode->mName.data, "Node", 4)) + pScene->mRootNode->mName.Set(""); + + // copy meshes + if (meshes.empty()) + { + throw DeadlyImportError("An unknown error occurred during converting"); + } + pScene->mNumMeshes = (unsigned int)meshes.size(); + pScene->mMeshes = new aiMesh*[pScene->mNumMeshes]; + ::memcpy(pScene->mMeshes,&meshes[0],pScene->mNumMeshes*sizeof(void*)); + + // copy materials + pScene->mNumMaterials = (unsigned int)omaterials.size(); + pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials]; + ::memcpy(pScene->mMaterials,&omaterials[0],pScene->mNumMaterials*sizeof(void*)); + + // copy lights + pScene->mNumLights = (unsigned int)lights.size(); + if (lights.size()) + { + pScene->mLights = new aiLight*[lights.size()]; + ::memcpy(pScene->mLights,&lights[0],lights.size()*sizeof(void*)); + } } #endif //!defined ASSIMP_BUILD_NO_AC_IMPORTER diff --git a/src/3rdparty/assimp/code/ACLoader.h b/src/3rdparty/assimp/code/ACLoader.h index 3f5089258..52563adad 100644 --- a/src/3rdparty/assimp/code/ACLoader.h +++ b/src/3rdparty/assimp/code/ACLoader.h @@ -2,11 +2,11 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2012, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above @@ -23,16 +23,16 @@ following conditions are met: derived from this software without specific prior written permission of the assimp team. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- @@ -47,9 +47,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include "BaseImporter.h" -#include "../include/assimp/types.h" +#include -namespace Assimp { +struct aiNode; +struct aiMesh; +struct aiMaterial; +struct aiLight; + + +namespace Assimp { // --------------------------------------------------------------------------- /** AC3D (*.ac) importer class @@ -57,209 +63,210 @@ namespace Assimp { class AC3DImporter : public BaseImporter { public: - AC3DImporter(); - ~AC3DImporter(); - - - - // Represents an AC3D material - struct Material - { - Material() - : rgb (0.6f,0.6f,0.6f) - , spec (1.f,1.f,1.f) - , shin (0.f) - , trans (0.f) - {} + AC3DImporter(); + ~AC3DImporter(); + + + + // Represents an AC3D material + struct Material + { + Material() + : rgb (0.6f,0.6f,0.6f) + , spec (1.f,1.f,1.f) + , shin (0.f) + , trans (0.f) + {} - // base color of the material - aiColor3D rgb; + // base color of the material + aiColor3D rgb; - // ambient color of the material - aiColor3D amb; + // ambient color of the material + aiColor3D amb; - // emissive color of the material - aiColor3D emis; + // emissive color of the material + aiColor3D emis; - // specular color of the material - aiColor3D spec; + // specular color of the material + aiColor3D spec; - // shininess exponent - float shin; + // shininess exponent + float shin; - // transparency. 0 == opaque - float trans; + // transparency. 0 == opaque + float trans; - // name of the material. optional. - std::string name; - }; + // name of the material. optional. + std::string name; + }; - // Represents an AC3D surface - struct Surface - { - Surface() - : mat (0) - , flags (0) - {} + // Represents an AC3D surface + struct Surface + { + Surface() + : mat (0) + , flags (0) + {} - unsigned int mat,flags; + unsigned int mat,flags; - typedef std::pair SurfaceEntry; - std::vector< SurfaceEntry > entries; - }; + typedef std::pair SurfaceEntry; + std::vector< SurfaceEntry > entries; + }; - // Represents an AC3D object - struct Object - { - Object() - : type (World) - , name( "" ) - , children() - , texture( "" ) - , texRepeat( 1.f, 1.f ) - , texOffset( 0.0f, 0.0f ) - , rotation() - , translation() - , vertices() - , surfaces() - , numRefs (0) - , subDiv (0) - {} + // Represents an AC3D object + struct Object + { + Object() + : type (World) + , name( "" ) + , children() + , texture( "" ) + , texRepeat( 1.f, 1.f ) + , texOffset( 0.0f, 0.0f ) + , rotation() + , translation() + , vertices() + , surfaces() + , numRefs (0) + , subDiv (0) + , crease() + {} - // Type description - enum Type - { - World = 0x0, - Poly = 0x1, - Group = 0x2, - Light = 0x4 - } type; + // Type description + enum Type + { + World = 0x0, + Poly = 0x1, + Group = 0x2, + Light = 0x4 + } type; - // name of the object - std::string name; + // name of the object + std::string name; - // object children - std::vector children; + // object children + std::vector children; - // texture to be assigned to all surfaces of the object - std::string texture; + // texture to be assigned to all surfaces of the object + std::string texture; - // texture repat factors (scaling for all coordinates) - aiVector2D texRepeat, texOffset; + // texture repat factors (scaling for all coordinates) + aiVector2D texRepeat, texOffset; - // rotation matrix - aiMatrix3x3 rotation; + // rotation matrix + aiMatrix3x3 rotation; - // translation vector - aiVector3D translation; + // translation vector + aiVector3D translation; - // vertices - std::vector vertices; + // vertices + std::vector vertices; - // surfaces - std::vector surfaces; + // surfaces + std::vector surfaces; - // number of indices (= num verts in verbose format) - unsigned int numRefs; - - // number of subdivisions to be performed on the - // imported data - unsigned int subDiv; - - // max angle limit for smoothing - float crease; - }; + // number of indices (= num verts in verbose format) + unsigned int numRefs; + + // number of subdivisions to be performed on the + // imported data + unsigned int subDiv; + + // max angle limit for smoothing + float crease; + }; public: - // ------------------------------------------------------------------- - /** Returns whether the class can handle the format of the given file. - * See BaseImporter::CanRead() for details. - */ - bool CanRead( const std::string& pFile, IOSystem* pIOHandler, - bool checkSig) const; + // ------------------------------------------------------------------- + /** Returns whether the class can handle the format of the given file. + * See BaseImporter::CanRead() for details. + */ + bool CanRead( const std::string& pFile, IOSystem* pIOHandler, + bool checkSig) const; protected: - // ------------------------------------------------------------------- - /** Return importer meta information. - * See #BaseImporter::GetInfo for the details */ - const aiImporterDesc* GetInfo () const; + // ------------------------------------------------------------------- + /** Return importer meta information. + * See #BaseImporter::GetInfo for the details */ + const aiImporterDesc* GetInfo () const; - // ------------------------------------------------------------------- - /** Imports the given file into the given scene structure. - * See BaseImporter::InternReadFile() for details*/ - void InternReadFile( const std::string& pFile, aiScene* pScene, - IOSystem* pIOHandler); + // ------------------------------------------------------------------- + /** Imports the given file into the given scene structure. + * See BaseImporter::InternReadFile() for details*/ + void InternReadFile( const std::string& pFile, aiScene* pScene, + IOSystem* pIOHandler); - // ------------------------------------------------------------------- - /** Called prior to ReadFile(). - * The function is a request to the importer to update its configuration - * basing on the Importer's configuration property list.*/ - void SetupProperties(const Importer* pImp); + // ------------------------------------------------------------------- + /** Called prior to ReadFile(). + * The function is a request to the importer to update its configuration + * basing on the Importer's configuration property list.*/ + void SetupProperties(const Importer* pImp); private: - // ------------------------------------------------------------------- - /** Get the next line from the file. - * @return false if the end of the file was reached*/ - bool GetNextLine(); - - // ------------------------------------------------------------------- - /** Load the object section. This method is called recursively to - * load subobjects, the method returns after a 'kids 0' was - * encountered. - * @objects List of output objects*/ - void LoadObjectSection(std::vector& objects); - - // ------------------------------------------------------------------- - /** Convert all objects into meshes and nodes. - * @param object Current object to work on - * @param meshes Pointer to the list of output meshes - * @param outMaterials List of output materials - * @param materials Material list - * @param Scenegraph node for the object */ - aiNode* ConvertObjectSection(Object& object, - std::vector& meshes, - std::vector& outMaterials, - const std::vector& materials, - aiNode* parent = NULL); - - // ------------------------------------------------------------------- - /** Convert a material - * @param object Current object - * @param matSrc Source material description - * @param matDest Destination material to be filled */ - void ConvertMaterial(const Object& object, - const Material& matSrc, - aiMaterial& matDest); + // ------------------------------------------------------------------- + /** Get the next line from the file. + * @return false if the end of the file was reached*/ + bool GetNextLine(); + + // ------------------------------------------------------------------- + /** Load the object section. This method is called recursively to + * load subobjects, the method returns after a 'kids 0' was + * encountered. + * @objects List of output objects*/ + void LoadObjectSection(std::vector& objects); + + // ------------------------------------------------------------------- + /** Convert all objects into meshes and nodes. + * @param object Current object to work on + * @param meshes Pointer to the list of output meshes + * @param outMaterials List of output materials + * @param materials Material list + * @param Scenegraph node for the object */ + aiNode* ConvertObjectSection(Object& object, + std::vector& meshes, + std::vector& outMaterials, + const std::vector& materials, + aiNode* parent = NULL); + + // ------------------------------------------------------------------- + /** Convert a material + * @param object Current object + * @param matSrc Source material description + * @param matDest Destination material to be filled */ + void ConvertMaterial(const Object& object, + const Material& matSrc, + aiMaterial& matDest); private: - // points to the next data line - const char* buffer; + // points to the next data line + const char* buffer; - // Configuration option: if enabled, up to two meshes - // are generated per material: those faces who have - // their bf cull flags set are separated. - bool configSplitBFCull; + // Configuration option: if enabled, up to two meshes + // are generated per material: those faces who have + // their bf cull flags set are separated. + bool configSplitBFCull; - // Configuration switch: subdivision surfaces are only - // evaluated if the value is true. - bool configEvalSubdivision; + // Configuration switch: subdivision surfaces are only + // evaluated if the value is true. + bool configEvalSubdivision; - // counts how many objects we have in the tree. - // basing on this information we can find a - // good estimate how many meshes we'll have in the final scene. - unsigned int mNumMeshes; + // counts how many objects we have in the tree. + // basing on this information we can find a + // good estimate how many meshes we'll have in the final scene. + unsigned int mNumMeshes; - // current list of light sources - std::vector* mLights; + // current list of light sources + std::vector* mLights; - // name counters - unsigned int lights, groups, polys, worlds; + // name counters + unsigned int lights, groups, polys, worlds; }; } // end of namespace Assimp diff --git a/src/3rdparty/assimp/code/ASELoader.cpp b/src/3rdparty/assimp/code/ASELoader.cpp index 9be97c87d..39a33e9fd 100644 --- a/src/3rdparty/assimp/code/ASELoader.cpp +++ b/src/3rdparty/assimp/code/ASELoader.cpp @@ -3,12 +3,12 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2012, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above @@ -25,16 +25,16 @@ conditions are met: derived from this software without specific prior written permission of the assimp team. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --------------------------------------------------------------------------- */ @@ -43,7 +43,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * @brief Implementation of the ASE importer class */ -#include "AssimpPCH.h" #ifndef ASSIMP_BUILD_NO_ASE_IMPORTER // internal headers @@ -51,6 +50,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "StringComparison.h" #include "SkeletonMeshBuilder.h" #include "TargetAnimation.h" +#include +#include +#include +#include + +#include // utilities #include "fast_atof.h" @@ -59,1258 +64,1258 @@ using namespace Assimp; using namespace Assimp::ASE; static const aiImporterDesc desc = { - "ASE Importer", - "", - "", - "Similar to 3DS but text-encoded", - aiImporterFlags_SupportTextFlavour, - 0, - 0, - 0, - 0, - "ase ask" + "ASE Importer", + "", + "", + "Similar to 3DS but text-encoded", + aiImporterFlags_SupportTextFlavour, + 0, + 0, + 0, + 0, + "ase ask" }; // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer ASEImporter::ASEImporter() -: noSkeletonMesh() + : mParser(), + mBuffer(), + pcScene(), + configRecomputeNormals(), + noSkeletonMesh() {} // ------------------------------------------------------------------------------------------------ -// Destructor, private as well +// Destructor, private as well ASEImporter::~ASEImporter() {} // ------------------------------------------------------------------------------------------------ -// Returns whether the class can handle the format of the given file. +// Returns whether the class can handle the format of the given file. bool ASEImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool cs) const { - // check file extension - const std::string extension = GetExtension(pFile); - - if( extension == "ase" || extension == "ask") - return true; - - if ((!extension.length() || cs) && pIOHandler) { - const char* tokens[] = {"*3dsmax_asciiexport"}; - return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1); - } - return false; + // check file extension + const std::string extension = GetExtension(pFile); + + if( extension == "ase" || extension == "ask") + return true; + + if ((!extension.length() || cs) && pIOHandler) { + const char* tokens[] = {"*3dsmax_asciiexport"}; + return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1); + } + return false; } // ------------------------------------------------------------------------------------------------ // Loader meta information const aiImporterDesc* ASEImporter::GetInfo () const { - return &desc; + return &desc; } // ------------------------------------------------------------------------------------------------ // Setup configuration options void ASEImporter::SetupProperties(const Importer* pImp) { - configRecomputeNormals = (pImp->GetPropertyInteger( - AI_CONFIG_IMPORT_ASE_RECONSTRUCT_NORMALS,1) ? true : false); + configRecomputeNormals = (pImp->GetPropertyInteger( + AI_CONFIG_IMPORT_ASE_RECONSTRUCT_NORMALS,1) ? true : false); - noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES,0) != 0; + noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES,0) != 0; } // ------------------------------------------------------------------------------------------------ -// Imports the given file into the given scene structure. -void ASEImporter::InternReadFile( const std::string& pFile, - aiScene* pScene, IOSystem* pIOHandler) +// Imports the given file into the given scene structure. +void ASEImporter::InternReadFile( const std::string& pFile, + aiScene* pScene, IOSystem* pIOHandler) { - boost::scoped_ptr file( pIOHandler->Open( pFile, "rb")); - - // Check whether we can read from the file - if( file.get() == NULL) { - throw DeadlyImportError( "Failed to open ASE file " + pFile + "."); - } - - // Allocate storage and copy the contents of the file to a memory buffer - std::vector mBuffer2; - TextFileToBuffer(file.get(),mBuffer2); - - this->mBuffer = &mBuffer2[0]; - this->pcScene = pScene; - - // ------------------------------------------------------------------ - // Guess the file format by looking at the extension - // ASC is considered to be the older format 110, - // ASE is the actual version 200 (that is currently written by max) - // ------------------------------------------------------------------ - unsigned int defaultFormat; - std::string::size_type s = pFile.length()-1; - switch (pFile.c_str()[s]) { - - case 'C': - case 'c': - defaultFormat = AI_ASE_OLD_FILE_FORMAT; - break; - default: - defaultFormat = AI_ASE_NEW_FILE_FORMAT; - }; - - // Construct an ASE parser and parse the file - ASE::Parser parser(mBuffer,defaultFormat); - mParser = &parser; - mParser->Parse(); - - //------------------------------------------------------------------ - // Check whether we god at least one mesh. If we did - generate - // materials and copy meshes. - // ------------------------------------------------------------------ - if ( !mParser->m_vMeshes.empty()) { - - // If absolutely no material has been loaded from the file - // we need to generate a default material - GenerateDefaultMaterial(); - - // process all meshes - bool tookNormals = false; - std::vector avOutMeshes; - avOutMeshes.reserve(mParser->m_vMeshes.size()*2); - for (std::vector::iterator i = mParser->m_vMeshes.begin();i != mParser->m_vMeshes.end();++i) { - if ((*i).bSkip) { - continue; - } - BuildUniqueRepresentation(*i); - - // Need to generate proper vertex normals if necessary - if(GenerateNormals(*i)) { - tookNormals = true; - } - - // Convert all meshes to aiMesh objects - ConvertMeshes(*i,avOutMeshes); - } - if (tookNormals) { - DefaultLogger::get()->debug("ASE: Taking normals from the file. Use " - "the AI_CONFIG_IMPORT_ASE_RECONSTRUCT_NORMALS setting if you " - "experience problems"); - } - - // Now build the output mesh list. Remove dummies - pScene->mNumMeshes = (unsigned int)avOutMeshes.size(); - aiMesh** pp = pScene->mMeshes = new aiMesh*[pScene->mNumMeshes]; - for (std::vector::const_iterator i = avOutMeshes.begin();i != avOutMeshes.end();++i) { - if (!(*i)->mNumFaces) { - continue; - } - *pp++ = *i; - } - pScene->mNumMeshes = (unsigned int)(pp - pScene->mMeshes); - - // Build final material indices (remove submaterials and setup - // the final list) - BuildMaterialIndices(); - } - - // ------------------------------------------------------------------ - // Copy all scene graph nodes - lights, cameras, dummies and meshes - // into one huge list. - //------------------------------------------------------------------ - std::vector nodes; - nodes.reserve(mParser->m_vMeshes.size() +mParser->m_vLights.size() - + mParser->m_vCameras.size() + mParser->m_vDummies.size()); - - // Lights - for (std::vector::iterator it = mParser->m_vLights.begin(), - end = mParser->m_vLights.end();it != end; ++it)nodes.push_back(&(*it)); - // Cameras - for (std::vector::iterator it = mParser->m_vCameras.begin(), - end = mParser->m_vCameras.end();it != end; ++it)nodes.push_back(&(*it)); - // Meshes - for (std::vector::iterator it = mParser->m_vMeshes.begin(), - end = mParser->m_vMeshes.end();it != end; ++it)nodes.push_back(&(*it)); - // Dummies - for (std::vector::iterator it = mParser->m_vDummies.begin(), - end = mParser->m_vDummies.end();it != end; ++it)nodes.push_back(&(*it)); - - // build the final node graph - BuildNodes(nodes); - - // build output animations - BuildAnimations(nodes); - - // build output cameras - BuildCameras(); - - // build output lights - BuildLights(); - - // ------------------------------------------------------------------ - // If we have no meshes use the SkeletonMeshBuilder helper class - // to build a mesh for the animation skeleton - // FIXME: very strange results - // ------------------------------------------------------------------ - if (!pScene->mNumMeshes) { - pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE; - if (!noSkeletonMesh) { - SkeletonMeshBuilder skeleton(pScene); - } - } + std::unique_ptr file( pIOHandler->Open( pFile, "rb")); + + // Check whether we can read from the file + if( file.get() == NULL) { + throw DeadlyImportError( "Failed to open ASE file " + pFile + "."); + } + + // Allocate storage and copy the contents of the file to a memory buffer + std::vector mBuffer2; + TextFileToBuffer(file.get(),mBuffer2); + + this->mBuffer = &mBuffer2[0]; + this->pcScene = pScene; + + // ------------------------------------------------------------------ + // Guess the file format by looking at the extension + // ASC is considered to be the older format 110, + // ASE is the actual version 200 (that is currently written by max) + // ------------------------------------------------------------------ + unsigned int defaultFormat; + std::string::size_type s = pFile.length()-1; + switch (pFile.c_str()[s]) { + + case 'C': + case 'c': + defaultFormat = AI_ASE_OLD_FILE_FORMAT; + break; + default: + defaultFormat = AI_ASE_NEW_FILE_FORMAT; + }; + + // Construct an ASE parser and parse the file + ASE::Parser parser(mBuffer,defaultFormat); + mParser = &parser; + mParser->Parse(); + + //------------------------------------------------------------------ + // Check whether we god at least one mesh. If we did - generate + // materials and copy meshes. + // ------------------------------------------------------------------ + if ( !mParser->m_vMeshes.empty()) { + + // If absolutely no material has been loaded from the file + // we need to generate a default material + GenerateDefaultMaterial(); + + // process all meshes + bool tookNormals = false; + std::vector avOutMeshes; + avOutMeshes.reserve(mParser->m_vMeshes.size()*2); + for (std::vector::iterator i = mParser->m_vMeshes.begin();i != mParser->m_vMeshes.end();++i) { + if ((*i).bSkip) { + continue; + } + BuildUniqueRepresentation(*i); + + // Need to generate proper vertex normals if necessary + if(GenerateNormals(*i)) { + tookNormals = true; + } + + // Convert all meshes to aiMesh objects + ConvertMeshes(*i,avOutMeshes); + } + if (tookNormals) { + DefaultLogger::get()->debug("ASE: Taking normals from the file. Use " + "the AI_CONFIG_IMPORT_ASE_RECONSTRUCT_NORMALS setting if you " + "experience problems"); + } + + // Now build the output mesh list. Remove dummies + pScene->mNumMeshes = (unsigned int)avOutMeshes.size(); + aiMesh** pp = pScene->mMeshes = new aiMesh*[pScene->mNumMeshes]; + for (std::vector::const_iterator i = avOutMeshes.begin();i != avOutMeshes.end();++i) { + if (!(*i)->mNumFaces) { + continue; + } + *pp++ = *i; + } + pScene->mNumMeshes = (unsigned int)(pp - pScene->mMeshes); + + // Build final material indices (remove submaterials and setup + // the final list) + BuildMaterialIndices(); + } + + // ------------------------------------------------------------------ + // Copy all scene graph nodes - lights, cameras, dummies and meshes + // into one huge list. + //------------------------------------------------------------------ + std::vector nodes; + nodes.reserve(mParser->m_vMeshes.size() +mParser->m_vLights.size() + + mParser->m_vCameras.size() + mParser->m_vDummies.size()); + + // Lights + for (auto &light : mParser->m_vLights)nodes.push_back(&light); + // Cameras + for (auto &camera : mParser->m_vCameras)nodes.push_back(&camera); + // Meshes + for (auto &mesh : mParser->m_vMeshes)nodes.push_back(&mesh); + // Dummies + for (auto &dummy : mParser->m_vDummies)nodes.push_back(&dummy); + + // build the final node graph + BuildNodes(nodes); + + // build output animations + BuildAnimations(nodes); + + // build output cameras + BuildCameras(); + + // build output lights + BuildLights(); + + // ------------------------------------------------------------------ + // If we have no meshes use the SkeletonMeshBuilder helper class + // to build a mesh for the animation skeleton + // FIXME: very strange results + // ------------------------------------------------------------------ + if (!pScene->mNumMeshes) { + pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE; + if (!noSkeletonMesh) { + SkeletonMeshBuilder skeleton(pScene); + } + } } // ------------------------------------------------------------------------------------------------ void ASEImporter::GenerateDefaultMaterial() { - ai_assert(NULL != mParser); - - bool bHas = false; - for (std::vector::iterator i = mParser->m_vMeshes.begin();i != mParser->m_vMeshes.end();++i) { - if ((*i).bSkip)continue; - if (ASE::Face::DEFAULT_MATINDEX == (*i).iMaterialIndex) { - (*i).iMaterialIndex = (unsigned int)mParser->m_vMaterials.size(); - bHas = true; - } - } - if (bHas || mParser->m_vMaterials.empty()) { - // add a simple material without submaterials to the parser's list - mParser->m_vMaterials.push_back ( ASE::Material() ); - ASE::Material& mat = mParser->m_vMaterials.back(); - - mat.mDiffuse = aiColor3D(0.6f,0.6f,0.6f); - mat.mSpecular = aiColor3D(1.0f,1.0f,1.0f); - mat.mAmbient = aiColor3D(0.05f,0.05f,0.05f); - mat.mShading = Discreet3DS::Gouraud; - mat.mName = AI_DEFAULT_MATERIAL_NAME; - } + ai_assert(NULL != mParser); + + bool bHas = false; + for (std::vector::iterator i = mParser->m_vMeshes.begin();i != mParser->m_vMeshes.end();++i) { + if ((*i).bSkip)continue; + if (ASE::Face::DEFAULT_MATINDEX == (*i).iMaterialIndex) { + (*i).iMaterialIndex = (unsigned int)mParser->m_vMaterials.size(); + bHas = true; + } + } + if (bHas || mParser->m_vMaterials.empty()) { + // add a simple material without submaterials to the parser's list + mParser->m_vMaterials.push_back ( ASE::Material() ); + ASE::Material& mat = mParser->m_vMaterials.back(); + + mat.mDiffuse = aiColor3D(0.6f,0.6f,0.6f); + mat.mSpecular = aiColor3D(1.0f,1.0f,1.0f); + mat.mAmbient = aiColor3D(0.05f,0.05f,0.05f); + mat.mShading = Discreet3DS::Gouraud; + mat.mName = AI_DEFAULT_MATERIAL_NAME; + } } // ------------------------------------------------------------------------------------------------ void ASEImporter::BuildAnimations(const std::vector& nodes) { - // check whether we have at least one mesh which has animations - std::vector::const_iterator i = nodes.begin(); - unsigned int iNum = 0; - for (;i != nodes.end();++i) { - - // TODO: Implement Bezier & TCB support - if ((*i)->mAnim.mPositionType != ASE::Animation::TRACK) { - DefaultLogger::get()->warn("ASE: Position controller uses Bezier/TCB keys. " - "This is not supported."); - } - if ((*i)->mAnim.mRotationType != ASE::Animation::TRACK) { - DefaultLogger::get()->warn("ASE: Rotation controller uses Bezier/TCB keys. " - "This is not supported."); - } - if ((*i)->mAnim.mScalingType != ASE::Animation::TRACK) { - DefaultLogger::get()->warn("ASE: Position controller uses Bezier/TCB keys. " - "This is not supported."); - } - - // We compare against 1 here - firstly one key is not - // really an animation and secondly MAX writes dummies - // that represent the node transformation. - if ((*i)->mAnim.akeyPositions.size()>1 || (*i)->mAnim.akeyRotations.size()>1 || (*i)->mAnim.akeyScaling.size()>1){ - ++iNum; - } - if ((*i)->mTargetAnim.akeyPositions.size() > 1 && is_not_qnan( (*i)->mTargetPosition.x )) { - ++iNum; - } - } - if (iNum) { - // Generate a new animation channel and setup everything for it - pcScene->mNumAnimations = 1; - pcScene->mAnimations = new aiAnimation*[1]; - aiAnimation* pcAnim = pcScene->mAnimations[0] = new aiAnimation(); - pcAnim->mNumChannels = iNum; - pcAnim->mChannels = new aiNodeAnim*[iNum]; - pcAnim->mTicksPerSecond = mParser->iFrameSpeed * mParser->iTicksPerFrame; - - iNum = 0; - - // Now iterate through all meshes and collect all data we can find - for (i = nodes.begin();i != nodes.end();++i) { - - ASE::BaseNode* me = *i; - if ( me->mTargetAnim.akeyPositions.size() > 1 && is_not_qnan( me->mTargetPosition.x )) { - // Generate an extra channel for the camera/light target. - // BuildNodes() does also generate an extra node, named - // .Target. - aiNodeAnim* nd = pcAnim->mChannels[iNum++] = new aiNodeAnim(); - nd->mNodeName.Set(me->mName + ".Target"); - - // If there is no input position channel we will need - // to supply the default position from the node's - // local transformation matrix. - /*TargetAnimationHelper helper; - if (me->mAnim.akeyPositions.empty()) - { - aiMatrix4x4& mat = (*i)->mTransform; - helper.SetFixedMainAnimationChannel(aiVector3D( - mat.a4, mat.b4, mat.c4)); - } - else helper.SetMainAnimationChannel (&me->mAnim.akeyPositions); - helper.SetTargetAnimationChannel (&me->mTargetAnim.akeyPositions); - - helper.Process(&me->mTargetAnim.akeyPositions);*/ - - // Allocate the key array and fill it - nd->mNumPositionKeys = (unsigned int) me->mTargetAnim.akeyPositions.size(); - nd->mPositionKeys = new aiVectorKey[nd->mNumPositionKeys]; - - ::memcpy(nd->mPositionKeys,&me->mTargetAnim.akeyPositions[0], - nd->mNumPositionKeys * sizeof(aiVectorKey)); - } - - if (me->mAnim.akeyPositions.size() > 1 || me->mAnim.akeyRotations.size() > 1 || me->mAnim.akeyScaling.size() > 1) { - // Begin a new node animation channel for this node - aiNodeAnim* nd = pcAnim->mChannels[iNum++] = new aiNodeAnim(); - nd->mNodeName.Set(me->mName); - - // copy position keys - if (me->mAnim.akeyPositions.size() > 1 ) - { - // Allocate the key array and fill it - nd->mNumPositionKeys = (unsigned int) me->mAnim.akeyPositions.size(); - nd->mPositionKeys = new aiVectorKey[nd->mNumPositionKeys]; - - ::memcpy(nd->mPositionKeys,&me->mAnim.akeyPositions[0], - nd->mNumPositionKeys * sizeof(aiVectorKey)); - } - // copy rotation keys - if (me->mAnim.akeyRotations.size() > 1 ) { - // Allocate the key array and fill it - nd->mNumRotationKeys = (unsigned int) me->mAnim.akeyRotations.size(); - nd->mRotationKeys = new aiQuatKey[nd->mNumRotationKeys]; - - // -------------------------------------------------------------------- - // Rotation keys are offsets to the previous keys. - // We have the quaternion representations of all - // of them, so we just need to concatenate all - // (unit-length) quaternions to get the absolute - // rotations. - // Rotation keys are ABSOLUTE for older files - // -------------------------------------------------------------------- - - aiQuaternion cur; - for (unsigned int a = 0; a < nd->mNumRotationKeys;++a) { - aiQuatKey q = me->mAnim.akeyRotations[a]; - - if (mParser->iFileFormat > 110) { - cur = (a ? cur*q.mValue : q.mValue); - q.mValue = cur.Normalize(); - } - nd->mRotationKeys[a] = q; - - // need this to get to Assimp quaternion conventions - nd->mRotationKeys[a].mValue.w *= -1.f; - } - } - // copy scaling keys - if (me->mAnim.akeyScaling.size() > 1 ) { - // Allocate the key array and fill it - nd->mNumScalingKeys = (unsigned int) me->mAnim.akeyScaling.size(); - nd->mScalingKeys = new aiVectorKey[nd->mNumScalingKeys]; - - ::memcpy(nd->mScalingKeys,&me->mAnim.akeyScaling[0], - nd->mNumScalingKeys * sizeof(aiVectorKey)); - } - } - } - } + // check whether we have at least one mesh which has animations + std::vector::const_iterator i = nodes.begin(); + unsigned int iNum = 0; + for (;i != nodes.end();++i) { + + // TODO: Implement Bezier & TCB support + if ((*i)->mAnim.mPositionType != ASE::Animation::TRACK) { + DefaultLogger::get()->warn("ASE: Position controller uses Bezier/TCB keys. " + "This is not supported."); + } + if ((*i)->mAnim.mRotationType != ASE::Animation::TRACK) { + DefaultLogger::get()->warn("ASE: Rotation controller uses Bezier/TCB keys. " + "This is not supported."); + } + if ((*i)->mAnim.mScalingType != ASE::Animation::TRACK) { + DefaultLogger::get()->warn("ASE: Position controller uses Bezier/TCB keys. " + "This is not supported."); + } + + // We compare against 1 here - firstly one key is not + // really an animation and secondly MAX writes dummies + // that represent the node transformation. + if ((*i)->mAnim.akeyPositions.size()>1 || (*i)->mAnim.akeyRotations.size()>1 || (*i)->mAnim.akeyScaling.size()>1){ + ++iNum; + } + if ((*i)->mTargetAnim.akeyPositions.size() > 1 && is_not_qnan( (*i)->mTargetPosition.x )) { + ++iNum; + } + } + if (iNum) { + // Generate a new animation channel and setup everything for it + pcScene->mNumAnimations = 1; + pcScene->mAnimations = new aiAnimation*[1]; + aiAnimation* pcAnim = pcScene->mAnimations[0] = new aiAnimation(); + pcAnim->mNumChannels = iNum; + pcAnim->mChannels = new aiNodeAnim*[iNum]; + pcAnim->mTicksPerSecond = mParser->iFrameSpeed * mParser->iTicksPerFrame; + + iNum = 0; + + // Now iterate through all meshes and collect all data we can find + for (i = nodes.begin();i != nodes.end();++i) { + + ASE::BaseNode* me = *i; + if ( me->mTargetAnim.akeyPositions.size() > 1 && is_not_qnan( me->mTargetPosition.x )) { + // Generate an extra channel for the camera/light target. + // BuildNodes() does also generate an extra node, named + // .Target. + aiNodeAnim* nd = pcAnim->mChannels[iNum++] = new aiNodeAnim(); + nd->mNodeName.Set(me->mName + ".Target"); + + // If there is no input position channel we will need + // to supply the default position from the node's + // local transformation matrix. + /*TargetAnimationHelper helper; + if (me->mAnim.akeyPositions.empty()) + { + aiMatrix4x4& mat = (*i)->mTransform; + helper.SetFixedMainAnimationChannel(aiVector3D( + mat.a4, mat.b4, mat.c4)); + } + else helper.SetMainAnimationChannel (&me->mAnim.akeyPositions); + helper.SetTargetAnimationChannel (&me->mTargetAnim.akeyPositions); + + helper.Process(&me->mTargetAnim.akeyPositions);*/ + + // Allocate the key array and fill it + nd->mNumPositionKeys = (unsigned int) me->mTargetAnim.akeyPositions.size(); + nd->mPositionKeys = new aiVectorKey[nd->mNumPositionKeys]; + + ::memcpy(nd->mPositionKeys,&me->mTargetAnim.akeyPositions[0], + nd->mNumPositionKeys * sizeof(aiVectorKey)); + } + + if (me->mAnim.akeyPositions.size() > 1 || me->mAnim.akeyRotations.size() > 1 || me->mAnim.akeyScaling.size() > 1) { + // Begin a new node animation channel for this node + aiNodeAnim* nd = pcAnim->mChannels[iNum++] = new aiNodeAnim(); + nd->mNodeName.Set(me->mName); + + // copy position keys + if (me->mAnim.akeyPositions.size() > 1 ) + { + // Allocate the key array and fill it + nd->mNumPositionKeys = (unsigned int) me->mAnim.akeyPositions.size(); + nd->mPositionKeys = new aiVectorKey[nd->mNumPositionKeys]; + + ::memcpy(nd->mPositionKeys,&me->mAnim.akeyPositions[0], + nd->mNumPositionKeys * sizeof(aiVectorKey)); + } + // copy rotation keys + if (me->mAnim.akeyRotations.size() > 1 ) { + // Allocate the key array and fill it + nd->mNumRotationKeys = (unsigned int) me->mAnim.akeyRotations.size(); + nd->mRotationKeys = new aiQuatKey[nd->mNumRotationKeys]; + + // -------------------------------------------------------------------- + // Rotation keys are offsets to the previous keys. + // We have the quaternion representations of all + // of them, so we just need to concatenate all + // (unit-length) quaternions to get the absolute + // rotations. + // Rotation keys are ABSOLUTE for older files + // -------------------------------------------------------------------- + + aiQuaternion cur; + for (unsigned int a = 0; a < nd->mNumRotationKeys;++a) { + aiQuatKey q = me->mAnim.akeyRotations[a]; + + if (mParser->iFileFormat > 110) { + cur = (a ? cur*q.mValue : q.mValue); + q.mValue = cur.Normalize(); + } + nd->mRotationKeys[a] = q; + + // need this to get to Assimp quaternion conventions + nd->mRotationKeys[a].mValue.w *= -1.f; + } + } + // copy scaling keys + if (me->mAnim.akeyScaling.size() > 1 ) { + // Allocate the key array and fill it + nd->mNumScalingKeys = (unsigned int) me->mAnim.akeyScaling.size(); + nd->mScalingKeys = new aiVectorKey[nd->mNumScalingKeys]; + + ::memcpy(nd->mScalingKeys,&me->mAnim.akeyScaling[0], + nd->mNumScalingKeys * sizeof(aiVectorKey)); + } + } + } + } } // ------------------------------------------------------------------------------------------------ // Build output cameras void ASEImporter::BuildCameras() { - if (!mParser->m_vCameras.empty()) { - pcScene->mNumCameras = (unsigned int)mParser->m_vCameras.size(); - pcScene->mCameras = new aiCamera*[pcScene->mNumCameras]; - - for (unsigned int i = 0; i < pcScene->mNumCameras;++i) { - aiCamera* out = pcScene->mCameras[i] = new aiCamera(); - ASE::Camera& in = mParser->m_vCameras[i]; - - // copy members - out->mClipPlaneFar = in.mFar; - out->mClipPlaneNear = (in.mNear ? in.mNear : 0.1f); - out->mHorizontalFOV = in.mFOV; - - out->mName.Set(in.mName); - } - } + if (!mParser->m_vCameras.empty()) { + pcScene->mNumCameras = (unsigned int)mParser->m_vCameras.size(); + pcScene->mCameras = new aiCamera*[pcScene->mNumCameras]; + + for (unsigned int i = 0; i < pcScene->mNumCameras;++i) { + aiCamera* out = pcScene->mCameras[i] = new aiCamera(); + ASE::Camera& in = mParser->m_vCameras[i]; + + // copy members + out->mClipPlaneFar = in.mFar; + out->mClipPlaneNear = (in.mNear ? in.mNear : 0.1f); + out->mHorizontalFOV = in.mFOV; + + out->mName.Set(in.mName); + } + } } // ------------------------------------------------------------------------------------------------ // Build output lights void ASEImporter::BuildLights() { - if (!mParser->m_vLights.empty()) { - pcScene->mNumLights = (unsigned int)mParser->m_vLights.size(); - pcScene->mLights = new aiLight*[pcScene->mNumLights]; - - for (unsigned int i = 0; i < pcScene->mNumLights;++i) { - aiLight* out = pcScene->mLights[i] = new aiLight(); - ASE::Light& in = mParser->m_vLights[i]; - - // The direction is encoded in the transformation matrix of the node. - // In 3DS MAX the light source points into negative Z direction if - // the node transformation is the identity. - out->mDirection = aiVector3D(0.f,0.f,-1.f); - - out->mName.Set(in.mName); - switch (in.mLightType) - { - case ASE::Light::TARGET: - out->mType = aiLightSource_SPOT; - out->mAngleInnerCone = AI_DEG_TO_RAD(in.mAngle); - out->mAngleOuterCone = (in.mFalloff ? AI_DEG_TO_RAD(in.mFalloff) : out->mAngleInnerCone); - break; - - case ASE::Light::DIRECTIONAL: - out->mType = aiLightSource_DIRECTIONAL; - break; - - default: - //case ASE::Light::OMNI: - out->mType = aiLightSource_POINT; - break; - }; - out->mColorDiffuse = out->mColorSpecular = in.mColor * in.mIntensity; - } - } + if (!mParser->m_vLights.empty()) { + pcScene->mNumLights = (unsigned int)mParser->m_vLights.size(); + pcScene->mLights = new aiLight*[pcScene->mNumLights]; + + for (unsigned int i = 0; i < pcScene->mNumLights;++i) { + aiLight* out = pcScene->mLights[i] = new aiLight(); + ASE::Light& in = mParser->m_vLights[i]; + + // The direction is encoded in the transformation matrix of the node. + // In 3DS MAX the light source points into negative Z direction if + // the node transformation is the identity. + out->mDirection = aiVector3D(0.f,0.f,-1.f); + + out->mName.Set(in.mName); + switch (in.mLightType) + { + case ASE::Light::TARGET: + out->mType = aiLightSource_SPOT; + out->mAngleInnerCone = AI_DEG_TO_RAD(in.mAngle); + out->mAngleOuterCone = (in.mFalloff ? AI_DEG_TO_RAD(in.mFalloff) : out->mAngleInnerCone); + break; + + case ASE::Light::DIRECTIONAL: + out->mType = aiLightSource_DIRECTIONAL; + break; + + default: + //case ASE::Light::OMNI: + out->mType = aiLightSource_POINT; + break; + }; + out->mColorDiffuse = out->mColorSpecular = in.mColor * in.mIntensity; + } + } } // ------------------------------------------------------------------------------------------------ void ASEImporter::AddNodes(const std::vector& nodes, - aiNode* pcParent,const char* szName) + aiNode* pcParent,const char* szName) { - aiMatrix4x4 m; - AddNodes(nodes,pcParent,szName,m); + aiMatrix4x4 m; + AddNodes(nodes,pcParent,szName,m); } // ------------------------------------------------------------------------------------------------ // Add meshes to a given node void ASEImporter::AddMeshes(const ASE::BaseNode* snode,aiNode* node) { - for (unsigned int i = 0; i < pcScene->mNumMeshes;++i) { - // Get the name of the mesh (the mesh instance has been temporarily stored in the third vertex color) - const aiMesh* pcMesh = pcScene->mMeshes[i]; - const ASE::Mesh* mesh = (const ASE::Mesh*)pcMesh->mColors[2]; - - if (mesh == snode) { - ++node->mNumMeshes; - } - } - - if(node->mNumMeshes) { - node->mMeshes = new unsigned int[node->mNumMeshes]; - for (unsigned int i = 0, p = 0; i < pcScene->mNumMeshes;++i) { - - const aiMesh* pcMesh = pcScene->mMeshes[i]; - const ASE::Mesh* mesh = (const ASE::Mesh*)pcMesh->mColors[2]; - if (mesh == snode) { - node->mMeshes[p++] = i; - - // Transform all vertices of the mesh back into their local space -> - // at the moment they are pretransformed - aiMatrix4x4 m = mesh->mTransform; - m.Inverse(); - - aiVector3D* pvCurPtr = pcMesh->mVertices; - const aiVector3D* pvEndPtr = pvCurPtr + pcMesh->mNumVertices; - while (pvCurPtr != pvEndPtr) { - *pvCurPtr = m * (*pvCurPtr); - pvCurPtr++; - } - - // Do the same for the normal vectors, if we have them. - // As always, inverse transpose. - if (pcMesh->mNormals) { - aiMatrix3x3 m3 = aiMatrix3x3( mesh->mTransform ); - m3.Transpose(); - - pvCurPtr = pcMesh->mNormals; - pvEndPtr = pvCurPtr + pcMesh->mNumVertices; - while (pvCurPtr != pvEndPtr) { - *pvCurPtr = m3 * (*pvCurPtr); - pvCurPtr++; - } - } - } - } - } + for (unsigned int i = 0; i < pcScene->mNumMeshes;++i) { + // Get the name of the mesh (the mesh instance has been temporarily stored in the third vertex color) + const aiMesh* pcMesh = pcScene->mMeshes[i]; + const ASE::Mesh* mesh = (const ASE::Mesh*)pcMesh->mColors[2]; + + if (mesh == snode) { + ++node->mNumMeshes; + } + } + + if(node->mNumMeshes) { + node->mMeshes = new unsigned int[node->mNumMeshes]; + for (unsigned int i = 0, p = 0; i < pcScene->mNumMeshes;++i) { + + const aiMesh* pcMesh = pcScene->mMeshes[i]; + const ASE::Mesh* mesh = (const ASE::Mesh*)pcMesh->mColors[2]; + if (mesh == snode) { + node->mMeshes[p++] = i; + + // Transform all vertices of the mesh back into their local space -> + // at the moment they are pretransformed + aiMatrix4x4 m = mesh->mTransform; + m.Inverse(); + + aiVector3D* pvCurPtr = pcMesh->mVertices; + const aiVector3D* pvEndPtr = pvCurPtr + pcMesh->mNumVertices; + while (pvCurPtr != pvEndPtr) { + *pvCurPtr = m * (*pvCurPtr); + pvCurPtr++; + } + + // Do the same for the normal vectors, if we have them. + // As always, inverse transpose. + if (pcMesh->mNormals) { + aiMatrix3x3 m3 = aiMatrix3x3( mesh->mTransform ); + m3.Transpose(); + + pvCurPtr = pcMesh->mNormals; + pvEndPtr = pvCurPtr + pcMesh->mNumVertices; + while (pvCurPtr != pvEndPtr) { + *pvCurPtr = m3 * (*pvCurPtr); + pvCurPtr++; + } + } + } + } + } } // ------------------------------------------------------------------------------------------------ // Add child nodes to a given parent node void ASEImporter::AddNodes (const std::vector& nodes, - aiNode* pcParent, const char* szName, - const aiMatrix4x4& mat) + aiNode* pcParent, const char* szName, + const aiMatrix4x4& mat) { - const size_t len = szName ? ::strlen(szName) : 0; - ai_assert(4 <= AI_MAX_NUMBER_OF_COLOR_SETS); - - // Receives child nodes for the pcParent node - std::vector apcNodes; - - // Now iterate through all nodes in the scene and search for one - // which has *us* as parent. - for (std::vector::const_iterator it = nodes.begin(), end = nodes.end(); it != end; ++it) { - const BaseNode* snode = *it; - if (szName) { - if (len != snode->mParent.length() || ::strcmp(szName,snode->mParent.c_str())) - continue; - } - else if (snode->mParent.length()) - continue; - - (*it)->mProcessed = true; - - // Allocate a new node and add it to the output data structure - apcNodes.push_back(new aiNode()); - aiNode* node = apcNodes.back(); - - node->mName.Set((snode->mName.length() ? snode->mName.c_str() : "Unnamed_Node")); - node->mParent = pcParent; - - // Setup the transformation matrix of the node - aiMatrix4x4 mParentAdjust = mat; - mParentAdjust.Inverse(); - node->mTransformation = mParentAdjust*snode->mTransform; - - // Add sub nodes - prevent stack overflow due to recursive parenting - if (node->mName != node->mParent->mName) { - AddNodes(nodes,node,node->mName.data,snode->mTransform); - } - - // Further processing depends on the type of the node - if (snode->mType == ASE::BaseNode::Mesh) { - // If the type of this node is "Mesh" we need to search - // the list of output meshes in the data structure for - // all those that belonged to this node once. This is - // slightly inconvinient here and a better solution should - // be used when this code is refactored next. - AddMeshes(snode,node); - } - else if (is_not_qnan( snode->mTargetPosition.x )) { - // If this is a target camera or light we generate a small - // child node which marks the position of the camera - // target (the direction information is contained in *this* - // node's animation track but the exact target position - // would be lost otherwise) - if (!node->mNumChildren) { - node->mChildren = new aiNode*[1]; - } - - aiNode* nd = new aiNode(); - - nd->mName.Set ( snode->mName + ".Target" ); - - nd->mTransformation.a4 = snode->mTargetPosition.x - snode->mTransform.a4; - nd->mTransformation.b4 = snode->mTargetPosition.y - snode->mTransform.b4; - nd->mTransformation.c4 = snode->mTargetPosition.z - snode->mTransform.c4; - - nd->mParent = node; - - // The .Target node is always the first child node - for (unsigned int m = 0; m < node->mNumChildren;++m) - node->mChildren[m+1] = node->mChildren[m]; - - node->mChildren[0] = nd; - node->mNumChildren++; - - // What we did is so great, it is at least worth a debug message - DefaultLogger::get()->debug("ASE: Generating separate target node ("+snode->mName+")"); - } - } - - // Allocate enough space for the child nodes - // We allocate one slot more in case this is a target camera/light - pcParent->mNumChildren = (unsigned int)apcNodes.size(); - if (pcParent->mNumChildren) { - pcParent->mChildren = new aiNode*[apcNodes.size()+1 /* PLUS ONE !!! */]; - - // now build all nodes for our nice new children - for (unsigned int p = 0; p < apcNodes.size();++p) - pcParent->mChildren[p] = apcNodes[p]; - } - return; + const size_t len = szName ? ::strlen(szName) : 0; + ai_assert(4 <= AI_MAX_NUMBER_OF_COLOR_SETS); + + // Receives child nodes for the pcParent node + std::vector apcNodes; + + // Now iterate through all nodes in the scene and search for one + // which has *us* as parent. + for (std::vector::const_iterator it = nodes.begin(), end = nodes.end(); it != end; ++it) { + const BaseNode* snode = *it; + if (szName) { + if (len != snode->mParent.length() || ::strcmp(szName,snode->mParent.c_str())) + continue; + } + else if (snode->mParent.length()) + continue; + + (*it)->mProcessed = true; + + // Allocate a new node and add it to the output data structure + apcNodes.push_back(new aiNode()); + aiNode* node = apcNodes.back(); + + node->mName.Set((snode->mName.length() ? snode->mName.c_str() : "Unnamed_Node")); + node->mParent = pcParent; + + // Setup the transformation matrix of the node + aiMatrix4x4 mParentAdjust = mat; + mParentAdjust.Inverse(); + node->mTransformation = mParentAdjust*snode->mTransform; + + // Add sub nodes - prevent stack overflow due to recursive parenting + if (node->mName != node->mParent->mName) { + AddNodes(nodes,node,node->mName.data,snode->mTransform); + } + + // Further processing depends on the type of the node + if (snode->mType == ASE::BaseNode::Mesh) { + // If the type of this node is "Mesh" we need to search + // the list of output meshes in the data structure for + // all those that belonged to this node once. This is + // slightly inconvinient here and a better solution should + // be used when this code is refactored next. + AddMeshes(snode,node); + } + else if (is_not_qnan( snode->mTargetPosition.x )) { + // If this is a target camera or light we generate a small + // child node which marks the position of the camera + // target (the direction information is contained in *this* + // node's animation track but the exact target position + // would be lost otherwise) + if (!node->mNumChildren) { + node->mChildren = new aiNode*[1]; + } + + aiNode* nd = new aiNode(); + + nd->mName.Set ( snode->mName + ".Target" ); + + nd->mTransformation.a4 = snode->mTargetPosition.x - snode->mTransform.a4; + nd->mTransformation.b4 = snode->mTargetPosition.y - snode->mTransform.b4; + nd->mTransformation.c4 = snode->mTargetPosition.z - snode->mTransform.c4; + + nd->mParent = node; + + // The .Target node is always the first child node + for (unsigned int m = 0; m < node->mNumChildren;++m) + node->mChildren[m+1] = node->mChildren[m]; + + node->mChildren[0] = nd; + node->mNumChildren++; + + // What we did is so great, it is at least worth a debug message + DefaultLogger::get()->debug("ASE: Generating separate target node ("+snode->mName+")"); + } + } + + // Allocate enough space for the child nodes + // We allocate one slot more in case this is a target camera/light + pcParent->mNumChildren = (unsigned int)apcNodes.size(); + if (pcParent->mNumChildren) { + pcParent->mChildren = new aiNode*[apcNodes.size()+1 /* PLUS ONE !!! */]; + + // now build all nodes for our nice new children + for (unsigned int p = 0; p < apcNodes.size();++p) + pcParent->mChildren[p] = apcNodes[p]; + } + return; } // ------------------------------------------------------------------------------------------------ // Build the output node graph -void ASEImporter::BuildNodes(std::vector& nodes) { - ai_assert(NULL != pcScene); - - // allocate the one and only root node - aiNode* root = pcScene->mRootNode = new aiNode(); - root->mName.Set(""); - - // Setup the coordinate system transformation - pcScene->mRootNode->mNumChildren = 1; - pcScene->mRootNode->mChildren = new aiNode*[1]; - aiNode* ch = pcScene->mRootNode->mChildren[0] = new aiNode(); - ch->mParent = root; - - // Change the transformation matrix of all nodes - for (std::vector::iterator it = nodes.begin(), end = nodes.end();it != end; ++it) { - aiMatrix4x4& m = (*it)->mTransform; - m.Transpose(); // row-order vs column-order - } - - // add all nodes - AddNodes(nodes,ch,NULL); - - // now iterate through al nodes and find those that have not yet - // been added to the nodegraph (= their parent could not be recognized) - std::vector aiList; - for (std::vector::iterator it = nodes.begin(), end = nodes.end();it != end; ++it) { - if ((*it)->mProcessed) { - continue; - } - - // check whether our parent is known - bool bKnowParent = false; - - // search the list another time, starting *here* and try to find out whether - // there is a node that references *us* as a parent - for (std::vector::const_iterator it2 = nodes.begin();it2 != end; ++it2) { - if (it2 == it) { - continue; - } - - if ((*it2)->mName == (*it)->mParent) { - bKnowParent = true; - break; - } - } - if (!bKnowParent) { - aiList.push_back(*it); - } - } - - // Are there ane orphaned nodes? - if (!aiList.empty()) { - std::vector apcNodes; - apcNodes.reserve(aiList.size() + pcScene->mRootNode->mNumChildren); - - for (unsigned int i = 0; i < pcScene->mRootNode->mNumChildren;++i) - apcNodes.push_back(pcScene->mRootNode->mChildren[i]); - - delete[] pcScene->mRootNode->mChildren; - for (std::vector::/*const_*/iterator i = aiList.begin();i != aiList.end();++i) { - const ASE::BaseNode* src = *i; - - // The parent is not known, so we can assume that we must add - // this node to the root node of the whole scene - aiNode* pcNode = new aiNode(); - pcNode->mParent = pcScene->mRootNode; - pcNode->mName.Set(src->mName); - AddMeshes(src,pcNode); - AddNodes(nodes,pcNode,pcNode->mName.data); - apcNodes.push_back(pcNode); - } - - // Regenerate our output array - pcScene->mRootNode->mChildren = new aiNode*[apcNodes.size()]; - for (unsigned int i = 0; i < apcNodes.size();++i) - pcScene->mRootNode->mChildren[i] = apcNodes[i]; - - pcScene->mRootNode->mNumChildren = (unsigned int)apcNodes.size(); - } - - // Reset the third color set to NULL - we used this field to store a temporary pointer - for (unsigned int i = 0; i < pcScene->mNumMeshes;++i) - pcScene->mMeshes[i]->mColors[2] = NULL; - - // The root node should not have at least one child or the file is valid - if (!pcScene->mRootNode->mNumChildren) { - throw DeadlyImportError("ASE: No nodes loaded. The file is either empty or corrupt"); - } - - // Now rotate the whole scene 90 degrees around the x axis to convert to internal coordinate system - pcScene->mRootNode->mTransformation = aiMatrix4x4(1.f,0.f,0.f,0.f, - 0.f,0.f,1.f,0.f,0.f,-1.f,0.f,0.f,0.f,0.f,0.f,1.f); +void ASEImporter::BuildNodes(std::vector& nodes) { + ai_assert(NULL != pcScene); + + // allocate the one and only root node + aiNode* root = pcScene->mRootNode = new aiNode(); + root->mName.Set(""); + + // Setup the coordinate system transformation + pcScene->mRootNode->mNumChildren = 1; + pcScene->mRootNode->mChildren = new aiNode*[1]; + aiNode* ch = pcScene->mRootNode->mChildren[0] = new aiNode(); + ch->mParent = root; + + // Change the transformation matrix of all nodes + for (BaseNode *node : nodes) { + aiMatrix4x4& m = node->mTransform; + m.Transpose(); // row-order vs column-order + } + + // add all nodes + AddNodes(nodes,ch,NULL); + + // now iterate through al nodes and find those that have not yet + // been added to the nodegraph (= their parent could not be recognized) + std::vector aiList; + for (std::vector::iterator it = nodes.begin(), end = nodes.end();it != end; ++it) { + if ((*it)->mProcessed) { + continue; + } + + // check whether our parent is known + bool bKnowParent = false; + + // search the list another time, starting *here* and try to find out whether + // there is a node that references *us* as a parent + for (std::vector::const_iterator it2 = nodes.begin();it2 != end; ++it2) { + if (it2 == it) { + continue; + } + + if ((*it2)->mName == (*it)->mParent) { + bKnowParent = true; + break; + } + } + if (!bKnowParent) { + aiList.push_back(*it); + } + } + + // Are there ane orphaned nodes? + if (!aiList.empty()) { + std::vector apcNodes; + apcNodes.reserve(aiList.size() + pcScene->mRootNode->mNumChildren); + + for (unsigned int i = 0; i < pcScene->mRootNode->mNumChildren;++i) + apcNodes.push_back(pcScene->mRootNode->mChildren[i]); + + delete[] pcScene->mRootNode->mChildren; + for (std::vector::/*const_*/iterator i = aiList.begin();i != aiList.end();++i) { + const ASE::BaseNode* src = *i; + + // The parent is not known, so we can assume that we must add + // this node to the root node of the whole scene + aiNode* pcNode = new aiNode(); + pcNode->mParent = pcScene->mRootNode; + pcNode->mName.Set(src->mName); + AddMeshes(src,pcNode); + AddNodes(nodes,pcNode,pcNode->mName.data); + apcNodes.push_back(pcNode); + } + + // Regenerate our output array + pcScene->mRootNode->mChildren = new aiNode*[apcNodes.size()]; + for (unsigned int i = 0; i < apcNodes.size();++i) + pcScene->mRootNode->mChildren[i] = apcNodes[i]; + + pcScene->mRootNode->mNumChildren = (unsigned int)apcNodes.size(); + } + + // Reset the third color set to NULL - we used this field to store a temporary pointer + for (unsigned int i = 0; i < pcScene->mNumMeshes;++i) + pcScene->mMeshes[i]->mColors[2] = NULL; + + // The root node should not have at least one child or the file is valid + if (!pcScene->mRootNode->mNumChildren) { + throw DeadlyImportError("ASE: No nodes loaded. The file is either empty or corrupt"); + } + + // Now rotate the whole scene 90 degrees around the x axis to convert to internal coordinate system + pcScene->mRootNode->mTransformation = aiMatrix4x4(1.f,0.f,0.f,0.f, + 0.f,0.f,1.f,0.f,0.f,-1.f,0.f,0.f,0.f,0.f,0.f,1.f); } // ------------------------------------------------------------------------------------------------ // Convert the imported data to the internal verbose representation -void ASEImporter::BuildUniqueRepresentation(ASE::Mesh& mesh) { - // allocate output storage - std::vector mPositions; - std::vector amTexCoords[AI_MAX_NUMBER_OF_TEXTURECOORDS]; - std::vector mVertexColors; - std::vector mNormals; - std::vector mBoneVertices; - - unsigned int iSize = (unsigned int)mesh.mFaces.size() * 3; - mPositions.resize(iSize); - - // optional texture coordinates - for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS;++i) { - if (!mesh.amTexCoords[i].empty()) { - amTexCoords[i].resize(iSize); - } - } - // optional vertex colors - if (!mesh.mVertexColors.empty()) { - mVertexColors.resize(iSize); - } - - // optional vertex normals (vertex normals can simply be copied) - if (!mesh.mNormals.empty()) { - mNormals.resize(iSize); - } - // bone vertices. There is no need to change the bone list - if (!mesh.mBoneVertices.empty()) { - mBoneVertices.resize(iSize); - } - - // iterate through all faces in the mesh - unsigned int iCurrent = 0, fi = 0; - for (std::vector::iterator i = mesh.mFaces.begin();i != mesh.mFaces.end();++i,++fi) { - for (unsigned int n = 0; n < 3;++n,++iCurrent) - { - mPositions[iCurrent] = mesh.mPositions[(*i).mIndices[n]]; - - // add texture coordinates - for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c) { - if (mesh.amTexCoords[c].empty())break; - amTexCoords[c][iCurrent] = mesh.amTexCoords[c][(*i).amUVIndices[c][n]]; - } - // add vertex colors - if (!mesh.mVertexColors.empty()) { - mVertexColors[iCurrent] = mesh.mVertexColors[(*i).mColorIndices[n]]; - } - // add normal vectors - if (!mesh.mNormals.empty()) { - mNormals[iCurrent] = mesh.mNormals[fi*3+n]; - mNormals[iCurrent].Normalize(); - } - - // handle bone vertices - if ((*i).mIndices[n] < mesh.mBoneVertices.size()) { - // (sometimes this will cause bone verts to be duplicated - // however, I' quite sure Schrompf' JoinVerticesStep - // will fix that again ...) - mBoneVertices[iCurrent] = mesh.mBoneVertices[(*i).mIndices[n]]; - } - (*i).mIndices[n] = iCurrent; - } - } - - // replace the old arrays - mesh.mNormals = mNormals; - mesh.mPositions = mPositions; - mesh.mVertexColors = mVertexColors; - - for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c) - mesh.amTexCoords[c] = amTexCoords[c]; +void ASEImporter::BuildUniqueRepresentation(ASE::Mesh& mesh) { + // allocate output storage + std::vector mPositions; + std::vector amTexCoords[AI_MAX_NUMBER_OF_TEXTURECOORDS]; + std::vector mVertexColors; + std::vector mNormals; + std::vector mBoneVertices; + + unsigned int iSize = (unsigned int)mesh.mFaces.size() * 3; + mPositions.resize(iSize); + + // optional texture coordinates + for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS;++i) { + if (!mesh.amTexCoords[i].empty()) { + amTexCoords[i].resize(iSize); + } + } + // optional vertex colors + if (!mesh.mVertexColors.empty()) { + mVertexColors.resize(iSize); + } + + // optional vertex normals (vertex normals can simply be copied) + if (!mesh.mNormals.empty()) { + mNormals.resize(iSize); + } + // bone vertices. There is no need to change the bone list + if (!mesh.mBoneVertices.empty()) { + mBoneVertices.resize(iSize); + } + + // iterate through all faces in the mesh + unsigned int iCurrent = 0, fi = 0; + for (std::vector::iterator i = mesh.mFaces.begin();i != mesh.mFaces.end();++i,++fi) { + for (unsigned int n = 0; n < 3;++n,++iCurrent) + { + mPositions[iCurrent] = mesh.mPositions[(*i).mIndices[n]]; + + // add texture coordinates + for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c) { + if (mesh.amTexCoords[c].empty())break; + amTexCoords[c][iCurrent] = mesh.amTexCoords[c][(*i).amUVIndices[c][n]]; + } + // add vertex colors + if (!mesh.mVertexColors.empty()) { + mVertexColors[iCurrent] = mesh.mVertexColors[(*i).mColorIndices[n]]; + } + // add normal vectors + if (!mesh.mNormals.empty()) { + mNormals[iCurrent] = mesh.mNormals[fi*3+n]; + mNormals[iCurrent].Normalize(); + } + + // handle bone vertices + if ((*i).mIndices[n] < mesh.mBoneVertices.size()) { + // (sometimes this will cause bone verts to be duplicated + // however, I' quite sure Schrompf' JoinVerticesStep + // will fix that again ...) + mBoneVertices[iCurrent] = mesh.mBoneVertices[(*i).mIndices[n]]; + } + (*i).mIndices[n] = iCurrent; + } + } + + // replace the old arrays + mesh.mNormals = mNormals; + mesh.mPositions = mPositions; + mesh.mVertexColors = mVertexColors; + + for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c) + mesh.amTexCoords[c] = amTexCoords[c]; } // ------------------------------------------------------------------------------------------------ // Copy a texture from the ASE structs to the output material void CopyASETexture(aiMaterial& mat, ASE::Texture& texture, aiTextureType type) { - // Setup the texture name - aiString tex; - tex.Set( texture.mMapName); - mat.AddProperty( &tex, AI_MATKEY_TEXTURE(type,0)); + // Setup the texture name + aiString tex; + tex.Set( texture.mMapName); + mat.AddProperty( &tex, AI_MATKEY_TEXTURE(type,0)); - // Setup the texture blend factor - if (is_not_qnan(texture.mTextureBlend)) - mat.AddProperty( &texture.mTextureBlend, 1, AI_MATKEY_TEXBLEND(type,0)); + // Setup the texture blend factor + if (is_not_qnan(texture.mTextureBlend)) + mat.AddProperty( &texture.mTextureBlend, 1, AI_MATKEY_TEXBLEND(type,0)); - // Setup texture UV transformations - mat.AddProperty(&texture.mOffsetU,5,AI_MATKEY_UVTRANSFORM(type,0)); + // Setup texture UV transformations + mat.AddProperty(&texture.mOffsetU,5,AI_MATKEY_UVTRANSFORM(type,0)); } // ------------------------------------------------------------------------------------------------ // Convert from ASE material to output material void ASEImporter::ConvertMaterial(ASE::Material& mat) { - // LARGE TODO: Much code her is copied from 3DS ... join them maybe? - - // Allocate the output material - mat.pcInstance = new aiMaterial(); - - // At first add the base ambient color of the - // scene to the material - mat.mAmbient.r += mParser->m_clrAmbient.r; - mat.mAmbient.g += mParser->m_clrAmbient.g; - mat.mAmbient.b += mParser->m_clrAmbient.b; - - aiString name; - name.Set( mat.mName); - mat.pcInstance->AddProperty( &name, AI_MATKEY_NAME); - - // material colors - mat.pcInstance->AddProperty( &mat.mAmbient, 1, AI_MATKEY_COLOR_AMBIENT); - mat.pcInstance->AddProperty( &mat.mDiffuse, 1, AI_MATKEY_COLOR_DIFFUSE); - mat.pcInstance->AddProperty( &mat.mSpecular, 1, AI_MATKEY_COLOR_SPECULAR); - mat.pcInstance->AddProperty( &mat.mEmissive, 1, AI_MATKEY_COLOR_EMISSIVE); - - // shininess - if (0.0f != mat.mSpecularExponent && 0.0f != mat.mShininessStrength) - { - mat.pcInstance->AddProperty( &mat.mSpecularExponent, 1, AI_MATKEY_SHININESS); - mat.pcInstance->AddProperty( &mat.mShininessStrength, 1, AI_MATKEY_SHININESS_STRENGTH); - } - // If there is no shininess, we can disable phong lighting - else if (D3DS::Discreet3DS::Metal == mat.mShading || - D3DS::Discreet3DS::Phong == mat.mShading || - D3DS::Discreet3DS::Blinn == mat.mShading) - { - mat.mShading = D3DS::Discreet3DS::Gouraud; - } - - // opacity - mat.pcInstance->AddProperty( &mat.mTransparency,1,AI_MATKEY_OPACITY); - - // Two sided rendering? - if (mat.mTwoSided) - { - int i = 1; - mat.pcInstance->AddProperty(&i,1,AI_MATKEY_TWOSIDED); - } - - // shading mode - aiShadingMode eShading = aiShadingMode_NoShading; - switch (mat.mShading) - { - case D3DS::Discreet3DS::Flat: - eShading = aiShadingMode_Flat; break; - case D3DS::Discreet3DS::Phong : - eShading = aiShadingMode_Phong; break; - case D3DS::Discreet3DS::Blinn : - eShading = aiShadingMode_Blinn; break; - - // I don't know what "Wire" shading should be, - // assume it is simple lambertian diffuse (L dot N) shading - case D3DS::Discreet3DS::Wire: - { - // set the wireframe flag - unsigned int iWire = 1; - mat.pcInstance->AddProperty( (int*)&iWire,1,AI_MATKEY_ENABLE_WIREFRAME); - } - case D3DS::Discreet3DS::Gouraud: - eShading = aiShadingMode_Gouraud; break; - case D3DS::Discreet3DS::Metal : - eShading = aiShadingMode_CookTorrance; break; - } - mat.pcInstance->AddProperty( (int*)&eShading,1,AI_MATKEY_SHADING_MODEL); - - // DIFFUSE texture - if( mat.sTexDiffuse.mMapName.length() > 0) - CopyASETexture(*mat.pcInstance,mat.sTexDiffuse, aiTextureType_DIFFUSE); - - // SPECULAR texture - if( mat.sTexSpecular.mMapName.length() > 0) - CopyASETexture(*mat.pcInstance,mat.sTexSpecular, aiTextureType_SPECULAR); - - // AMBIENT texture - if( mat.sTexAmbient.mMapName.length() > 0) - CopyASETexture(*mat.pcInstance,mat.sTexAmbient, aiTextureType_AMBIENT); - - // OPACITY texture - if( mat.sTexOpacity.mMapName.length() > 0) - CopyASETexture(*mat.pcInstance,mat.sTexOpacity, aiTextureType_OPACITY); - - // EMISSIVE texture - if( mat.sTexEmissive.mMapName.length() > 0) - CopyASETexture(*mat.pcInstance,mat.sTexEmissive, aiTextureType_EMISSIVE); - - // BUMP texture - if( mat.sTexBump.mMapName.length() > 0) - CopyASETexture(*mat.pcInstance,mat.sTexBump, aiTextureType_HEIGHT); - - // SHININESS texture - if( mat.sTexShininess.mMapName.length() > 0) - CopyASETexture(*mat.pcInstance,mat.sTexShininess, aiTextureType_SHININESS); - - // store the name of the material itself, too - if( mat.mName.length() > 0) { - aiString tex;tex.Set( mat.mName); - mat.pcInstance->AddProperty( &tex, AI_MATKEY_NAME); - } - return; + // LARGE TODO: Much code her is copied from 3DS ... join them maybe? + + // Allocate the output material + mat.pcInstance = new aiMaterial(); + + // At first add the base ambient color of the + // scene to the material + mat.mAmbient.r += mParser->m_clrAmbient.r; + mat.mAmbient.g += mParser->m_clrAmbient.g; + mat.mAmbient.b += mParser->m_clrAmbient.b; + + aiString name; + name.Set( mat.mName); + mat.pcInstance->AddProperty( &name, AI_MATKEY_NAME); + + // material colors + mat.pcInstance->AddProperty( &mat.mAmbient, 1, AI_MATKEY_COLOR_AMBIENT); + mat.pcInstance->AddProperty( &mat.mDiffuse, 1, AI_MATKEY_COLOR_DIFFUSE); + mat.pcInstance->AddProperty( &mat.mSpecular, 1, AI_MATKEY_COLOR_SPECULAR); + mat.pcInstance->AddProperty( &mat.mEmissive, 1, AI_MATKEY_COLOR_EMISSIVE); + + // shininess + if (0.0f != mat.mSpecularExponent && 0.0f != mat.mShininessStrength) + { + mat.pcInstance->AddProperty( &mat.mSpecularExponent, 1, AI_MATKEY_SHININESS); + mat.pcInstance->AddProperty( &mat.mShininessStrength, 1, AI_MATKEY_SHININESS_STRENGTH); + } + // If there is no shininess, we can disable phong lighting + else if (D3DS::Discreet3DS::Metal == mat.mShading || + D3DS::Discreet3DS::Phong == mat.mShading || + D3DS::Discreet3DS::Blinn == mat.mShading) + { + mat.mShading = D3DS::Discreet3DS::Gouraud; + } + + // opacity + mat.pcInstance->AddProperty( &mat.mTransparency,1,AI_MATKEY_OPACITY); + + // Two sided rendering? + if (mat.mTwoSided) + { + int i = 1; + mat.pcInstance->AddProperty(&i,1,AI_MATKEY_TWOSIDED); + } + + // shading mode + aiShadingMode eShading = aiShadingMode_NoShading; + switch (mat.mShading) + { + case D3DS::Discreet3DS::Flat: + eShading = aiShadingMode_Flat; break; + case D3DS::Discreet3DS::Phong : + eShading = aiShadingMode_Phong; break; + case D3DS::Discreet3DS::Blinn : + eShading = aiShadingMode_Blinn; break; + + // I don't know what "Wire" shading should be, + // assume it is simple lambertian diffuse (L dot N) shading + case D3DS::Discreet3DS::Wire: + { + // set the wireframe flag + unsigned int iWire = 1; + mat.pcInstance->AddProperty( (int*)&iWire,1,AI_MATKEY_ENABLE_WIREFRAME); + } + case D3DS::Discreet3DS::Gouraud: + eShading = aiShadingMode_Gouraud; break; + case D3DS::Discreet3DS::Metal : + eShading = aiShadingMode_CookTorrance; break; + } + mat.pcInstance->AddProperty( (int*)&eShading,1,AI_MATKEY_SHADING_MODEL); + + // DIFFUSE texture + if( mat.sTexDiffuse.mMapName.length() > 0) + CopyASETexture(*mat.pcInstance,mat.sTexDiffuse, aiTextureType_DIFFUSE); + + // SPECULAR texture + if( mat.sTexSpecular.mMapName.length() > 0) + CopyASETexture(*mat.pcInstance,mat.sTexSpecular, aiTextureType_SPECULAR); + + // AMBIENT texture + if( mat.sTexAmbient.mMapName.length() > 0) + CopyASETexture(*mat.pcInstance,mat.sTexAmbient, aiTextureType_AMBIENT); + + // OPACITY texture + if( mat.sTexOpacity.mMapName.length() > 0) + CopyASETexture(*mat.pcInstance,mat.sTexOpacity, aiTextureType_OPACITY); + + // EMISSIVE texture + if( mat.sTexEmissive.mMapName.length() > 0) + CopyASETexture(*mat.pcInstance,mat.sTexEmissive, aiTextureType_EMISSIVE); + + // BUMP texture + if( mat.sTexBump.mMapName.length() > 0) + CopyASETexture(*mat.pcInstance,mat.sTexBump, aiTextureType_HEIGHT); + + // SHININESS texture + if( mat.sTexShininess.mMapName.length() > 0) + CopyASETexture(*mat.pcInstance,mat.sTexShininess, aiTextureType_SHININESS); + + // store the name of the material itself, too + if( mat.mName.length() > 0) { + aiString tex;tex.Set( mat.mName); + mat.pcInstance->AddProperty( &tex, AI_MATKEY_NAME); + } + return; } // ------------------------------------------------------------------------------------------------ // Build output meshes void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector& avOutMeshes) { - // validate the material index of the mesh - if (mesh.iMaterialIndex >= mParser->m_vMaterials.size()) { - mesh.iMaterialIndex = (unsigned int)mParser->m_vMaterials.size()-1; - DefaultLogger::get()->warn("Material index is out of range"); - } - - // If the material the mesh is assigned to is consisting of submeshes, split it - if (!mParser->m_vMaterials[mesh.iMaterialIndex].avSubMaterials.empty()) { - std::vector vSubMaterials = mParser-> - m_vMaterials[mesh.iMaterialIndex].avSubMaterials; - - std::vector* aiSplit = new std::vector[vSubMaterials.size()]; - - // build a list of all faces per submaterial - for (unsigned int i = 0; i < mesh.mFaces.size();++i) { - // check range - if (mesh.mFaces[i].iMaterial >= vSubMaterials.size()) { - DefaultLogger::get()->warn("Submaterial index is out of range"); - - // use the last material instead - aiSplit[vSubMaterials.size()-1].push_back(i); - } - else aiSplit[mesh.mFaces[i].iMaterial].push_back(i); - } - - // now generate submeshes - for (unsigned int p = 0; p < vSubMaterials.size();++p) { - if (!aiSplit[p].empty()) { - - aiMesh* p_pcOut = new aiMesh(); - p_pcOut->mPrimitiveTypes = aiPrimitiveType_TRIANGLE; - - // let the sub material index - p_pcOut->mMaterialIndex = p; - - // we will need this material - mParser->m_vMaterials[mesh.iMaterialIndex].avSubMaterials[p].bNeed = true; - - // store the real index here ... color channel 3 - p_pcOut->mColors[3] = (aiColor4D*)(uintptr_t)mesh.iMaterialIndex; - - // store a pointer to the mesh in color channel 2 - p_pcOut->mColors[2] = (aiColor4D*) &mesh; - avOutMeshes.push_back(p_pcOut); - - // convert vertices - p_pcOut->mNumVertices = (unsigned int)aiSplit[p].size()*3; - p_pcOut->mNumFaces = (unsigned int)aiSplit[p].size(); - - // receive output vertex weights - std::vector > *avOutputBones = NULL; - if (!mesh.mBones.empty()) { - avOutputBones = new std::vector >[mesh.mBones.size()]; - } - - // allocate enough storage for faces - p_pcOut->mFaces = new aiFace[p_pcOut->mNumFaces]; - - unsigned int iBase = 0,iIndex; - if (p_pcOut->mNumVertices) { - p_pcOut->mVertices = new aiVector3D[p_pcOut->mNumVertices]; - p_pcOut->mNormals = new aiVector3D[p_pcOut->mNumVertices]; - for (unsigned int q = 0; q < aiSplit[p].size();++q) { - - iIndex = aiSplit[p][q]; - - p_pcOut->mFaces[q].mIndices = new unsigned int[3]; - p_pcOut->mFaces[q].mNumIndices = 3; - - for (unsigned int t = 0; t < 3;++t, ++iBase) { - const uint32_t iIndex2 = mesh.mFaces[iIndex].mIndices[t]; - - p_pcOut->mVertices[iBase] = mesh.mPositions [iIndex2]; - p_pcOut->mNormals [iBase] = mesh.mNormals [iIndex2]; - - // convert bones, if existing - if (!mesh.mBones.empty()) { - // check whether there is a vertex weight for this vertex index - if (iIndex2 < mesh.mBoneVertices.size()) { - - for (std::vector >::const_iterator - blubb = mesh.mBoneVertices[iIndex2].mBoneWeights.begin(); - blubb != mesh.mBoneVertices[iIndex2].mBoneWeights.end();++blubb) { - - // NOTE: illegal cases have already been filtered out - avOutputBones[(*blubb).first].push_back(std::pair( - iBase,(*blubb).second)); - } - } - } - p_pcOut->mFaces[q].mIndices[t] = iBase; - } - } - } - // convert texture coordinates (up to AI_MAX_NUMBER_OF_TEXTURECOORDS sets supported) - for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c) { - if (!mesh.amTexCoords[c].empty()) - { - p_pcOut->mTextureCoords[c] = new aiVector3D[p_pcOut->mNumVertices]; - iBase = 0; - for (unsigned int q = 0; q < aiSplit[p].size();++q) { - iIndex = aiSplit[p][q]; - for (unsigned int t = 0; t < 3;++t) { - p_pcOut->mTextureCoords[c][iBase++] = mesh.amTexCoords[c][mesh.mFaces[iIndex].mIndices[t]]; - } - } - // Setup the number of valid vertex components - p_pcOut->mNumUVComponents[c] = mesh.mNumUVComponents[c]; - } - } - - // Convert vertex colors (only one set supported) - if (!mesh.mVertexColors.empty()){ - p_pcOut->mColors[0] = new aiColor4D[p_pcOut->mNumVertices]; - iBase = 0; - for (unsigned int q = 0; q < aiSplit[p].size();++q) { - iIndex = aiSplit[p][q]; - for (unsigned int t = 0; t < 3;++t) { - p_pcOut->mColors[0][iBase++] = mesh.mVertexColors[mesh.mFaces[iIndex].mIndices[t]]; - } - } - } - // Copy bones - if (!mesh.mBones.empty()) { - p_pcOut->mNumBones = 0; - for (unsigned int mrspock = 0; mrspock < mesh.mBones.size();++mrspock) - if (!avOutputBones[mrspock].empty())p_pcOut->mNumBones++; - - p_pcOut->mBones = new aiBone* [ p_pcOut->mNumBones ]; - aiBone** pcBone = p_pcOut->mBones; - for (unsigned int mrspock = 0; mrspock < mesh.mBones.size();++mrspock) - { - if (!avOutputBones[mrspock].empty()) { - // we will need this bone. add it to the output mesh and - // add all per-vertex weights - aiBone* pc = *pcBone = new aiBone(); - pc->mName.Set(mesh.mBones[mrspock].mName); - - pc->mNumWeights = (unsigned int)avOutputBones[mrspock].size(); - pc->mWeights = new aiVertexWeight[pc->mNumWeights]; - - for (unsigned int captainkirk = 0; captainkirk < pc->mNumWeights;++captainkirk) - { - const std::pair& ref = avOutputBones[mrspock][captainkirk]; - pc->mWeights[captainkirk].mVertexId = ref.first; - pc->mWeights[captainkirk].mWeight = ref.second; - } - ++pcBone; - } - } - // delete allocated storage - delete[] avOutputBones; - } - } - } - // delete storage - delete[] aiSplit; - } - else - { - // Otherwise we can simply copy the data to one output mesh - // This codepath needs less memory and uses fast memcpy()s - // to do the actual copying. So I think it is worth the - // effort here. - - aiMesh* p_pcOut = new aiMesh(); - p_pcOut->mPrimitiveTypes = aiPrimitiveType_TRIANGLE; - - // set an empty sub material index - p_pcOut->mMaterialIndex = ASE::Face::DEFAULT_MATINDEX; - mParser->m_vMaterials[mesh.iMaterialIndex].bNeed = true; - - // store the real index here ... in color channel 3 - p_pcOut->mColors[3] = (aiColor4D*)(uintptr_t)mesh.iMaterialIndex; - - // store a pointer to the mesh in color channel 2 - p_pcOut->mColors[2] = (aiColor4D*) &mesh; - avOutMeshes.push_back(p_pcOut); - - // If the mesh hasn't faces or vertices, there are two cases - // possible: 1. the model is invalid. 2. This is a dummy - // helper object which we are going to remove later ... - if (mesh.mFaces.empty() || mesh.mPositions.empty()) { - return; - } - - // convert vertices - p_pcOut->mNumVertices = (unsigned int)mesh.mPositions.size(); - p_pcOut->mNumFaces = (unsigned int)mesh.mFaces.size(); - - // allocate enough storage for faces - p_pcOut->mFaces = new aiFace[p_pcOut->mNumFaces]; - - // copy vertices - p_pcOut->mVertices = new aiVector3D[mesh.mPositions.size()]; - memcpy(p_pcOut->mVertices,&mesh.mPositions[0], - mesh.mPositions.size() * sizeof(aiVector3D)); - - // copy normals - p_pcOut->mNormals = new aiVector3D[mesh.mNormals.size()]; - memcpy(p_pcOut->mNormals,&mesh.mNormals[0], - mesh.mNormals.size() * sizeof(aiVector3D)); - - // copy texture coordinates - for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c) { - if (!mesh.amTexCoords[c].empty()) { - p_pcOut->mTextureCoords[c] = new aiVector3D[mesh.amTexCoords[c].size()]; - memcpy(p_pcOut->mTextureCoords[c],&mesh.amTexCoords[c][0], - mesh.amTexCoords[c].size() * sizeof(aiVector3D)); - - // setup the number of valid vertex components - p_pcOut->mNumUVComponents[c] = mesh.mNumUVComponents[c]; - } - } - - // copy vertex colors - if (!mesh.mVertexColors.empty()) { - p_pcOut->mColors[0] = new aiColor4D[mesh.mVertexColors.size()]; - memcpy(p_pcOut->mColors[0],&mesh.mVertexColors[0], - mesh.mVertexColors.size() * sizeof(aiColor4D)); - } - - // copy faces - for (unsigned int iFace = 0; iFace < p_pcOut->mNumFaces;++iFace) { - p_pcOut->mFaces[iFace].mNumIndices = 3; - p_pcOut->mFaces[iFace].mIndices = new unsigned int[3]; - - // copy indices - p_pcOut->mFaces[iFace].mIndices[0] = mesh.mFaces[iFace].mIndices[0]; - p_pcOut->mFaces[iFace].mIndices[1] = mesh.mFaces[iFace].mIndices[1]; - p_pcOut->mFaces[iFace].mIndices[2] = mesh.mFaces[iFace].mIndices[2]; - } - - // copy vertex bones - if (!mesh.mBones.empty() && !mesh.mBoneVertices.empty()) { - std::vector > avBonesOut( mesh.mBones.size() ); - - // find all vertex weights for this bone - unsigned int quak = 0; - for (std::vector::const_iterator harrypotter = mesh.mBoneVertices.begin(); - harrypotter != mesh.mBoneVertices.end();++harrypotter,++quak) { - - for (std::vector >::const_iterator - ronaldweasley = (*harrypotter).mBoneWeights.begin(); - ronaldweasley != (*harrypotter).mBoneWeights.end();++ronaldweasley) - { - aiVertexWeight weight; - weight.mVertexId = quak; - weight.mWeight = (*ronaldweasley).second; - avBonesOut[(*ronaldweasley).first].push_back(weight); - } - } - - // now build a final bone list - p_pcOut->mNumBones = 0; - for (unsigned int jfkennedy = 0; jfkennedy < mesh.mBones.size();++jfkennedy) - if (!avBonesOut[jfkennedy].empty())p_pcOut->mNumBones++; - - p_pcOut->mBones = new aiBone*[p_pcOut->mNumBones]; - aiBone** pcBone = p_pcOut->mBones; - for (unsigned int jfkennedy = 0; jfkennedy < mesh.mBones.size();++jfkennedy) { - if (!avBonesOut[jfkennedy].empty()) { - aiBone* pc = *pcBone = new aiBone(); - pc->mName.Set(mesh.mBones[jfkennedy].mName); - pc->mNumWeights = (unsigned int)avBonesOut[jfkennedy].size(); - pc->mWeights = new aiVertexWeight[pc->mNumWeights]; - ::memcpy(pc->mWeights,&avBonesOut[jfkennedy][0], - sizeof(aiVertexWeight) * pc->mNumWeights); - ++pcBone; - } - } - } - } + // validate the material index of the mesh + if (mesh.iMaterialIndex >= mParser->m_vMaterials.size()) { + mesh.iMaterialIndex = (unsigned int)mParser->m_vMaterials.size()-1; + DefaultLogger::get()->warn("Material index is out of range"); + } + + // If the material the mesh is assigned to is consisting of submeshes, split it + if (!mParser->m_vMaterials[mesh.iMaterialIndex].avSubMaterials.empty()) { + std::vector vSubMaterials = mParser-> + m_vMaterials[mesh.iMaterialIndex].avSubMaterials; + + std::vector* aiSplit = new std::vector[vSubMaterials.size()]; + + // build a list of all faces per submaterial + for (unsigned int i = 0; i < mesh.mFaces.size();++i) { + // check range + if (mesh.mFaces[i].iMaterial >= vSubMaterials.size()) { + DefaultLogger::get()->warn("Submaterial index is out of range"); + + // use the last material instead + aiSplit[vSubMaterials.size()-1].push_back(i); + } + else aiSplit[mesh.mFaces[i].iMaterial].push_back(i); + } + + // now generate submeshes + for (unsigned int p = 0; p < vSubMaterials.size();++p) { + if (!aiSplit[p].empty()) { + + aiMesh* p_pcOut = new aiMesh(); + p_pcOut->mPrimitiveTypes = aiPrimitiveType_TRIANGLE; + + // let the sub material index + p_pcOut->mMaterialIndex = p; + + // we will need this material + mParser->m_vMaterials[mesh.iMaterialIndex].avSubMaterials[p].bNeed = true; + + // store the real index here ... color channel 3 + p_pcOut->mColors[3] = (aiColor4D*)(uintptr_t)mesh.iMaterialIndex; + + // store a pointer to the mesh in color channel 2 + p_pcOut->mColors[2] = (aiColor4D*) &mesh; + avOutMeshes.push_back(p_pcOut); + + // convert vertices + p_pcOut->mNumVertices = (unsigned int)aiSplit[p].size()*3; + p_pcOut->mNumFaces = (unsigned int)aiSplit[p].size(); + + // receive output vertex weights + std::vector > *avOutputBones = NULL; + if (!mesh.mBones.empty()) { + avOutputBones = new std::vector >[mesh.mBones.size()]; + } + + // allocate enough storage for faces + p_pcOut->mFaces = new aiFace[p_pcOut->mNumFaces]; + + unsigned int iBase = 0,iIndex; + if (p_pcOut->mNumVertices) { + p_pcOut->mVertices = new aiVector3D[p_pcOut->mNumVertices]; + p_pcOut->mNormals = new aiVector3D[p_pcOut->mNumVertices]; + for (unsigned int q = 0; q < aiSplit[p].size();++q) { + + iIndex = aiSplit[p][q]; + + p_pcOut->mFaces[q].mIndices = new unsigned int[3]; + p_pcOut->mFaces[q].mNumIndices = 3; + + for (unsigned int t = 0; t < 3;++t, ++iBase) { + const uint32_t iIndex2 = mesh.mFaces[iIndex].mIndices[t]; + + p_pcOut->mVertices[iBase] = mesh.mPositions [iIndex2]; + p_pcOut->mNormals [iBase] = mesh.mNormals [iIndex2]; + + // convert bones, if existing + if (!mesh.mBones.empty()) { + // check whether there is a vertex weight for this vertex index + if (iIndex2 < mesh.mBoneVertices.size()) { + + for (std::vector >::const_iterator + blubb = mesh.mBoneVertices[iIndex2].mBoneWeights.begin(); + blubb != mesh.mBoneVertices[iIndex2].mBoneWeights.end();++blubb) { + + // NOTE: illegal cases have already been filtered out + avOutputBones[(*blubb).first].push_back(std::pair( + iBase,(*blubb).second)); + } + } + } + p_pcOut->mFaces[q].mIndices[t] = iBase; + } + } + } + // convert texture coordinates (up to AI_MAX_NUMBER_OF_TEXTURECOORDS sets supported) + for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c) { + if (!mesh.amTexCoords[c].empty()) + { + p_pcOut->mTextureCoords[c] = new aiVector3D[p_pcOut->mNumVertices]; + iBase = 0; + for (unsigned int q = 0; q < aiSplit[p].size();++q) { + iIndex = aiSplit[p][q]; + for (unsigned int t = 0; t < 3;++t) { + p_pcOut->mTextureCoords[c][iBase++] = mesh.amTexCoords[c][mesh.mFaces[iIndex].mIndices[t]]; + } + } + // Setup the number of valid vertex components + p_pcOut->mNumUVComponents[c] = mesh.mNumUVComponents[c]; + } + } + + // Convert vertex colors (only one set supported) + if (!mesh.mVertexColors.empty()){ + p_pcOut->mColors[0] = new aiColor4D[p_pcOut->mNumVertices]; + iBase = 0; + for (unsigned int q = 0; q < aiSplit[p].size();++q) { + iIndex = aiSplit[p][q]; + for (unsigned int t = 0; t < 3;++t) { + p_pcOut->mColors[0][iBase++] = mesh.mVertexColors[mesh.mFaces[iIndex].mIndices[t]]; + } + } + } + // Copy bones + if (!mesh.mBones.empty()) { + p_pcOut->mNumBones = 0; + for (unsigned int mrspock = 0; mrspock < mesh.mBones.size();++mrspock) + if (!avOutputBones[mrspock].empty())p_pcOut->mNumBones++; + + p_pcOut->mBones = new aiBone* [ p_pcOut->mNumBones ]; + aiBone** pcBone = p_pcOut->mBones; + for (unsigned int mrspock = 0; mrspock < mesh.mBones.size();++mrspock) + { + if (!avOutputBones[mrspock].empty()) { + // we will need this bone. add it to the output mesh and + // add all per-vertex weights + aiBone* pc = *pcBone = new aiBone(); + pc->mName.Set(mesh.mBones[mrspock].mName); + + pc->mNumWeights = (unsigned int)avOutputBones[mrspock].size(); + pc->mWeights = new aiVertexWeight[pc->mNumWeights]; + + for (unsigned int captainkirk = 0; captainkirk < pc->mNumWeights;++captainkirk) + { + const std::pair& ref = avOutputBones[mrspock][captainkirk]; + pc->mWeights[captainkirk].mVertexId = ref.first; + pc->mWeights[captainkirk].mWeight = ref.second; + } + ++pcBone; + } + } + // delete allocated storage + delete[] avOutputBones; + } + } + } + // delete storage + delete[] aiSplit; + } + else + { + // Otherwise we can simply copy the data to one output mesh + // This codepath needs less memory and uses fast memcpy()s + // to do the actual copying. So I think it is worth the + // effort here. + + aiMesh* p_pcOut = new aiMesh(); + p_pcOut->mPrimitiveTypes = aiPrimitiveType_TRIANGLE; + + // set an empty sub material index + p_pcOut->mMaterialIndex = ASE::Face::DEFAULT_MATINDEX; + mParser->m_vMaterials[mesh.iMaterialIndex].bNeed = true; + + // store the real index here ... in color channel 3 + p_pcOut->mColors[3] = (aiColor4D*)(uintptr_t)mesh.iMaterialIndex; + + // store a pointer to the mesh in color channel 2 + p_pcOut->mColors[2] = (aiColor4D*) &mesh; + avOutMeshes.push_back(p_pcOut); + + // If the mesh hasn't faces or vertices, there are two cases + // possible: 1. the model is invalid. 2. This is a dummy + // helper object which we are going to remove later ... + if (mesh.mFaces.empty() || mesh.mPositions.empty()) { + return; + } + + // convert vertices + p_pcOut->mNumVertices = (unsigned int)mesh.mPositions.size(); + p_pcOut->mNumFaces = (unsigned int)mesh.mFaces.size(); + + // allocate enough storage for faces + p_pcOut->mFaces = new aiFace[p_pcOut->mNumFaces]; + + // copy vertices + p_pcOut->mVertices = new aiVector3D[mesh.mPositions.size()]; + memcpy(p_pcOut->mVertices,&mesh.mPositions[0], + mesh.mPositions.size() * sizeof(aiVector3D)); + + // copy normals + p_pcOut->mNormals = new aiVector3D[mesh.mNormals.size()]; + memcpy(p_pcOut->mNormals,&mesh.mNormals[0], + mesh.mNormals.size() * sizeof(aiVector3D)); + + // copy texture coordinates + for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c) { + if (!mesh.amTexCoords[c].empty()) { + p_pcOut->mTextureCoords[c] = new aiVector3D[mesh.amTexCoords[c].size()]; + memcpy(p_pcOut->mTextureCoords[c],&mesh.amTexCoords[c][0], + mesh.amTexCoords[c].size() * sizeof(aiVector3D)); + + // setup the number of valid vertex components + p_pcOut->mNumUVComponents[c] = mesh.mNumUVComponents[c]; + } + } + + // copy vertex colors + if (!mesh.mVertexColors.empty()) { + p_pcOut->mColors[0] = new aiColor4D[mesh.mVertexColors.size()]; + memcpy(p_pcOut->mColors[0],&mesh.mVertexColors[0], + mesh.mVertexColors.size() * sizeof(aiColor4D)); + } + + // copy faces + for (unsigned int iFace = 0; iFace < p_pcOut->mNumFaces;++iFace) { + p_pcOut->mFaces[iFace].mNumIndices = 3; + p_pcOut->mFaces[iFace].mIndices = new unsigned int[3]; + + // copy indices + p_pcOut->mFaces[iFace].mIndices[0] = mesh.mFaces[iFace].mIndices[0]; + p_pcOut->mFaces[iFace].mIndices[1] = mesh.mFaces[iFace].mIndices[1]; + p_pcOut->mFaces[iFace].mIndices[2] = mesh.mFaces[iFace].mIndices[2]; + } + + // copy vertex bones + if (!mesh.mBones.empty() && !mesh.mBoneVertices.empty()) { + std::vector > avBonesOut( mesh.mBones.size() ); + + // find all vertex weights for this bone + unsigned int quak = 0; + for (std::vector::const_iterator harrypotter = mesh.mBoneVertices.begin(); + harrypotter != mesh.mBoneVertices.end();++harrypotter,++quak) { + + for (std::vector >::const_iterator + ronaldweasley = (*harrypotter).mBoneWeights.begin(); + ronaldweasley != (*harrypotter).mBoneWeights.end();++ronaldweasley) + { + aiVertexWeight weight; + weight.mVertexId = quak; + weight.mWeight = (*ronaldweasley).second; + avBonesOut[(*ronaldweasley).first].push_back(weight); + } + } + + // now build a final bone list + p_pcOut->mNumBones = 0; + for (unsigned int jfkennedy = 0; jfkennedy < mesh.mBones.size();++jfkennedy) + if (!avBonesOut[jfkennedy].empty())p_pcOut->mNumBones++; + + p_pcOut->mBones = new aiBone*[p_pcOut->mNumBones]; + aiBone** pcBone = p_pcOut->mBones; + for (unsigned int jfkennedy = 0; jfkennedy < mesh.mBones.size();++jfkennedy) { + if (!avBonesOut[jfkennedy].empty()) { + aiBone* pc = *pcBone = new aiBone(); + pc->mName.Set(mesh.mBones[jfkennedy].mName); + pc->mNumWeights = (unsigned int)avBonesOut[jfkennedy].size(); + pc->mWeights = new aiVertexWeight[pc->mNumWeights]; + ::memcpy(pc->mWeights,&avBonesOut[jfkennedy][0], + sizeof(aiVertexWeight) * pc->mNumWeights); + ++pcBone; + } + } + } + } } // ------------------------------------------------------------------------------------------------ // Setup proper material indices and build output materials void ASEImporter::BuildMaterialIndices() { - ai_assert(NULL != pcScene); - - // iterate through all materials and check whether we need them - for (unsigned int iMat = 0; iMat < mParser->m_vMaterials.size();++iMat) - { - ASE::Material& mat = mParser->m_vMaterials[iMat]; - if (mat.bNeed) { - // Convert it to the aiMaterial layout - ConvertMaterial(mat); - ++pcScene->mNumMaterials; - } - for (unsigned int iSubMat = 0; iSubMat < mat.avSubMaterials.size();++iSubMat) - { - ASE::Material& submat = mat.avSubMaterials[iSubMat]; - if (submat.bNeed) { - // Convert it to the aiMaterial layout - ConvertMaterial(submat); - ++pcScene->mNumMaterials; - } - } - } - - // allocate the output material array - pcScene->mMaterials = new aiMaterial*[pcScene->mNumMaterials]; - D3DS::Material** pcIntMaterials = new D3DS::Material*[pcScene->mNumMaterials]; - - unsigned int iNum = 0; - for (unsigned int iMat = 0; iMat < mParser->m_vMaterials.size();++iMat) { - ASE::Material& mat = mParser->m_vMaterials[iMat]; - if (mat.bNeed) - { - ai_assert(NULL != mat.pcInstance); - pcScene->mMaterials[iNum] = mat.pcInstance; - - // Store the internal material, too - pcIntMaterials[iNum] = &mat; - - // Iterate through all meshes and search for one which is using - // this top-level material index - for (unsigned int iMesh = 0; iMesh < pcScene->mNumMeshes;++iMesh) - { - aiMesh* mesh = pcScene->mMeshes[iMesh]; - if (ASE::Face::DEFAULT_MATINDEX == mesh->mMaterialIndex && - iMat == (uintptr_t)mesh->mColors[3]) - { - mesh->mMaterialIndex = iNum; - mesh->mColors[3] = NULL; - } - } - iNum++; - } - for (unsigned int iSubMat = 0; iSubMat < mat.avSubMaterials.size();++iSubMat) { - ASE::Material& submat = mat.avSubMaterials[iSubMat]; - if (submat.bNeed) { - ai_assert(NULL != submat.pcInstance); - pcScene->mMaterials[iNum] = submat.pcInstance; - - // Store the internal material, too - pcIntMaterials[iNum] = &submat; - - // Iterate through all meshes and search for one which is using - // this sub-level material index - for (unsigned int iMesh = 0; iMesh < pcScene->mNumMeshes;++iMesh) { - aiMesh* mesh = pcScene->mMeshes[iMesh]; - - if (iSubMat == mesh->mMaterialIndex && iMat == (uintptr_t)mesh->mColors[3]) { - mesh->mMaterialIndex = iNum; - mesh->mColors[3] = NULL; - } - } - iNum++; - } - } - } - - // Dekete our temporary array - delete[] pcIntMaterials; + ai_assert(NULL != pcScene); + + // iterate through all materials and check whether we need them + for (unsigned int iMat = 0; iMat < mParser->m_vMaterials.size();++iMat) + { + ASE::Material& mat = mParser->m_vMaterials[iMat]; + if (mat.bNeed) { + // Convert it to the aiMaterial layout + ConvertMaterial(mat); + ++pcScene->mNumMaterials; + } + for (unsigned int iSubMat = 0; iSubMat < mat.avSubMaterials.size();++iSubMat) + { + ASE::Material& submat = mat.avSubMaterials[iSubMat]; + if (submat.bNeed) { + // Convert it to the aiMaterial layout + ConvertMaterial(submat); + ++pcScene->mNumMaterials; + } + } + } + + // allocate the output material array + pcScene->mMaterials = new aiMaterial*[pcScene->mNumMaterials]; + D3DS::Material** pcIntMaterials = new D3DS::Material*[pcScene->mNumMaterials]; + + unsigned int iNum = 0; + for (unsigned int iMat = 0; iMat < mParser->m_vMaterials.size();++iMat) { + ASE::Material& mat = mParser->m_vMaterials[iMat]; + if (mat.bNeed) + { + ai_assert(NULL != mat.pcInstance); + pcScene->mMaterials[iNum] = mat.pcInstance; + + // Store the internal material, too + pcIntMaterials[iNum] = &mat; + + // Iterate through all meshes and search for one which is using + // this top-level material index + for (unsigned int iMesh = 0; iMesh < pcScene->mNumMeshes;++iMesh) + { + aiMesh* mesh = pcScene->mMeshes[iMesh]; + if (ASE::Face::DEFAULT_MATINDEX == mesh->mMaterialIndex && + iMat == (uintptr_t)mesh->mColors[3]) + { + mesh->mMaterialIndex = iNum; + mesh->mColors[3] = NULL; + } + } + iNum++; + } + for (unsigned int iSubMat = 0; iSubMat < mat.avSubMaterials.size();++iSubMat) { + ASE::Material& submat = mat.avSubMaterials[iSubMat]; + if (submat.bNeed) { + ai_assert(NULL != submat.pcInstance); + pcScene->mMaterials[iNum] = submat.pcInstance; + + // Store the internal material, too + pcIntMaterials[iNum] = &submat; + + // Iterate through all meshes and search for one which is using + // this sub-level material index + for (unsigned int iMesh = 0; iMesh < pcScene->mNumMeshes;++iMesh) { + aiMesh* mesh = pcScene->mMeshes[iMesh]; + + if (iSubMat == mesh->mMaterialIndex && iMat == (uintptr_t)mesh->mColors[3]) { + mesh->mMaterialIndex = iNum; + mesh->mColors[3] = NULL; + } + } + iNum++; + } + } + } + + // Dekete our temporary array + delete[] pcIntMaterials; } // ------------------------------------------------------------------------------------------------ // Generate normal vectors basing on smoothing groups -bool ASEImporter::GenerateNormals(ASE::Mesh& mesh) { - - if (!mesh.mNormals.empty() && !configRecomputeNormals) - { - // Check whether there are only uninitialized normals. If there are - // some, skip all normals from the file and compute them on our own - for (std::vector::const_iterator qq = mesh.mNormals.begin();qq != mesh.mNormals.end();++qq) { - if ((*qq).x || (*qq).y || (*qq).z) - { - return true; - } - } - } - // The array is reused. - ComputeNormalsWithSmoothingsGroups(mesh); - return false; +bool ASEImporter::GenerateNormals(ASE::Mesh& mesh) { + + if (!mesh.mNormals.empty() && !configRecomputeNormals) + { + // Check whether there are only uninitialized normals. If there are + // some, skip all normals from the file and compute them on our own + for (std::vector::const_iterator qq = mesh.mNormals.begin();qq != mesh.mNormals.end();++qq) { + if ((*qq).x || (*qq).y || (*qq).z) + { + return true; + } + } + } + // The array is reused. + ComputeNormalsWithSmoothingsGroups(mesh); + return false; } #endif // !! ASSIMP_BUILD_NO_BASE_IMPORTER diff --git a/src/3rdparty/assimp/code/ASELoader.h b/src/3rdparty/assimp/code/ASELoader.h index 903376a3c..b775fc6bb 100644 --- a/src/3rdparty/assimp/code/ASELoader.h +++ b/src/3rdparty/assimp/code/ASELoader.h @@ -2,11 +2,11 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2012, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above @@ -23,16 +23,16 @@ following conditions are met: derived from this software without specific prior written permission of the assimp team. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- @@ -45,7 +45,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define AI_ASELOADER_H_INCLUDED #include "BaseImporter.h" -#include "../include/assimp/types.h" +#include struct aiNode; #include "ASEParser.h" @@ -57,147 +57,147 @@ namespace Assimp { /** Importer class for the 3DS ASE ASCII format. * */ -class ASEImporter : public BaseImporter { +class ASEImporter : public BaseImporter { public: - ASEImporter(); - ~ASEImporter(); + ASEImporter(); + ~ASEImporter(); public: - // ------------------------------------------------------------------- - /** Returns whether the class can handle the format of the given file. - * See BaseImporter::CanRead() for details. - */ - bool CanRead( const std::string& pFile, IOSystem* pIOHandler, - bool checkSig) const; + // ------------------------------------------------------------------- + /** Returns whether the class can handle the format of the given file. + * See BaseImporter::CanRead() for details. + */ + bool CanRead( const std::string& pFile, IOSystem* pIOHandler, + bool checkSig) const; protected: - // ------------------------------------------------------------------- - /** Return importer meta information. - * See #BaseImporter::GetInfo for the details - */ - const aiImporterDesc* GetInfo () const; + // ------------------------------------------------------------------- + /** Return importer meta information. + * See #BaseImporter::GetInfo for the details + */ + const aiImporterDesc* GetInfo () const; - // ------------------------------------------------------------------- - /** Imports the given file into the given scene structure. - * See BaseImporter::InternReadFile() for details - */ - void InternReadFile( const std::string& pFile, aiScene* pScene, - IOSystem* pIOHandler); + // ------------------------------------------------------------------- + /** Imports the given file into the given scene structure. + * See BaseImporter::InternReadFile() for details + */ + void InternReadFile( const std::string& pFile, aiScene* pScene, + IOSystem* pIOHandler); - // ------------------------------------------------------------------- - /** Called prior to ReadFile(). - * The function is a request to the importer to update its configuration - * basing on the Importer's configuration property list. - */ - void SetupProperties(const Importer* pImp); + // ------------------------------------------------------------------- + /** Called prior to ReadFile(). + * The function is a request to the importer to update its configuration + * basing on the Importer's configuration property list. + */ + void SetupProperties(const Importer* pImp); private: - // ------------------------------------------------------------------- - /** Generate normal vectors basing on smoothing groups - * (in some cases the normal are already contained in the file) - * \param mesh Mesh to work on - * \return false if the normals have been recomputed - */ - bool GenerateNormals(ASE::Mesh& mesh); + // ------------------------------------------------------------------- + /** Generate normal vectors basing on smoothing groups + * (in some cases the normal are already contained in the file) + * \param mesh Mesh to work on + * \return false if the normals have been recomputed + */ + bool GenerateNormals(ASE::Mesh& mesh); - // ------------------------------------------------------------------- - /** Create valid vertex/normal/UV/color/face lists. - * All elements are unique, faces have only one set of indices - * after this step occurs. - * \param mesh Mesh to work on - */ - void BuildUniqueRepresentation(ASE::Mesh& mesh); + // ------------------------------------------------------------------- + /** Create valid vertex/normal/UV/color/face lists. + * All elements are unique, faces have only one set of indices + * after this step occurs. + * \param mesh Mesh to work on + */ + void BuildUniqueRepresentation(ASE::Mesh& mesh); - /** Create one-material-per-mesh meshes ;-) - * \param mesh Mesh to work with - * \param Receives the list of all created meshes - */ - void ConvertMeshes(ASE::Mesh& mesh, std::vector& avOut); + /** Create one-material-per-mesh meshes ;-) + * \param mesh Mesh to work with + * \param Receives the list of all created meshes + */ + void ConvertMeshes(ASE::Mesh& mesh, std::vector& avOut); - // ------------------------------------------------------------------- - /** Convert a material to a aiMaterial object - * \param mat Input material - */ - void ConvertMaterial(ASE::Material& mat); + // ------------------------------------------------------------------- + /** Convert a material to a aiMaterial object + * \param mat Input material + */ + void ConvertMaterial(ASE::Material& mat); - // ------------------------------------------------------------------- - /** Setup the final material indices for each mesh - */ - void BuildMaterialIndices(); + // ------------------------------------------------------------------- + /** Setup the final material indices for each mesh + */ + void BuildMaterialIndices(); - // ------------------------------------------------------------------- - /** Build the node graph - */ - void BuildNodes(std::vector& nodes); + // ------------------------------------------------------------------- + /** Build the node graph + */ + void BuildNodes(std::vector& nodes); - // ------------------------------------------------------------------- - /** Build output cameras - */ - void BuildCameras(); + // ------------------------------------------------------------------- + /** Build output cameras + */ + void BuildCameras(); - // ------------------------------------------------------------------- - /** Build output lights - */ - void BuildLights(); + // ------------------------------------------------------------------- + /** Build output lights + */ + void BuildLights(); - // ------------------------------------------------------------------- - /** Build output animations - */ - void BuildAnimations(const std::vector& nodes); + // ------------------------------------------------------------------- + /** Build output animations + */ + void BuildAnimations(const std::vector& nodes); - // ------------------------------------------------------------------- - /** Add sub nodes to a node - * \param pcParent parent node to be filled - * \param szName Name of the parent node - * \param matrix Current transform - */ - void AddNodes(const std::vector& nodes, - aiNode* pcParent,const char* szName); + // ------------------------------------------------------------------- + /** Add sub nodes to a node + * \param pcParent parent node to be filled + * \param szName Name of the parent node + * \param matrix Current transform + */ + void AddNodes(const std::vector& nodes, + aiNode* pcParent,const char* szName); - void AddNodes(const std::vector& nodes, - aiNode* pcParent,const char* szName, - const aiMatrix4x4& matrix); + void AddNodes(const std::vector& nodes, + aiNode* pcParent,const char* szName, + const aiMatrix4x4& matrix); - void AddMeshes(const ASE::BaseNode* snode,aiNode* node); + void AddMeshes(const ASE::BaseNode* snode,aiNode* node); - // ------------------------------------------------------------------- - /** Generate a default material and add it to the parser's list - * Called if no material has been found in the file (rare for ASE, - * but not impossible) - */ - void GenerateDefaultMaterial(); + // ------------------------------------------------------------------- + /** Generate a default material and add it to the parser's list + * Called if no material has been found in the file (rare for ASE, + * but not impossible) + */ + void GenerateDefaultMaterial(); protected: - /** Parser instance */ - ASE::Parser* mParser; + /** Parser instance */ + ASE::Parser* mParser; - /** Buffer to hold the loaded file */ - char* mBuffer; + /** Buffer to hold the loaded file */ + char* mBuffer; - /** Scene to be filled */ - aiScene* pcScene; + /** Scene to be filled */ + aiScene* pcScene; - /** Config options: Recompute the normals in every case - WA - for 3DS Max broken ASE normal export */ - bool configRecomputeNormals; - bool noSkeletonMesh; + /** Config options: Recompute the normals in every case - WA + for 3DS Max broken ASE normal export */ + bool configRecomputeNormals; + bool noSkeletonMesh; }; } // end of namespace Assimp diff --git a/src/3rdparty/assimp/code/ASEParser.cpp b/src/3rdparty/assimp/code/ASEParser.cpp index df505a445..204f8bf62 100644 --- a/src/3rdparty/assimp/code/ASEParser.cpp +++ b/src/3rdparty/assimp/code/ASEParser.cpp @@ -3,12 +3,12 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2012, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above @@ -25,25 +25,25 @@ conditions are met: derived from this software without specific prior written permission of the assimp team. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --------------------------------------------------------------------------- */ /** @file ASEParser.cpp - * @brief Implementation of the ASE parser class + * @brief Implementation of the ASE parser class */ -#include "AssimpPCH.h" + #ifndef ASSIMP_BUILD_NO_ASE_IMPORTER // internal headers @@ -51,6 +51,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "ASELoader.h" #include "MaterialSystem.h" #include "fast_atof.h" +#include using namespace Assimp; using namespace Assimp::ASE; @@ -60,32 +61,32 @@ using namespace Assimp::ASE; // Begin an ASE parsing function #define AI_ASE_PARSER_INIT() \ - int iDepth = 0; + int iDepth = 0; // ------------------------------------------------------------------------------------------------ // Handle a "top-level" section in the file. EOF is no error in this case. #define AI_ASE_HANDLE_TOP_LEVEL_SECTION() \ - else if ('{' == *filePtr)iDepth++; \ - else if ('}' == *filePtr) \ - { \ - if (0 == --iDepth) \ - { \ - ++filePtr; \ - SkipToNextToken(); \ - return; \ - } \ - } \ - else if ('\0' == *filePtr) \ - { \ - return; \ - } \ - if(IsLineEnd(*filePtr) && !bLastWasEndLine) \ - { \ - ++iLineNumber; \ - bLastWasEndLine = true; \ - } else bLastWasEndLine = false; \ - ++filePtr; + else if ('{' == *filePtr)iDepth++; \ + else if ('}' == *filePtr) \ + { \ + if (0 == --iDepth) \ + { \ + ++filePtr; \ + SkipToNextToken(); \ + return; \ + } \ + } \ + else if ('\0' == *filePtr) \ + { \ + return; \ + } \ + if(IsLineEnd(*filePtr) && !bLastWasEndLine) \ + { \ + ++iLineNumber; \ + bLastWasEndLine = true; \ + } else bLastWasEndLine = false; \ + ++filePtr; // ------------------------------------------------------------------------------------------------ // Handle a nested section in the file. EOF is an error in this case @@ -93,2061 +94,2061 @@ using namespace Assimp::ASE; // @param msg Full name of the section (including the asterisk) #define AI_ASE_HANDLE_SECTION(level, msg) \ - if ('{' == *filePtr)iDepth++; \ - else if ('}' == *filePtr) \ - { \ - if (0 == --iDepth) \ - { \ - ++filePtr; \ - SkipToNextToken(); \ - return; \ - } \ - } \ - else if ('\0' == *filePtr) \ - { \ - LogError("Encountered unexpected EOL while parsing a " msg \ - " chunk (Level " level ")"); \ - } \ - if(IsLineEnd(*filePtr) && !bLastWasEndLine) \ - { \ - ++iLineNumber; \ - bLastWasEndLine = true; \ - } else bLastWasEndLine = false; \ - ++filePtr; + if ('{' == *filePtr)iDepth++; \ + else if ('}' == *filePtr) \ + { \ + if (0 == --iDepth) \ + { \ + ++filePtr; \ + SkipToNextToken(); \ + return; \ + } \ + } \ + else if ('\0' == *filePtr) \ + { \ + LogError("Encountered unexpected EOL while parsing a " msg \ + " chunk (Level " level ")"); \ + } \ + if(IsLineEnd(*filePtr) && !bLastWasEndLine) \ + { \ + ++iLineNumber; \ + bLastWasEndLine = true; \ + } else bLastWasEndLine = false; \ + ++filePtr; // ------------------------------------------------------------------------------------------------ Parser::Parser (const char* szFile, unsigned int fileFormatDefault) { - ai_assert(NULL != szFile); - filePtr = szFile; - iFileFormat = fileFormatDefault; - - // make sure that the color values are invalid - m_clrBackground.r = get_qnan(); - m_clrAmbient.r = get_qnan(); - - // setup some default values - iLineNumber = 0; - iFirstFrame = 0; - iLastFrame = 0; - iFrameSpeed = 30; // use 30 as default value for this property - iTicksPerFrame = 1; // use 1 as default value for this property - bLastWasEndLine = false; // need to handle \r\n seqs due to binary file mapping + ai_assert(NULL != szFile); + filePtr = szFile; + iFileFormat = fileFormatDefault; + + // make sure that the color values are invalid + m_clrBackground.r = get_qnan(); + m_clrAmbient.r = get_qnan(); + + // setup some default values + iLineNumber = 0; + iFirstFrame = 0; + iLastFrame = 0; + iFrameSpeed = 30; // use 30 as default value for this property + iTicksPerFrame = 1; // use 1 as default value for this property + bLastWasEndLine = false; // need to handle \r\n seqs due to binary file mapping } // ------------------------------------------------------------------------------------------------ void Parser::LogWarning(const char* szWarn) { - ai_assert(NULL != szWarn); + ai_assert(NULL != szWarn); - char szTemp[1024]; + char szTemp[1024]; #if _MSC_VER >= 1400 - sprintf_s(szTemp,"Line %i: %s",iLineNumber,szWarn); + sprintf_s(szTemp, "Line %u: %s",iLineNumber,szWarn); #else - snprintf(szTemp,1024,"Line %i: %s",iLineNumber,szWarn); + ai_snprintf(szTemp,1024,"Line %u: %s",iLineNumber,szWarn); #endif - // output the warning to the logger ... - DefaultLogger::get()->warn(szTemp); + // output the warning to the logger ... + DefaultLogger::get()->warn(szTemp); } // ------------------------------------------------------------------------------------------------ void Parser::LogInfo(const char* szWarn) { - ai_assert(NULL != szWarn); + ai_assert(NULL != szWarn); - char szTemp[1024]; + char szTemp[1024]; #if _MSC_VER >= 1400 - sprintf_s(szTemp,"Line %i: %s",iLineNumber,szWarn); + sprintf_s(szTemp,"Line %u: %s",iLineNumber,szWarn); #else - snprintf(szTemp,1024,"Line %i: %s",iLineNumber,szWarn); + ai_snprintf(szTemp,1024,"Line %u: %s",iLineNumber,szWarn); #endif - // output the information to the logger ... - DefaultLogger::get()->info(szTemp); + // output the information to the logger ... + DefaultLogger::get()->info(szTemp); } // ------------------------------------------------------------------------------------------------ -void Parser::LogError(const char* szWarn) +AI_WONT_RETURN void Parser::LogError(const char* szWarn) { - ai_assert(NULL != szWarn); + ai_assert(NULL != szWarn); - char szTemp[1024]; + char szTemp[1024]; #if _MSC_VER >= 1400 - sprintf_s(szTemp,"Line %i: %s",iLineNumber,szWarn); + sprintf_s(szTemp,"Line %u: %s",iLineNumber,szWarn); #else - snprintf(szTemp,1024,"Line %i: %s",iLineNumber,szWarn); + ai_snprintf(szTemp,1024,"Line %u: %s",iLineNumber,szWarn); #endif - // throw an exception - throw DeadlyImportError(szTemp); + // throw an exception + throw DeadlyImportError(szTemp); } // ------------------------------------------------------------------------------------------------ bool Parser::SkipToNextToken() { - while (true) - { - char me = *filePtr; - - // increase the line number counter if necessary - if (IsLineEnd(me) && !bLastWasEndLine) - { - ++iLineNumber; - bLastWasEndLine = true; - } - else bLastWasEndLine = false; - if ('*' == me || '}' == me || '{' == me)return true; - if ('\0' == me)return false; - - ++filePtr; - } + while (true) + { + char me = *filePtr; + + // increase the line number counter if necessary + if (IsLineEnd(me) && !bLastWasEndLine) + { + ++iLineNumber; + bLastWasEndLine = true; + } + else bLastWasEndLine = false; + if ('*' == me || '}' == me || '{' == me)return true; + if ('\0' == me)return false; + + ++filePtr; + } } // ------------------------------------------------------------------------------------------------ bool Parser::SkipSection() { - // must handle subsections ... - int iCnt = 0; - while (true) - { - if ('}' == *filePtr) - { - --iCnt; - if (0 == iCnt) - { - // go to the next valid token ... - ++filePtr; - SkipToNextToken(); - return true; - } - } - else if ('{' == *filePtr) - { - ++iCnt; - } - else if ('\0' == *filePtr) - { - LogWarning("Unable to parse block: Unexpected EOF, closing bracket \'}\' was expected [#1]"); - return false; - } - else if(IsLineEnd(*filePtr))++iLineNumber; - ++filePtr; - } + // must handle subsections ... + int iCnt = 0; + while (true) + { + if ('}' == *filePtr) + { + --iCnt; + if (0 == iCnt) + { + // go to the next valid token ... + ++filePtr; + SkipToNextToken(); + return true; + } + } + else if ('{' == *filePtr) + { + ++iCnt; + } + else if ('\0' == *filePtr) + { + LogWarning("Unable to parse block: Unexpected EOF, closing bracket \'}\' was expected [#1]"); + return false; + } + else if(IsLineEnd(*filePtr))++iLineNumber; + ++filePtr; + } } // ------------------------------------------------------------------------------------------------ void Parser::Parse() { - AI_ASE_PARSER_INIT(); - while (true) - { - if ('*' == *filePtr) - { - ++filePtr; - - // Version should be 200. Validate this ... - if (TokenMatch(filePtr,"3DSMAX_ASCIIEXPORT",18)) - { - unsigned int fmt; - ParseLV4MeshLong(fmt); - - if (fmt > 200) - { - LogWarning("Unknown file format version: *3DSMAX_ASCIIEXPORT should \ - be <= 200"); - } - // ************************************************************* - // - fmt will be 0 if we're unable to read the version number - // there are some faulty files without a version number ... - // in this case we'll guess the exact file format by looking - // at the file extension (ASE, ASK, ASC) - // ************************************************************* - - if (fmt)iFileFormat = fmt; - continue; - } - // main scene information - if (TokenMatch(filePtr,"SCENE",5)) - { - ParseLV1SceneBlock(); - continue; - } - // "group" - no implementation yet, in facte - // we're just ignoring them for the moment - if (TokenMatch(filePtr,"GROUP",5)) - { - Parse(); - continue; - } - // material list - if (TokenMatch(filePtr,"MATERIAL_LIST",13)) - { - ParseLV1MaterialListBlock(); - continue; - } - // geometric object (mesh) - if (TokenMatch(filePtr,"GEOMOBJECT",10)) - - { - m_vMeshes.push_back(Mesh()); - ParseLV1ObjectBlock(m_vMeshes.back()); - continue; - } - // helper object = dummy in the hierarchy - if (TokenMatch(filePtr,"HELPEROBJECT",12)) - - { - m_vDummies.push_back(Dummy()); - ParseLV1ObjectBlock(m_vDummies.back()); - continue; - } - // light object - if (TokenMatch(filePtr,"LIGHTOBJECT",11)) - - { - m_vLights.push_back(Light()); - ParseLV1ObjectBlock(m_vLights.back()); - continue; - } - // camera object - if (TokenMatch(filePtr,"CAMERAOBJECT",12)) - { - m_vCameras.push_back(Camera()); - ParseLV1ObjectBlock(m_vCameras.back()); - continue; - } - // comment - print it on the console - if (TokenMatch(filePtr,"COMMENT",7)) - { - std::string out = ""; - ParseString(out,"*COMMENT"); - LogInfo(("Comment: " + out).c_str()); - continue; - } - // ASC bone weights - if (AI_ASE_IS_OLD_FILE_FORMAT() && TokenMatch(filePtr,"MESH_SOFTSKINVERTS",18)) - { - ParseLV1SoftSkinBlock(); - } - } - AI_ASE_HANDLE_TOP_LEVEL_SECTION(); - } - return; + AI_ASE_PARSER_INIT(); + while (true) + { + if ('*' == *filePtr) + { + ++filePtr; + + // Version should be 200. Validate this ... + if (TokenMatch(filePtr,"3DSMAX_ASCIIEXPORT",18)) + { + unsigned int fmt; + ParseLV4MeshLong(fmt); + + if (fmt > 200) + { + LogWarning("Unknown file format version: *3DSMAX_ASCIIEXPORT should \ + be <= 200"); + } + // ************************************************************* + // - fmt will be 0 if we're unable to read the version number + // there are some faulty files without a version number ... + // in this case we'll guess the exact file format by looking + // at the file extension (ASE, ASK, ASC) + // ************************************************************* + + if (fmt)iFileFormat = fmt; + continue; + } + // main scene information + if (TokenMatch(filePtr,"SCENE",5)) + { + ParseLV1SceneBlock(); + continue; + } + // "group" - no implementation yet, in facte + // we're just ignoring them for the moment + if (TokenMatch(filePtr,"GROUP",5)) + { + Parse(); + continue; + } + // material list + if (TokenMatch(filePtr,"MATERIAL_LIST",13)) + { + ParseLV1MaterialListBlock(); + continue; + } + // geometric object (mesh) + if (TokenMatch(filePtr,"GEOMOBJECT",10)) + + { + m_vMeshes.push_back(Mesh()); + ParseLV1ObjectBlock(m_vMeshes.back()); + continue; + } + // helper object = dummy in the hierarchy + if (TokenMatch(filePtr,"HELPEROBJECT",12)) + + { + m_vDummies.push_back(Dummy()); + ParseLV1ObjectBlock(m_vDummies.back()); + continue; + } + // light object + if (TokenMatch(filePtr,"LIGHTOBJECT",11)) + + { + m_vLights.push_back(Light()); + ParseLV1ObjectBlock(m_vLights.back()); + continue; + } + // camera object + if (TokenMatch(filePtr,"CAMERAOBJECT",12)) + { + m_vCameras.push_back(Camera()); + ParseLV1ObjectBlock(m_vCameras.back()); + continue; + } + // comment - print it on the console + if (TokenMatch(filePtr,"COMMENT",7)) + { + std::string out = ""; + ParseString(out,"*COMMENT"); + LogInfo(("Comment: " + out).c_str()); + continue; + } + // ASC bone weights + if (AI_ASE_IS_OLD_FILE_FORMAT() && TokenMatch(filePtr,"MESH_SOFTSKINVERTS",18)) + { + ParseLV1SoftSkinBlock(); + } + } + AI_ASE_HANDLE_TOP_LEVEL_SECTION(); + } + return; } // ------------------------------------------------------------------------------------------------ void Parser::ParseLV1SoftSkinBlock() { - // TODO: fix line counting here - - // ************************************************************** - // The soft skin block is formatted differently. There are no - // nested sections supported and the single elements aren't - // marked by keywords starting with an asterisk. - - /** - FORMAT BEGIN - - *MESH_SOFTSKINVERTS { - - - - [for times:] - [for times:] - } - - FORMAT END - */ - // ************************************************************** - while (true) - { - if (*filePtr == '}' ) {++filePtr;return;} - else if (*filePtr == '\0') return; - else if (*filePtr == '{' ) ++filePtr; - - else // if (!IsSpace(*filePtr) && !IsLineEnd(*filePtr)) - { - ASE::Mesh* curMesh = NULL; - unsigned int numVerts = 0; - - const char* sz = filePtr; - while (!IsSpaceOrNewLine(*filePtr))++filePtr; - - const unsigned int diff = (unsigned int)(filePtr-sz); - if (diff) - { - std::string name = std::string(sz,diff); - for (std::vector::iterator it = m_vMeshes.begin(); - it != m_vMeshes.end(); ++it) - { - if ((*it).mName == name) - { - curMesh = & (*it); - break; - } - } - if (!curMesh) - { - LogWarning("Encountered unknown mesh in *MESH_SOFTSKINVERTS section"); - - // Skip the mesh data - until we find a new mesh - // or the end of the *MESH_SOFTSKINVERTS section - while (true) - { - SkipSpacesAndLineEnd(&filePtr); - if (*filePtr == '}') - {++filePtr;return;} - else if (!IsNumeric(*filePtr)) - break; - - SkipLine(&filePtr); - } - } - else - { - SkipSpacesAndLineEnd(&filePtr); - ParseLV4MeshLong(numVerts); - - // Reserve enough storage - curMesh->mBoneVertices.reserve(numVerts); - - for (unsigned int i = 0; i < numVerts;++i) - { - SkipSpacesAndLineEnd(&filePtr); - unsigned int numWeights; - ParseLV4MeshLong(numWeights); - - curMesh->mBoneVertices.push_back(ASE::BoneVertex()); - ASE::BoneVertex& vert = curMesh->mBoneVertices.back(); - - // Reserve enough storage - vert.mBoneWeights.reserve(numWeights); - - for (unsigned int w = 0; w < numWeights;++w) - { - std::string bone; - ParseString(bone,"*MESH_SOFTSKINVERTS.Bone"); - - // Find the bone in the mesh's list - std::pair me; - me.first = -1; - - for (unsigned int n = 0; n < curMesh->mBones.size();++n) - { - if (curMesh->mBones[n].mName == bone) - { - me.first = n; - break; - } - } - if (-1 == me.first) - { - // We don't have this bone yet, so add it to the list - me.first = (int)curMesh->mBones.size(); - curMesh->mBones.push_back(ASE::Bone(bone)); - } - ParseLV4MeshFloat( me.second ); - - // Add the new bone weight to list - vert.mBoneWeights.push_back(me); - } - } - } - } - } - ++filePtr; - SkipSpacesAndLineEnd(&filePtr); - } + // TODO: fix line counting here + + // ************************************************************** + // The soft skin block is formatted differently. There are no + // nested sections supported and the single elements aren't + // marked by keywords starting with an asterisk. + + /** + FORMAT BEGIN + + *MESH_SOFTSKINVERTS { + + + + [for times:] + [for times:] + } + + FORMAT END + */ + // ************************************************************** + while (true) + { + if (*filePtr == '}' ) {++filePtr;return;} + else if (*filePtr == '\0') return; + else if (*filePtr == '{' ) ++filePtr; + + else // if (!IsSpace(*filePtr) && !IsLineEnd(*filePtr)) + { + ASE::Mesh* curMesh = NULL; + unsigned int numVerts = 0; + + const char* sz = filePtr; + while (!IsSpaceOrNewLine(*filePtr))++filePtr; + + const unsigned int diff = (unsigned int)(filePtr-sz); + if (diff) + { + std::string name = std::string(sz,diff); + for (std::vector::iterator it = m_vMeshes.begin(); + it != m_vMeshes.end(); ++it) + { + if ((*it).mName == name) + { + curMesh = & (*it); + break; + } + } + if (!curMesh) + { + LogWarning("Encountered unknown mesh in *MESH_SOFTSKINVERTS section"); + + // Skip the mesh data - until we find a new mesh + // or the end of the *MESH_SOFTSKINVERTS section + while (true) + { + SkipSpacesAndLineEnd(&filePtr); + if (*filePtr == '}') + {++filePtr;return;} + else if (!IsNumeric(*filePtr)) + break; + + SkipLine(&filePtr); + } + } + else + { + SkipSpacesAndLineEnd(&filePtr); + ParseLV4MeshLong(numVerts); + + // Reserve enough storage + curMesh->mBoneVertices.reserve(numVerts); + + for (unsigned int i = 0; i < numVerts;++i) + { + SkipSpacesAndLineEnd(&filePtr); + unsigned int numWeights; + ParseLV4MeshLong(numWeights); + + curMesh->mBoneVertices.push_back(ASE::BoneVertex()); + ASE::BoneVertex& vert = curMesh->mBoneVertices.back(); + + // Reserve enough storage + vert.mBoneWeights.reserve(numWeights); + + for (unsigned int w = 0; w < numWeights;++w) + { + std::string bone; + ParseString(bone,"*MESH_SOFTSKINVERTS.Bone"); + + // Find the bone in the mesh's list + std::pair me; + me.first = -1; + + for (unsigned int n = 0; n < curMesh->mBones.size();++n) + { + if (curMesh->mBones[n].mName == bone) + { + me.first = n; + break; + } + } + if (-1 == me.first) + { + // We don't have this bone yet, so add it to the list + me.first = (int)curMesh->mBones.size(); + curMesh->mBones.push_back(ASE::Bone(bone)); + } + ParseLV4MeshFloat( me.second ); + + // Add the new bone weight to list + vert.mBoneWeights.push_back(me); + } + } + } + } + } + ++filePtr; + SkipSpacesAndLineEnd(&filePtr); + } } // ------------------------------------------------------------------------------------------------ void Parser::ParseLV1SceneBlock() { - AI_ASE_PARSER_INIT(); - while (true) - { - if ('*' == *filePtr) - { - ++filePtr; - if (TokenMatch(filePtr,"SCENE_BACKGROUND_STATIC",23)) - - { - // parse a color triple and assume it is really the bg color - ParseLV4MeshFloatTriple( &m_clrBackground.r ); - continue; - } - if (TokenMatch(filePtr,"SCENE_AMBIENT_STATIC",20)) - - { - // parse a color triple and assume it is really the bg color - ParseLV4MeshFloatTriple( &m_clrAmbient.r ); - continue; - } - if (TokenMatch(filePtr,"SCENE_FIRSTFRAME",16)) - { - ParseLV4MeshLong(iFirstFrame); - continue; - } - if (TokenMatch(filePtr,"SCENE_LASTFRAME",15)) - { - ParseLV4MeshLong(iLastFrame); - continue; - } - if (TokenMatch(filePtr,"SCENE_FRAMESPEED",16)) - { - ParseLV4MeshLong(iFrameSpeed); - continue; - } - if (TokenMatch(filePtr,"SCENE_TICKSPERFRAME",19)) - { - ParseLV4MeshLong(iTicksPerFrame); - continue; - } - } - AI_ASE_HANDLE_TOP_LEVEL_SECTION(); - } + AI_ASE_PARSER_INIT(); + while (true) + { + if ('*' == *filePtr) + { + ++filePtr; + if (TokenMatch(filePtr,"SCENE_BACKGROUND_STATIC",23)) + + { + // parse a color triple and assume it is really the bg color + ParseLV4MeshFloatTriple( &m_clrBackground.r ); + continue; + } + if (TokenMatch(filePtr,"SCENE_AMBIENT_STATIC",20)) + + { + // parse a color triple and assume it is really the bg color + ParseLV4MeshFloatTriple( &m_clrAmbient.r ); + continue; + } + if (TokenMatch(filePtr,"SCENE_FIRSTFRAME",16)) + { + ParseLV4MeshLong(iFirstFrame); + continue; + } + if (TokenMatch(filePtr,"SCENE_LASTFRAME",15)) + { + ParseLV4MeshLong(iLastFrame); + continue; + } + if (TokenMatch(filePtr,"SCENE_FRAMESPEED",16)) + { + ParseLV4MeshLong(iFrameSpeed); + continue; + } + if (TokenMatch(filePtr,"SCENE_TICKSPERFRAME",19)) + { + ParseLV4MeshLong(iTicksPerFrame); + continue; + } + } + AI_ASE_HANDLE_TOP_LEVEL_SECTION(); + } } // ------------------------------------------------------------------------------------------------ void Parser::ParseLV1MaterialListBlock() { - AI_ASE_PARSER_INIT(); - - unsigned int iMaterialCount = 0; - unsigned int iOldMaterialCount = (unsigned int)m_vMaterials.size(); - while (true) - { - if ('*' == *filePtr) - { - ++filePtr; - if (TokenMatch(filePtr,"MATERIAL_COUNT",14)) - { - ParseLV4MeshLong(iMaterialCount); - - // now allocate enough storage to hold all materials - m_vMaterials.resize(iOldMaterialCount+iMaterialCount); - continue; - } - if (TokenMatch(filePtr,"MATERIAL",8)) - { - unsigned int iIndex = 0; - ParseLV4MeshLong(iIndex); - - if (iIndex >= iMaterialCount) - { - LogWarning("Out of range: material index is too large"); - iIndex = iMaterialCount-1; - } - - // get a reference to the material - Material& sMat = m_vMaterials[iIndex+iOldMaterialCount]; - // parse the material block - ParseLV2MaterialBlock(sMat); - continue; - } - } - AI_ASE_HANDLE_TOP_LEVEL_SECTION(); - } + AI_ASE_PARSER_INIT(); + + unsigned int iMaterialCount = 0; + unsigned int iOldMaterialCount = (unsigned int)m_vMaterials.size(); + while (true) + { + if ('*' == *filePtr) + { + ++filePtr; + if (TokenMatch(filePtr,"MATERIAL_COUNT",14)) + { + ParseLV4MeshLong(iMaterialCount); + + // now allocate enough storage to hold all materials + m_vMaterials.resize(iOldMaterialCount+iMaterialCount); + continue; + } + if (TokenMatch(filePtr,"MATERIAL",8)) + { + unsigned int iIndex = 0; + ParseLV4MeshLong(iIndex); + + if (iIndex >= iMaterialCount) + { + LogWarning("Out of range: material index is too large"); + iIndex = iMaterialCount-1; + } + + // get a reference to the material + Material& sMat = m_vMaterials[iIndex+iOldMaterialCount]; + // parse the material block + ParseLV2MaterialBlock(sMat); + continue; + } + } + AI_ASE_HANDLE_TOP_LEVEL_SECTION(); + } } // ------------------------------------------------------------------------------------------------ void Parser::ParseLV2MaterialBlock(ASE::Material& mat) { - AI_ASE_PARSER_INIT(); - - unsigned int iNumSubMaterials = 0; - while (true) - { - if ('*' == *filePtr) - { - ++filePtr; - if (TokenMatch(filePtr,"MATERIAL_NAME",13)) - { - if (!ParseString(mat.mName,"*MATERIAL_NAME")) - SkipToNextToken(); - continue; - } - // ambient material color - if (TokenMatch(filePtr,"MATERIAL_AMBIENT",16)) - { - ParseLV4MeshFloatTriple(&mat.mAmbient.r); - continue; - } - // diffuse material color - if (TokenMatch(filePtr,"MATERIAL_DIFFUSE",16) ) - { - ParseLV4MeshFloatTriple(&mat.mDiffuse.r); - continue; - } - // specular material color - if (TokenMatch(filePtr,"MATERIAL_SPECULAR",17)) - { - ParseLV4MeshFloatTriple(&mat.mSpecular.r); - continue; - } - // material shading type - if (TokenMatch(filePtr,"MATERIAL_SHADING",16)) - { - if (TokenMatch(filePtr,"Blinn",5)) - { - mat.mShading = Discreet3DS::Blinn; - } - else if (TokenMatch(filePtr,"Phong",5)) - { - mat.mShading = Discreet3DS::Phong; - } - else if (TokenMatch(filePtr,"Flat",4)) - { - mat.mShading = Discreet3DS::Flat; - } - else if (TokenMatch(filePtr,"Wire",4)) - { - mat.mShading = Discreet3DS::Wire; - } - else - { - // assume gouraud shading - mat.mShading = Discreet3DS::Gouraud; - SkipToNextToken(); - } - continue; - } - // material transparency - if (TokenMatch(filePtr,"MATERIAL_TRANSPARENCY",21)) - { - ParseLV4MeshFloat(mat.mTransparency); - mat.mTransparency = 1.0f - mat.mTransparency;continue; - } - // material self illumination - if (TokenMatch(filePtr,"MATERIAL_SELFILLUM",18)) - { - float f = 0.0f; - ParseLV4MeshFloat(f); - - mat.mEmissive.r = f; - mat.mEmissive.g = f; - mat.mEmissive.b = f; - continue; - } - // material shininess - if (TokenMatch(filePtr,"MATERIAL_SHINE",14) ) - { - ParseLV4MeshFloat(mat.mSpecularExponent); - mat.mSpecularExponent *= 15; - continue; - } - // two-sided material - if (TokenMatch(filePtr,"MATERIAL_TWOSIDED",17) ) - { - mat.mTwoSided = true; - continue; - } - // material shininess strength - if (TokenMatch(filePtr,"MATERIAL_SHINESTRENGTH",22)) - { - ParseLV4MeshFloat(mat.mShininessStrength); - continue; - } - // diffuse color map - if (TokenMatch(filePtr,"MAP_DIFFUSE",11)) - { - // parse the texture block - ParseLV3MapBlock(mat.sTexDiffuse); - continue; - } - // ambient color map - if (TokenMatch(filePtr,"MAP_AMBIENT",11)) - { - // parse the texture block - ParseLV3MapBlock(mat.sTexAmbient); - continue; - } - // specular color map - if (TokenMatch(filePtr,"MAP_SPECULAR",12)) - { - // parse the texture block - ParseLV3MapBlock(mat.sTexSpecular); - continue; - } - // opacity map - if (TokenMatch(filePtr,"MAP_OPACITY",11)) - { - // parse the texture block - ParseLV3MapBlock(mat.sTexOpacity); - continue; - } - // emissive map - if (TokenMatch(filePtr,"MAP_SELFILLUM",13)) - { - // parse the texture block - ParseLV3MapBlock(mat.sTexEmissive); - continue; - } - // bump map - if (TokenMatch(filePtr,"MAP_BUMP",8)) - { - // parse the texture block - ParseLV3MapBlock(mat.sTexBump); - } - // specular/shininess map - if (TokenMatch(filePtr,"MAP_SHINESTRENGTH",17)) - { - // parse the texture block - ParseLV3MapBlock(mat.sTexShininess); - continue; - } - // number of submaterials - if (TokenMatch(filePtr,"NUMSUBMTLS",10)) - { - ParseLV4MeshLong(iNumSubMaterials); - - // allocate enough storage - mat.avSubMaterials.resize(iNumSubMaterials); - } - // submaterial chunks - if (TokenMatch(filePtr,"SUBMATERIAL",11)) - { - - unsigned int iIndex = 0; - ParseLV4MeshLong(iIndex); - - if (iIndex >= iNumSubMaterials) - { - LogWarning("Out of range: submaterial index is too large"); - iIndex = iNumSubMaterials-1; - } - - // get a reference to the material - Material& sMat = mat.avSubMaterials[iIndex]; - - // parse the material block - ParseLV2MaterialBlock(sMat); - continue; - } - } - AI_ASE_HANDLE_SECTION("2","*MATERIAL"); - } + AI_ASE_PARSER_INIT(); + + unsigned int iNumSubMaterials = 0; + while (true) + { + if ('*' == *filePtr) + { + ++filePtr; + if (TokenMatch(filePtr,"MATERIAL_NAME",13)) + { + if (!ParseString(mat.mName,"*MATERIAL_NAME")) + SkipToNextToken(); + continue; + } + // ambient material color + if (TokenMatch(filePtr,"MATERIAL_AMBIENT",16)) + { + ParseLV4MeshFloatTriple(&mat.mAmbient.r); + continue; + } + // diffuse material color + if (TokenMatch(filePtr,"MATERIAL_DIFFUSE",16) ) + { + ParseLV4MeshFloatTriple(&mat.mDiffuse.r); + continue; + } + // specular material color + if (TokenMatch(filePtr,"MATERIAL_SPECULAR",17)) + { + ParseLV4MeshFloatTriple(&mat.mSpecular.r); + continue; + } + // material shading type + if (TokenMatch(filePtr,"MATERIAL_SHADING",16)) + { + if (TokenMatch(filePtr,"Blinn",5)) + { + mat.mShading = Discreet3DS::Blinn; + } + else if (TokenMatch(filePtr,"Phong",5)) + { + mat.mShading = Discreet3DS::Phong; + } + else if (TokenMatch(filePtr,"Flat",4)) + { + mat.mShading = Discreet3DS::Flat; + } + else if (TokenMatch(filePtr,"Wire",4)) + { + mat.mShading = Discreet3DS::Wire; + } + else + { + // assume gouraud shading + mat.mShading = Discreet3DS::Gouraud; + SkipToNextToken(); + } + continue; + } + // material transparency + if (TokenMatch(filePtr,"MATERIAL_TRANSPARENCY",21)) + { + ParseLV4MeshFloat(mat.mTransparency); + mat.mTransparency = 1.0f - mat.mTransparency;continue; + } + // material self illumination + if (TokenMatch(filePtr,"MATERIAL_SELFILLUM",18)) + { + float f = 0.0f; + ParseLV4MeshFloat(f); + + mat.mEmissive.r = f; + mat.mEmissive.g = f; + mat.mEmissive.b = f; + continue; + } + // material shininess + if (TokenMatch(filePtr,"MATERIAL_SHINE",14) ) + { + ParseLV4MeshFloat(mat.mSpecularExponent); + mat.mSpecularExponent *= 15; + continue; + } + // two-sided material + if (TokenMatch(filePtr,"MATERIAL_TWOSIDED",17) ) + { + mat.mTwoSided = true; + continue; + } + // material shininess strength + if (TokenMatch(filePtr,"MATERIAL_SHINESTRENGTH",22)) + { + ParseLV4MeshFloat(mat.mShininessStrength); + continue; + } + // diffuse color map + if (TokenMatch(filePtr,"MAP_DIFFUSE",11)) + { + // parse the texture block + ParseLV3MapBlock(mat.sTexDiffuse); + continue; + } + // ambient color map + if (TokenMatch(filePtr,"MAP_AMBIENT",11)) + { + // parse the texture block + ParseLV3MapBlock(mat.sTexAmbient); + continue; + } + // specular color map + if (TokenMatch(filePtr,"MAP_SPECULAR",12)) + { + // parse the texture block + ParseLV3MapBlock(mat.sTexSpecular); + continue; + } + // opacity map + if (TokenMatch(filePtr,"MAP_OPACITY",11)) + { + // parse the texture block + ParseLV3MapBlock(mat.sTexOpacity); + continue; + } + // emissive map + if (TokenMatch(filePtr,"MAP_SELFILLUM",13)) + { + // parse the texture block + ParseLV3MapBlock(mat.sTexEmissive); + continue; + } + // bump map + if (TokenMatch(filePtr,"MAP_BUMP",8)) + { + // parse the texture block + ParseLV3MapBlock(mat.sTexBump); + } + // specular/shininess map + if (TokenMatch(filePtr,"MAP_SHINESTRENGTH",17)) + { + // parse the texture block + ParseLV3MapBlock(mat.sTexShininess); + continue; + } + // number of submaterials + if (TokenMatch(filePtr,"NUMSUBMTLS",10)) + { + ParseLV4MeshLong(iNumSubMaterials); + + // allocate enough storage + mat.avSubMaterials.resize(iNumSubMaterials); + } + // submaterial chunks + if (TokenMatch(filePtr,"SUBMATERIAL",11)) + { + + unsigned int iIndex = 0; + ParseLV4MeshLong(iIndex); + + if (iIndex >= iNumSubMaterials) + { + LogWarning("Out of range: submaterial index is too large"); + iIndex = iNumSubMaterials-1; + } + + // get a reference to the material + Material& sMat = mat.avSubMaterials[iIndex]; + + // parse the material block + ParseLV2MaterialBlock(sMat); + continue; + } + } + AI_ASE_HANDLE_SECTION("2","*MATERIAL"); + } } // ------------------------------------------------------------------------------------------------ void Parser::ParseLV3MapBlock(Texture& map) { - AI_ASE_PARSER_INIT(); - - // *********************************************************** - // *BITMAP should not be there if *MAP_CLASS is not BITMAP, - // but we need to expect that case ... if the path is - // empty the texture won't be used later. - // *********************************************************** - bool parsePath = true; - while (true) - { - if ('*' == *filePtr) - { - ++filePtr; - // type of map - if (TokenMatch(filePtr,"MAP_CLASS" ,9)) - { - std::string temp; - if(!ParseString(temp,"*MAP_CLASS")) - SkipToNextToken(); - if (temp != "Bitmap" && temp != "Normal Bump") - { - DefaultLogger::get()->warn("ASE: Skipping unknown map type: " + temp); - parsePath = false; - } - continue; - } - // path to the texture - if (parsePath && TokenMatch(filePtr,"BITMAP" ,6)) - { - if(!ParseString(map.mMapName,"*BITMAP")) - SkipToNextToken(); - - if (map.mMapName == "None") - { - // Files with 'None' as map name are produced by - // an Maja to ASE exporter which name I forgot .. - DefaultLogger::get()->warn("ASE: Skipping invalid map entry"); - map.mMapName = ""; - } - - continue; - } - // offset on the u axis - if (TokenMatch(filePtr,"UVW_U_OFFSET" ,12)) - { - ParseLV4MeshFloat(map.mOffsetU); - continue; - } - // offset on the v axis - if (TokenMatch(filePtr,"UVW_V_OFFSET" ,12)) - { - ParseLV4MeshFloat(map.mOffsetV); - continue; - } - // tiling on the u axis - if (TokenMatch(filePtr,"UVW_U_TILING" ,12)) - { - ParseLV4MeshFloat(map.mScaleU); - continue; - } - // tiling on the v axis - if (TokenMatch(filePtr,"UVW_V_TILING" ,12)) - { - ParseLV4MeshFloat(map.mScaleV); - continue; - } - // rotation around the z-axis - if (TokenMatch(filePtr,"UVW_ANGLE" ,9)) - { - ParseLV4MeshFloat(map.mRotation); - continue; - } - // map blending factor - if (TokenMatch(filePtr,"MAP_AMOUNT" ,10)) - { - ParseLV4MeshFloat(map.mTextureBlend); - continue; - } - } - AI_ASE_HANDLE_SECTION("3","*MAP_XXXXXX"); - } - return; + AI_ASE_PARSER_INIT(); + + // *********************************************************** + // *BITMAP should not be there if *MAP_CLASS is not BITMAP, + // but we need to expect that case ... if the path is + // empty the texture won't be used later. + // *********************************************************** + bool parsePath = true; + while (true) + { + if ('*' == *filePtr) + { + ++filePtr; + // type of map + if (TokenMatch(filePtr,"MAP_CLASS" ,9)) + { + std::string temp; + if(!ParseString(temp,"*MAP_CLASS")) + SkipToNextToken(); + if (temp != "Bitmap" && temp != "Normal Bump") + { + DefaultLogger::get()->warn("ASE: Skipping unknown map type: " + temp); + parsePath = false; + } + continue; + } + // path to the texture + if (parsePath && TokenMatch(filePtr,"BITMAP" ,6)) + { + if(!ParseString(map.mMapName,"*BITMAP")) + SkipToNextToken(); + + if (map.mMapName == "None") + { + // Files with 'None' as map name are produced by + // an Maja to ASE exporter which name I forgot .. + DefaultLogger::get()->warn("ASE: Skipping invalid map entry"); + map.mMapName = ""; + } + + continue; + } + // offset on the u axis + if (TokenMatch(filePtr,"UVW_U_OFFSET" ,12)) + { + ParseLV4MeshFloat(map.mOffsetU); + continue; + } + // offset on the v axis + if (TokenMatch(filePtr,"UVW_V_OFFSET" ,12)) + { + ParseLV4MeshFloat(map.mOffsetV); + continue; + } + // tiling on the u axis + if (TokenMatch(filePtr,"UVW_U_TILING" ,12)) + { + ParseLV4MeshFloat(map.mScaleU); + continue; + } + // tiling on the v axis + if (TokenMatch(filePtr,"UVW_V_TILING" ,12)) + { + ParseLV4MeshFloat(map.mScaleV); + continue; + } + // rotation around the z-axis + if (TokenMatch(filePtr,"UVW_ANGLE" ,9)) + { + ParseLV4MeshFloat(map.mRotation); + continue; + } + // map blending factor + if (TokenMatch(filePtr,"MAP_AMOUNT" ,10)) + { + ParseLV4MeshFloat(map.mTextureBlend); + continue; + } + } + AI_ASE_HANDLE_SECTION("3","*MAP_XXXXXX"); + } + return; } // ------------------------------------------------------------------------------------------------ bool Parser::ParseString(std::string& out,const char* szName) { - char szBuffer[1024]; - if (!SkipSpaces(&filePtr)) - { - - sprintf(szBuffer,"Unable to parse %s block: Unexpected EOL",szName); - LogWarning(szBuffer); - return false; - } - // there must be '"' - if ('\"' != *filePtr) - { - - sprintf(szBuffer,"Unable to parse %s block: Strings are expected " - "to be enclosed in double quotation marks",szName); - LogWarning(szBuffer); - return false; - } - ++filePtr; - const char* sz = filePtr; - while (true) - { - if ('\"' == *sz)break; - else if ('\0' == *sz) - { - sprintf(szBuffer,"Unable to parse %s block: Strings are expected to " - "be enclosed in double quotation marks but EOF was reached before " - "a closing quotation mark was encountered",szName); - LogWarning(szBuffer); - return false; - } - sz++; - } - out = std::string(filePtr,(uintptr_t)sz-(uintptr_t)filePtr); - filePtr = sz+1; - return true; + char szBuffer[1024]; + if (!SkipSpaces(&filePtr)) + { + + ai_snprintf(szBuffer, 1024, "Unable to parse %s block: Unexpected EOL",szName); + LogWarning(szBuffer); + return false; + } + // there must be '"' + if ('\"' != *filePtr) + { + + ai_snprintf(szBuffer, 1024, "Unable to parse %s block: Strings are expected " + "to be enclosed in double quotation marks",szName); + LogWarning(szBuffer); + return false; + } + ++filePtr; + const char* sz = filePtr; + while (true) + { + if ('\"' == *sz)break; + else if ('\0' == *sz) + { + ai_snprintf(szBuffer, 1024, "Unable to parse %s block: Strings are expected to " + "be enclosed in double quotation marks but EOF was reached before " + "a closing quotation mark was encountered",szName); + LogWarning(szBuffer); + return false; + } + sz++; + } + out = std::string(filePtr,(uintptr_t)sz-(uintptr_t)filePtr); + filePtr = sz+1; + return true; } // ------------------------------------------------------------------------------------------------ void Parser::ParseLV1ObjectBlock(ASE::BaseNode& node) { - AI_ASE_PARSER_INIT(); - while (true) - { - if ('*' == *filePtr) - { - ++filePtr; - - // first process common tokens such as node name and transform - // name of the mesh/node - if (TokenMatch(filePtr,"NODE_NAME" ,9)) - { - if(!ParseString(node.mName,"*NODE_NAME")) - SkipToNextToken(); - continue; - } - // name of the parent of the node - if (TokenMatch(filePtr,"NODE_PARENT" ,11) ) - { - if(!ParseString(node.mParent,"*NODE_PARENT")) - SkipToNextToken(); - continue; - } - // transformation matrix of the node - if (TokenMatch(filePtr,"NODE_TM" ,7)) - { - ParseLV2NodeTransformBlock(node); - continue; - } - // animation data of the node - if (TokenMatch(filePtr,"TM_ANIMATION" ,12)) - { - ParseLV2AnimationBlock(node); - continue; - } - - if (node.mType == BaseNode::Light) - { - // light settings - if (TokenMatch(filePtr,"LIGHT_SETTINGS" ,14)) - { - ParseLV2LightSettingsBlock((ASE::Light&)node); - continue; - } - // type of the light source - if (TokenMatch(filePtr,"LIGHT_TYPE" ,10)) - { - if (!ASSIMP_strincmp("omni",filePtr,4)) - { - ((ASE::Light&)node).mLightType = ASE::Light::OMNI; - } - else if (!ASSIMP_strincmp("target",filePtr,6)) - { - ((ASE::Light&)node).mLightType = ASE::Light::TARGET; - } - else if (!ASSIMP_strincmp("free",filePtr,4)) - { - ((ASE::Light&)node).mLightType = ASE::Light::FREE; - } - else if (!ASSIMP_strincmp("directional",filePtr,11)) - { - ((ASE::Light&)node).mLightType = ASE::Light::DIRECTIONAL; - } - else - { - LogWarning("Unknown kind of light source"); - } - continue; - } - } - else if (node.mType == BaseNode::Camera) - { - // Camera settings - if (TokenMatch(filePtr,"CAMERA_SETTINGS" ,15)) - { - ParseLV2CameraSettingsBlock((ASE::Camera&)node); - continue; - } - else if (TokenMatch(filePtr,"CAMERA_TYPE" ,11)) - { - if (!ASSIMP_strincmp("target",filePtr,6)) - { - ((ASE::Camera&)node).mCameraType = ASE::Camera::TARGET; - } - else if (!ASSIMP_strincmp("free",filePtr,4)) - { - ((ASE::Camera&)node).mCameraType = ASE::Camera::FREE; - } - else - { - LogWarning("Unknown kind of camera"); - } - continue; - } - } - else if (node.mType == BaseNode::Mesh) - { - // mesh data - // FIX: Older files use MESH_SOFTSKIN - if (TokenMatch(filePtr,"MESH" ,4) || - TokenMatch(filePtr,"MESH_SOFTSKIN",13)) - { - ParseLV2MeshBlock((ASE::Mesh&)node); - continue; - } - // mesh material index - if (TokenMatch(filePtr,"MATERIAL_REF" ,12)) - { - ParseLV4MeshLong(((ASE::Mesh&)node).iMaterialIndex); - continue; - } - } - } - AI_ASE_HANDLE_TOP_LEVEL_SECTION(); - } - return; + AI_ASE_PARSER_INIT(); + while (true) + { + if ('*' == *filePtr) + { + ++filePtr; + + // first process common tokens such as node name and transform + // name of the mesh/node + if (TokenMatch(filePtr,"NODE_NAME" ,9)) + { + if(!ParseString(node.mName,"*NODE_NAME")) + SkipToNextToken(); + continue; + } + // name of the parent of the node + if (TokenMatch(filePtr,"NODE_PARENT" ,11) ) + { + if(!ParseString(node.mParent,"*NODE_PARENT")) + SkipToNextToken(); + continue; + } + // transformation matrix of the node + if (TokenMatch(filePtr,"NODE_TM" ,7)) + { + ParseLV2NodeTransformBlock(node); + continue; + } + // animation data of the node + if (TokenMatch(filePtr,"TM_ANIMATION" ,12)) + { + ParseLV2AnimationBlock(node); + continue; + } + + if (node.mType == BaseNode::Light) + { + // light settings + if (TokenMatch(filePtr,"LIGHT_SETTINGS" ,14)) + { + ParseLV2LightSettingsBlock((ASE::Light&)node); + continue; + } + // type of the light source + if (TokenMatch(filePtr,"LIGHT_TYPE" ,10)) + { + if (!ASSIMP_strincmp("omni",filePtr,4)) + { + ((ASE::Light&)node).mLightType = ASE::Light::OMNI; + } + else if (!ASSIMP_strincmp("target",filePtr,6)) + { + ((ASE::Light&)node).mLightType = ASE::Light::TARGET; + } + else if (!ASSIMP_strincmp("free",filePtr,4)) + { + ((ASE::Light&)node).mLightType = ASE::Light::FREE; + } + else if (!ASSIMP_strincmp("directional",filePtr,11)) + { + ((ASE::Light&)node).mLightType = ASE::Light::DIRECTIONAL; + } + else + { + LogWarning("Unknown kind of light source"); + } + continue; + } + } + else if (node.mType == BaseNode::Camera) + { + // Camera settings + if (TokenMatch(filePtr,"CAMERA_SETTINGS" ,15)) + { + ParseLV2CameraSettingsBlock((ASE::Camera&)node); + continue; + } + else if (TokenMatch(filePtr,"CAMERA_TYPE" ,11)) + { + if (!ASSIMP_strincmp("target",filePtr,6)) + { + ((ASE::Camera&)node).mCameraType = ASE::Camera::TARGET; + } + else if (!ASSIMP_strincmp("free",filePtr,4)) + { + ((ASE::Camera&)node).mCameraType = ASE::Camera::FREE; + } + else + { + LogWarning("Unknown kind of camera"); + } + continue; + } + } + else if (node.mType == BaseNode::Mesh) + { + // mesh data + // FIX: Older files use MESH_SOFTSKIN + if (TokenMatch(filePtr,"MESH" ,4) || + TokenMatch(filePtr,"MESH_SOFTSKIN",13)) + { + ParseLV2MeshBlock((ASE::Mesh&)node); + continue; + } + // mesh material index + if (TokenMatch(filePtr,"MATERIAL_REF" ,12)) + { + ParseLV4MeshLong(((ASE::Mesh&)node).iMaterialIndex); + continue; + } + } + } + AI_ASE_HANDLE_TOP_LEVEL_SECTION(); + } + return; } // ------------------------------------------------------------------------------------------------ void Parser::ParseLV2CameraSettingsBlock(ASE::Camera& camera) { - AI_ASE_PARSER_INIT(); - while (true) - { - if ('*' == *filePtr) - { - ++filePtr; - if (TokenMatch(filePtr,"CAMERA_NEAR" ,11)) - { - ParseLV4MeshFloat(camera.mNear); - continue; - } - if (TokenMatch(filePtr,"CAMERA_FAR" ,10)) - { - ParseLV4MeshFloat(camera.mFar); - continue; - } - if (TokenMatch(filePtr,"CAMERA_FOV" ,10)) - { - ParseLV4MeshFloat(camera.mFOV); - continue; - } - } - AI_ASE_HANDLE_SECTION("2","CAMERA_SETTINGS"); - } - return; + AI_ASE_PARSER_INIT(); + while (true) + { + if ('*' == *filePtr) + { + ++filePtr; + if (TokenMatch(filePtr,"CAMERA_NEAR" ,11)) + { + ParseLV4MeshFloat(camera.mNear); + continue; + } + if (TokenMatch(filePtr,"CAMERA_FAR" ,10)) + { + ParseLV4MeshFloat(camera.mFar); + continue; + } + if (TokenMatch(filePtr,"CAMERA_FOV" ,10)) + { + ParseLV4MeshFloat(camera.mFOV); + continue; + } + } + AI_ASE_HANDLE_SECTION("2","CAMERA_SETTINGS"); + } + return; } // ------------------------------------------------------------------------------------------------ void Parser::ParseLV2LightSettingsBlock(ASE::Light& light) { - AI_ASE_PARSER_INIT(); - while (true) - { - if ('*' == *filePtr) - { - ++filePtr; - if (TokenMatch(filePtr,"LIGHT_COLOR" ,11)) - { - ParseLV4MeshFloatTriple(&light.mColor.r); - continue; - } - if (TokenMatch(filePtr,"LIGHT_INTENS" ,12)) - { - ParseLV4MeshFloat(light.mIntensity); - continue; - } - if (TokenMatch(filePtr,"LIGHT_HOTSPOT" ,13)) - { - ParseLV4MeshFloat(light.mAngle); - continue; - } - if (TokenMatch(filePtr,"LIGHT_FALLOFF" ,13)) - { - ParseLV4MeshFloat(light.mFalloff); - continue; - } - } - AI_ASE_HANDLE_SECTION("2","LIGHT_SETTINGS"); - } - return; + AI_ASE_PARSER_INIT(); + while (true) + { + if ('*' == *filePtr) + { + ++filePtr; + if (TokenMatch(filePtr,"LIGHT_COLOR" ,11)) + { + ParseLV4MeshFloatTriple(&light.mColor.r); + continue; + } + if (TokenMatch(filePtr,"LIGHT_INTENS" ,12)) + { + ParseLV4MeshFloat(light.mIntensity); + continue; + } + if (TokenMatch(filePtr,"LIGHT_HOTSPOT" ,13)) + { + ParseLV4MeshFloat(light.mAngle); + continue; + } + if (TokenMatch(filePtr,"LIGHT_FALLOFF" ,13)) + { + ParseLV4MeshFloat(light.mFalloff); + continue; + } + } + AI_ASE_HANDLE_SECTION("2","LIGHT_SETTINGS"); + } + return; } // ------------------------------------------------------------------------------------------------ void Parser::ParseLV2AnimationBlock(ASE::BaseNode& mesh) { - AI_ASE_PARSER_INIT(); - - ASE::Animation* anim = &mesh.mAnim; - while (true) - { - if ('*' == *filePtr) - { - ++filePtr; - if (TokenMatch(filePtr,"NODE_NAME" ,9)) - { - std::string temp; - if(!ParseString(temp,"*NODE_NAME")) - SkipToNextToken(); - - // If the name of the node contains .target it - // represents an animated camera or spot light - // target. - if (std::string::npos != temp.find(".Target")) - { - if ((mesh.mType != BaseNode::Camera || ((ASE::Camera&)mesh).mCameraType != ASE::Camera::TARGET) && - ( mesh.mType != BaseNode::Light || ((ASE::Light&)mesh).mLightType != ASE::Light::TARGET)) - { - - DefaultLogger::get()->error("ASE: Found target animation channel " - "but the node is neither a camera nor a spot light"); - anim = NULL; - } - else anim = &mesh.mTargetAnim; - } - continue; - } - - // position keyframes - if (TokenMatch(filePtr,"CONTROL_POS_TRACK" ,17) || - TokenMatch(filePtr,"CONTROL_POS_BEZIER" ,18) || - TokenMatch(filePtr,"CONTROL_POS_TCB" ,15)) - { - if (!anim)SkipSection(); - else ParseLV3PosAnimationBlock(*anim); - continue; - } - // scaling keyframes - if (TokenMatch(filePtr,"CONTROL_SCALE_TRACK" ,19) || - TokenMatch(filePtr,"CONTROL_SCALE_BEZIER" ,20) || - TokenMatch(filePtr,"CONTROL_SCALE_TCB" ,17)) - { - if (!anim || anim == &mesh.mTargetAnim) - { - // Target animation channels may have no rotation channels - DefaultLogger::get()->error("ASE: Ignoring scaling channel in target animation"); - SkipSection(); - } - else ParseLV3ScaleAnimationBlock(*anim); - continue; - } - // rotation keyframes - if (TokenMatch(filePtr,"CONTROL_ROT_TRACK" ,17) || - TokenMatch(filePtr,"CONTROL_ROT_BEZIER" ,18) || - TokenMatch(filePtr,"CONTROL_ROT_TCB" ,15)) - { - if (!anim || anim == &mesh.mTargetAnim) - { - // Target animation channels may have no rotation channels - DefaultLogger::get()->error("ASE: Ignoring rotation channel in target animation"); - SkipSection(); - } - else ParseLV3RotAnimationBlock(*anim); - continue; - } - } - AI_ASE_HANDLE_SECTION("2","TM_ANIMATION"); - } + AI_ASE_PARSER_INIT(); + + ASE::Animation* anim = &mesh.mAnim; + while (true) + { + if ('*' == *filePtr) + { + ++filePtr; + if (TokenMatch(filePtr,"NODE_NAME" ,9)) + { + std::string temp; + if(!ParseString(temp,"*NODE_NAME")) + SkipToNextToken(); + + // If the name of the node contains .target it + // represents an animated camera or spot light + // target. + if (std::string::npos != temp.find(".Target")) + { + if ((mesh.mType != BaseNode::Camera || ((ASE::Camera&)mesh).mCameraType != ASE::Camera::TARGET) && + ( mesh.mType != BaseNode::Light || ((ASE::Light&)mesh).mLightType != ASE::Light::TARGET)) + { + + DefaultLogger::get()->error("ASE: Found target animation channel " + "but the node is neither a camera nor a spot light"); + anim = NULL; + } + else anim = &mesh.mTargetAnim; + } + continue; + } + + // position keyframes + if (TokenMatch(filePtr,"CONTROL_POS_TRACK" ,17) || + TokenMatch(filePtr,"CONTROL_POS_BEZIER" ,18) || + TokenMatch(filePtr,"CONTROL_POS_TCB" ,15)) + { + if (!anim)SkipSection(); + else ParseLV3PosAnimationBlock(*anim); + continue; + } + // scaling keyframes + if (TokenMatch(filePtr,"CONTROL_SCALE_TRACK" ,19) || + TokenMatch(filePtr,"CONTROL_SCALE_BEZIER" ,20) || + TokenMatch(filePtr,"CONTROL_SCALE_TCB" ,17)) + { + if (!anim || anim == &mesh.mTargetAnim) + { + // Target animation channels may have no rotation channels + DefaultLogger::get()->error("ASE: Ignoring scaling channel in target animation"); + SkipSection(); + } + else ParseLV3ScaleAnimationBlock(*anim); + continue; + } + // rotation keyframes + if (TokenMatch(filePtr,"CONTROL_ROT_TRACK" ,17) || + TokenMatch(filePtr,"CONTROL_ROT_BEZIER" ,18) || + TokenMatch(filePtr,"CONTROL_ROT_TCB" ,15)) + { + if (!anim || anim == &mesh.mTargetAnim) + { + // Target animation channels may have no rotation channels + DefaultLogger::get()->error("ASE: Ignoring rotation channel in target animation"); + SkipSection(); + } + else ParseLV3RotAnimationBlock(*anim); + continue; + } + } + AI_ASE_HANDLE_SECTION("2","TM_ANIMATION"); + } } // ------------------------------------------------------------------------------------------------ void Parser::ParseLV3ScaleAnimationBlock(ASE::Animation& anim) { - AI_ASE_PARSER_INIT(); - unsigned int iIndex; - - while (true) - { - if ('*' == *filePtr) - { - ++filePtr; - - bool b = false; - - // For the moment we're just reading the three floats - - // we ignore the ádditional information for bezier's and TCBs - - // simple scaling keyframe - if (TokenMatch(filePtr,"CONTROL_SCALE_SAMPLE" ,20)) - { - b = true; - anim.mScalingType = ASE::Animation::TRACK; - } - - // Bezier scaling keyframe - if (TokenMatch(filePtr,"CONTROL_BEZIER_SCALE_KEY" ,24)) - { - b = true; - anim.mScalingType = ASE::Animation::BEZIER; - } - // TCB scaling keyframe - if (TokenMatch(filePtr,"CONTROL_TCB_SCALE_KEY" ,21)) - { - b = true; - anim.mScalingType = ASE::Animation::TCB; - } - if (b) - { - anim.akeyScaling.push_back(aiVectorKey()); - aiVectorKey& key = anim.akeyScaling.back(); - ParseLV4MeshFloatTriple(&key.mValue.x,iIndex); - key.mTime = (double)iIndex; - } - } - AI_ASE_HANDLE_SECTION("3","*CONTROL_POS_TRACK"); - } + AI_ASE_PARSER_INIT(); + unsigned int iIndex; + + while (true) + { + if ('*' == *filePtr) + { + ++filePtr; + + bool b = false; + + // For the moment we're just reading the three floats - + // we ignore the �dditional information for bezier's and TCBs + + // simple scaling keyframe + if (TokenMatch(filePtr,"CONTROL_SCALE_SAMPLE" ,20)) + { + b = true; + anim.mScalingType = ASE::Animation::TRACK; + } + + // Bezier scaling keyframe + if (TokenMatch(filePtr,"CONTROL_BEZIER_SCALE_KEY" ,24)) + { + b = true; + anim.mScalingType = ASE::Animation::BEZIER; + } + // TCB scaling keyframe + if (TokenMatch(filePtr,"CONTROL_TCB_SCALE_KEY" ,21)) + { + b = true; + anim.mScalingType = ASE::Animation::TCB; + } + if (b) + { + anim.akeyScaling.push_back(aiVectorKey()); + aiVectorKey& key = anim.akeyScaling.back(); + ParseLV4MeshFloatTriple(&key.mValue.x,iIndex); + key.mTime = (double)iIndex; + } + } + AI_ASE_HANDLE_SECTION("3","*CONTROL_POS_TRACK"); + } } // ------------------------------------------------------------------------------------------------ void Parser::ParseLV3PosAnimationBlock(ASE::Animation& anim) { - AI_ASE_PARSER_INIT(); - unsigned int iIndex; - while (true) - { - if ('*' == *filePtr) - { - ++filePtr; - - bool b = false; - - // For the moment we're just reading the three floats - - // we ignore the ádditional information for bezier's and TCBs - - // simple scaling keyframe - if (TokenMatch(filePtr,"CONTROL_POS_SAMPLE" ,18)) - { - b = true; - anim.mPositionType = ASE::Animation::TRACK; - } - - // Bezier scaling keyframe - if (TokenMatch(filePtr,"CONTROL_BEZIER_POS_KEY" ,22)) - { - b = true; - anim.mPositionType = ASE::Animation::BEZIER; - } - // TCB scaling keyframe - if (TokenMatch(filePtr,"CONTROL_TCB_POS_KEY" ,19)) - { - b = true; - anim.mPositionType = ASE::Animation::TCB; - } - if (b) - { - anim.akeyPositions.push_back(aiVectorKey()); - aiVectorKey& key = anim.akeyPositions.back(); - ParseLV4MeshFloatTriple(&key.mValue.x,iIndex); - key.mTime = (double)iIndex; - } - } - AI_ASE_HANDLE_SECTION("3","*CONTROL_POS_TRACK"); - } + AI_ASE_PARSER_INIT(); + unsigned int iIndex; + while (true) + { + if ('*' == *filePtr) + { + ++filePtr; + + bool b = false; + + // For the moment we're just reading the three floats - + // we ignore the �dditional information for bezier's and TCBs + + // simple scaling keyframe + if (TokenMatch(filePtr,"CONTROL_POS_SAMPLE" ,18)) + { + b = true; + anim.mPositionType = ASE::Animation::TRACK; + } + + // Bezier scaling keyframe + if (TokenMatch(filePtr,"CONTROL_BEZIER_POS_KEY" ,22)) + { + b = true; + anim.mPositionType = ASE::Animation::BEZIER; + } + // TCB scaling keyframe + if (TokenMatch(filePtr,"CONTROL_TCB_POS_KEY" ,19)) + { + b = true; + anim.mPositionType = ASE::Animation::TCB; + } + if (b) + { + anim.akeyPositions.push_back(aiVectorKey()); + aiVectorKey& key = anim.akeyPositions.back(); + ParseLV4MeshFloatTriple(&key.mValue.x,iIndex); + key.mTime = (double)iIndex; + } + } + AI_ASE_HANDLE_SECTION("3","*CONTROL_POS_TRACK"); + } } // ------------------------------------------------------------------------------------------------ void Parser::ParseLV3RotAnimationBlock(ASE::Animation& anim) { - AI_ASE_PARSER_INIT(); - unsigned int iIndex; - while (true) - { - if ('*' == *filePtr) - { - ++filePtr; - - bool b = false; - - // For the moment we're just reading the floats - - // we ignore the ádditional information for bezier's and TCBs - - // simple scaling keyframe - if (TokenMatch(filePtr,"CONTROL_ROT_SAMPLE" ,18)) - { - b = true; - anim.mRotationType = ASE::Animation::TRACK; - } - - // Bezier scaling keyframe - if (TokenMatch(filePtr,"CONTROL_BEZIER_ROT_KEY" ,22)) - { - b = true; - anim.mRotationType = ASE::Animation::BEZIER; - } - // TCB scaling keyframe - if (TokenMatch(filePtr,"CONTROL_TCB_ROT_KEY" ,19)) - { - b = true; - anim.mRotationType = ASE::Animation::TCB; - } - if (b) - { - anim.akeyRotations.push_back(aiQuatKey()); - aiQuatKey& key = anim.akeyRotations.back(); - aiVector3D v;float f; - ParseLV4MeshFloatTriple(&v.x,iIndex); - ParseLV4MeshFloat(f); - key.mTime = (double)iIndex; - key.mValue = aiQuaternion(v,f); - } - } - AI_ASE_HANDLE_SECTION("3","*CONTROL_ROT_TRACK"); - } + AI_ASE_PARSER_INIT(); + unsigned int iIndex; + while (true) + { + if ('*' == *filePtr) + { + ++filePtr; + + bool b = false; + + // For the moment we're just reading the floats - + // we ignore the �dditional information for bezier's and TCBs + + // simple scaling keyframe + if (TokenMatch(filePtr,"CONTROL_ROT_SAMPLE" ,18)) + { + b = true; + anim.mRotationType = ASE::Animation::TRACK; + } + + // Bezier scaling keyframe + if (TokenMatch(filePtr,"CONTROL_BEZIER_ROT_KEY" ,22)) + { + b = true; + anim.mRotationType = ASE::Animation::BEZIER; + } + // TCB scaling keyframe + if (TokenMatch(filePtr,"CONTROL_TCB_ROT_KEY" ,19)) + { + b = true; + anim.mRotationType = ASE::Animation::TCB; + } + if (b) + { + anim.akeyRotations.push_back(aiQuatKey()); + aiQuatKey& key = anim.akeyRotations.back(); + aiVector3D v;float f; + ParseLV4MeshFloatTriple(&v.x,iIndex); + ParseLV4MeshFloat(f); + key.mTime = (double)iIndex; + key.mValue = aiQuaternion(v,f); + } + } + AI_ASE_HANDLE_SECTION("3","*CONTROL_ROT_TRACK"); + } } // ------------------------------------------------------------------------------------------------ void Parser::ParseLV2NodeTransformBlock(ASE::BaseNode& mesh) { - AI_ASE_PARSER_INIT(); - int mode = 0; - while (true) - { - if ('*' == *filePtr) - { - ++filePtr; - // name of the node - if (TokenMatch(filePtr,"NODE_NAME" ,9)) - { - std::string temp; - if(!ParseString(temp,"*NODE_NAME")) - SkipToNextToken(); - - std::string::size_type s; - if (temp == mesh.mName) - { - mode = 1; - } - else if (std::string::npos != (s = temp.find(".Target")) && - mesh.mName == temp.substr(0,s)) - { - // This should be either a target light or a target camera - if ( (mesh.mType == BaseNode::Light && ((ASE::Light&)mesh) .mLightType == ASE::Light::TARGET) || - (mesh.mType == BaseNode::Camera && ((ASE::Camera&)mesh).mCameraType == ASE::Camera::TARGET)) - { - mode = 2; - } - else DefaultLogger::get()->error("ASE: Ignoring target transform, " - "this is no spot light or target camera"); - } - else - { - DefaultLogger::get()->error("ASE: Unknown node transformation: " + temp); - // mode = 0 - } - continue; - } - if (mode) - { - // fourth row of the transformation matrix - and also the - // only information here that is interesting for targets - if (TokenMatch(filePtr,"TM_ROW3" ,7)) - { - ParseLV4MeshFloatTriple((mode == 1 ? mesh.mTransform[3] : &mesh.mTargetPosition.x)); - continue; - } - if (mode == 1) - { - // first row of the transformation matrix - if (TokenMatch(filePtr,"TM_ROW0" ,7)) - { - ParseLV4MeshFloatTriple(mesh.mTransform[0]); - continue; - } - // second row of the transformation matrix - if (TokenMatch(filePtr,"TM_ROW1" ,7)) - { - ParseLV4MeshFloatTriple(mesh.mTransform[1]); - continue; - } - // third row of the transformation matrix - if (TokenMatch(filePtr,"TM_ROW2" ,7)) - { - ParseLV4MeshFloatTriple(mesh.mTransform[2]); - continue; - } - // inherited position axes - if (TokenMatch(filePtr,"INHERIT_POS" ,11)) - { - unsigned int aiVal[3]; - ParseLV4MeshLongTriple(aiVal); - - for (unsigned int i = 0; i < 3;++i) - mesh.inherit.abInheritPosition[i] = aiVal[i] != 0; - continue; - } - // inherited rotation axes - if (TokenMatch(filePtr,"INHERIT_ROT" ,11)) - { - unsigned int aiVal[3]; - ParseLV4MeshLongTriple(aiVal); - - for (unsigned int i = 0; i < 3;++i) - mesh.inherit.abInheritRotation[i] = aiVal[i] != 0; - continue; - } - // inherited scaling axes - if (TokenMatch(filePtr,"INHERIT_SCL" ,11)) - { - unsigned int aiVal[3]; - ParseLV4MeshLongTriple(aiVal); - - for (unsigned int i = 0; i < 3;++i) - mesh.inherit.abInheritScaling[i] = aiVal[i] != 0; - continue; - } - } - } - } - AI_ASE_HANDLE_SECTION("2","*NODE_TM"); - } - return; + AI_ASE_PARSER_INIT(); + int mode = 0; + while (true) + { + if ('*' == *filePtr) + { + ++filePtr; + // name of the node + if (TokenMatch(filePtr,"NODE_NAME" ,9)) + { + std::string temp; + if(!ParseString(temp,"*NODE_NAME")) + SkipToNextToken(); + + std::string::size_type s; + if (temp == mesh.mName) + { + mode = 1; + } + else if (std::string::npos != (s = temp.find(".Target")) && + mesh.mName == temp.substr(0,s)) + { + // This should be either a target light or a target camera + if ( (mesh.mType == BaseNode::Light && ((ASE::Light&)mesh) .mLightType == ASE::Light::TARGET) || + (mesh.mType == BaseNode::Camera && ((ASE::Camera&)mesh).mCameraType == ASE::Camera::TARGET)) + { + mode = 2; + } + else DefaultLogger::get()->error("ASE: Ignoring target transform, " + "this is no spot light or target camera"); + } + else + { + DefaultLogger::get()->error("ASE: Unknown node transformation: " + temp); + // mode = 0 + } + continue; + } + if (mode) + { + // fourth row of the transformation matrix - and also the + // only information here that is interesting for targets + if (TokenMatch(filePtr,"TM_ROW3" ,7)) + { + ParseLV4MeshFloatTriple((mode == 1 ? mesh.mTransform[3] : &mesh.mTargetPosition.x)); + continue; + } + if (mode == 1) + { + // first row of the transformation matrix + if (TokenMatch(filePtr,"TM_ROW0" ,7)) + { + ParseLV4MeshFloatTriple(mesh.mTransform[0]); + continue; + } + // second row of the transformation matrix + if (TokenMatch(filePtr,"TM_ROW1" ,7)) + { + ParseLV4MeshFloatTriple(mesh.mTransform[1]); + continue; + } + // third row of the transformation matrix + if (TokenMatch(filePtr,"TM_ROW2" ,7)) + { + ParseLV4MeshFloatTriple(mesh.mTransform[2]); + continue; + } + // inherited position axes + if (TokenMatch(filePtr,"INHERIT_POS" ,11)) + { + unsigned int aiVal[3]; + ParseLV4MeshLongTriple(aiVal); + + for (unsigned int i = 0; i < 3;++i) + mesh.inherit.abInheritPosition[i] = aiVal[i] != 0; + continue; + } + // inherited rotation axes + if (TokenMatch(filePtr,"INHERIT_ROT" ,11)) + { + unsigned int aiVal[3]; + ParseLV4MeshLongTriple(aiVal); + + for (unsigned int i = 0; i < 3;++i) + mesh.inherit.abInheritRotation[i] = aiVal[i] != 0; + continue; + } + // inherited scaling axes + if (TokenMatch(filePtr,"INHERIT_SCL" ,11)) + { + unsigned int aiVal[3]; + ParseLV4MeshLongTriple(aiVal); + + for (unsigned int i = 0; i < 3;++i) + mesh.inherit.abInheritScaling[i] = aiVal[i] != 0; + continue; + } + } + } + } + AI_ASE_HANDLE_SECTION("2","*NODE_TM"); + } + return; } // ------------------------------------------------------------------------------------------------ void Parser::ParseLV2MeshBlock(ASE::Mesh& mesh) { - AI_ASE_PARSER_INIT(); - - unsigned int iNumVertices = 0; - unsigned int iNumFaces = 0; - unsigned int iNumTVertices = 0; - unsigned int iNumTFaces = 0; - unsigned int iNumCVertices = 0; - unsigned int iNumCFaces = 0; - while (true) - { - if ('*' == *filePtr) - { - ++filePtr; - // Number of vertices in the mesh - if (TokenMatch(filePtr,"MESH_NUMVERTEX" ,14)) - { - ParseLV4MeshLong(iNumVertices); - continue; - } - // Number of texture coordinates in the mesh - if (TokenMatch(filePtr,"MESH_NUMTVERTEX" ,15)) - { - ParseLV4MeshLong(iNumTVertices); - continue; - } - // Number of vertex colors in the mesh - if (TokenMatch(filePtr,"MESH_NUMCVERTEX" ,15)) - { - ParseLV4MeshLong(iNumCVertices); - continue; - } - // Number of regular faces in the mesh - if (TokenMatch(filePtr,"MESH_NUMFACES" ,13)) - { - ParseLV4MeshLong(iNumFaces); - continue; - } - // Number of UVWed faces in the mesh - if (TokenMatch(filePtr,"MESH_NUMTVFACES" ,15)) - { - ParseLV4MeshLong(iNumTFaces); - continue; - } - // Number of colored faces in the mesh - if (TokenMatch(filePtr,"MESH_NUMCVFACES" ,15)) - { - ParseLV4MeshLong(iNumCFaces); - continue; - } - // mesh vertex list block - if (TokenMatch(filePtr,"MESH_VERTEX_LIST" ,16)) - { - ParseLV3MeshVertexListBlock(iNumVertices,mesh); - continue; - } - // mesh face list block - if (TokenMatch(filePtr,"MESH_FACE_LIST" ,14)) - { - ParseLV3MeshFaceListBlock(iNumFaces,mesh); - continue; - } - // mesh texture vertex list block - if (TokenMatch(filePtr,"MESH_TVERTLIST" ,14)) - { - ParseLV3MeshTListBlock(iNumTVertices,mesh); - continue; - } - // mesh texture face block - if (TokenMatch(filePtr,"MESH_TFACELIST" ,14)) - { - ParseLV3MeshTFaceListBlock(iNumTFaces,mesh); - continue; - } - // mesh color vertex list block - if (TokenMatch(filePtr,"MESH_CVERTLIST" ,14)) - { - ParseLV3MeshCListBlock(iNumCVertices,mesh); - continue; - } - // mesh color face block - if (TokenMatch(filePtr,"MESH_CFACELIST" ,14)) - { - ParseLV3MeshCFaceListBlock(iNumCFaces,mesh); - continue; - } - // mesh normals - if (TokenMatch(filePtr,"MESH_NORMALS" ,12)) - { - ParseLV3MeshNormalListBlock(mesh); - continue; - } - // another mesh UV channel ... - if (TokenMatch(filePtr,"MESH_MAPPINGCHANNEL" ,19)) - { - - unsigned int iIndex = 0; - ParseLV4MeshLong(iIndex); - - if (iIndex < 2) - { - LogWarning("Mapping channel has an invalid index. Skipping UV channel"); - // skip it ... - SkipSection(); - } - if (iIndex > AI_MAX_NUMBER_OF_TEXTURECOORDS) - { - LogWarning("Too many UV channels specified. Skipping channel .."); - // skip it ... - SkipSection(); - } - else - { - // parse the mapping channel - ParseLV3MappingChannel(iIndex-1,mesh); - } - continue; - } - // mesh animation keyframe. Not supported - if (TokenMatch(filePtr,"MESH_ANIMATION" ,14)) - { - - LogWarning("Found *MESH_ANIMATION element in ASE/ASK file. " - "Keyframe animation is not supported by Assimp, this element " - "will be ignored"); - //SkipSection(); - continue; - } - if (TokenMatch(filePtr,"MESH_WEIGHTS" ,12)) - { - ParseLV3MeshWeightsBlock(mesh);continue; - } - } - AI_ASE_HANDLE_SECTION("2","*MESH"); - } - return; + AI_ASE_PARSER_INIT(); + + unsigned int iNumVertices = 0; + unsigned int iNumFaces = 0; + unsigned int iNumTVertices = 0; + unsigned int iNumTFaces = 0; + unsigned int iNumCVertices = 0; + unsigned int iNumCFaces = 0; + while (true) + { + if ('*' == *filePtr) + { + ++filePtr; + // Number of vertices in the mesh + if (TokenMatch(filePtr,"MESH_NUMVERTEX" ,14)) + { + ParseLV4MeshLong(iNumVertices); + continue; + } + // Number of texture coordinates in the mesh + if (TokenMatch(filePtr,"MESH_NUMTVERTEX" ,15)) + { + ParseLV4MeshLong(iNumTVertices); + continue; + } + // Number of vertex colors in the mesh + if (TokenMatch(filePtr,"MESH_NUMCVERTEX" ,15)) + { + ParseLV4MeshLong(iNumCVertices); + continue; + } + // Number of regular faces in the mesh + if (TokenMatch(filePtr,"MESH_NUMFACES" ,13)) + { + ParseLV4MeshLong(iNumFaces); + continue; + } + // Number of UVWed faces in the mesh + if (TokenMatch(filePtr,"MESH_NUMTVFACES" ,15)) + { + ParseLV4MeshLong(iNumTFaces); + continue; + } + // Number of colored faces in the mesh + if (TokenMatch(filePtr,"MESH_NUMCVFACES" ,15)) + { + ParseLV4MeshLong(iNumCFaces); + continue; + } + // mesh vertex list block + if (TokenMatch(filePtr,"MESH_VERTEX_LIST" ,16)) + { + ParseLV3MeshVertexListBlock(iNumVertices,mesh); + continue; + } + // mesh face list block + if (TokenMatch(filePtr,"MESH_FACE_LIST" ,14)) + { + ParseLV3MeshFaceListBlock(iNumFaces,mesh); + continue; + } + // mesh texture vertex list block + if (TokenMatch(filePtr,"MESH_TVERTLIST" ,14)) + { + ParseLV3MeshTListBlock(iNumTVertices,mesh); + continue; + } + // mesh texture face block + if (TokenMatch(filePtr,"MESH_TFACELIST" ,14)) + { + ParseLV3MeshTFaceListBlock(iNumTFaces,mesh); + continue; + } + // mesh color vertex list block + if (TokenMatch(filePtr,"MESH_CVERTLIST" ,14)) + { + ParseLV3MeshCListBlock(iNumCVertices,mesh); + continue; + } + // mesh color face block + if (TokenMatch(filePtr,"MESH_CFACELIST" ,14)) + { + ParseLV3MeshCFaceListBlock(iNumCFaces,mesh); + continue; + } + // mesh normals + if (TokenMatch(filePtr,"MESH_NORMALS" ,12)) + { + ParseLV3MeshNormalListBlock(mesh); + continue; + } + // another mesh UV channel ... + if (TokenMatch(filePtr,"MESH_MAPPINGCHANNEL" ,19)) + { + + unsigned int iIndex = 0; + ParseLV4MeshLong(iIndex); + + if (iIndex < 2) + { + LogWarning("Mapping channel has an invalid index. Skipping UV channel"); + // skip it ... + SkipSection(); + } + if (iIndex > AI_MAX_NUMBER_OF_TEXTURECOORDS) + { + LogWarning("Too many UV channels specified. Skipping channel .."); + // skip it ... + SkipSection(); + } + else + { + // parse the mapping channel + ParseLV3MappingChannel(iIndex-1,mesh); + } + continue; + } + // mesh animation keyframe. Not supported + if (TokenMatch(filePtr,"MESH_ANIMATION" ,14)) + { + + LogWarning("Found *MESH_ANIMATION element in ASE/ASK file. " + "Keyframe animation is not supported by Assimp, this element " + "will be ignored"); + //SkipSection(); + continue; + } + if (TokenMatch(filePtr,"MESH_WEIGHTS" ,12)) + { + ParseLV3MeshWeightsBlock(mesh);continue; + } + } + AI_ASE_HANDLE_SECTION("2","*MESH"); + } + return; } // ------------------------------------------------------------------------------------------------ void Parser::ParseLV3MeshWeightsBlock(ASE::Mesh& mesh) { - AI_ASE_PARSER_INIT(); - - unsigned int iNumVertices = 0, iNumBones = 0; - while (true) - { - if ('*' == *filePtr) - { - ++filePtr; - - // Number of bone vertices ... - if (TokenMatch(filePtr,"MESH_NUMVERTEX" ,14)) - { - ParseLV4MeshLong(iNumVertices); - continue; - } - // Number of bones - if (TokenMatch(filePtr,"MESH_NUMBONE" ,11)) - { - ParseLV4MeshLong(iNumBones); - continue; - } - // parse the list of bones - if (TokenMatch(filePtr,"MESH_BONE_LIST" ,14)) - { - ParseLV4MeshBones(iNumBones,mesh); - continue; - } - // parse the list of bones vertices - if (TokenMatch(filePtr,"MESH_BONE_VERTEX_LIST" ,21) ) - { - ParseLV4MeshBonesVertices(iNumVertices,mesh); - continue; - } - } - AI_ASE_HANDLE_SECTION("3","*MESH_WEIGHTS"); - } - return; + AI_ASE_PARSER_INIT(); + + unsigned int iNumVertices = 0, iNumBones = 0; + while (true) + { + if ('*' == *filePtr) + { + ++filePtr; + + // Number of bone vertices ... + if (TokenMatch(filePtr,"MESH_NUMVERTEX" ,14)) + { + ParseLV4MeshLong(iNumVertices); + continue; + } + // Number of bones + if (TokenMatch(filePtr,"MESH_NUMBONE" ,12)) + { + ParseLV4MeshLong(iNumBones); + continue; + } + // parse the list of bones + if (TokenMatch(filePtr,"MESH_BONE_LIST" ,14)) + { + ParseLV4MeshBones(iNumBones,mesh); + continue; + } + // parse the list of bones vertices + if (TokenMatch(filePtr,"MESH_BONE_VERTEX_LIST" ,21) ) + { + ParseLV4MeshBonesVertices(iNumVertices,mesh); + continue; + } + } + AI_ASE_HANDLE_SECTION("3","*MESH_WEIGHTS"); + } + return; } // ------------------------------------------------------------------------------------------------ void Parser::ParseLV4MeshBones(unsigned int iNumBones,ASE::Mesh& mesh) { - AI_ASE_PARSER_INIT(); - mesh.mBones.resize(iNumBones); - while (true) - { - if ('*' == *filePtr) - { - ++filePtr; - - // Mesh bone with name ... - if (TokenMatch(filePtr,"MESH_BONE_NAME" ,16)) - { - // parse an index ... - if(SkipSpaces(&filePtr)) - { - unsigned int iIndex = strtoul10(filePtr,&filePtr); - if (iIndex >= iNumBones) - { - LogWarning("Bone index is out of bounds"); - continue; - } - if (!ParseString(mesh.mBones[iIndex].mName,"*MESH_BONE_NAME")) - SkipToNextToken(); - continue; - } - } - } - AI_ASE_HANDLE_SECTION("3","*MESH_BONE_LIST"); - } + AI_ASE_PARSER_INIT(); + mesh.mBones.resize(iNumBones); + while (true) + { + if ('*' == *filePtr) + { + ++filePtr; + + // Mesh bone with name ... + if (TokenMatch(filePtr,"MESH_BONE_NAME" ,14)) + { + // parse an index ... + if(SkipSpaces(&filePtr)) + { + unsigned int iIndex = strtoul10(filePtr,&filePtr); + if (iIndex >= iNumBones) + { + LogWarning("Bone index is out of bounds"); + continue; + } + if (!ParseString(mesh.mBones[iIndex].mName,"*MESH_BONE_NAME")) + SkipToNextToken(); + continue; + } + } + } + AI_ASE_HANDLE_SECTION("3","*MESH_BONE_LIST"); + } } // ------------------------------------------------------------------------------------------------ void Parser::ParseLV4MeshBonesVertices(unsigned int iNumVertices,ASE::Mesh& mesh) { - AI_ASE_PARSER_INIT(); - mesh.mBoneVertices.resize(iNumVertices); - while (true) - { - if ('*' == *filePtr) - { - ++filePtr; - - // Mesh bone vertex - if (TokenMatch(filePtr,"MESH_BONE_VERTEX" ,16)) - { - // read the vertex index - unsigned int iIndex = strtoul10(filePtr,&filePtr); - if (iIndex >= mesh.mPositions.size()) - { - iIndex = (unsigned int)mesh.mPositions.size()-1; - LogWarning("Bone vertex index is out of bounds. Using the largest valid " - "bone vertex index instead"); - } - - // --- ignored - float afVert[3]; - ParseLV4MeshFloatTriple(afVert); - - std::pair pairOut; - while (true) - { - // first parse the bone index ... - if (!SkipSpaces(&filePtr))break; - pairOut.first = strtoul10(filePtr,&filePtr); - - // then parse the vertex weight - if (!SkipSpaces(&filePtr))break; - filePtr = fast_atoreal_move(filePtr,pairOut.second); - - // -1 marks unused entries - if (-1 != pairOut.first) - { - mesh.mBoneVertices[iIndex].mBoneWeights.push_back(pairOut); - } - } - continue; - } - } - AI_ASE_HANDLE_SECTION("4","*MESH_BONE_VERTEX"); - } - return; + AI_ASE_PARSER_INIT(); + mesh.mBoneVertices.resize(iNumVertices); + while (true) + { + if ('*' == *filePtr) + { + ++filePtr; + + // Mesh bone vertex + if (TokenMatch(filePtr,"MESH_BONE_VERTEX" ,16)) + { + // read the vertex index + unsigned int iIndex = strtoul10(filePtr,&filePtr); + if (iIndex >= mesh.mPositions.size()) + { + iIndex = (unsigned int)mesh.mPositions.size()-1; + LogWarning("Bone vertex index is out of bounds. Using the largest valid " + "bone vertex index instead"); + } + + // --- ignored + float afVert[3]; + ParseLV4MeshFloatTriple(afVert); + + std::pair pairOut; + while (true) + { + // first parse the bone index ... + if (!SkipSpaces(&filePtr))break; + pairOut.first = strtoul10(filePtr,&filePtr); + + // then parse the vertex weight + if (!SkipSpaces(&filePtr))break; + filePtr = fast_atoreal_move(filePtr,pairOut.second); + + // -1 marks unused entries + if (-1 != pairOut.first) + { + mesh.mBoneVertices[iIndex].mBoneWeights.push_back(pairOut); + } + } + continue; + } + } + AI_ASE_HANDLE_SECTION("4","*MESH_BONE_VERTEX"); + } + return; } // ------------------------------------------------------------------------------------------------ void Parser::ParseLV3MeshVertexListBlock( - unsigned int iNumVertices, ASE::Mesh& mesh) + unsigned int iNumVertices, ASE::Mesh& mesh) { - AI_ASE_PARSER_INIT(); - - // allocate enough storage in the array - mesh.mPositions.resize(iNumVertices); - while (true) - { - if ('*' == *filePtr) - { - ++filePtr; - - // Vertex entry - if (TokenMatch(filePtr,"MESH_VERTEX" ,11)) - { - - aiVector3D vTemp; - unsigned int iIndex; - ParseLV4MeshFloatTriple(&vTemp.x,iIndex); - - if (iIndex >= iNumVertices) - { - LogWarning("Invalid vertex index. It will be ignored"); - } - else mesh.mPositions[iIndex] = vTemp; - continue; - } - } - AI_ASE_HANDLE_SECTION("3","*MESH_VERTEX_LIST"); - } - return; + AI_ASE_PARSER_INIT(); + + // allocate enough storage in the array + mesh.mPositions.resize(iNumVertices); + while (true) + { + if ('*' == *filePtr) + { + ++filePtr; + + // Vertex entry + if (TokenMatch(filePtr,"MESH_VERTEX" ,11)) + { + + aiVector3D vTemp; + unsigned int iIndex; + ParseLV4MeshFloatTriple(&vTemp.x,iIndex); + + if (iIndex >= iNumVertices) + { + LogWarning("Invalid vertex index. It will be ignored"); + } + else mesh.mPositions[iIndex] = vTemp; + continue; + } + } + AI_ASE_HANDLE_SECTION("3","*MESH_VERTEX_LIST"); + } + return; } // ------------------------------------------------------------------------------------------------ void Parser::ParseLV3MeshFaceListBlock(unsigned int iNumFaces, ASE::Mesh& mesh) { - AI_ASE_PARSER_INIT(); - - // allocate enough storage in the face array - mesh.mFaces.resize(iNumFaces); - while (true) - { - if ('*' == *filePtr) - { - ++filePtr; - - // Face entry - if (TokenMatch(filePtr,"MESH_FACE" ,9)) - { - - ASE::Face mFace; - ParseLV4MeshFace(mFace); - - if (mFace.iFace >= iNumFaces) - { - LogWarning("Face has an invalid index. It will be ignored"); - } - else mesh.mFaces[mFace.iFace] = mFace; - continue; - } - } - AI_ASE_HANDLE_SECTION("3","*MESH_FACE_LIST"); - } - return; + AI_ASE_PARSER_INIT(); + + // allocate enough storage in the face array + mesh.mFaces.resize(iNumFaces); + while (true) + { + if ('*' == *filePtr) + { + ++filePtr; + + // Face entry + if (TokenMatch(filePtr,"MESH_FACE" ,9)) + { + + ASE::Face mFace; + ParseLV4MeshFace(mFace); + + if (mFace.iFace >= iNumFaces) + { + LogWarning("Face has an invalid index. It will be ignored"); + } + else mesh.mFaces[mFace.iFace] = mFace; + continue; + } + } + AI_ASE_HANDLE_SECTION("3","*MESH_FACE_LIST"); + } + return; } // ------------------------------------------------------------------------------------------------ void Parser::ParseLV3MeshTListBlock(unsigned int iNumVertices, - ASE::Mesh& mesh, unsigned int iChannel) + ASE::Mesh& mesh, unsigned int iChannel) { - AI_ASE_PARSER_INIT(); - - // allocate enough storage in the array - mesh.amTexCoords[iChannel].resize(iNumVertices); - while (true) - { - if ('*' == *filePtr) - { - ++filePtr; - - // Vertex entry - if (TokenMatch(filePtr,"MESH_TVERT" ,10)) - { - aiVector3D vTemp; - unsigned int iIndex; - ParseLV4MeshFloatTriple(&vTemp.x,iIndex); - - if (iIndex >= iNumVertices) - { - LogWarning("Tvertex has an invalid index. It will be ignored"); - } - else mesh.amTexCoords[iChannel][iIndex] = vTemp; - - if (0.0f != vTemp.z) - { - // we need 3 coordinate channels - mesh.mNumUVComponents[iChannel] = 3; - } - continue; - } - } - AI_ASE_HANDLE_SECTION("3","*MESH_TVERT_LIST"); - } - return; + AI_ASE_PARSER_INIT(); + + // allocate enough storage in the array + mesh.amTexCoords[iChannel].resize(iNumVertices); + while (true) + { + if ('*' == *filePtr) + { + ++filePtr; + + // Vertex entry + if (TokenMatch(filePtr,"MESH_TVERT" ,10)) + { + aiVector3D vTemp; + unsigned int iIndex; + ParseLV4MeshFloatTriple(&vTemp.x,iIndex); + + if (iIndex >= iNumVertices) + { + LogWarning("Tvertex has an invalid index. It will be ignored"); + } + else mesh.amTexCoords[iChannel][iIndex] = vTemp; + + if (0.0f != vTemp.z) + { + // we need 3 coordinate channels + mesh.mNumUVComponents[iChannel] = 3; + } + continue; + } + } + AI_ASE_HANDLE_SECTION("3","*MESH_TVERT_LIST"); + } + return; } // ------------------------------------------------------------------------------------------------ void Parser::ParseLV3MeshTFaceListBlock(unsigned int iNumFaces, - ASE::Mesh& mesh, unsigned int iChannel) + ASE::Mesh& mesh, unsigned int iChannel) { - AI_ASE_PARSER_INIT(); - while (true) - { - if ('*' == *filePtr) - { - ++filePtr; - - // Face entry - if (TokenMatch(filePtr,"MESH_TFACE" ,10)) - { - unsigned int aiValues[3]; - unsigned int iIndex = 0; - - ParseLV4MeshLongTriple(aiValues,iIndex); - if (iIndex >= iNumFaces || iIndex >= mesh.mFaces.size()) - { - LogWarning("UV-Face has an invalid index. It will be ignored"); - } - else - { - // copy UV indices - mesh.mFaces[iIndex].amUVIndices[iChannel][0] = aiValues[0]; - mesh.mFaces[iIndex].amUVIndices[iChannel][1] = aiValues[1]; - mesh.mFaces[iIndex].amUVIndices[iChannel][2] = aiValues[2]; - } - continue; - } - } - AI_ASE_HANDLE_SECTION("3","*MESH_TFACE_LIST"); - } - return; + AI_ASE_PARSER_INIT(); + while (true) + { + if ('*' == *filePtr) + { + ++filePtr; + + // Face entry + if (TokenMatch(filePtr,"MESH_TFACE" ,10)) + { + unsigned int aiValues[3]; + unsigned int iIndex = 0; + + ParseLV4MeshLongTriple(aiValues,iIndex); + if (iIndex >= iNumFaces || iIndex >= mesh.mFaces.size()) + { + LogWarning("UV-Face has an invalid index. It will be ignored"); + } + else + { + // copy UV indices + mesh.mFaces[iIndex].amUVIndices[iChannel][0] = aiValues[0]; + mesh.mFaces[iIndex].amUVIndices[iChannel][1] = aiValues[1]; + mesh.mFaces[iIndex].amUVIndices[iChannel][2] = aiValues[2]; + } + continue; + } + } + AI_ASE_HANDLE_SECTION("3","*MESH_TFACE_LIST"); + } + return; } // ------------------------------------------------------------------------------------------------ void Parser::ParseLV3MappingChannel(unsigned int iChannel, ASE::Mesh& mesh) { - AI_ASE_PARSER_INIT(); - - unsigned int iNumTVertices = 0; - unsigned int iNumTFaces = 0; - while (true) - { - if ('*' == *filePtr) - { - ++filePtr; - - // Number of texture coordinates in the mesh - if (TokenMatch(filePtr,"MESH_NUMTVERTEX" ,15)) - { - ParseLV4MeshLong(iNumTVertices); - continue; - } - // Number of UVWed faces in the mesh - if (TokenMatch(filePtr,"MESH_NUMTVFACES" ,15)) - { - ParseLV4MeshLong(iNumTFaces); - continue; - } - // mesh texture vertex list block - if (TokenMatch(filePtr,"MESH_TVERTLIST" ,14)) - { - ParseLV3MeshTListBlock(iNumTVertices,mesh,iChannel); - continue; - } - // mesh texture face block - if (TokenMatch(filePtr,"MESH_TFACELIST" ,14)) - { - ParseLV3MeshTFaceListBlock(iNumTFaces,mesh, iChannel); - continue; - } - } - AI_ASE_HANDLE_SECTION("3","*MESH_MAPPING_CHANNEL"); - } - return; + AI_ASE_PARSER_INIT(); + + unsigned int iNumTVertices = 0; + unsigned int iNumTFaces = 0; + while (true) + { + if ('*' == *filePtr) + { + ++filePtr; + + // Number of texture coordinates in the mesh + if (TokenMatch(filePtr,"MESH_NUMTVERTEX" ,15)) + { + ParseLV4MeshLong(iNumTVertices); + continue; + } + // Number of UVWed faces in the mesh + if (TokenMatch(filePtr,"MESH_NUMTVFACES" ,15)) + { + ParseLV4MeshLong(iNumTFaces); + continue; + } + // mesh texture vertex list block + if (TokenMatch(filePtr,"MESH_TVERTLIST" ,14)) + { + ParseLV3MeshTListBlock(iNumTVertices,mesh,iChannel); + continue; + } + // mesh texture face block + if (TokenMatch(filePtr,"MESH_TFACELIST" ,14)) + { + ParseLV3MeshTFaceListBlock(iNumTFaces,mesh, iChannel); + continue; + } + } + AI_ASE_HANDLE_SECTION("3","*MESH_MAPPING_CHANNEL"); + } + return; } // ------------------------------------------------------------------------------------------------ void Parser::ParseLV3MeshCListBlock(unsigned int iNumVertices, ASE::Mesh& mesh) { - AI_ASE_PARSER_INIT(); - - // allocate enough storage in the array - mesh.mVertexColors.resize(iNumVertices); - while (true) - { - if ('*' == *filePtr) - { - ++filePtr; - - // Vertex entry - if (TokenMatch(filePtr,"MESH_VERTCOL" ,12)) - { - aiColor4D vTemp; - vTemp.a = 1.0f; - unsigned int iIndex; - ParseLV4MeshFloatTriple(&vTemp.r,iIndex); - - if (iIndex >= iNumVertices) - { - LogWarning("Vertex color has an invalid index. It will be ignored"); - } - else mesh.mVertexColors[iIndex] = vTemp; - continue; - } - } - AI_ASE_HANDLE_SECTION("3","*MESH_CVERTEX_LIST"); - } - return; + AI_ASE_PARSER_INIT(); + + // allocate enough storage in the array + mesh.mVertexColors.resize(iNumVertices); + while (true) + { + if ('*' == *filePtr) + { + ++filePtr; + + // Vertex entry + if (TokenMatch(filePtr,"MESH_VERTCOL" ,12)) + { + aiColor4D vTemp; + vTemp.a = 1.0f; + unsigned int iIndex; + ParseLV4MeshFloatTriple(&vTemp.r,iIndex); + + if (iIndex >= iNumVertices) + { + LogWarning("Vertex color has an invalid index. It will be ignored"); + } + else mesh.mVertexColors[iIndex] = vTemp; + continue; + } + } + AI_ASE_HANDLE_SECTION("3","*MESH_CVERTEX_LIST"); + } + return; } // ------------------------------------------------------------------------------------------------ void Parser::ParseLV3MeshCFaceListBlock(unsigned int iNumFaces, ASE::Mesh& mesh) { - AI_ASE_PARSER_INIT(); - while (true) - { - if ('*' == *filePtr) - { - ++filePtr; - - // Face entry - if (TokenMatch(filePtr,"MESH_CFACE" ,11)) - { - unsigned int aiValues[3]; - unsigned int iIndex = 0; - - ParseLV4MeshLongTriple(aiValues,iIndex); - if (iIndex >= iNumFaces || iIndex >= mesh.mFaces.size()) - { - LogWarning("UV-Face has an invalid index. It will be ignored"); - } - else - { - // copy color indices - mesh.mFaces[iIndex].mColorIndices[0] = aiValues[0]; - mesh.mFaces[iIndex].mColorIndices[1] = aiValues[1]; - mesh.mFaces[iIndex].mColorIndices[2] = aiValues[2]; - } - continue; - } - } - AI_ASE_HANDLE_SECTION("3","*MESH_CFACE_LIST"); - } - return; + AI_ASE_PARSER_INIT(); + while (true) + { + if ('*' == *filePtr) + { + ++filePtr; + + // Face entry + if (TokenMatch(filePtr,"MESH_CFACE" ,11)) + { + unsigned int aiValues[3]; + unsigned int iIndex = 0; + + ParseLV4MeshLongTriple(aiValues,iIndex); + if (iIndex >= iNumFaces || iIndex >= mesh.mFaces.size()) + { + LogWarning("UV-Face has an invalid index. It will be ignored"); + } + else + { + // copy color indices + mesh.mFaces[iIndex].mColorIndices[0] = aiValues[0]; + mesh.mFaces[iIndex].mColorIndices[1] = aiValues[1]; + mesh.mFaces[iIndex].mColorIndices[2] = aiValues[2]; + } + continue; + } + } + AI_ASE_HANDLE_SECTION("3","*MESH_CFACE_LIST"); + } + return; } // ------------------------------------------------------------------------------------------------ void Parser::ParseLV3MeshNormalListBlock(ASE::Mesh& sMesh) { - AI_ASE_PARSER_INIT(); - - // Allocate enough storage for the normals - sMesh.mNormals.resize(sMesh.mFaces.size()*3,aiVector3D( 0.f, 0.f, 0.f )); - unsigned int index, faceIdx = UINT_MAX; - - // FIXME: rewrite this and find out how to interpret the normals - // correctly. This is crap. - - // Smooth the vertex and face normals together. The result - // will be edgy then, but otherwise everything would be soft ... - while (true) { - if ('*' == *filePtr) { - ++filePtr; - if (faceIdx != UINT_MAX && TokenMatch(filePtr,"MESH_VERTEXNORMAL",17)) { - aiVector3D vNormal; - ParseLV4MeshFloatTriple(&vNormal.x,index); - if (faceIdx >= sMesh.mFaces.size()) - continue; - - // Make sure we assign it to the correct face - const ASE::Face& face = sMesh.mFaces[faceIdx]; - if (index == face.mIndices[0]) - index = 0; - else if (index == face.mIndices[1]) - index = 1; - else if (index == face.mIndices[2]) - index = 2; - else { - DefaultLogger::get()->error("ASE: Invalid vertex index in MESH_VERTEXNORMAL section"); - continue; - } - // We'll renormalize later - sMesh.mNormals[faceIdx*3+index] += vNormal; - continue; - } - if (TokenMatch(filePtr,"MESH_FACENORMAL",15)) { - aiVector3D vNormal; - ParseLV4MeshFloatTriple(&vNormal.x,faceIdx); - - if (faceIdx >= sMesh.mFaces.size()) { - DefaultLogger::get()->error("ASE: Invalid vertex index in MESH_FACENORMAL section"); - continue; - } - - // We'll renormalize later - sMesh.mNormals[faceIdx*3] += vNormal; - sMesh.mNormals[faceIdx*3+1] += vNormal; - sMesh.mNormals[faceIdx*3+2] += vNormal; - continue; - } - } - AI_ASE_HANDLE_SECTION("3","*MESH_NORMALS"); - } - return; + AI_ASE_PARSER_INIT(); + + // Allocate enough storage for the normals + sMesh.mNormals.resize(sMesh.mFaces.size()*3,aiVector3D( 0.f, 0.f, 0.f )); + unsigned int index, faceIdx = UINT_MAX; + + // FIXME: rewrite this and find out how to interpret the normals + // correctly. This is crap. + + // Smooth the vertex and face normals together. The result + // will be edgy then, but otherwise everything would be soft ... + while (true) { + if ('*' == *filePtr) { + ++filePtr; + if (faceIdx != UINT_MAX && TokenMatch(filePtr,"MESH_VERTEXNORMAL",17)) { + aiVector3D vNormal; + ParseLV4MeshFloatTriple(&vNormal.x,index); + if (faceIdx >= sMesh.mFaces.size()) + continue; + + // Make sure we assign it to the correct face + const ASE::Face& face = sMesh.mFaces[faceIdx]; + if (index == face.mIndices[0]) + index = 0; + else if (index == face.mIndices[1]) + index = 1; + else if (index == face.mIndices[2]) + index = 2; + else { + DefaultLogger::get()->error("ASE: Invalid vertex index in MESH_VERTEXNORMAL section"); + continue; + } + // We'll renormalize later + sMesh.mNormals[faceIdx*3+index] += vNormal; + continue; + } + if (TokenMatch(filePtr,"MESH_FACENORMAL",15)) { + aiVector3D vNormal; + ParseLV4MeshFloatTriple(&vNormal.x,faceIdx); + + if (faceIdx >= sMesh.mFaces.size()) { + DefaultLogger::get()->error("ASE: Invalid vertex index in MESH_FACENORMAL section"); + continue; + } + + // We'll renormalize later + sMesh.mNormals[faceIdx*3] += vNormal; + sMesh.mNormals[faceIdx*3+1] += vNormal; + sMesh.mNormals[faceIdx*3+2] += vNormal; + continue; + } + } + AI_ASE_HANDLE_SECTION("3","*MESH_NORMALS"); + } + return; } // ------------------------------------------------------------------------------------------------ void Parser::ParseLV4MeshFace(ASE::Face& out) -{ - // skip spaces and tabs - if(!SkipSpaces(&filePtr)) - { - LogWarning("Unable to parse *MESH_FACE Element: Unexpected EOL [#1]"); - SkipToNextToken(); - return; - } - - // parse the face index - out.iFace = strtoul10(filePtr,&filePtr); - - // next character should be ':' - if(!SkipSpaces(&filePtr)) - { - // FIX: there are some ASE files which haven't got : here .... - LogWarning("Unable to parse *MESH_FACE Element: Unexpected EOL. \':\' expected [#2]"); - SkipToNextToken(); - return; - } - // FIX: There are some ASE files which haven't got ':' here - if(':' == *filePtr)++filePtr; - - // Parse all mesh indices - for (unsigned int i = 0; i < 3;++i) - { - unsigned int iIndex = 0; - if(!SkipSpaces(&filePtr)) - { - LogWarning("Unable to parse *MESH_FACE Element: Unexpected EOL"); - SkipToNextToken(); - return; - } - switch (*filePtr) - { - case 'A': - case 'a': - break; - case 'B': - case 'b': - iIndex = 1; - break; - case 'C': - case 'c': - iIndex = 2; - break; - default: - LogWarning("Unable to parse *MESH_FACE Element: Unexpected EOL. " - "A,B or C expected [#3]"); - SkipToNextToken(); - return; - }; - ++filePtr; - - // next character should be ':' - if(!SkipSpaces(&filePtr) || ':' != *filePtr) - { - LogWarning("Unable to parse *MESH_FACE Element: " - "Unexpected EOL. \':\' expected [#2]"); - SkipToNextToken(); - return; - } - - ++filePtr; - if(!SkipSpaces(&filePtr)) - { - LogWarning("Unable to parse *MESH_FACE Element: Unexpected EOL. " - "Vertex index ecpected [#4]"); - SkipToNextToken(); - return; - } - out.mIndices[iIndex] = strtoul10(filePtr,&filePtr); - } - - // now we need to skip the AB, BC, CA blocks. - while (true) - { - if ('*' == *filePtr)break; - if (IsLineEnd(*filePtr)) - { - //iLineNumber++; - return; - } - filePtr++; - } - - // parse the smoothing group of the face - if (TokenMatch(filePtr,"*MESH_SMOOTHING",15)) - { - if(!SkipSpaces(&filePtr)) - { - LogWarning("Unable to parse *MESH_SMOOTHING Element: " - "Unexpected EOL. Smoothing group(s) expected [#5]"); - SkipToNextToken(); - return; - } - - // Parse smoothing groups until we don't anymore see commas - // FIX: There needn't always be a value, sad but true - while (true) - { - if (*filePtr < '9' && *filePtr >= '0') - { - out.iSmoothGroup |= (1 << strtoul10(filePtr,&filePtr)); - } - SkipSpaces(&filePtr); - if (',' != *filePtr) - { - break; - } - ++filePtr; - SkipSpaces(&filePtr); - } - } - - // *MESH_MTLID is optional, too - while (true) - { - if ('*' == *filePtr)break; - if (IsLineEnd(*filePtr)) - { - return; - } - filePtr++; - } - - if (TokenMatch(filePtr,"*MESH_MTLID",11)) - { - if(!SkipSpaces(&filePtr)) - { - LogWarning("Unable to parse *MESH_MTLID Element: Unexpected EOL. " - "Material index expected [#6]"); - SkipToNextToken(); - return; - } - out.iMaterial = strtoul10(filePtr,&filePtr); - } - return; +{ + // skip spaces and tabs + if(!SkipSpaces(&filePtr)) + { + LogWarning("Unable to parse *MESH_FACE Element: Unexpected EOL [#1]"); + SkipToNextToken(); + return; + } + + // parse the face index + out.iFace = strtoul10(filePtr,&filePtr); + + // next character should be ':' + if(!SkipSpaces(&filePtr)) + { + // FIX: there are some ASE files which haven't got : here .... + LogWarning("Unable to parse *MESH_FACE Element: Unexpected EOL. \':\' expected [#2]"); + SkipToNextToken(); + return; + } + // FIX: There are some ASE files which haven't got ':' here + if(':' == *filePtr)++filePtr; + + // Parse all mesh indices + for (unsigned int i = 0; i < 3;++i) + { + unsigned int iIndex = 0; + if(!SkipSpaces(&filePtr)) + { + LogWarning("Unable to parse *MESH_FACE Element: Unexpected EOL"); + SkipToNextToken(); + return; + } + switch (*filePtr) + { + case 'A': + case 'a': + break; + case 'B': + case 'b': + iIndex = 1; + break; + case 'C': + case 'c': + iIndex = 2; + break; + default: + LogWarning("Unable to parse *MESH_FACE Element: Unexpected EOL. " + "A,B or C expected [#3]"); + SkipToNextToken(); + return; + }; + ++filePtr; + + // next character should be ':' + if(!SkipSpaces(&filePtr) || ':' != *filePtr) + { + LogWarning("Unable to parse *MESH_FACE Element: " + "Unexpected EOL. \':\' expected [#2]"); + SkipToNextToken(); + return; + } + + ++filePtr; + if(!SkipSpaces(&filePtr)) + { + LogWarning("Unable to parse *MESH_FACE Element: Unexpected EOL. " + "Vertex index ecpected [#4]"); + SkipToNextToken(); + return; + } + out.mIndices[iIndex] = strtoul10(filePtr,&filePtr); + } + + // now we need to skip the AB, BC, CA blocks. + while (true) + { + if ('*' == *filePtr)break; + if (IsLineEnd(*filePtr)) + { + //iLineNumber++; + return; + } + filePtr++; + } + + // parse the smoothing group of the face + if (TokenMatch(filePtr,"*MESH_SMOOTHING",15)) + { + if(!SkipSpaces(&filePtr)) + { + LogWarning("Unable to parse *MESH_SMOOTHING Element: " + "Unexpected EOL. Smoothing group(s) expected [#5]"); + SkipToNextToken(); + return; + } + + // Parse smoothing groups until we don't anymore see commas + // FIX: There needn't always be a value, sad but true + while (true) + { + if (*filePtr < '9' && *filePtr >= '0') + { + out.iSmoothGroup |= (1 << strtoul10(filePtr,&filePtr)); + } + SkipSpaces(&filePtr); + if (',' != *filePtr) + { + break; + } + ++filePtr; + SkipSpaces(&filePtr); + } + } + + // *MESH_MTLID is optional, too + while (true) + { + if ('*' == *filePtr)break; + if (IsLineEnd(*filePtr)) + { + return; + } + filePtr++; + } + + if (TokenMatch(filePtr,"*MESH_MTLID",11)) + { + if(!SkipSpaces(&filePtr)) + { + LogWarning("Unable to parse *MESH_MTLID Element: Unexpected EOL. " + "Material index expected [#6]"); + SkipToNextToken(); + return; + } + out.iMaterial = strtoul10(filePtr,&filePtr); + } + return; } // ------------------------------------------------------------------------------------------------ void Parser::ParseLV4MeshLongTriple(unsigned int* apOut) { - ai_assert(NULL != apOut); + ai_assert(NULL != apOut); - for (unsigned int i = 0; i < 3;++i) - ParseLV4MeshLong(apOut[i]); + for (unsigned int i = 0; i < 3;++i) + ParseLV4MeshLong(apOut[i]); } // ------------------------------------------------------------------------------------------------ void Parser::ParseLV4MeshLongTriple(unsigned int* apOut, unsigned int& rIndexOut) { - ai_assert(NULL != apOut); + ai_assert(NULL != apOut); - // parse the index - ParseLV4MeshLong(rIndexOut); + // parse the index + ParseLV4MeshLong(rIndexOut); - // parse the three others - ParseLV4MeshLongTriple(apOut); + // parse the three others + ParseLV4MeshLongTriple(apOut); } // ------------------------------------------------------------------------------------------------ void Parser::ParseLV4MeshFloatTriple(float* apOut, unsigned int& rIndexOut) { - ai_assert(NULL != apOut); + ai_assert(NULL != apOut); + + // parse the index + ParseLV4MeshLong(rIndexOut); - // parse the index - ParseLV4MeshLong(rIndexOut); - - // parse the three others - ParseLV4MeshFloatTriple(apOut); + // parse the three others + ParseLV4MeshFloatTriple(apOut); } // ------------------------------------------------------------------------------------------------ void Parser::ParseLV4MeshFloatTriple(float* apOut) { - ai_assert(NULL != apOut); + ai_assert(NULL != apOut); - for (unsigned int i = 0; i < 3;++i) - ParseLV4MeshFloat(apOut[i]); + for (unsigned int i = 0; i < 3;++i) + ParseLV4MeshFloat(apOut[i]); } // ------------------------------------------------------------------------------------------------ void Parser::ParseLV4MeshFloat(float& fOut) { - // skip spaces and tabs - if(!SkipSpaces(&filePtr)) - { - // LOG - LogWarning("Unable to parse float: unexpected EOL [#1]"); - fOut = 0.0f; - ++iLineNumber; - return; - } - // parse the first float - filePtr = fast_atoreal_move(filePtr,fOut); + // skip spaces and tabs + if(!SkipSpaces(&filePtr)) + { + // LOG + LogWarning("Unable to parse float: unexpected EOL [#1]"); + fOut = 0.0f; + ++iLineNumber; + return; + } + // parse the first float + filePtr = fast_atoreal_move(filePtr,fOut); } // ------------------------------------------------------------------------------------------------ void Parser::ParseLV4MeshLong(unsigned int& iOut) { - // Skip spaces and tabs - if(!SkipSpaces(&filePtr)) - { - // LOG - LogWarning("Unable to parse long: unexpected EOL [#1]"); - iOut = 0; - ++iLineNumber; - return; - } - // parse the value - iOut = strtoul10(filePtr,&filePtr); + // Skip spaces and tabs + if(!SkipSpaces(&filePtr)) + { + // LOG + LogWarning("Unable to parse long: unexpected EOL [#1]"); + iOut = 0; + ++iLineNumber; + return; + } + // parse the value + iOut = strtoul10(filePtr,&filePtr); } #endif // !! ASSIMP_BUILD_NO_BASE_IMPORTER diff --git a/src/3rdparty/assimp/code/ASEParser.h b/src/3rdparty/assimp/code/ASEParser.h index dec53a52c..667c7c5a0 100644 --- a/src/3rdparty/assimp/code/ASEParser.h +++ b/src/3rdparty/assimp/code/ASEParser.h @@ -2,11 +2,11 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2012, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above @@ -23,16 +23,16 @@ following conditions are met: derived from this software without specific prior written permission of the assimp team. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- @@ -43,15 +43,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_ASEFILEHELPER_H_INC #define AI_ASEFILEHELPER_H_INC -// STL/CRT headers -#include -#include -#include - // public ASSIMP headers -#include "../include/assimp/types.h" -#include "../include/assimp/mesh.h" -#include "../include/assimp/anim.h" +#include +#include +#include // for some helper routines like IsSpace() #include "ParsingUtils.h" @@ -60,8 +55,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // ASE is quite similar to 3ds. We can reuse some structures #include "3DSLoader.h" -namespace Assimp { -namespace ASE { +namespace Assimp { +namespace ASE { using namespace D3DS; @@ -69,121 +64,121 @@ using namespace D3DS; /** Helper structure representing an ASE material */ struct Material : public D3DS::Material { - //! Default constructor - Material() : pcInstance(NULL), bNeed (false) - {} + //! Default constructor + Material() : pcInstance(NULL), bNeed (false) + {} - //! Contains all sub materials of this material - std::vector avSubMaterials; + //! Contains all sub materials of this material + std::vector avSubMaterials; - //! aiMaterial object - aiMaterial* pcInstance; + //! aiMaterial object + aiMaterial* pcInstance; - //! Can we remove this material? - bool bNeed; + //! Can we remove this material? + bool bNeed; }; // --------------------------------------------------------------------------- /** Helper structure to represent an ASE file face */ struct Face : public FaceWithSmoothingGroup { - //! Default constructor. Initializes everything with 0 - Face() - { - mColorIndices[0] = mColorIndices[1] = mColorIndices[2] = 0; - for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS;++i) - { - amUVIndices[i][0] = amUVIndices[i][1] = amUVIndices[i][2] = 0; - } + //! Default constructor. Initializes everything with 0 + Face() + { + mColorIndices[0] = mColorIndices[1] = mColorIndices[2] = 0; + for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS;++i) + { + amUVIndices[i][0] = amUVIndices[i][1] = amUVIndices[i][2] = 0; + } - iMaterial = DEFAULT_MATINDEX; - iFace = 0; - } + iMaterial = DEFAULT_MATINDEX; + iFace = 0; + } - //! special value to indicate that no material index has - //! been assigned to a face. The default material index - //! will replace this value later. - static const unsigned int DEFAULT_MATINDEX = 0xFFFFFFFF; + //! special value to indicate that no material index has + //! been assigned to a face. The default material index + //! will replace this value later. + static const unsigned int DEFAULT_MATINDEX = 0xFFFFFFFF; - //! Indices into each list of texture coordinates - unsigned int amUVIndices[AI_MAX_NUMBER_OF_TEXTURECOORDS][3]; + //! Indices into each list of texture coordinates + unsigned int amUVIndices[AI_MAX_NUMBER_OF_TEXTURECOORDS][3]; - //! Index into the list of vertex colors - unsigned int mColorIndices[3]; + //! Index into the list of vertex colors + unsigned int mColorIndices[3]; - //! (Sub)Material index to be assigned to this face - unsigned int iMaterial; + //! (Sub)Material index to be assigned to this face + unsigned int iMaterial; - //! Index of the face. It is not specified whether it is - //! a requirement of the file format that all faces are - //! written in sequential order, so we have to expect this case - unsigned int iFace; + //! Index of the face. It is not specified whether it is + //! a requirement of the file format that all faces are + //! written in sequential order, so we have to expect this case + unsigned int iFace; }; // --------------------------------------------------------------------------- /** Helper structure to represent an ASE file bone */ struct Bone { - //! Constructor - Bone() - { - static int iCnt = 0; - - // Generate a default name for the bone - char szTemp[128]; - ::sprintf(szTemp,"UNNAMED_%i",iCnt++); - mName = szTemp; - } - - //! Construction from an existing name - Bone( const std::string& name) - : mName (name) - {} - - //! Name of the bone - std::string mName; + //! Constructor + Bone() + { + static int iCnt = 0; + + // Generate a default name for the bone + char szTemp[128]; + ::ai_snprintf(szTemp, 128, "UNNAMED_%i",iCnt++); + mName = szTemp; + } + + //! Construction from an existing name + explicit Bone( const std::string& name) + : mName (name) + {} + + //! Name of the bone + std::string mName; }; // --------------------------------------------------------------------------- /** Helper structure to represent an ASE file bone vertex */ struct BoneVertex { - //! Bone and corresponding vertex weight. - //! -1 for unrequired bones .... - std::vector > mBoneWeights; + //! Bone and corresponding vertex weight. + //! -1 for unrequired bones .... + std::vector > mBoneWeights; - //! Position of the bone vertex. - //! MUST be identical to the vertex position - //aiVector3D mPosition; + //! Position of the bone vertex. + //! MUST be identical to the vertex position + //aiVector3D mPosition; }; // --------------------------------------------------------------------------- /** Helper structure to represent an ASE file animation */ struct Animation { - enum Type - { - TRACK = 0x0, - BEZIER = 0x1, - TCB = 0x2 - } mRotationType, mScalingType, mPositionType; + enum Type + { + TRACK = 0x0, + BEZIER = 0x1, + TCB = 0x2 + } mRotationType, mScalingType, mPositionType; - Animation() - : mRotationType (TRACK) - , mScalingType (TRACK) - , mPositionType (TRACK) - {} + Animation() + : mRotationType (TRACK) + , mScalingType (TRACK) + , mPositionType (TRACK) + {} - //! List of track rotation keyframes - std::vector< aiQuatKey > akeyRotations; + //! List of track rotation keyframes + std::vector< aiQuatKey > akeyRotations; - //! List of track position keyframes - std::vector< aiVectorKey > akeyPositions; + //! List of track position keyframes + std::vector< aiVectorKey > akeyPositions; - //! List of track scaling keyframes - std::vector< aiVectorKey > akeyScaling; + //! List of track scaling keyframes + std::vector< aiVectorKey > akeyScaling; }; @@ -191,175 +186,175 @@ struct Animation /** Helper structure to represent the inheritance information of an ASE node */ struct InheritanceInfo { - //! Default constructor - InheritanceInfo() - { - // set the inheritance flag for all axes by default to true - for (unsigned int i = 0; i < 3;++i) - abInheritPosition[i] = abInheritRotation[i] = abInheritScaling[i] = true; - } - - //! Inherit the parent's position?, axis order is x,y,z - bool abInheritPosition[3]; - - //! Inherit the parent's rotation?, axis order is x,y,z - bool abInheritRotation[3]; - - //! Inherit the parent's scaling?, axis order is x,y,z - bool abInheritScaling[3]; + //! Default constructor + InheritanceInfo() + { + // set the inheritance flag for all axes by default to true + for (unsigned int i = 0; i < 3;++i) + abInheritPosition[i] = abInheritRotation[i] = abInheritScaling[i] = true; + } + + //! Inherit the parent's position?, axis order is x,y,z + bool abInheritPosition[3]; + + //! Inherit the parent's rotation?, axis order is x,y,z + bool abInheritRotation[3]; + + //! Inherit the parent's scaling?, axis order is x,y,z + bool abInheritScaling[3]; }; // --------------------------------------------------------------------------- /** Represents an ASE file node. Base class for mesh, light and cameras */ struct BaseNode { - enum Type {Light, Camera, Mesh, Dummy} mType; + enum Type {Light, Camera, Mesh, Dummy} mType; - //! Constructor. Creates a default name for the node - BaseNode(Type _mType) - : mType (_mType) - , mProcessed (false) - { - // generate a default name for the node - static int iCnt = 0; - char szTemp[128]; // should be sufficiently large - ::sprintf(szTemp,"UNNAMED_%i",iCnt++); - mName = szTemp; + //! Constructor. Creates a default name for the node + explicit BaseNode(Type _mType) + : mType (_mType) + , mProcessed (false) + { + // generate a default name for the node + static int iCnt = 0; + char szTemp[128]; // should be sufficiently large + ::ai_snprintf(szTemp, 128, "UNNAMED_%i",iCnt++); + mName = szTemp; - // Set mTargetPosition to qnan - const float qnan = get_qnan(); - mTargetPosition.x = qnan; - } + // Set mTargetPosition to qnan + const float qnan = get_qnan(); + mTargetPosition.x = qnan; + } - //! Name of the mesh - std::string mName; + //! Name of the mesh + std::string mName; - //! Name of the parent of the node - //! "" if there is no parent ... - std::string mParent; + //! Name of the parent of the node + //! "" if there is no parent ... + std::string mParent; - //! Transformation matrix of the node - aiMatrix4x4 mTransform; + //! Transformation matrix of the node + aiMatrix4x4 mTransform; - //! Target position (target lights and cameras) - aiVector3D mTargetPosition; + //! Target position (target lights and cameras) + aiVector3D mTargetPosition; - //! Specifies which axes transformations a node inherits - //! from its parent ... - InheritanceInfo inherit; + //! Specifies which axes transformations a node inherits + //! from its parent ... + InheritanceInfo inherit; - //! Animation channels for the node - Animation mAnim; + //! Animation channels for the node + Animation mAnim; - //! Needed for lights and cameras: target animation channel - //! Should contain position keys only. - Animation mTargetAnim; + //! Needed for lights and cameras: target animation channel + //! Should contain position keys only. + Animation mTargetAnim; - bool mProcessed; + bool mProcessed; }; // --------------------------------------------------------------------------- /** Helper structure to represent an ASE file mesh */ struct Mesh : public MeshWithSmoothingGroups, public BaseNode { - //! Constructor. - Mesh() - : BaseNode (BaseNode::Mesh) - , bSkip (false) - { - // use 2 texture vertex components by default - for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c) - this->mNumUVComponents[c] = 2; + //! Constructor. + Mesh() + : BaseNode (BaseNode::Mesh) + , bSkip (false) + { + // use 2 texture vertex components by default + for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c) + this->mNumUVComponents[c] = 2; - // setup the default material index by default - iMaterialIndex = Face::DEFAULT_MATINDEX; - } + // setup the default material index by default + iMaterialIndex = Face::DEFAULT_MATINDEX; + } - //! List of all texture coordinate sets - std::vector amTexCoords[AI_MAX_NUMBER_OF_TEXTURECOORDS]; + //! List of all texture coordinate sets + std::vector amTexCoords[AI_MAX_NUMBER_OF_TEXTURECOORDS]; - //! List of all vertex color sets. - std::vector mVertexColors; + //! List of all vertex color sets. + std::vector mVertexColors; - //! List of all bone vertices - std::vector mBoneVertices; + //! List of all bone vertices + std::vector mBoneVertices; - //! List of all bones - std::vector mBones; + //! List of all bones + std::vector mBones; - //! Material index of the mesh - unsigned int iMaterialIndex; + //! Material index of the mesh + unsigned int iMaterialIndex; - //! Number of vertex components for each UVW set - unsigned int mNumUVComponents[AI_MAX_NUMBER_OF_TEXTURECOORDS]; + //! Number of vertex components for each UVW set + unsigned int mNumUVComponents[AI_MAX_NUMBER_OF_TEXTURECOORDS]; - //! used internally - bool bSkip; + //! used internally + bool bSkip; }; // --------------------------------------------------------------------------- /** Helper structure to represent an ASE light source */ struct Light : public BaseNode { - enum LightType - { - OMNI, - TARGET, - FREE, - DIRECTIONAL - }; - - //! Constructor. - Light() - : BaseNode (BaseNode::Light) - , mLightType (OMNI) - , mColor (1.f,1.f,1.f) - , mIntensity (1.f) // light is white by default - , mAngle (45.f) - , mFalloff (0.f) - { - } - - LightType mLightType; - aiColor3D mColor; - float mIntensity; - float mAngle; // in degrees - float mFalloff; + enum LightType + { + OMNI, + TARGET, + FREE, + DIRECTIONAL + }; + + //! Constructor. + Light() + : BaseNode (BaseNode::Light) + , mLightType (OMNI) + , mColor (1.f,1.f,1.f) + , mIntensity (1.f) // light is white by default + , mAngle (45.f) + , mFalloff (0.f) + { + } + + LightType mLightType; + aiColor3D mColor; + float mIntensity; + float mAngle; // in degrees + float mFalloff; }; // --------------------------------------------------------------------------- /** Helper structure to represent an ASE camera */ struct Camera : public BaseNode { - enum CameraType - { - FREE, - TARGET - }; - - //! Constructor - Camera() - : BaseNode (BaseNode::Camera) - , mFOV (0.75f) // in radians - , mNear (0.1f) - , mFar (1000.f) // could be zero - , mCameraType (FREE) - { - } - - float mFOV, mNear, mFar; - CameraType mCameraType; + enum CameraType + { + FREE, + TARGET + }; + + //! Constructor + Camera() + : BaseNode (BaseNode::Camera) + , mFOV (0.75f) // in radians + , mNear (0.1f) + , mFar (1000.f) // could be zero + , mCameraType (FREE) + { + } + + float mFOV, mNear, mFar; + CameraType mCameraType; }; // --------------------------------------------------------------------------- /** Helper structure to represent an ASE helper object (dummy) */ struct Dummy : public BaseNode { - //! Constructor - Dummy() - : BaseNode (BaseNode::Dummy) - { - } + //! Constructor + Dummy() + : BaseNode (BaseNode::Dummy) + { + } }; // Parameters to Parser::Parse() @@ -367,8 +362,8 @@ struct Dummy : public BaseNode #define AI_ASE_OLD_FILE_FORMAT 110 // Internally we're a little bit more tolerant -#define AI_ASE_IS_NEW_FILE_FORMAT() (iFileFormat >= 200) -#define AI_ASE_IS_OLD_FILE_FORMAT() (iFileFormat < 200) +#define AI_ASE_IS_NEW_FILE_FORMAT() (iFileFormat >= 200) +#define AI_ASE_IS_OLD_FILE_FORMAT() (iFileFormat < 200) // ------------------------------------------------------------------------------- /** \brief Class to parse ASE files @@ -378,288 +373,288 @@ class Parser private: - Parser() {} + Parser() {} public: - // ------------------------------------------------------------------- - //! Construct a parser from a given input file which is - //! guaranted to be terminated with zero. - //! @param szFile Input file - //! @param fileFormatDefault Assumed file format version. If the - //! file format is specified in the file the new value replaces - //! the default value. - Parser (const char* szFile, unsigned int fileFormatDefault); + // ------------------------------------------------------------------- + //! Construct a parser from a given input file which is + //! guaranted to be terminated with zero. + //! @param szFile Input file + //! @param fileFormatDefault Assumed file format version. If the + //! file format is specified in the file the new value replaces + //! the default value. + Parser (const char* szFile, unsigned int fileFormatDefault); - // ------------------------------------------------------------------- - //! Parses the file into the parsers internal representation - void Parse(); + // ------------------------------------------------------------------- + //! Parses the file into the parsers internal representation + void Parse(); private: - // ------------------------------------------------------------------- - //! Parse the *SCENE block in a file - void ParseLV1SceneBlock(); - - // ------------------------------------------------------------------- - //! Parse the *MESH_SOFTSKINVERTS block in a file - void ParseLV1SoftSkinBlock(); - - // ------------------------------------------------------------------- - //! Parse the *MATERIAL_LIST block in a file - void ParseLV1MaterialListBlock(); - - // ------------------------------------------------------------------- - //! Parse a *OBJECT block in a file - //! \param mesh Node to be filled - void ParseLV1ObjectBlock(BaseNode& mesh); - - // ------------------------------------------------------------------- - //! Parse a *MATERIAL blocks in a material list - //! \param mat Material structure to be filled - void ParseLV2MaterialBlock(Material& mat); - - // ------------------------------------------------------------------- - //! Parse a *NODE_TM block in a file - //! \param mesh Node (!) object to be filled - void ParseLV2NodeTransformBlock(BaseNode& mesh); - - // ------------------------------------------------------------------- - //! Parse a *TM_ANIMATION block in a file - //! \param mesh Mesh object to be filled - void ParseLV2AnimationBlock(BaseNode& mesh); - void ParseLV3PosAnimationBlock(ASE::Animation& anim); - void ParseLV3ScaleAnimationBlock(ASE::Animation& anim); - void ParseLV3RotAnimationBlock(ASE::Animation& anim); - - // ------------------------------------------------------------------- - //! Parse a *MESH block in a file - //! \param mesh Mesh object to be filled - void ParseLV2MeshBlock(Mesh& mesh); - - // ------------------------------------------------------------------- - //! Parse a *LIGHT_SETTINGS block in a file - //! \param light Light object to be filled - void ParseLV2LightSettingsBlock(Light& light); - - // ------------------------------------------------------------------- - //! Parse a *CAMERA_SETTINGS block in a file - //! \param cam Camera object to be filled - void ParseLV2CameraSettingsBlock(Camera& cam); - - // ------------------------------------------------------------------- - //! Parse the *MAP_XXXXXX blocks in a material - //! \param map Texture structure to be filled - void ParseLV3MapBlock(Texture& map); - - // ------------------------------------------------------------------- - //! Parse a *MESH_VERTEX_LIST block in a file - //! \param iNumVertices Value of *MESH_NUMVERTEX, if present. - //! Otherwise zero. This is used to check the consistency of the file. - //! A warning is sent to the logger if the validations fails. - //! \param mesh Mesh object to be filled - void ParseLV3MeshVertexListBlock( - unsigned int iNumVertices,Mesh& mesh); - - // ------------------------------------------------------------------- - //! Parse a *MESH_FACE_LIST block in a file - //! \param iNumFaces Value of *MESH_NUMFACES, if present. - //! Otherwise zero. This is used to check the consistency of the file. - //! A warning is sent to the logger if the validations fails. - //! \param mesh Mesh object to be filled - void ParseLV3MeshFaceListBlock( - unsigned int iNumFaces,Mesh& mesh); - - // ------------------------------------------------------------------- - //! Parse a *MESH_TVERT_LIST block in a file - //! \param iNumVertices Value of *MESH_NUMTVERTEX, if present. - //! Otherwise zero. This is used to check the consistency of the file. - //! A warning is sent to the logger if the validations fails. - //! \param mesh Mesh object to be filled - //! \param iChannel Output UVW channel - void ParseLV3MeshTListBlock( - unsigned int iNumVertices,Mesh& mesh, unsigned int iChannel = 0); - - // ------------------------------------------------------------------- - //! Parse a *MESH_TFACELIST block in a file - //! \param iNumFaces Value of *MESH_NUMTVFACES, if present. - //! Otherwise zero. This is used to check the consistency of the file. - //! A warning is sent to the logger if the validations fails. - //! \param mesh Mesh object to be filled - //! \param iChannel Output UVW channel - void ParseLV3MeshTFaceListBlock( - unsigned int iNumFaces,Mesh& mesh, unsigned int iChannel = 0); - - // ------------------------------------------------------------------- - //! Parse an additional mapping channel - //! (specified via *MESH_MAPPINGCHANNEL) - //! \param iChannel Channel index to be filled - //! \param mesh Mesh object to be filled - void ParseLV3MappingChannel( - unsigned int iChannel, Mesh& mesh); - - // ------------------------------------------------------------------- - //! Parse a *MESH_CVERTLIST block in a file - //! \param iNumVertices Value of *MESH_NUMCVERTEX, if present. - //! Otherwise zero. This is used to check the consistency of the file. - //! A warning is sent to the logger if the validations fails. - //! \param mesh Mesh object to be filled - void ParseLV3MeshCListBlock( - unsigned int iNumVertices, Mesh& mesh); - - // ------------------------------------------------------------------- - //! Parse a *MESH_CFACELIST block in a file - //! \param iNumFaces Value of *MESH_NUMCVFACES, if present. - //! Otherwise zero. This is used to check the consistency of the file. - //! A warning is sent to the logger if the validations fails. - //! \param mesh Mesh object to be filled - void ParseLV3MeshCFaceListBlock( - unsigned int iNumFaces, Mesh& mesh); - - // ------------------------------------------------------------------- - //! Parse a *MESH_NORMALS block in a file - //! \param mesh Mesh object to be filled - void ParseLV3MeshNormalListBlock(Mesh& mesh); - - // ------------------------------------------------------------------- - //! Parse a *MESH_WEIGHTSblock in a file - //! \param mesh Mesh object to be filled - void ParseLV3MeshWeightsBlock(Mesh& mesh); - - // ------------------------------------------------------------------- - //! Parse the bone list of a file - //! \param mesh Mesh object to be filled - //! \param iNumBones Number of bones in the mesh - void ParseLV4MeshBones(unsigned int iNumBones,Mesh& mesh); - - // ------------------------------------------------------------------- - //! Parse the bone vertices list of a file - //! \param mesh Mesh object to be filled - //! \param iNumVertices Number of vertices to be parsed - void ParseLV4MeshBonesVertices(unsigned int iNumVertices,Mesh& mesh); - - // ------------------------------------------------------------------- - //! Parse a *MESH_FACE block in a file - //! \param out receive the face data - void ParseLV4MeshFace(ASE::Face& out); - - // ------------------------------------------------------------------- - //! Parse a *MESH_VERT block in a file - //! (also works for MESH_TVERT, MESH_CFACE, MESH_VERTCOL ...) - //! \param apOut Output buffer (3 floats) - //! \param rIndexOut Output index - void ParseLV4MeshFloatTriple(float* apOut, unsigned int& rIndexOut); - - // ------------------------------------------------------------------- - //! Parse a *MESH_VERT block in a file - //! (also works for MESH_TVERT, MESH_CFACE, MESH_VERTCOL ...) - //! \param apOut Output buffer (3 floats) - void ParseLV4MeshFloatTriple(float* apOut); - - // ------------------------------------------------------------------- - //! Parse a *MESH_TFACE block in a file - //! (also works for MESH_CFACE) - //! \param apOut Output buffer (3 ints) - //! \param rIndexOut Output index - void ParseLV4MeshLongTriple(unsigned int* apOut, unsigned int& rIndexOut); - - // ------------------------------------------------------------------- - //! Parse a *MESH_TFACE block in a file - //! (also works for MESH_CFACE) - //! \param apOut Output buffer (3 ints) - void ParseLV4MeshLongTriple(unsigned int* apOut); - - // ------------------------------------------------------------------- - //! Parse a single float element - //! \param fOut Output float - void ParseLV4MeshFloat(float& fOut); - - // ------------------------------------------------------------------- - //! Parse a single int element - //! \param iOut Output integer - void ParseLV4MeshLong(unsigned int& iOut); - - // ------------------------------------------------------------------- - //! Skip everything to the next: '*' or '\0' - bool SkipToNextToken(); - - // ------------------------------------------------------------------- - //! Skip the current section until the token after the closing }. - //! This function handles embedded subsections correctly - bool SkipSection(); - - // ------------------------------------------------------------------- - //! Output a warning to the logger - //! \param szWarn Warn message - void LogWarning(const char* szWarn); - - // ------------------------------------------------------------------- - //! Output a message to the logger - //! \param szWarn Message - void LogInfo(const char* szWarn); - - // ------------------------------------------------------------------- - //! Output an error to the logger - //! \param szWarn Error message - void LogError(const char* szWarn); - - // ------------------------------------------------------------------- - //! Parse a string, enclosed in double quotation marks - //! \param out Output string - //! \param szName Name of the enclosing element -> used in error - //! messages. - //! \return false if an error occured - bool ParseString(std::string& out,const char* szName); + // ------------------------------------------------------------------- + //! Parse the *SCENE block in a file + void ParseLV1SceneBlock(); + + // ------------------------------------------------------------------- + //! Parse the *MESH_SOFTSKINVERTS block in a file + void ParseLV1SoftSkinBlock(); + + // ------------------------------------------------------------------- + //! Parse the *MATERIAL_LIST block in a file + void ParseLV1MaterialListBlock(); + + // ------------------------------------------------------------------- + //! Parse a *OBJECT block in a file + //! \param mesh Node to be filled + void ParseLV1ObjectBlock(BaseNode& mesh); + + // ------------------------------------------------------------------- + //! Parse a *MATERIAL blocks in a material list + //! \param mat Material structure to be filled + void ParseLV2MaterialBlock(Material& mat); + + // ------------------------------------------------------------------- + //! Parse a *NODE_TM block in a file + //! \param mesh Node (!) object to be filled + void ParseLV2NodeTransformBlock(BaseNode& mesh); + + // ------------------------------------------------------------------- + //! Parse a *TM_ANIMATION block in a file + //! \param mesh Mesh object to be filled + void ParseLV2AnimationBlock(BaseNode& mesh); + void ParseLV3PosAnimationBlock(ASE::Animation& anim); + void ParseLV3ScaleAnimationBlock(ASE::Animation& anim); + void ParseLV3RotAnimationBlock(ASE::Animation& anim); + + // ------------------------------------------------------------------- + //! Parse a *MESH block in a file + //! \param mesh Mesh object to be filled + void ParseLV2MeshBlock(Mesh& mesh); + + // ------------------------------------------------------------------- + //! Parse a *LIGHT_SETTINGS block in a file + //! \param light Light object to be filled + void ParseLV2LightSettingsBlock(Light& light); + + // ------------------------------------------------------------------- + //! Parse a *CAMERA_SETTINGS block in a file + //! \param cam Camera object to be filled + void ParseLV2CameraSettingsBlock(Camera& cam); + + // ------------------------------------------------------------------- + //! Parse the *MAP_XXXXXX blocks in a material + //! \param map Texture structure to be filled + void ParseLV3MapBlock(Texture& map); + + // ------------------------------------------------------------------- + //! Parse a *MESH_VERTEX_LIST block in a file + //! \param iNumVertices Value of *MESH_NUMVERTEX, if present. + //! Otherwise zero. This is used to check the consistency of the file. + //! A warning is sent to the logger if the validations fails. + //! \param mesh Mesh object to be filled + void ParseLV3MeshVertexListBlock( + unsigned int iNumVertices,Mesh& mesh); + + // ------------------------------------------------------------------- + //! Parse a *MESH_FACE_LIST block in a file + //! \param iNumFaces Value of *MESH_NUMFACES, if present. + //! Otherwise zero. This is used to check the consistency of the file. + //! A warning is sent to the logger if the validations fails. + //! \param mesh Mesh object to be filled + void ParseLV3MeshFaceListBlock( + unsigned int iNumFaces,Mesh& mesh); + + // ------------------------------------------------------------------- + //! Parse a *MESH_TVERT_LIST block in a file + //! \param iNumVertices Value of *MESH_NUMTVERTEX, if present. + //! Otherwise zero. This is used to check the consistency of the file. + //! A warning is sent to the logger if the validations fails. + //! \param mesh Mesh object to be filled + //! \param iChannel Output UVW channel + void ParseLV3MeshTListBlock( + unsigned int iNumVertices,Mesh& mesh, unsigned int iChannel = 0); + + // ------------------------------------------------------------------- + //! Parse a *MESH_TFACELIST block in a file + //! \param iNumFaces Value of *MESH_NUMTVFACES, if present. + //! Otherwise zero. This is used to check the consistency of the file. + //! A warning is sent to the logger if the validations fails. + //! \param mesh Mesh object to be filled + //! \param iChannel Output UVW channel + void ParseLV3MeshTFaceListBlock( + unsigned int iNumFaces,Mesh& mesh, unsigned int iChannel = 0); + + // ------------------------------------------------------------------- + //! Parse an additional mapping channel + //! (specified via *MESH_MAPPINGCHANNEL) + //! \param iChannel Channel index to be filled + //! \param mesh Mesh object to be filled + void ParseLV3MappingChannel( + unsigned int iChannel, Mesh& mesh); + + // ------------------------------------------------------------------- + //! Parse a *MESH_CVERTLIST block in a file + //! \param iNumVertices Value of *MESH_NUMCVERTEX, if present. + //! Otherwise zero. This is used to check the consistency of the file. + //! A warning is sent to the logger if the validations fails. + //! \param mesh Mesh object to be filled + void ParseLV3MeshCListBlock( + unsigned int iNumVertices, Mesh& mesh); + + // ------------------------------------------------------------------- + //! Parse a *MESH_CFACELIST block in a file + //! \param iNumFaces Value of *MESH_NUMCVFACES, if present. + //! Otherwise zero. This is used to check the consistency of the file. + //! A warning is sent to the logger if the validations fails. + //! \param mesh Mesh object to be filled + void ParseLV3MeshCFaceListBlock( + unsigned int iNumFaces, Mesh& mesh); + + // ------------------------------------------------------------------- + //! Parse a *MESH_NORMALS block in a file + //! \param mesh Mesh object to be filled + void ParseLV3MeshNormalListBlock(Mesh& mesh); + + // ------------------------------------------------------------------- + //! Parse a *MESH_WEIGHTSblock in a file + //! \param mesh Mesh object to be filled + void ParseLV3MeshWeightsBlock(Mesh& mesh); + + // ------------------------------------------------------------------- + //! Parse the bone list of a file + //! \param mesh Mesh object to be filled + //! \param iNumBones Number of bones in the mesh + void ParseLV4MeshBones(unsigned int iNumBones,Mesh& mesh); + + // ------------------------------------------------------------------- + //! Parse the bone vertices list of a file + //! \param mesh Mesh object to be filled + //! \param iNumVertices Number of vertices to be parsed + void ParseLV4MeshBonesVertices(unsigned int iNumVertices,Mesh& mesh); + + // ------------------------------------------------------------------- + //! Parse a *MESH_FACE block in a file + //! \param out receive the face data + void ParseLV4MeshFace(ASE::Face& out); + + // ------------------------------------------------------------------- + //! Parse a *MESH_VERT block in a file + //! (also works for MESH_TVERT, MESH_CFACE, MESH_VERTCOL ...) + //! \param apOut Output buffer (3 floats) + //! \param rIndexOut Output index + void ParseLV4MeshFloatTriple(float* apOut, unsigned int& rIndexOut); + + // ------------------------------------------------------------------- + //! Parse a *MESH_VERT block in a file + //! (also works for MESH_TVERT, MESH_CFACE, MESH_VERTCOL ...) + //! \param apOut Output buffer (3 floats) + void ParseLV4MeshFloatTriple(float* apOut); + + // ------------------------------------------------------------------- + //! Parse a *MESH_TFACE block in a file + //! (also works for MESH_CFACE) + //! \param apOut Output buffer (3 ints) + //! \param rIndexOut Output index + void ParseLV4MeshLongTriple(unsigned int* apOut, unsigned int& rIndexOut); + + // ------------------------------------------------------------------- + //! Parse a *MESH_TFACE block in a file + //! (also works for MESH_CFACE) + //! \param apOut Output buffer (3 ints) + void ParseLV4MeshLongTriple(unsigned int* apOut); + + // ------------------------------------------------------------------- + //! Parse a single float element + //! \param fOut Output float + void ParseLV4MeshFloat(float& fOut); + + // ------------------------------------------------------------------- + //! Parse a single int element + //! \param iOut Output integer + void ParseLV4MeshLong(unsigned int& iOut); + + // ------------------------------------------------------------------- + //! Skip everything to the next: '*' or '\0' + bool SkipToNextToken(); + + // ------------------------------------------------------------------- + //! Skip the current section until the token after the closing }. + //! This function handles embedded subsections correctly + bool SkipSection(); + + // ------------------------------------------------------------------- + //! Output a warning to the logger + //! \param szWarn Warn message + void LogWarning(const char* szWarn); + + // ------------------------------------------------------------------- + //! Output a message to the logger + //! \param szWarn Message + void LogInfo(const char* szWarn); + + // ------------------------------------------------------------------- + //! Output an error to the logger + //! \param szWarn Error message + AI_WONT_RETURN void LogError(const char* szWarn) AI_WONT_RETURN_SUFFIX; + + // ------------------------------------------------------------------- + //! Parse a string, enclosed in double quotation marks + //! \param out Output string + //! \param szName Name of the enclosing element -> used in error + //! messages. + //! \return false if an error occurred + bool ParseString(std::string& out,const char* szName); public: - //! Pointer to current data - const char* filePtr; + //! Pointer to current data + const char* filePtr; - //! background color to be passed to the viewer - //! QNAN if none was found - aiColor3D m_clrBackground; + //! background color to be passed to the viewer + //! QNAN if none was found + aiColor3D m_clrBackground; - //! Base ambient color to be passed to all materials - //! QNAN if none was found - aiColor3D m_clrAmbient; + //! Base ambient color to be passed to all materials + //! QNAN if none was found + aiColor3D m_clrAmbient; - //! List of all materials found in the file - std::vector m_vMaterials; + //! List of all materials found in the file + std::vector m_vMaterials; - //! List of all meshes found in the file - std::vector m_vMeshes; + //! List of all meshes found in the file + std::vector m_vMeshes; - //! List of all dummies found in the file - std::vector m_vDummies; + //! List of all dummies found in the file + std::vector m_vDummies; - //! List of all lights found in the file - std::vector m_vLights; + //! List of all lights found in the file + std::vector m_vLights; - //! List of all cameras found in the file - std::vector m_vCameras; + //! List of all cameras found in the file + std::vector m_vCameras; - //! Current line in the file - unsigned int iLineNumber; + //! Current line in the file + unsigned int iLineNumber; - //! First frame - unsigned int iFirstFrame; + //! First frame + unsigned int iFirstFrame; - //! Last frame - unsigned int iLastFrame; + //! Last frame + unsigned int iLastFrame; - //! Frame speed - frames per second - unsigned int iFrameSpeed; + //! Frame speed - frames per second + unsigned int iFrameSpeed; - //! Ticks per frame - unsigned int iTicksPerFrame; + //! Ticks per frame + unsigned int iTicksPerFrame; - //! true if the last character read was an end-line character - bool bLastWasEndLine; + //! true if the last character read was an end-line character + bool bLastWasEndLine; - //! File format version - unsigned int iFileFormat; + //! File format version + unsigned int iFileFormat; }; diff --git a/src/3rdparty/assimp/code/AssbinExporter.cpp b/src/3rdparty/assimp/code/AssbinExporter.cpp new file mode 100644 index 000000000..9240d3739 --- /dev/null +++ b/src/3rdparty/assimp/code/AssbinExporter.cpp @@ -0,0 +1,768 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2016, assimp team +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the +following conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +---------------------------------------------------------------------- +*/ +/** @file AssbinExporter.cpp + * ASSBIN exporter main code + */ +#include "assbin_chunks.h" +#include +#include +#include +#include +#include "ProcessHelper.h" +#include "Exceptional.h" + +#ifdef ASSIMP_BUILD_NO_OWN_ZLIB +# include +#else +# include "../contrib/zlib/zlib.h" +#endif + +#include + + +#ifndef ASSIMP_BUILD_NO_EXPORT +#ifndef ASSIMP_BUILD_NO_ASSBIN_EXPORTER + +using namespace Assimp; + +namespace Assimp { + +template +size_t Write(IOStream * stream, const T& v) +{ + return stream->Write( &v, sizeof(T), 1 ); +} + + +// ----------------------------------------------------------------------------------- +// Serialize an aiString +template <> +inline size_t Write(IOStream * stream, const aiString& s) +{ + const size_t s2 = (uint32_t)s.length; + stream->Write(&s,4,1); + stream->Write(s.data,s2,1); + return s2+4; +} + +// ----------------------------------------------------------------------------------- +// Serialize an unsigned int as uint32_t +template <> +inline size_t Write(IOStream * stream, const unsigned int& w) +{ + const uint32_t t = (uint32_t)w; + if (w > t) { + // this shouldn't happen, integers in Assimp data structures never exceed 2^32 + throw new DeadlyExportError("loss of data due to 64 -> 32 bit integer conversion"); + } + + stream->Write(&t,4,1); + return 4; +} + +// ----------------------------------------------------------------------------------- +// Serialize an unsigned int as uint16_t +template <> +inline size_t Write(IOStream * stream, const uint16_t& w) +{ + static_assert(sizeof(uint16_t)==2, "sizeof(uint16_t)==2"); + stream->Write(&w,2,1); + return 2; +} + +// ----------------------------------------------------------------------------------- +// Serialize a float +template <> +inline size_t Write(IOStream * stream, const float& f) +{ + static_assert(sizeof(float)==4, "sizeof(float)==4"); + stream->Write(&f,4,1); + return 4; +} + +// ----------------------------------------------------------------------------------- +// Serialize a double +template <> +inline size_t Write(IOStream * stream, const double& f) +{ + static_assert(sizeof(double)==8, "sizeof(double)==8"); + stream->Write(&f,8,1); + return 8; +} + +// ----------------------------------------------------------------------------------- +// Serialize a vec3 +template <> +inline size_t Write(IOStream * stream, const aiVector3D& v) +{ + size_t t = Write(stream,v.x); + t += Write(stream,v.y); + t += Write(stream,v.z); + return t; +} + +// ----------------------------------------------------------------------------------- +// Serialize a color value +template <> +inline size_t Write(IOStream * stream, const aiColor4D& v) +{ + size_t t = Write(stream,v.r); + t += Write(stream,v.g); + t += Write(stream,v.b); + t += Write(stream,v.a); + return t; +} + +// ----------------------------------------------------------------------------------- +// Serialize a quaternion +template <> +inline size_t Write(IOStream * stream, const aiQuaternion& v) +{ + size_t t = Write(stream,v.w); + t += Write(stream,v.x); + t += Write(stream,v.y); + t += Write(stream,v.z); + return 16; +} + + +// ----------------------------------------------------------------------------------- +// Serialize a vertex weight +template <> +inline size_t Write(IOStream * stream, const aiVertexWeight& v) +{ + size_t t = Write(stream,v.mVertexId); + return t+Write(stream,v.mWeight); +} + +// ----------------------------------------------------------------------------------- +// Serialize a mat4x4 +template <> +inline size_t Write(IOStream * stream, const aiMatrix4x4& m) +{ + for (unsigned int i = 0; i < 4;++i) { + for (unsigned int i2 = 0; i2 < 4;++i2) { + Write(stream,m[i][i2]); + } + } + return 64; +} + +// ----------------------------------------------------------------------------------- +// Serialize an aiVectorKey +template <> +inline size_t Write(IOStream * stream, const aiVectorKey& v) +{ + const size_t t = Write(stream,v.mTime); + return t + Write(stream,v.mValue); +} + +// ----------------------------------------------------------------------------------- +// Serialize an aiQuatKey +template <> +inline size_t Write(IOStream * stream, const aiQuatKey& v) +{ + const size_t t = Write(stream,v.mTime); + return t + Write(stream,v.mValue); +} + +template +inline size_t WriteBounds(IOStream * stream, const T* in, unsigned int size) +{ + T minc,maxc; + ArrayBounds(in,size,minc,maxc); + + const size_t t = Write(stream,minc); + return t + Write(stream,maxc); +} + +// We use this to write out non-byte arrays so that we write using the specializations. +// This way we avoid writing out extra bytes that potentially come from struct alignment. +template +inline size_t WriteArray(IOStream * stream, const T* in, unsigned int size) +{ + size_t n = 0; + for (unsigned int i=0; i(stream,in[i]); + return n; +} + + // ---------------------------------------------------------------------------------- + /** @class AssbinChunkWriter + * @brief Chunk writer mechanism for the .assbin file structure + * + * This is a standard in-memory IOStream (most of the code is based on BlobIOStream), + * the difference being that this takes another IOStream as a "container" in the + * constructor, and when it is destroyed, it appends the magic number, the chunk size, + * and the chunk contents to the container stream. This allows relatively easy chunk + * chunk construction, even recursively. + */ + class AssbinChunkWriter : public IOStream + { + private: + + uint8_t* buffer; + uint32_t magic; + IOStream * container; + size_t cur_size, cursor, initial; + + private: + // ------------------------------------------------------------------- + void Grow(size_t need = 0) + { + size_t new_size = std::max(initial, std::max( need, cur_size+(cur_size>>1) )); + + const uint8_t* const old = buffer; + buffer = new uint8_t[new_size]; + + if (old) { + memcpy(buffer,old,cur_size); + delete[] old; + } + + cur_size = new_size; + } + + public: + + AssbinChunkWriter( IOStream * container, uint32_t magic, size_t initial = 4096) + : buffer(NULL), magic(magic), container(container), cur_size(0), cursor(0), initial(initial) + { + } + + virtual ~AssbinChunkWriter() + { + if (container) { + container->Write( &magic, sizeof(uint32_t), 1 ); + container->Write( &cursor, sizeof(uint32_t), 1 ); + container->Write( buffer, 1, cursor ); + } + if (buffer) delete[] buffer; + } + + void * GetBufferPointer() { return buffer; } + + // ------------------------------------------------------------------- + virtual size_t Read(void* /*pvBuffer*/, size_t /*pSize*/, size_t /*pCount*/) { return 0; } + virtual aiReturn Seek(size_t /*pOffset*/, aiOrigin /*pOrigin*/) { return aiReturn_FAILURE; } + virtual size_t Tell() const { return cursor; } + virtual void Flush() { } + + virtual size_t FileSize() const + { + return cursor; + } + + // ------------------------------------------------------------------- + virtual size_t Write(const void* pvBuffer, size_t pSize, size_t pCount) + { + pSize *= pCount; + if (cursor + pSize > cur_size) { + Grow(cursor + pSize); + } + + memcpy(buffer+cursor, pvBuffer, pSize); + cursor += pSize; + + return pCount; + } + + }; + + // ---------------------------------------------------------------------------------- + /** @class AssbinExport + * @brief Assbin exporter class + * + * This class performs the .assbin exporting, and is responsible for the file layout. + */ + class AssbinExport + { + private: + bool shortened; + bool compressed; + + protected: + + // ----------------------------------------------------------------------------------- + void WriteBinaryNode( IOStream * container, const aiNode* node) + { + AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AINODE ); + + Write(&chunk,node->mName); + Write(&chunk,node->mTransformation); + Write(&chunk,node->mNumChildren); + Write(&chunk,node->mNumMeshes); + + for (unsigned int i = 0; i < node->mNumMeshes;++i) { + Write(&chunk,node->mMeshes[i]); + } + + for (unsigned int i = 0; i < node->mNumChildren;++i) { + WriteBinaryNode( &chunk, node->mChildren[i] ); + } + } + + // ----------------------------------------------------------------------------------- + void WriteBinaryTexture(IOStream * container, const aiTexture* tex) + { + AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AITEXTURE ); + + Write(&chunk,tex->mWidth); + Write(&chunk,tex->mHeight); + chunk.Write( tex->achFormatHint, sizeof(char), 4 ); + + if(!shortened) { + if (!tex->mHeight) { + chunk.Write(tex->pcData,1,tex->mWidth); + } + else { + chunk.Write(tex->pcData,1,tex->mWidth*tex->mHeight*4); + } + } + + } + + // ----------------------------------------------------------------------------------- + void WriteBinaryBone(IOStream * container, const aiBone* b) + { + AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIBONE ); + + Write(&chunk,b->mName); + Write(&chunk,b->mNumWeights); + Write(&chunk,b->mOffsetMatrix); + + // for the moment we write dumb min/max values for the bones, too. + // maybe I'll add a better, hash-like solution later + if (shortened) { + WriteBounds(&chunk,b->mWeights,b->mNumWeights); + } // else write as usual + else WriteArray(&chunk,b->mWeights,b->mNumWeights); + } + + // ----------------------------------------------------------------------------------- + void WriteBinaryMesh(IOStream * container, const aiMesh* mesh) + { + AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIMESH ); + + Write(&chunk,mesh->mPrimitiveTypes); + Write(&chunk,mesh->mNumVertices); + Write(&chunk,mesh->mNumFaces); + Write(&chunk,mesh->mNumBones); + Write(&chunk,mesh->mMaterialIndex); + + // first of all, write bits for all existent vertex components + unsigned int c = 0; + if (mesh->mVertices) { + c |= ASSBIN_MESH_HAS_POSITIONS; + } + if (mesh->mNormals) { + c |= ASSBIN_MESH_HAS_NORMALS; + } + if (mesh->mTangents && mesh->mBitangents) { + c |= ASSBIN_MESH_HAS_TANGENTS_AND_BITANGENTS; + } + for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n) { + if (!mesh->mTextureCoords[n]) { + break; + } + c |= ASSBIN_MESH_HAS_TEXCOORD(n); + } + for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS;++n) { + if (!mesh->mColors[n]) { + break; + } + c |= ASSBIN_MESH_HAS_COLOR(n); + } + Write(&chunk,c); + + aiVector3D minVec, maxVec; + if (mesh->mVertices) { + if (shortened) { + WriteBounds(&chunk,mesh->mVertices,mesh->mNumVertices); + } // else write as usual + else WriteArray(&chunk,mesh->mVertices,mesh->mNumVertices); + } + if (mesh->mNormals) { + if (shortened) { + WriteBounds(&chunk,mesh->mNormals,mesh->mNumVertices); + } // else write as usual + else WriteArray(&chunk,mesh->mNormals,mesh->mNumVertices); + } + if (mesh->mTangents && mesh->mBitangents) { + if (shortened) { + WriteBounds(&chunk,mesh->mTangents,mesh->mNumVertices); + WriteBounds(&chunk,mesh->mBitangents,mesh->mNumVertices); + } // else write as usual + else { + WriteArray(&chunk,mesh->mTangents,mesh->mNumVertices); + WriteArray(&chunk,mesh->mBitangents,mesh->mNumVertices); + } + } + for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS;++n) { + if (!mesh->mColors[n]) + break; + + if (shortened) { + WriteBounds(&chunk,mesh->mColors[n],mesh->mNumVertices); + } // else write as usual + else WriteArray(&chunk,mesh->mColors[n],mesh->mNumVertices); + } + for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n) { + if (!mesh->mTextureCoords[n]) + break; + + // write number of UV components + Write(&chunk,mesh->mNumUVComponents[n]); + + if (shortened) { + WriteBounds(&chunk,mesh->mTextureCoords[n],mesh->mNumVertices); + } // else write as usual + else WriteArray(&chunk,mesh->mTextureCoords[n],mesh->mNumVertices); + } + + // write faces. There are no floating-point calculations involved + // in these, so we can write a simple hash over the face data + // to the dump file. We generate a single 32 Bit hash for 512 faces + // using Assimp's standard hashing function. + if (shortened) { + unsigned int processed = 0; + for (unsigned int job;(job = std::min(mesh->mNumFaces-processed,512u));processed += job) { + + uint32_t hash = 0; + for (unsigned int a = 0; a < job;++a) { + + const aiFace& f = mesh->mFaces[processed+a]; + uint32_t tmp = f.mNumIndices; + hash = SuperFastHash(reinterpret_cast(&tmp),sizeof tmp,hash); + for (unsigned int i = 0; i < f.mNumIndices; ++i) { + static_assert(AI_MAX_VERTICES <= 0xffffffff, "AI_MAX_VERTICES <= 0xffffffff"); + tmp = static_cast( f.mIndices[i] ); + hash = SuperFastHash(reinterpret_cast(&tmp),sizeof tmp,hash); + } + } + Write(&chunk,hash); + } + } + else // else write as usual + { + // if there are less than 2^16 vertices, we can simply use 16 bit integers ... + for (unsigned int i = 0; i < mesh->mNumFaces;++i) { + const aiFace& f = mesh->mFaces[i]; + + static_assert(AI_MAX_FACE_INDICES <= 0xffff, "AI_MAX_FACE_INDICES <= 0xffff"); + Write(&chunk,f.mNumIndices); + + for (unsigned int a = 0; a < f.mNumIndices;++a) { + if (mesh->mNumVertices < (1u<<16)) { + Write(&chunk,f.mIndices[a]); + } + else Write(&chunk,f.mIndices[a]); + } + } + } + + // write bones + if (mesh->mNumBones) { + for (unsigned int a = 0; a < mesh->mNumBones;++a) { + const aiBone* b = mesh->mBones[a]; + WriteBinaryBone(&chunk,b); + } + } + } + + // ----------------------------------------------------------------------------------- + void WriteBinaryMaterialProperty(IOStream * container, const aiMaterialProperty* prop) + { + AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIMATERIALPROPERTY ); + + Write(&chunk,prop->mKey); + Write(&chunk,prop->mSemantic); + Write(&chunk,prop->mIndex); + + Write(&chunk,prop->mDataLength); + Write(&chunk,(unsigned int)prop->mType); + chunk.Write(prop->mData,1,prop->mDataLength); + } + + // ----------------------------------------------------------------------------------- + void WriteBinaryMaterial(IOStream * container, const aiMaterial* mat) + { + AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIMATERIAL); + + Write(&chunk,mat->mNumProperties); + for (unsigned int i = 0; i < mat->mNumProperties;++i) { + WriteBinaryMaterialProperty( &chunk, mat->mProperties[i]); + } + } + + // ----------------------------------------------------------------------------------- + void WriteBinaryNodeAnim(IOStream * container, const aiNodeAnim* nd) + { + AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AINODEANIM ); + + Write(&chunk,nd->mNodeName); + Write(&chunk,nd->mNumPositionKeys); + Write(&chunk,nd->mNumRotationKeys); + Write(&chunk,nd->mNumScalingKeys); + Write(&chunk,nd->mPreState); + Write(&chunk,nd->mPostState); + + if (nd->mPositionKeys) { + if (shortened) { + WriteBounds(&chunk,nd->mPositionKeys,nd->mNumPositionKeys); + + } // else write as usual + else WriteArray(&chunk,nd->mPositionKeys,nd->mNumPositionKeys); + } + if (nd->mRotationKeys) { + if (shortened) { + WriteBounds(&chunk,nd->mRotationKeys,nd->mNumRotationKeys); + + } // else write as usual + else WriteArray(&chunk,nd->mRotationKeys,nd->mNumRotationKeys); + } + if (nd->mScalingKeys) { + if (shortened) { + WriteBounds(&chunk,nd->mScalingKeys,nd->mNumScalingKeys); + + } // else write as usual + else WriteArray(&chunk,nd->mScalingKeys,nd->mNumScalingKeys); + } + } + + + // ----------------------------------------------------------------------------------- + void WriteBinaryAnim( IOStream * container, const aiAnimation* anim ) + { + AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIANIMATION ); + + Write(&chunk,anim->mName); + Write(&chunk,anim->mDuration); + Write(&chunk,anim->mTicksPerSecond); + Write(&chunk,anim->mNumChannels); + + for (unsigned int a = 0; a < anim->mNumChannels;++a) { + const aiNodeAnim* nd = anim->mChannels[a]; + WriteBinaryNodeAnim(&chunk,nd); + } + } + + // ----------------------------------------------------------------------------------- + void WriteBinaryLight( IOStream * container, const aiLight* l ) + { + AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AILIGHT ); + + Write(&chunk,l->mName); + Write(&chunk,l->mType); + + if (l->mType != aiLightSource_DIRECTIONAL) { + Write(&chunk,l->mAttenuationConstant); + Write(&chunk,l->mAttenuationLinear); + Write(&chunk,l->mAttenuationQuadratic); + } + + Write(&chunk,(const aiVector3D&)l->mColorDiffuse); + Write(&chunk,(const aiVector3D&)l->mColorSpecular); + Write(&chunk,(const aiVector3D&)l->mColorAmbient); + + if (l->mType == aiLightSource_SPOT) { + Write(&chunk,l->mAngleInnerCone); + Write(&chunk,l->mAngleOuterCone); + } + + } + + // ----------------------------------------------------------------------------------- + void WriteBinaryCamera( IOStream * container, const aiCamera* cam ) + { + AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AICAMERA ); + + Write(&chunk,cam->mName); + Write(&chunk,cam->mPosition); + Write(&chunk,cam->mLookAt); + Write(&chunk,cam->mUp); + Write(&chunk,cam->mHorizontalFOV); + Write(&chunk,cam->mClipPlaneNear); + Write(&chunk,cam->mClipPlaneFar); + Write(&chunk,cam->mAspect); + } + + // ----------------------------------------------------------------------------------- + void WriteBinaryScene( IOStream * container, const aiScene* scene) + { + AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AISCENE ); + + // basic scene information + Write(&chunk,scene->mFlags); + Write(&chunk,scene->mNumMeshes); + Write(&chunk,scene->mNumMaterials); + Write(&chunk,scene->mNumAnimations); + Write(&chunk,scene->mNumTextures); + Write(&chunk,scene->mNumLights); + Write(&chunk,scene->mNumCameras); + + // write node graph + WriteBinaryNode( &chunk, scene->mRootNode ); + + // write all meshes + for (unsigned int i = 0; i < scene->mNumMeshes;++i) { + const aiMesh* mesh = scene->mMeshes[i]; + WriteBinaryMesh( &chunk,mesh); + } + + // write materials + for (unsigned int i = 0; i< scene->mNumMaterials; ++i) { + const aiMaterial* mat = scene->mMaterials[i]; + WriteBinaryMaterial(&chunk,mat); + } + + // write all animations + for (unsigned int i = 0; i < scene->mNumAnimations;++i) { + const aiAnimation* anim = scene->mAnimations[i]; + WriteBinaryAnim(&chunk,anim); + } + + + // write all textures + for (unsigned int i = 0; i < scene->mNumTextures;++i) { + const aiTexture* mesh = scene->mTextures[i]; + WriteBinaryTexture(&chunk,mesh); + } + + // write lights + for (unsigned int i = 0; i < scene->mNumLights;++i) { + const aiLight* l = scene->mLights[i]; + WriteBinaryLight(&chunk,l); + } + + // write cameras + for (unsigned int i = 0; i < scene->mNumCameras;++i) { + const aiCamera* cam = scene->mCameras[i]; + WriteBinaryCamera(&chunk,cam); + } + + } + + public: + AssbinExport() + : shortened(false), compressed(false) // temporary settings until properties are introduced for exporters + { + } + + // ----------------------------------------------------------------------------------- + // Write a binary model dump + void WriteBinaryDump(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene) + { + IOStream * out = pIOSystem->Open( pFile, "wb" ); + if (!out) return; + + time_t tt = time(NULL); + tm* p = gmtime(&tt); + + // header + char s[64]; + memset( s, 0, 64 ); +#if _MSC_VER >= 1400 + sprintf_s(s,"ASSIMP.binary-dump.%s",asctime(p)); +#else + ai_snprintf(s,64,"ASSIMP.binary-dump.%s",asctime(p)); +#endif + out->Write( s, 44, 1 ); + // == 44 bytes + + Write( out, ASSBIN_VERSION_MAJOR ); + Write( out, ASSBIN_VERSION_MINOR ); + Write( out, aiGetVersionRevision() ); + Write( out, aiGetCompileFlags() ); + Write( out, shortened ); + Write( out, compressed ); + // == 20 bytes + + char buff[256]; + strncpy(buff,pFile,256); + out->Write(buff,sizeof(char),256); + + char cmd[] = "\0"; + strncpy(buff,cmd,128); + out->Write(buff,sizeof(char),128); + + // leave 64 bytes free for future extensions + memset(buff,0xcd,64); + out->Write(buff,sizeof(char),64); + // == 435 bytes + + // ==== total header size: 512 bytes + ai_assert( out->Tell() == ASSBIN_HEADER_LENGTH ); + + // Up to here the data is uncompressed. For compressed files, the rest + // is compressed using standard DEFLATE from zlib. + if (compressed) + { + AssbinChunkWriter uncompressedStream( NULL, 0 ); + WriteBinaryScene( &uncompressedStream, pScene ); + + uLongf uncompressedSize = uncompressedStream.Tell(); + uLongf compressedSize = (uLongf)(uncompressedStream.Tell() * 1.001 + 12.); + uint8_t* compressedBuffer = new uint8_t[ compressedSize ]; + + compress2( compressedBuffer, &compressedSize, (const Bytef*)uncompressedStream.GetBufferPointer(), uncompressedSize, 9 ); + + out->Write( &uncompressedSize, sizeof(uint32_t), 1 ); + out->Write( compressedBuffer, sizeof(char), compressedSize ); + + delete[] compressedBuffer; + } + else + { + WriteBinaryScene( out, pScene ); + } + + pIOSystem->Close( out ); + } + }; + +void ExportSceneAssbin(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* pProperties) +{ + AssbinExport exporter; + exporter.WriteBinaryDump( pFile, pIOSystem, pScene ); +} +} // end of namespace Assimp + +#endif // ASSIMP_BUILD_NO_ASSBIN_EXPORTER +#endif // ASSIMP_BUILD_NO_EXPORT diff --git a/src/3rdparty/assimp/code/AssbinExporter.h b/src/3rdparty/assimp/code/AssbinExporter.h new file mode 100644 index 000000000..4a0219c04 --- /dev/null +++ b/src/3rdparty/assimp/code/AssbinExporter.h @@ -0,0 +1,49 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2016, assimp team +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the +following conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +---------------------------------------------------------------------- +*/ + +/** @file AssbinExporter.h + * ASSBIN Exporter Main Header + */ +#ifndef AI_ASSBINEXPORTER_H_INC +#define AI_ASSBINEXPORTER_H_INC + +// nothing really needed here - reserved for future use like properties + +#endif diff --git a/src/3rdparty/assimp/code/AssbinLoader.cpp b/src/3rdparty/assimp/code/AssbinLoader.cpp new file mode 100644 index 000000000..c4261c4cb --- /dev/null +++ b/src/3rdparty/assimp/code/AssbinLoader.cpp @@ -0,0 +1,686 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2016, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------- +*/ + +/** @file AssbinLoader.cpp + * @brief Implementation of the .assbin importer class + * + * see assbin_chunks.h + */ + +#ifndef ASSIMP_BUILD_NO_ASSBIN_IMPORTER + +// internal headers +#include "AssbinLoader.h" +#include "assbin_chunks.h" +#include "MemoryIOWrapper.h" +#include +#include +#include + +#ifdef ASSIMP_BUILD_NO_OWN_ZLIB +# include +#else +# include +#endif + +using namespace Assimp; + +static const aiImporterDesc desc = { + ".assbin Importer", + "Gargaj / Conspiracy", + "", + "", + aiImporterFlags_SupportBinaryFlavour | aiImporterFlags_SupportCompressedFlavour, + 0, + 0, + 0, + 0, + "assbin" +}; + +const aiImporterDesc* AssbinImporter::GetInfo() const +{ + return &desc; +} + +bool AssbinImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool /*checkSig*/ ) const +{ + IOStream * in = pIOHandler->Open(pFile); + if (!in) + return false; + + char s[32]; + in->Read( s, sizeof(char), 32 ); + + pIOHandler->Close(in); + + return strncmp( s, "ASSIMP.binary-dump.", 19 ) == 0; +} + +template +T Read(IOStream * stream) +{ + T t; + stream->Read( &t, sizeof(T), 1 ); + return t; +} + +template <> +aiVector3D Read(IOStream * stream) +{ + aiVector3D v; + v.x = Read(stream); + v.y = Read(stream); + v.z = Read(stream); + return v; +} + +template <> +aiColor4D Read(IOStream * stream) +{ + aiColor4D c; + c.r = Read(stream); + c.g = Read(stream); + c.b = Read(stream); + c.a = Read(stream); + return c; +} + +template <> +aiQuaternion Read(IOStream * stream) +{ + aiQuaternion v; + v.w = Read(stream); + v.x = Read(stream); + v.y = Read(stream); + v.z = Read(stream); + return v; +} + +template <> +aiString Read(IOStream * stream) +{ + aiString s; + stream->Read(&s.length,4,1); + stream->Read(s.data,s.length,1); + s.data[s.length] = 0; + return s; +} + +template <> +aiVertexWeight Read(IOStream * stream) +{ + aiVertexWeight w; + w.mVertexId = Read(stream); + w.mWeight = Read(stream); + return w; +} + +template <> +aiMatrix4x4 Read(IOStream * stream) +{ + aiMatrix4x4 m; + for (unsigned int i = 0; i < 4;++i) { + for (unsigned int i2 = 0; i2 < 4;++i2) { + m[i][i2] = Read(stream); + } + } + return m; +} + +template <> +aiVectorKey Read(IOStream * stream) +{ + aiVectorKey v; + v.mTime = Read(stream); + v.mValue = Read(stream); + return v; +} + +template <> +aiQuatKey Read(IOStream * stream) +{ + aiQuatKey v; + v.mTime = Read(stream); + v.mValue = Read(stream); + return v; +} + +template +void ReadArray(IOStream * stream, T * out, unsigned int size) +{ + for (unsigned int i=0; i(stream); +} + +template void ReadBounds( IOStream * stream, T* /*p*/, unsigned int n ) +{ + // not sure what to do here, the data isn't really useful. + stream->Seek( sizeof(T) * n, aiOrigin_CUR ); +} + +void AssbinImporter::ReadBinaryNode( IOStream * stream, aiNode** node ) +{ + uint32_t chunkID = Read(stream); + ai_assert(chunkID == ASSBIN_CHUNK_AINODE); + /*uint32_t size =*/ Read(stream); + + *node = new aiNode(); + + (*node)->mName = Read(stream); + (*node)->mTransformation = Read(stream); + (*node)->mNumChildren = Read(stream); + (*node)->mNumMeshes = Read(stream); + + if ((*node)->mNumMeshes) + { + (*node)->mMeshes = new unsigned int[(*node)->mNumMeshes]; + for (unsigned int i = 0; i < (*node)->mNumMeshes; ++i) { + (*node)->mMeshes[i] = Read(stream); + } + } + + if ((*node)->mNumChildren) + { + (*node)->mChildren = new aiNode*[(*node)->mNumChildren]; + for (unsigned int i = 0; i < (*node)->mNumChildren; ++i) { + ReadBinaryNode( stream, &(*node)->mChildren[i] ); + } + } + +} + +// ----------------------------------------------------------------------------------- +void AssbinImporter::ReadBinaryBone( IOStream * stream, aiBone* b ) +{ + uint32_t chunkID = Read(stream); + ai_assert(chunkID == ASSBIN_CHUNK_AIBONE); + /*uint32_t size =*/ Read(stream); + + b->mName = Read(stream); + b->mNumWeights = Read(stream); + b->mOffsetMatrix = Read(stream); + + // for the moment we write dumb min/max values for the bones, too. + // maybe I'll add a better, hash-like solution later + if (shortened) + { + ReadBounds(stream,b->mWeights,b->mNumWeights); + } // else write as usual + else + { + b->mWeights = new aiVertexWeight[b->mNumWeights]; + ReadArray(stream,b->mWeights,b->mNumWeights); + } +} + + +void AssbinImporter::ReadBinaryMesh( IOStream * stream, aiMesh* mesh ) +{ + uint32_t chunkID = Read(stream); + ai_assert(chunkID == ASSBIN_CHUNK_AIMESH); + /*uint32_t size =*/ Read(stream); + + mesh->mPrimitiveTypes = Read(stream); + mesh->mNumVertices = Read(stream); + mesh->mNumFaces = Read(stream); + mesh->mNumBones = Read(stream); + mesh->mMaterialIndex = Read(stream); + + // first of all, write bits for all existent vertex components + unsigned int c = Read(stream); + + if (c & ASSBIN_MESH_HAS_POSITIONS) + { + if (shortened) { + ReadBounds(stream,mesh->mVertices,mesh->mNumVertices); + } // else write as usual + else + { + mesh->mVertices = new aiVector3D[mesh->mNumVertices]; + ReadArray(stream,mesh->mVertices,mesh->mNumVertices); + } + } + if (c & ASSBIN_MESH_HAS_NORMALS) + { + if (shortened) { + ReadBounds(stream,mesh->mNormals,mesh->mNumVertices); + } // else write as usual + else + { + mesh->mNormals = new aiVector3D[mesh->mNumVertices]; + ReadArray(stream,mesh->mNormals,mesh->mNumVertices); + } + } + if (c & ASSBIN_MESH_HAS_TANGENTS_AND_BITANGENTS) + { + if (shortened) { + ReadBounds(stream,mesh->mTangents,mesh->mNumVertices); + ReadBounds(stream,mesh->mBitangents,mesh->mNumVertices); + } // else write as usual + else + { + mesh->mTangents = new aiVector3D[mesh->mNumVertices]; + ReadArray(stream,mesh->mTangents,mesh->mNumVertices); + mesh->mBitangents = new aiVector3D[mesh->mNumVertices]; + ReadArray(stream,mesh->mBitangents,mesh->mNumVertices); + } + } + for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS;++n) + { + if (!(c & ASSBIN_MESH_HAS_COLOR(n))) + break; + + if (shortened) + { + ReadBounds(stream,mesh->mColors[n],mesh->mNumVertices); + } // else write as usual + else + { + mesh->mColors[n] = new aiColor4D[mesh->mNumVertices]; + ReadArray(stream,mesh->mColors[n],mesh->mNumVertices); + } + } + for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n) + { + if (!(c & ASSBIN_MESH_HAS_TEXCOORD(n))) + break; + + // write number of UV components + mesh->mNumUVComponents[n] = Read(stream); + + if (shortened) { + ReadBounds(stream,mesh->mTextureCoords[n],mesh->mNumVertices); + } // else write as usual + else + { + mesh->mTextureCoords[n] = new aiVector3D[mesh->mNumVertices]; + ReadArray(stream,mesh->mTextureCoords[n],mesh->mNumVertices); + } + } + + // write faces. There are no floating-point calculations involved + // in these, so we can write a simple hash over the face data + // to the dump file. We generate a single 32 Bit hash for 512 faces + // using Assimp's standard hashing function. + if (shortened) { + Read(stream); + } + else // else write as usual + { + // if there are less than 2^16 vertices, we can simply use 16 bit integers ... + mesh->mFaces = new aiFace[mesh->mNumFaces]; + for (unsigned int i = 0; i < mesh->mNumFaces;++i) { + aiFace& f = mesh->mFaces[i]; + + static_assert(AI_MAX_FACE_INDICES <= 0xffff, "AI_MAX_FACE_INDICES <= 0xffff"); + f.mNumIndices = Read(stream); + f.mIndices = new unsigned int[f.mNumIndices]; + + for (unsigned int a = 0; a < f.mNumIndices;++a) { + if (mesh->mNumVertices < (1u<<16)) + { + f.mIndices[a] = Read(stream); + } + else + { + f.mIndices[a] = Read(stream); + } + } + } + } + + // write bones + if (mesh->mNumBones) { + mesh->mBones = new C_STRUCT aiBone*[mesh->mNumBones]; + for (unsigned int a = 0; a < mesh->mNumBones;++a) { + mesh->mBones[a] = new aiBone(); + ReadBinaryBone(stream,mesh->mBones[a]); + } + } +} + +void AssbinImporter::ReadBinaryMaterialProperty(IOStream * stream, aiMaterialProperty* prop) +{ + uint32_t chunkID = Read(stream); + ai_assert(chunkID == ASSBIN_CHUNK_AIMATERIALPROPERTY); + /*uint32_t size =*/ Read(stream); + + prop->mKey = Read(stream); + prop->mSemantic = Read(stream); + prop->mIndex = Read(stream); + + prop->mDataLength = Read(stream); + prop->mType = (aiPropertyTypeInfo)Read(stream); + prop->mData = new char [ prop->mDataLength ]; + stream->Read(prop->mData,1,prop->mDataLength); +} + +// ----------------------------------------------------------------------------------- +void AssbinImporter::ReadBinaryMaterial(IOStream * stream, aiMaterial* mat) +{ + uint32_t chunkID = Read(stream); + ai_assert(chunkID == ASSBIN_CHUNK_AIMATERIAL); + /*uint32_t size =*/ Read(stream); + + mat->mNumAllocated = mat->mNumProperties = Read(stream); + if (mat->mNumProperties) + { + if (mat->mProperties) + { + delete[] mat->mProperties; + } + mat->mProperties = new aiMaterialProperty*[mat->mNumProperties]; + for (unsigned int i = 0; i < mat->mNumProperties;++i) { + mat->mProperties[i] = new aiMaterialProperty(); + ReadBinaryMaterialProperty( stream, mat->mProperties[i]); + } + } +} + +// ----------------------------------------------------------------------------------- +void AssbinImporter::ReadBinaryNodeAnim(IOStream * stream, aiNodeAnim* nd) +{ + uint32_t chunkID = Read(stream); + ai_assert(chunkID == ASSBIN_CHUNK_AINODEANIM); + /*uint32_t size =*/ Read(stream); + + nd->mNodeName = Read(stream); + nd->mNumPositionKeys = Read(stream); + nd->mNumRotationKeys = Read(stream); + nd->mNumScalingKeys = Read(stream); + nd->mPreState = (aiAnimBehaviour)Read(stream); + nd->mPostState = (aiAnimBehaviour)Read(stream); + + if (nd->mNumPositionKeys) { + if (shortened) { + ReadBounds(stream,nd->mPositionKeys,nd->mNumPositionKeys); + + } // else write as usual + else { + nd->mPositionKeys = new aiVectorKey[nd->mNumPositionKeys]; + ReadArray(stream,nd->mPositionKeys,nd->mNumPositionKeys); + } + } + if (nd->mNumRotationKeys) { + if (shortened) { + ReadBounds(stream,nd->mRotationKeys,nd->mNumRotationKeys); + + } // else write as usual + else + { + nd->mRotationKeys = new aiQuatKey[nd->mNumRotationKeys]; + ReadArray(stream,nd->mRotationKeys,nd->mNumRotationKeys); + } + } + if (nd->mNumScalingKeys) { + if (shortened) { + ReadBounds(stream,nd->mScalingKeys,nd->mNumScalingKeys); + + } // else write as usual + else + { + nd->mScalingKeys = new aiVectorKey[nd->mNumScalingKeys]; + ReadArray(stream,nd->mScalingKeys,nd->mNumScalingKeys); + } + } +} + + +// ----------------------------------------------------------------------------------- +void AssbinImporter::ReadBinaryAnim( IOStream * stream, aiAnimation* anim ) +{ + uint32_t chunkID = Read(stream); + ai_assert(chunkID == ASSBIN_CHUNK_AIANIMATION); + /*uint32_t size =*/ Read(stream); + + anim->mName = Read (stream); + anim->mDuration = Read (stream); + anim->mTicksPerSecond = Read (stream); + anim->mNumChannels = Read(stream); + + if (anim->mNumChannels) + { + anim->mChannels = new aiNodeAnim*[ anim->mNumChannels ]; + for (unsigned int a = 0; a < anim->mNumChannels;++a) { + anim->mChannels[a] = new aiNodeAnim(); + ReadBinaryNodeAnim(stream,anim->mChannels[a]); + } + } +} + +void AssbinImporter::ReadBinaryTexture(IOStream * stream, aiTexture* tex) +{ + uint32_t chunkID = Read(stream); + ai_assert(chunkID == ASSBIN_CHUNK_AITEXTURE); + /*uint32_t size =*/ Read(stream); + + tex->mWidth = Read(stream); + tex->mHeight = Read(stream); + stream->Read( tex->achFormatHint, sizeof(char), 4 ); + + if(!shortened) { + if (!tex->mHeight) { + tex->pcData = new aiTexel[ tex->mWidth ]; + stream->Read(tex->pcData,1,tex->mWidth); + } + else { + tex->pcData = new aiTexel[ tex->mWidth*tex->mHeight ]; + stream->Read(tex->pcData,1,tex->mWidth*tex->mHeight*4); + } + } + +} + +// ----------------------------------------------------------------------------------- +void AssbinImporter::ReadBinaryLight( IOStream * stream, aiLight* l ) +{ + uint32_t chunkID = Read(stream); + ai_assert(chunkID == ASSBIN_CHUNK_AILIGHT); + /*uint32_t size =*/ Read(stream); + + l->mName = Read(stream); + l->mType = (aiLightSourceType)Read(stream); + + if (l->mType != aiLightSource_DIRECTIONAL) { + l->mAttenuationConstant = Read(stream); + l->mAttenuationLinear = Read(stream); + l->mAttenuationQuadratic = Read(stream); + } + + l->mColorDiffuse = Read(stream); + l->mColorSpecular = Read(stream); + l->mColorAmbient = Read(stream); + + if (l->mType == aiLightSource_SPOT) { + l->mAngleInnerCone = Read(stream); + l->mAngleOuterCone = Read(stream); + } + +} + +// ----------------------------------------------------------------------------------- +void AssbinImporter::ReadBinaryCamera( IOStream * stream, aiCamera* cam ) +{ + uint32_t chunkID = Read(stream); + ai_assert(chunkID == ASSBIN_CHUNK_AICAMERA); + /*uint32_t size =*/ Read(stream); + + cam->mName = Read(stream); + cam->mPosition = Read(stream); + cam->mLookAt = Read(stream); + cam->mUp = Read(stream); + cam->mHorizontalFOV = Read(stream); + cam->mClipPlaneNear = Read(stream); + cam->mClipPlaneFar = Read(stream); + cam->mAspect = Read(stream); +} + +void AssbinImporter::ReadBinaryScene( IOStream * stream, aiScene* scene ) +{ + uint32_t chunkID = Read(stream); + ai_assert(chunkID == ASSBIN_CHUNK_AISCENE); + /*uint32_t size =*/ Read(stream); + + scene->mFlags = Read(stream); + scene->mNumMeshes = Read(stream); + scene->mNumMaterials = Read(stream); + scene->mNumAnimations = Read(stream); + scene->mNumTextures = Read(stream); + scene->mNumLights = Read(stream); + scene->mNumCameras = Read(stream); + + // Read node graph + scene->mRootNode = new aiNode[1]; + ReadBinaryNode( stream, &scene->mRootNode ); + + // Read all meshes + if (scene->mNumMeshes) + { + scene->mMeshes = new aiMesh*[scene->mNumMeshes]; + for (unsigned int i = 0; i < scene->mNumMeshes;++i) { + scene->mMeshes[i] = new aiMesh(); + ReadBinaryMesh( stream,scene->mMeshes[i]); + } + } + + // Read materials + if (scene->mNumMaterials) + { + scene->mMaterials = new aiMaterial*[scene->mNumMaterials]; + for (unsigned int i = 0; i< scene->mNumMaterials; ++i) { + scene->mMaterials[i] = new aiMaterial(); + ReadBinaryMaterial(stream,scene->mMaterials[i]); + } + } + + // Read all animations + if (scene->mNumAnimations) + { + scene->mAnimations = new aiAnimation*[scene->mNumAnimations]; + for (unsigned int i = 0; i < scene->mNumAnimations;++i) { + scene->mAnimations[i] = new aiAnimation(); + ReadBinaryAnim(stream,scene->mAnimations[i]); + } + } + + // Read all textures + if (scene->mNumTextures) + { + scene->mTextures = new aiTexture*[scene->mNumTextures]; + for (unsigned int i = 0; i < scene->mNumTextures;++i) { + scene->mTextures[i] = new aiTexture(); + ReadBinaryTexture(stream,scene->mTextures[i]); + } + } + + // Read lights + if (scene->mNumLights) + { + scene->mLights = new aiLight*[scene->mNumLights]; + for (unsigned int i = 0; i < scene->mNumLights;++i) { + scene->mLights[i] = new aiLight(); + ReadBinaryLight(stream,scene->mLights[i]); + } + } + + // Read cameras + if (scene->mNumCameras) + { + scene->mCameras = new aiCamera*[scene->mNumCameras]; + for (unsigned int i = 0; i < scene->mNumCameras;++i) { + scene->mCameras[i] = new aiCamera(); + ReadBinaryCamera(stream,scene->mCameras[i]); + } + } + +} + +void AssbinImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler ) +{ + IOStream * stream = pIOHandler->Open(pFile,"rb"); + if (!stream) + return; + + stream->Seek( 44, aiOrigin_CUR ); // signature + + /*unsigned int versionMajor =*/ Read(stream); + /*unsigned int versionMinor =*/ Read(stream); + /*unsigned int versionRevision =*/ Read(stream); + /*unsigned int compileFlags =*/ Read(stream); + + shortened = Read(stream) > 0; + compressed = Read(stream) > 0; + + if (shortened) + throw DeadlyImportError( "Shortened binaries are not supported!" ); + + stream->Seek( 256, aiOrigin_CUR ); // original filename + stream->Seek( 128, aiOrigin_CUR ); // options + stream->Seek( 64, aiOrigin_CUR ); // padding + + if (compressed) + { + uLongf uncompressedSize = Read(stream); + uLongf compressedSize = stream->FileSize() - stream->Tell(); + + unsigned char * compressedData = new unsigned char[ compressedSize ]; + stream->Read( compressedData, 1, compressedSize ); + + unsigned char * uncompressedData = new unsigned char[ uncompressedSize ]; + + uncompress( uncompressedData, &uncompressedSize, compressedData, compressedSize ); + + MemoryIOStream io( uncompressedData, uncompressedSize ); + + ReadBinaryScene(&io,pScene); + + delete[] uncompressedData; + delete[] compressedData; + } + else + { + ReadBinaryScene(stream,pScene); + } + + pIOHandler->Close(stream); +} + +#endif // !! ASSIMP_BUILD_NO_ASSBIN_IMPORTER diff --git a/src/3rdparty/assimp/code/AssbinLoader.h b/src/3rdparty/assimp/code/AssbinLoader.h new file mode 100644 index 000000000..e8c8dd0cb --- /dev/null +++ b/src/3rdparty/assimp/code/AssbinLoader.h @@ -0,0 +1,105 @@ + +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2016, assimp team +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the +following conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +---------------------------------------------------------------------- +*/ + +/** @file AssbinLoader.h + * @brief .assbin File format loader + */ +#ifndef AI_ASSBINIMPORTER_H_INC +#define AI_ASSBINIMPORTER_H_INC + +#include "BaseImporter.h" +#include + +struct aiMesh; +struct aiNode; +struct aiBone; +struct aiMaterial; +struct aiMaterialProperty; +struct aiNodeAnim; +struct aiAnimation; +struct aiTexture; +struct aiLight; +struct aiCamera; + +#ifndef ASSIMP_BUILD_NO_ASSBIN_IMPORTER + +namespace Assimp { + +// --------------------------------------------------------------------------------- +/** Importer class for 3D Studio r3 and r4 3DS files + */ +class AssbinImporter : public BaseImporter +{ +private: + bool shortened; + bool compressed; +protected: + +public: + virtual bool CanRead( + const std::string& pFile, + IOSystem* pIOHandler, + bool checkSig + ) const; + virtual const aiImporterDesc* GetInfo() const; + virtual void InternReadFile( + const std::string& pFile, + aiScene* pScene, + IOSystem* pIOHandler + ); + void ReadBinaryScene( IOStream * stream, aiScene* pScene ); + void ReadBinaryNode( IOStream * stream, aiNode** mRootNode ); + void ReadBinaryMesh( IOStream * stream, aiMesh* mesh ); + void ReadBinaryBone( IOStream * stream, aiBone* bone ); + void ReadBinaryMaterial(IOStream * stream, aiMaterial* mat); + void ReadBinaryMaterialProperty(IOStream * stream, aiMaterialProperty* prop); + void ReadBinaryNodeAnim(IOStream * stream, aiNodeAnim* nd); + void ReadBinaryAnim( IOStream * stream, aiAnimation* anim ); + void ReadBinaryTexture(IOStream * stream, aiTexture* tex); + void ReadBinaryLight( IOStream * stream, aiLight* l ); + void ReadBinaryCamera( IOStream * stream, aiCamera* cam ); +}; + +} // end of namespace Assimp + +#endif // !! ASSIMP_BUILD_NO_ASSBIN_IMPORTER + +#endif // AI_ASSBINIMPORTER_H_INC diff --git a/src/3rdparty/assimp/code/Assimp.cpp b/src/3rdparty/assimp/code/Assimp.cpp index e5e696098..8507c8641 100644 --- a/src/3rdparty/assimp/code/Assimp.cpp +++ b/src/3rdparty/assimp/code/Assimp.cpp @@ -3,12 +3,12 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2012, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above @@ -25,16 +25,16 @@ conditions are met: derived from this software without specific prior written permission of the assimp team. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --------------------------------------------------------------------------- */ @@ -42,54 +42,68 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * @brief Implementation of the Plain-C API */ -#include "AssimpPCH.h" -#include "../include/assimp/cimport.h" +#include +#include +#include +#include +#include +#include #include "GenericProperty.h" #include "CInterfaceIOWrapper.h" #include "Importer.h" +#include "Exceptional.h" +#include "ScenePrivate.h" +#include "BaseImporter.h" +#include // ------------------------------------------------------------------------------------------------ #ifndef ASSIMP_BUILD_SINGLETHREADED -# include -# include +# include +# include #endif // ------------------------------------------------------------------------------------------------ using namespace Assimp; namespace Assimp { - // underlying structure for aiPropertyStore - typedef BatchLoader::PropertyMap PropertyMap; + // underlying structure for aiPropertyStore + typedef BatchLoader::PropertyMap PropertyMap; - /** Stores the LogStream objects for all active C log streams */ - struct mpred { - bool operator () (const aiLogStream& s0, const aiLogStream& s1) const { - return s0.callback LogStreamMap; + /** Stores the LogStream objects for all active C log streams */ + struct mpred { + bool operator () (const aiLogStream& s0, const aiLogStream& s1) const { + return s0.callback LogStreamMap; - /** Stores the LogStream objects allocated by #aiGetPredefinedLogStream */ - typedef std::list PredefLogStreamMap; + /** Stores the LogStream objects allocated by #aiGetPredefinedLogStream */ + typedef std::list PredefLogStreamMap; - /** Local storage of all active log streams */ - static LogStreamMap gActiveLogStreams; + /** Local storage of all active log streams */ + static LogStreamMap gActiveLogStreams; - /** Local storage of LogStreams allocated by #aiGetPredefinedLogStream */ - static PredefLogStreamMap gPredefinedStreams; + /** Local storage of LogStreams allocated by #aiGetPredefinedLogStream */ + static PredefLogStreamMap gPredefinedStreams; - /** Error message of the last failed import process */ - static std::string gLastErrorString; + /** Error message of the last failed import process */ + static std::string gLastErrorString; - /** Verbose logging active or not? */ - static aiBool gVerboseLogging = false; -} + /** Verbose logging active or not? */ + static aiBool gVerboseLogging = false; + + /** will return all registered importers. */ + void GetImporterInstanceList(std::vector< BaseImporter* >& out); + + /** will delete all registered importers. */ + void DeleteImporterInstanceList(std::vector< BaseImporter* >& out); +} // namespace assimp #ifndef ASSIMP_BUILD_SINGLETHREADED -/** Global mutex to manage the access to the logstream map */ -static boost::mutex gLogStreamMutex; +/** Global mutex to manage the access to the log-stream map */ +static std::mutex gLogStreamMutex; #endif @@ -98,512 +112,589 @@ static boost::mutex gLogStreamMutex; class LogToCallbackRedirector : public LogStream { public: - LogToCallbackRedirector(const aiLogStream& s) - : stream (s) { - ai_assert(NULL != s.callback); - } + explicit LogToCallbackRedirector(const aiLogStream& s) + : stream (s) { + ai_assert(NULL != s.callback); + } - ~LogToCallbackRedirector() { + ~LogToCallbackRedirector() { #ifndef ASSIMP_BUILD_SINGLETHREADED - boost::mutex::scoped_lock lock(gLogStreamMutex); + std::lock_guard lock(gLogStreamMutex); #endif - // (HACK) Check whether the 'stream.user' pointer points to a - // custom LogStream allocated by #aiGetPredefinedLogStream. - // In this case, we need to delete it, too. Of course, this - // might cause strange problems, but the chance is quite low. + // (HACK) Check whether the 'stream.user' pointer points to a + // custom LogStream allocated by #aiGetPredefinedLogStream. + // In this case, we need to delete it, too. Of course, this + // might cause strange problems, but the chance is quite low. - PredefLogStreamMap::iterator it = std::find(gPredefinedStreams.begin(), - gPredefinedStreams.end(), (Assimp::LogStream*)stream.user); + PredefLogStreamMap::iterator it = std::find(gPredefinedStreams.begin(), + gPredefinedStreams.end(), (Assimp::LogStream*)stream.user); - if (it != gPredefinedStreams.end()) { - delete *it; - gPredefinedStreams.erase(it); - } - } + if (it != gPredefinedStreams.end()) { + delete *it; + gPredefinedStreams.erase(it); + } + } - /** @copydoc LogStream::write */ - void write(const char* message) { - stream.callback(message,stream.user); - } + /** @copydoc LogStream::write */ + void write(const char* message) { + stream.callback(message,stream.user); + } private: - aiLogStream stream; + aiLogStream stream; }; // ------------------------------------------------------------------------------------------------ void ReportSceneNotFoundError() { - DefaultLogger::get()->error("Unable to find the Assimp::Importer for this aiScene. " - "The C-API does not accept scenes produced by the C++ API and vice versa"); + DefaultLogger::get()->error("Unable to find the Assimp::Importer for this aiScene. " + "The C-API does not accept scenes produced by the C++ API and vice versa"); - assert(false); + assert(false); } // ------------------------------------------------------------------------------------------------ -// Reads the given file and returns its content. +// Reads the given file and returns its content. const aiScene* aiImportFile( const char* pFile, unsigned int pFlags) { - return aiImportFileEx(pFile,pFlags,NULL); + return aiImportFileEx(pFile,pFlags,NULL); } // ------------------------------------------------------------------------------------------------ const aiScene* aiImportFileEx( const char* pFile, unsigned int pFlags, aiFileIO* pFS) { - return aiImportFileExWithProperties(pFile, pFlags, pFS, NULL); -} - + return aiImportFileExWithProperties(pFile, pFlags, pFS, NULL); +} + // ------------------------------------------------------------------------------------------------ -const aiScene* aiImportFileExWithProperties( const char* pFile, unsigned int pFlags, - aiFileIO* pFS, - const aiPropertyStore* props) +const aiScene* aiImportFileExWithProperties( const char* pFile, unsigned int pFlags, + aiFileIO* pFS, + const aiPropertyStore* props) { - ai_assert(NULL != pFile); + ai_assert(NULL != pFile); - const aiScene* scene = NULL; - ASSIMP_BEGIN_EXCEPTION_REGION(); + const aiScene* scene = NULL; + ASSIMP_BEGIN_EXCEPTION_REGION(); - // create an Importer for this file - Assimp::Importer* imp = new Assimp::Importer(); + // create an Importer for this file + Assimp::Importer* imp = new Assimp::Importer(); - // copy properties - if(props) { - const PropertyMap* pp = reinterpret_cast(props); - ImporterPimpl* pimpl = imp->Pimpl(); - pimpl->mIntProperties = pp->ints; - pimpl->mFloatProperties = pp->floats; - pimpl->mStringProperties = pp->strings; - pimpl->mMatrixProperties = pp->matrices; - } - // setup a custom IO system if necessary - if (pFS) { - imp->SetIOHandler( new CIOSystemWrapper (pFS) ); - } + // copy properties + if(props) { + const PropertyMap* pp = reinterpret_cast(props); + ImporterPimpl* pimpl = imp->Pimpl(); + pimpl->mIntProperties = pp->ints; + pimpl->mFloatProperties = pp->floats; + pimpl->mStringProperties = pp->strings; + pimpl->mMatrixProperties = pp->matrices; + } + // setup a custom IO system if necessary + if (pFS) { + imp->SetIOHandler( new CIOSystemWrapper (pFS) ); + } - // and have it read the file - scene = imp->ReadFile( pFile, pFlags); + // and have it read the file + scene = imp->ReadFile( pFile, pFlags); - // if succeeded, store the importer in the scene and keep it alive - if( scene) { - ScenePrivateData* priv = const_cast( ScenePriv(scene) ); - priv->mOrigImporter = imp; - } - else { - // if failed, extract error code and destroy the import - gLastErrorString = imp->GetErrorString(); - delete imp; - } + // if succeeded, store the importer in the scene and keep it alive + if( scene) { + ScenePrivateData* priv = const_cast( ScenePriv(scene) ); + priv->mOrigImporter = imp; + } + else { + // if failed, extract error code and destroy the import + gLastErrorString = imp->GetErrorString(); + delete imp; + } - // return imported data. If the import failed the pointer is NULL anyways - ASSIMP_END_EXCEPTION_REGION(const aiScene*); - return scene; + // return imported data. If the import failed the pointer is NULL anyways + ASSIMP_END_EXCEPTION_REGION(const aiScene*); + return scene; } // ------------------------------------------------------------------------------------------------ -const aiScene* aiImportFileFromMemory( - const char* pBuffer, - unsigned int pLength, - unsigned int pFlags, - const char* pHint) +const aiScene* aiImportFileFromMemory( + const char* pBuffer, + unsigned int pLength, + unsigned int pFlags, + const char* pHint) { - return aiImportFileFromMemoryWithProperties(pBuffer, pLength, pFlags, pHint, NULL); + return aiImportFileFromMemoryWithProperties(pBuffer, pLength, pFlags, pHint, NULL); } // ------------------------------------------------------------------------------------------------ -const aiScene* aiImportFileFromMemoryWithProperties( - const char* pBuffer, - unsigned int pLength, - unsigned int pFlags, - const char* pHint, - const aiPropertyStore* props) +const aiScene* aiImportFileFromMemoryWithProperties( + const char* pBuffer, + unsigned int pLength, + unsigned int pFlags, + const char* pHint, + const aiPropertyStore* props) { - ai_assert(NULL != pBuffer && 0 != pLength); + ai_assert( NULL != pBuffer ); + ai_assert( 0 != pLength ); - const aiScene* scene = NULL; - ASSIMP_BEGIN_EXCEPTION_REGION(); + const aiScene* scene = NULL; + ASSIMP_BEGIN_EXCEPTION_REGION(); - // create an Importer for this file - Assimp::Importer* imp = new Assimp::Importer(); + // create an Importer for this file + Assimp::Importer* imp = new Assimp::Importer(); - // copy properties - if(props) { - const PropertyMap* pp = reinterpret_cast(props); - ImporterPimpl* pimpl = imp->Pimpl(); - pimpl->mIntProperties = pp->ints; - pimpl->mFloatProperties = pp->floats; - pimpl->mStringProperties = pp->strings; - pimpl->mMatrixProperties = pp->matrices; - } + // copy properties + if(props) { + const PropertyMap* pp = reinterpret_cast(props); + ImporterPimpl* pimpl = imp->Pimpl(); + pimpl->mIntProperties = pp->ints; + pimpl->mFloatProperties = pp->floats; + pimpl->mStringProperties = pp->strings; + pimpl->mMatrixProperties = pp->matrices; + } - // and have it read the file from the memory buffer - scene = imp->ReadFileFromMemory( pBuffer, pLength, pFlags,pHint); + // and have it read the file from the memory buffer + scene = imp->ReadFileFromMemory( pBuffer, pLength, pFlags,pHint); - // if succeeded, store the importer in the scene and keep it alive - if( scene) { - ScenePrivateData* priv = const_cast( ScenePriv(scene) ); - priv->mOrigImporter = imp; - } - else { - // if failed, extract error code and destroy the import - gLastErrorString = imp->GetErrorString(); - delete imp; - } - // return imported data. If the import failed the pointer is NULL anyways - ASSIMP_END_EXCEPTION_REGION(const aiScene*); - return scene; -} - -// ------------------------------------------------------------------------------------------------ -// Releases all resources associated with the given import process. + // if succeeded, store the importer in the scene and keep it alive + if( scene) { + ScenePrivateData* priv = const_cast( ScenePriv(scene) ); + priv->mOrigImporter = imp; + } + else { + // if failed, extract error code and destroy the import + gLastErrorString = imp->GetErrorString(); + delete imp; + } + // return imported data. If the import failed the pointer is NULL anyways + ASSIMP_END_EXCEPTION_REGION(const aiScene*); + return scene; +} + +// ------------------------------------------------------------------------------------------------ +// Releases all resources associated with the given import process. void aiReleaseImport( const aiScene* pScene) { - if (!pScene) { - return; - } - - ASSIMP_BEGIN_EXCEPTION_REGION(); - - // find the importer associated with this data - const ScenePrivateData* priv = ScenePriv(pScene); - if( !priv || !priv->mOrigImporter) { - delete pScene; - } - else { - // deleting the Importer also deletes the scene - // Note: the reason that this is not written as 'delete priv->mOrigImporter' - // is a suspected bug in gcc 4.4+ (http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52339) - Importer* importer = priv->mOrigImporter; - delete importer; - } - - ASSIMP_END_EXCEPTION_REGION(void); + if (!pScene) { + return; + } + + ASSIMP_BEGIN_EXCEPTION_REGION(); + + // find the importer associated with this data + const ScenePrivateData* priv = ScenePriv(pScene); + if( !priv || !priv->mOrigImporter) { + delete pScene; + } + else { + // deleting the Importer also deletes the scene + // Note: the reason that this is not written as 'delete priv->mOrigImporter' + // is a suspected bug in gcc 4.4+ (http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52339) + Importer* importer = priv->mOrigImporter; + delete importer; + } + + ASSIMP_END_EXCEPTION_REGION(void); } // ------------------------------------------------------------------------------------------------ ASSIMP_API const aiScene* aiApplyPostProcessing(const aiScene* pScene, - unsigned int pFlags) + unsigned int pFlags) { - const aiScene* sc = NULL; - + const aiScene* sc = NULL; + - ASSIMP_BEGIN_EXCEPTION_REGION(); + ASSIMP_BEGIN_EXCEPTION_REGION(); - // find the importer associated with this data - const ScenePrivateData* priv = ScenePriv(pScene); - if( !priv || !priv->mOrigImporter) { - ReportSceneNotFoundError(); - return NULL; - } + // find the importer associated with this data + const ScenePrivateData* priv = ScenePriv(pScene); + if( !priv || !priv->mOrigImporter) { + ReportSceneNotFoundError(); + return NULL; + } - sc = priv->mOrigImporter->ApplyPostProcessing(pFlags); + sc = priv->mOrigImporter->ApplyPostProcessing(pFlags); - if (!sc) { - aiReleaseImport(pScene); - return NULL; - } + if (!sc) { + aiReleaseImport(pScene); + return NULL; + } - ASSIMP_END_EXCEPTION_REGION(const aiScene*); - return sc; + ASSIMP_END_EXCEPTION_REGION(const aiScene*); + return sc; +} + +// ------------------------------------------------------------------------------------------------ +ASSIMP_API const aiScene *aiApplyCustomizedPostProcessing( const aiScene *scene, + BaseProcess* process, + bool requestValidation ) { + const aiScene* sc( NULL ); + + ASSIMP_BEGIN_EXCEPTION_REGION(); + + // find the importer associated with this data + const ScenePrivateData* priv = ScenePriv( scene ); + if ( NULL == priv || NULL == priv->mOrigImporter ) { + ReportSceneNotFoundError(); + return NULL; + } + + sc = priv->mOrigImporter->ApplyCustomizedPostProcessing( process, requestValidation ); + + if ( !sc ) { + aiReleaseImport( scene ); + return NULL; + } + + ASSIMP_END_EXCEPTION_REGION( const aiScene* ); + + return sc; } // ------------------------------------------------------------------------------------------------ void CallbackToLogRedirector (const char* msg, char* dt) { - ai_assert(NULL != msg && NULL != dt); - LogStream* s = (LogStream*)dt; + ai_assert( NULL != msg ); + ai_assert( NULL != dt ); + LogStream* s = (LogStream*)dt; - s->write(msg); + s->write(msg); } // ------------------------------------------------------------------------------------------------ ASSIMP_API aiLogStream aiGetPredefinedLogStream(aiDefaultLogStream pStream,const char* file) { - aiLogStream sout; + aiLogStream sout; - ASSIMP_BEGIN_EXCEPTION_REGION(); - LogStream* stream = LogStream::createDefaultStream(pStream,file); - if (!stream) { - sout.callback = NULL; - sout.user = NULL; - } - else { - sout.callback = &CallbackToLogRedirector; - sout.user = (char*)stream; - } - gPredefinedStreams.push_back(stream); - ASSIMP_END_EXCEPTION_REGION(aiLogStream); - return sout; + ASSIMP_BEGIN_EXCEPTION_REGION(); + LogStream* stream = LogStream::createDefaultStream(pStream,file); + if (!stream) { + sout.callback = NULL; + sout.user = NULL; + } + else { + sout.callback = &CallbackToLogRedirector; + sout.user = (char*)stream; + } + gPredefinedStreams.push_back(stream); + ASSIMP_END_EXCEPTION_REGION(aiLogStream); + return sout; } // ------------------------------------------------------------------------------------------------ ASSIMP_API void aiAttachLogStream( const aiLogStream* stream ) { - ASSIMP_BEGIN_EXCEPTION_REGION(); + ASSIMP_BEGIN_EXCEPTION_REGION(); #ifndef ASSIMP_BUILD_SINGLETHREADED - boost::mutex::scoped_lock lock(gLogStreamMutex); + std::lock_guard lock(gLogStreamMutex); #endif - LogStream* lg = new LogToCallbackRedirector(*stream); - gActiveLogStreams[*stream] = lg; + LogStream* lg = new LogToCallbackRedirector(*stream); + gActiveLogStreams[*stream] = lg; - if (DefaultLogger::isNullLogger()) { - DefaultLogger::create(NULL,(gVerboseLogging == AI_TRUE ? Logger::VERBOSE : Logger::NORMAL)); - } - DefaultLogger::get()->attachStream(lg); - ASSIMP_END_EXCEPTION_REGION(void); + if (DefaultLogger::isNullLogger()) { + DefaultLogger::create(NULL,(gVerboseLogging == AI_TRUE ? Logger::VERBOSE : Logger::NORMAL)); + } + DefaultLogger::get()->attachStream(lg); + ASSIMP_END_EXCEPTION_REGION(void); } // ------------------------------------------------------------------------------------------------ ASSIMP_API aiReturn aiDetachLogStream( const aiLogStream* stream) { - ASSIMP_BEGIN_EXCEPTION_REGION(); + ASSIMP_BEGIN_EXCEPTION_REGION(); #ifndef ASSIMP_BUILD_SINGLETHREADED - boost::mutex::scoped_lock lock(gLogStreamMutex); + std::lock_guard lock(gLogStreamMutex); #endif - // find the logstream associated with this data - LogStreamMap::iterator it = gActiveLogStreams.find( *stream); - // it should be there... else the user is playing fools with us - if( it == gActiveLogStreams.end()) { - return AI_FAILURE; - } - DefaultLogger::get()->detatchStream( it->second ); - delete it->second; + // find the log-stream associated with this data + LogStreamMap::iterator it = gActiveLogStreams.find( *stream); + // it should be there... else the user is playing fools with us + if( it == gActiveLogStreams.end()) { + return AI_FAILURE; + } + DefaultLogger::get()->detatchStream( it->second ); + delete it->second; - gActiveLogStreams.erase( it); + gActiveLogStreams.erase( it); - if (gActiveLogStreams.empty()) { - DefaultLogger::kill(); - } - ASSIMP_END_EXCEPTION_REGION(aiReturn); - return AI_SUCCESS; + if (gActiveLogStreams.empty()) { + DefaultLogger::kill(); + } + ASSIMP_END_EXCEPTION_REGION(aiReturn); + return AI_SUCCESS; } // ------------------------------------------------------------------------------------------------ ASSIMP_API void aiDetachAllLogStreams(void) { - ASSIMP_BEGIN_EXCEPTION_REGION(); + ASSIMP_BEGIN_EXCEPTION_REGION(); #ifndef ASSIMP_BUILD_SINGLETHREADED - boost::mutex::scoped_lock lock(gLogStreamMutex); + std::lock_guard lock(gLogStreamMutex); #endif - for (LogStreamMap::iterator it = gActiveLogStreams.begin(); it != gActiveLogStreams.end(); ++it) { - DefaultLogger::get()->detatchStream( it->second ); - delete it->second; - } - gActiveLogStreams.clear(); - DefaultLogger::kill(); - ASSIMP_END_EXCEPTION_REGION(void); + Logger *logger( DefaultLogger::get() ); + if ( NULL == logger ) { + return; + } + + for (LogStreamMap::iterator it = gActiveLogStreams.begin(); it != gActiveLogStreams.end(); ++it) { + logger->detatchStream( it->second ); + delete it->second; + } + gActiveLogStreams.clear(); + DefaultLogger::kill(); + + ASSIMP_END_EXCEPTION_REGION(void); } // ------------------------------------------------------------------------------------------------ ASSIMP_API void aiEnableVerboseLogging(aiBool d) { - if (!DefaultLogger::isNullLogger()) { - DefaultLogger::get()->setLogSeverity((d == AI_TRUE ? Logger::VERBOSE : Logger::NORMAL)); - } - gVerboseLogging = d; + if (!DefaultLogger::isNullLogger()) { + DefaultLogger::get()->setLogSeverity((d == AI_TRUE ? Logger::VERBOSE : Logger::NORMAL)); + } + gVerboseLogging = d; } // ------------------------------------------------------------------------------------------------ -// Returns the error text of the last failed import process. +// Returns the error text of the last failed import process. const char* aiGetErrorString() { - return gLastErrorString.c_str(); + return gLastErrorString.c_str(); +} + +// ----------------------------------------------------------------------------------------------- +// Return the description of a importer given its index +const aiImporterDesc* aiGetImportFormatDescription( size_t pIndex) +{ + return Importer().GetImporterInfo(pIndex); +} + +// ----------------------------------------------------------------------------------------------- +// Return the number of importers +size_t aiGetImportFormatCount(void) +{ + return Importer().GetImporterCount(); } // ------------------------------------------------------------------------------------------------ -// Returns the error text of the last failed import process. +// Returns the error text of the last failed import process. aiBool aiIsExtensionSupported(const char* szExtension) { - ai_assert(NULL != szExtension); - aiBool candoit=AI_FALSE; - ASSIMP_BEGIN_EXCEPTION_REGION(); + ai_assert(NULL != szExtension); + aiBool candoit=AI_FALSE; + ASSIMP_BEGIN_EXCEPTION_REGION(); - // FIXME: no need to create a temporary Importer instance just for that .. - Assimp::Importer tmp; - candoit = tmp.IsExtensionSupported(std::string(szExtension)) ? AI_TRUE : AI_FALSE; + // FIXME: no need to create a temporary Importer instance just for that .. + Assimp::Importer tmp; + candoit = tmp.IsExtensionSupported(std::string(szExtension)) ? AI_TRUE : AI_FALSE; - ASSIMP_END_EXCEPTION_REGION(aiBool); - return candoit; + ASSIMP_END_EXCEPTION_REGION(aiBool); + return candoit; } // ------------------------------------------------------------------------------------------------ // Get a list of all file extensions supported by ASSIMP void aiGetExtensionList(aiString* szOut) { - ai_assert(NULL != szOut); - ASSIMP_BEGIN_EXCEPTION_REGION(); + ai_assert(NULL != szOut); + ASSIMP_BEGIN_EXCEPTION_REGION(); - // FIXME: no need to create a temporary Importer instance just for that .. - Assimp::Importer tmp; - tmp.GetExtensionList(*szOut); + // FIXME: no need to create a temporary Importer instance just for that .. + Assimp::Importer tmp; + tmp.GetExtensionList(*szOut); - ASSIMP_END_EXCEPTION_REGION(void); + ASSIMP_END_EXCEPTION_REGION(void); } // ------------------------------------------------------------------------------------------------ // Get the memory requirements for a particular import. void aiGetMemoryRequirements(const C_STRUCT aiScene* pIn, - C_STRUCT aiMemoryInfo* in) + C_STRUCT aiMemoryInfo* in) { - ASSIMP_BEGIN_EXCEPTION_REGION(); + ASSIMP_BEGIN_EXCEPTION_REGION(); - // find the importer associated with this data - const ScenePrivateData* priv = ScenePriv(pIn); - if( !priv || !priv->mOrigImporter) { - ReportSceneNotFoundError(); - return; - } + // find the importer associated with this data + const ScenePrivateData* priv = ScenePriv(pIn); + if( !priv || !priv->mOrigImporter) { + ReportSceneNotFoundError(); + return; + } - return priv->mOrigImporter->GetMemoryRequirements(*in); - ASSIMP_END_EXCEPTION_REGION(void); + return priv->mOrigImporter->GetMemoryRequirements(*in); + ASSIMP_END_EXCEPTION_REGION(void); } // ------------------------------------------------------------------------------------------------ ASSIMP_API aiPropertyStore* aiCreatePropertyStore(void) { - return reinterpret_cast( new PropertyMap() ); + return reinterpret_cast( new PropertyMap() ); } - // ------------------------------------------------------------------------------------------------ ASSIMP_API void aiReleasePropertyStore(aiPropertyStore* p) { - delete reinterpret_cast(p); + delete reinterpret_cast(p); } // ------------------------------------------------------------------------------------------------ // Importer::SetPropertyInteger ASSIMP_API void aiSetImportPropertyInteger(aiPropertyStore* p, const char* szName, int value) { - ASSIMP_BEGIN_EXCEPTION_REGION(); - PropertyMap* pp = reinterpret_cast(p); - SetGenericProperty(pp->ints,szName,value,NULL); - ASSIMP_END_EXCEPTION_REGION(void); + ASSIMP_BEGIN_EXCEPTION_REGION(); + PropertyMap* pp = reinterpret_cast(p); + SetGenericProperty(pp->ints,szName,value); + ASSIMP_END_EXCEPTION_REGION(void); } // ------------------------------------------------------------------------------------------------ // Importer::SetPropertyFloat ASSIMP_API void aiSetImportPropertyFloat(aiPropertyStore* p, const char* szName, float value) { - ASSIMP_BEGIN_EXCEPTION_REGION(); - PropertyMap* pp = reinterpret_cast(p); - SetGenericProperty(pp->floats,szName,value,NULL); - ASSIMP_END_EXCEPTION_REGION(void); + ASSIMP_BEGIN_EXCEPTION_REGION(); + PropertyMap* pp = reinterpret_cast(p); + SetGenericProperty(pp->floats,szName,value); + ASSIMP_END_EXCEPTION_REGION(void); } // ------------------------------------------------------------------------------------------------ // Importer::SetPropertyString ASSIMP_API void aiSetImportPropertyString(aiPropertyStore* p, const char* szName, - const C_STRUCT aiString* st) + const C_STRUCT aiString* st) { - if (!st) { - return; - } - ASSIMP_BEGIN_EXCEPTION_REGION(); - PropertyMap* pp = reinterpret_cast(p); - SetGenericProperty(pp->strings,szName,std::string(st->C_Str()),NULL); - ASSIMP_END_EXCEPTION_REGION(void); + if (!st) { + return; + } + ASSIMP_BEGIN_EXCEPTION_REGION(); + PropertyMap* pp = reinterpret_cast(p); + SetGenericProperty(pp->strings,szName,std::string(st->C_Str())); + ASSIMP_END_EXCEPTION_REGION(void); } // ------------------------------------------------------------------------------------------------ // Importer::SetPropertyMatrix ASSIMP_API void aiSetImportPropertyMatrix(aiPropertyStore* p, const char* szName, - const C_STRUCT aiMatrix4x4* mat) + const C_STRUCT aiMatrix4x4* mat) { - if (!mat) { - return; - } - ASSIMP_BEGIN_EXCEPTION_REGION(); - PropertyMap* pp = reinterpret_cast(p); - SetGenericProperty(pp->matrices,szName,*mat,NULL); - ASSIMP_END_EXCEPTION_REGION(void); + if (!mat) { + return; + } + ASSIMP_BEGIN_EXCEPTION_REGION(); + PropertyMap* pp = reinterpret_cast(p); + SetGenericProperty(pp->matrices,szName,*mat); + ASSIMP_END_EXCEPTION_REGION(void); } // ------------------------------------------------------------------------------------------------ // Rotation matrix to quaternion ASSIMP_API void aiCreateQuaternionFromMatrix(aiQuaternion* quat,const aiMatrix3x3* mat) { - ai_assert(NULL != quat && NULL != mat); - *quat = aiQuaternion(*mat); + ai_assert( NULL != quat ); + ai_assert( NULL != mat ); + *quat = aiQuaternion(*mat); } // ------------------------------------------------------------------------------------------------ // Matrix decomposition ASSIMP_API void aiDecomposeMatrix(const aiMatrix4x4* mat,aiVector3D* scaling, - aiQuaternion* rotation, - aiVector3D* position) + aiQuaternion* rotation, + aiVector3D* position) { - ai_assert(NULL != rotation && NULL != position && NULL != scaling && NULL != mat); - mat->Decompose(*scaling,*rotation,*position); + ai_assert( NULL != rotation ); + ai_assert( NULL != position ); + ai_assert( NULL != scaling ); + ai_assert( NULL != mat ); + mat->Decompose(*scaling,*rotation,*position); } // ------------------------------------------------------------------------------------------------ // Matrix transpose ASSIMP_API void aiTransposeMatrix3(aiMatrix3x3* mat) { - ai_assert(NULL != mat); - mat->Transpose(); + ai_assert(NULL != mat); + mat->Transpose(); } // ------------------------------------------------------------------------------------------------ ASSIMP_API void aiTransposeMatrix4(aiMatrix4x4* mat) { - ai_assert(NULL != mat); - mat->Transpose(); + ai_assert(NULL != mat); + mat->Transpose(); } // ------------------------------------------------------------------------------------------------ // Vector transformation -ASSIMP_API void aiTransformVecByMatrix3(aiVector3D* vec, - const aiMatrix3x3* mat) +ASSIMP_API void aiTransformVecByMatrix3(aiVector3D* vec, + const aiMatrix3x3* mat) { - ai_assert(NULL != mat && NULL != vec); - *vec *= (*mat); + ai_assert( NULL != mat ); + ai_assert( NULL != vec); + *vec *= (*mat); } // ------------------------------------------------------------------------------------------------ -ASSIMP_API void aiTransformVecByMatrix4(aiVector3D* vec, - const aiMatrix4x4* mat) +ASSIMP_API void aiTransformVecByMatrix4(aiVector3D* vec, + const aiMatrix4x4* mat) { - ai_assert(NULL != mat && NULL != vec); - *vec *= (*mat); + ai_assert( NULL != mat ); + ai_assert( NULL != vec ); + + *vec *= (*mat); } // ------------------------------------------------------------------------------------------------ // Matrix multiplication ASSIMP_API void aiMultiplyMatrix4( - aiMatrix4x4* dst, - const aiMatrix4x4* src) + aiMatrix4x4* dst, + const aiMatrix4x4* src) { - ai_assert(NULL != dst && NULL != src); - *dst = (*dst) * (*src); + ai_assert( NULL != dst ); + ai_assert( NULL != src ); + *dst = (*dst) * (*src); } // ------------------------------------------------------------------------------------------------ ASSIMP_API void aiMultiplyMatrix3( - aiMatrix3x3* dst, - const aiMatrix3x3* src) + aiMatrix3x3* dst, + const aiMatrix3x3* src) { - ai_assert(NULL != dst && NULL != src); - *dst = (*dst) * (*src); + ai_assert( NULL != dst ); + ai_assert( NULL != src ); + *dst = (*dst) * (*src); } // ------------------------------------------------------------------------------------------------ // Matrix identity ASSIMP_API void aiIdentityMatrix3( - aiMatrix3x3* mat) + aiMatrix3x3* mat) { - ai_assert(NULL != mat); - *mat = aiMatrix3x3(); + ai_assert(NULL != mat); + *mat = aiMatrix3x3(); } // ------------------------------------------------------------------------------------------------ ASSIMP_API void aiIdentityMatrix4( - aiMatrix4x4* mat) + aiMatrix4x4* mat) { - ai_assert(NULL != mat); - *mat = aiMatrix4x4(); + ai_assert(NULL != mat); + *mat = aiMatrix4x4(); } +// ------------------------------------------------------------------------------------------------ +ASSIMP_API C_STRUCT const aiImporterDesc* aiGetImporterDesc( const char *extension ) { + if( NULL == extension ) { + return NULL; + } + const aiImporterDesc *desc( NULL ); + std::vector< BaseImporter* > out; + GetImporterInstanceList( out ); + for( size_t i = 0; i < out.size(); ++i ) { + if( 0 == strncmp( out[ i ]->GetInfo()->mFileExtensions, extension, strlen( extension ) ) ) { + desc = out[ i ]->GetInfo(); + break; + } + } + + DeleteImporterInstanceList(out); + + return desc; +} +// ------------------------------------------------------------------------------------------------ diff --git a/src/3rdparty/assimp/code/AssimpCExport.cpp b/src/3rdparty/assimp/code/AssimpCExport.cpp index 1f806f133..c5f26fc47 100644 --- a/src/3rdparty/assimp/code/AssimpCExport.cpp +++ b/src/3rdparty/assimp/code/AssimpCExport.cpp @@ -3,12 +3,12 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2012, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above @@ -25,16 +25,16 @@ conditions are met: derived from this software without specific prior written permission of the assimp team. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --------------------------------------------------------------------------- */ @@ -43,85 +43,112 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Assimp C export interface. See Exporter.cpp for some notes. */ -#include "AssimpPCH.h" - #ifndef ASSIMP_BUILD_NO_EXPORT -#include "CInterfaceIOWrapper.h" +#include "CInterfaceIOWrapper.h" #include "SceneCombiner.h" +#include "ScenePrivate.h" +#include using namespace Assimp; // ------------------------------------------------------------------------------------------------ ASSIMP_API size_t aiGetExportFormatCount(void) { - return Exporter().GetExportFormatCount(); + return Exporter().GetExportFormatCount(); } // ------------------------------------------------------------------------------------------------ -ASSIMP_API const aiExportFormatDesc* aiGetExportFormatDescription( size_t pIndex) +ASSIMP_API const aiExportFormatDesc* aiGetExportFormatDescription( size_t index) { - return Exporter().GetExportFormatDescription(pIndex); + // Note: this is valid as the index always pertains to a built-in exporter, + // for which the returned structure is guaranteed to be of static storage duration. + Exporter exporter; + const aiExportFormatDesc* orig( exporter.GetExportFormatDescription( index ) ); + if (NULL == orig) { + return NULL; + } + + aiExportFormatDesc *desc = new aiExportFormatDesc; + desc->description = new char[ strlen( orig->description ) + 1 ]; + ::strncpy( (char*) desc->description, orig->description, strlen( orig->description ) ); + desc->fileExtension = new char[ strlen( orig->fileExtension ) + 1 ]; + ::strncpy( ( char* ) desc->fileExtension, orig->fileExtension, strlen( orig->fileExtension ) ); + desc->id = new char[ strlen( orig->id ) + 1 ]; + ::strncpy( ( char* ) desc->id, orig->id, strlen( orig->id ) ); + + return desc; } +// ------------------------------------------------------------------------------------------------ +ASSIMP_API void aiReleaseExportFormatDescription( const aiExportFormatDesc *desc ) { + if (NULL == desc) { + return; + } + + delete [] desc->description; + delete [] desc->fileExtension; + delete [] desc->id; + delete desc; +} // ------------------------------------------------------------------------------------------------ ASSIMP_API void aiCopyScene(const aiScene* pIn, aiScene** pOut) { - if (!pOut || !pIn) { - return; - } + if (!pOut || !pIn) { + return; + } - SceneCombiner::CopyScene(pOut,pIn,true); - ScenePriv(*pOut)->mIsCopy = true; + SceneCombiner::CopyScene(pOut,pIn,true); + ScenePriv(*pOut)->mIsCopy = true; } // ------------------------------------------------------------------------------------------------ ASSIMP_API void aiFreeScene(const C_STRUCT aiScene* pIn) { - // note: aiReleaseImport() is also able to delete scene copies, but in addition - // it also handles scenes with import metadata. - delete pIn; + // note: aiReleaseImport() is also able to delete scene copies, but in addition + // it also handles scenes with import metadata. + delete pIn; } // ------------------------------------------------------------------------------------------------ ASSIMP_API aiReturn aiExportScene( const aiScene* pScene, const char* pFormatId, const char* pFileName, unsigned int pPreprocessing ) { - return ::aiExportSceneEx(pScene,pFormatId,pFileName,NULL,pPreprocessing); + return ::aiExportSceneEx(pScene,pFormatId,pFileName,NULL,pPreprocessing); } // ------------------------------------------------------------------------------------------------ ASSIMP_API aiReturn aiExportSceneEx( const aiScene* pScene, const char* pFormatId, const char* pFileName, aiFileIO* pIO, unsigned int pPreprocessing ) { - Exporter exp; + Exporter exp; - if (pIO) { - exp.SetIOHandler(new CIOSystemWrapper(pIO)); - } - return exp.Export(pScene,pFormatId,pFileName,pPreprocessing); + if (pIO) { + exp.SetIOHandler(new CIOSystemWrapper(pIO)); + } + return exp.Export(pScene,pFormatId,pFileName,pPreprocessing); } // ------------------------------------------------------------------------------------------------ ASSIMP_API const C_STRUCT aiExportDataBlob* aiExportSceneToBlob( const aiScene* pScene, const char* pFormatId, unsigned int pPreprocessing ) { - Exporter exp; - if (!exp.ExportToBlob(pScene,pFormatId,pPreprocessing)) { - return NULL; - } - const aiExportDataBlob* blob = exp.GetOrphanedBlob(); - ai_assert(blob); - - return blob; + Exporter exp; + if (!exp.ExportToBlob(pScene,pFormatId,pPreprocessing)) { + return NULL; + } + const aiExportDataBlob* blob = exp.GetOrphanedBlob(); + ai_assert(blob); + + return blob; } // ------------------------------------------------------------------------------------------------ ASSIMP_API C_STRUCT void aiReleaseExportBlob( const aiExportDataBlob* pData ) { - delete pData; + delete pData; } #endif // !ASSIMP_BUILD_NO_EXPORT diff --git a/src/3rdparty/assimp/code/AssimpPCH.cpp b/src/3rdparty/assimp/code/AssimpPCH.cpp deleted file mode 100644 index 1f61feb2c..000000000 --- a/src/3rdparty/assimp/code/AssimpPCH.cpp +++ /dev/null @@ -1,135 +0,0 @@ - -// Actually just a dummy, used by the compiler to build the precompiled header. - -#include "AssimpPCH.h" -#include "./../include/assimp/version.h" - -static const unsigned int MajorVersion = 3; -static const unsigned int MinorVersion = 1; - -// -------------------------------------------------------------------------------- -// Legal information string - dont't remove this. -static const char* LEGAL_INFORMATION = - -"Open Asset Import Library (Assimp).\n" -"A free C/C++ library to import various 3D file formats into applications\n\n" - -"(c) 2008-2010, assimp team\n" -"License under the terms and conditions of the 3-clause BSD license\n" -"http://assimp.sourceforge.net\n" -; - -// ------------------------------------------------------------------------------------------------ -// Get legal string -ASSIMP_API const char* aiGetLegalString () { - return LEGAL_INFORMATION; -} - -// ------------------------------------------------------------------------------------------------ -// Get Assimp minor version -ASSIMP_API unsigned int aiGetVersionMinor () { - return MinorVersion; -} - -// ------------------------------------------------------------------------------------------------ -// Get Assimp major version -ASSIMP_API unsigned int aiGetVersionMajor () { - return MajorVersion; -} - -// ------------------------------------------------------------------------------------------------ -// Get flags used for compilation -ASSIMP_API unsigned int aiGetCompileFlags () { - - unsigned int flags = 0; - -#ifdef ASSIMP_BUILD_BOOST_WORKAROUND - flags |= ASSIMP_CFLAGS_NOBOOST; -#endif -#ifdef ASSIMP_BUILD_SINGLETHREADED - flags |= ASSIMP_CFLAGS_SINGLETHREADED; -#endif -#ifdef ASSIMP_BUILD_DEBUG - flags |= ASSIMP_CFLAGS_DEBUG; -#endif -#ifdef ASSIMP_BUILD_DLL_EXPORT - flags |= ASSIMP_CFLAGS_SHARED; -#endif -#ifdef _STLPORT_VERSION - flags |= ASSIMP_CFLAGS_STLPORT; -#endif - - return flags; -} - -// include current build revision, which is even updated from time to time -- :-) -#include "revision.h" - -// ------------------------------------------------------------------------------------------------ -ASSIMP_API unsigned int aiGetVersionRevision () -{ - return GitVersion; -} - -// ------------------------------------------------------------------------------------------------ -ASSIMP_API aiScene::aiScene() - : mFlags(0) - , mRootNode(NULL) - , mNumMeshes(0) - , mMeshes(NULL) - , mNumMaterials(0) - , mMaterials(NULL) - , mNumAnimations(0) - , mAnimations(NULL) - , mNumTextures(0) - , mTextures(NULL) - , mNumLights(0) - , mLights(NULL) - , mNumCameras(0) - , mCameras(NULL) - , mPrivate(new Assimp::ScenePrivateData()) - { - } - -// ------------------------------------------------------------------------------------------------ -ASSIMP_API aiScene::~aiScene() -{ - // delete all sub-objects recursively - delete mRootNode; - - // To make sure we won't crash if the data is invalid it's - // much better to check whether both mNumXXX and mXXX are - // valid instead of relying on just one of them. - if (mNumMeshes && mMeshes) - for( unsigned int a = 0; a < mNumMeshes; a++) - delete mMeshes[a]; - delete [] mMeshes; - - if (mNumMaterials && mMaterials) - for( unsigned int a = 0; a < mNumMaterials; a++) - delete mMaterials[a]; - delete [] mMaterials; - - if (mNumAnimations && mAnimations) - for( unsigned int a = 0; a < mNumAnimations; a++) - delete mAnimations[a]; - delete [] mAnimations; - - if (mNumTextures && mTextures) - for( unsigned int a = 0; a < mNumTextures; a++) - delete mTextures[a]; - delete [] mTextures; - - if (mNumLights && mLights) - for( unsigned int a = 0; a < mNumLights; a++) - delete mLights[a]; - delete [] mLights; - - if (mNumCameras && mCameras) - for( unsigned int a = 0; a < mNumCameras; a++) - delete mCameras[a]; - delete [] mCameras; - - delete static_cast( mPrivate ); -} - diff --git a/src/3rdparty/assimp/code/AssimpPCH.h b/src/3rdparty/assimp/code/AssimpPCH.h deleted file mode 100644 index 8fe30f31b..000000000 --- a/src/3rdparty/assimp/code/AssimpPCH.h +++ /dev/null @@ -1,166 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2012, assimp team - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ - -/** @file AssimpPCH.h - * PCH master include. Every unit in Assimp has to include it. - */ - -#ifndef ASSIMP_PCH_INCLUDED -#define ASSIMP_PCH_INCLUDED -#define ASSIMP_INTERNAL_BUILD - -// ---------------------------------------------------------------------------------------- -/* General compile config taken from defs.h. It is important that the user compiles - * using exactly the same settings in defs.h. Settings in AssimpPCH.h may differ, - * they won't affect the public API. - */ -#include "../include/assimp/defs.h" - -// Include our stdint.h replacement header for MSVC, take the global header for gcc/mingw -#if defined( _MSC_VER) && (_MSC_VER < 1600) -# include "../include/assimp/Compiler/pstdint.h" -#else -# include -#endif - -/* Undefine the min/max macros defined by some platform headers (namely Windows.h) to - * avoid obvious conflicts with std::min() and std::max(). - */ -#undef min -#undef max - -/* Concatenate two tokens after evaluating them - */ -#define _AI_CONCAT(a,b) a ## b -#define AI_CONCAT(a,b) _AI_CONCAT(a,b) - -/* Helper macro to set a pointer to NULL in debug builds - */ -#if (defined ASSIMP_BUILD_DEBUG) -# define AI_DEBUG_INVALIDATE_PTR(x) x = NULL; -#else -# define AI_DEBUG_INVALIDATE_PTR(x) -#endif - -/* Beginning with MSVC8 some C string manipulation functions are mapped to their _safe_ - * counterparts (e.g. _itoa_s). This avoids a lot of trouble with deprecation warnings. - */ -#if _MSC_VER >= 1400 && !(defined _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES) -# define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1 -#endif - -/* size_t to unsigned int, possible loss of data. The compiler is right with his warning - * but this loss of data won't be a problem for us. So shut up, little boy. - */ -#ifdef _MSC_VER -# pragma warning (disable : 4267) -#endif - -// ---------------------------------------------------------------------------------------- -/* Actually that's not required for MSVC. It is included somewhere in the deeper parts of - * the MSVC STL but it's necessary for proper build with STLport. - */ -#include - -#ifdef Q_OS_QNX -#include -#endif - -// Runtime/STL headers -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// Boost headers -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// Public ASSIMP headers -#include "../include/assimp/DefaultLogger.hpp" -#include "../include/assimp/IOStream.hpp" -#include "../include/assimp/IOSystem.hpp" -#include "../include/assimp/scene.h" -#include "../include/assimp/importerdesc.h" -#include "../include/assimp/postprocess.h" -#include "../include/assimp/Importer.hpp" -#include "../include/assimp/Exporter.hpp" - -// Internal utility headers -#include "BaseImporter.h" -#include "StringComparison.h" -#include "StreamReader.h" -#include "qnan.h" -#include "ScenePrivate.h" - - -// We need those constants, workaround for any platforms where nobody defined them yet -#if (!defined SIZE_MAX) -# define SIZE_MAX (~((size_t)0)) -#endif - -#if (!defined UINT_MAX) -# define UINT_MAX (~((unsigned int)0)) -#endif - - -#endif // !! ASSIMP_PCH_INCLUDED diff --git a/src/3rdparty/assimp/code/AssxmlExporter.cpp b/src/3rdparty/assimp/code/AssxmlExporter.cpp new file mode 100644 index 000000000..cf18837f5 --- /dev/null +++ b/src/3rdparty/assimp/code/AssxmlExporter.cpp @@ -0,0 +1,648 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2016, assimp team +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the +following conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +---------------------------------------------------------------------- +*/ +/** @file AssxmlExporter.cpp + * ASSXML exporter main code + */ +#include +#include "./../include/assimp/version.h" +#include "ProcessHelper.h" +#include +#include +#include + +#ifdef ASSIMP_BUILD_NO_OWN_ZLIB +# include +#else +# include +#endif + +#include +#include + +#ifndef ASSIMP_BUILD_NO_EXPORT +#ifndef ASSIMP_BUILD_NO_ASSXML_EXPORTER + +using namespace Assimp; + +namespace Assimp { + +namespace AssxmlExport { + +// ----------------------------------------------------------------------------------- +static int ioprintf( IOStream * io, const char *format, ... ) { + using namespace std; + if ( nullptr == io ) { + return -1; + } + + static const int Size = 4096; + char sz[ Size ]; + size_t len( strlen( format ) ); + ::memset( sz, '\0', Size ); + va_list va; + va_start( va, format ); + int nSize = vsnprintf( sz, Size-1, format, va ); + ai_assert( nSize < Size ); + va_end( va ); + + io->Write( sz, sizeof(char), nSize ); + + return nSize; +} + +// ----------------------------------------------------------------------------------- +// Convert a name to standard XML format +static void ConvertName(aiString& out, const aiString& in) { + out.length = 0; + for (unsigned int i = 0; i < in.length; ++i) { + switch (in.data[i]) { + case '<': + out.Append("<");break; + case '>': + out.Append(">");break; + case '&': + out.Append("&");break; + case '\"': + out.Append(""");break; + case '\'': + out.Append("'");break; + default: + out.data[out.length++] = in.data[i]; + } + } + out.data[out.length] = 0; +} + +// ----------------------------------------------------------------------------------- +// Write a single node as text dump +static void WriteNode(const aiNode* node, IOStream * io, unsigned int depth) { + char prefix[512]; + for (unsigned int i = 0; i < depth;++i) + prefix[i] = '\t'; + prefix[depth] = '\0'; + + const aiMatrix4x4& m = node->mTransformation; + + aiString name; + ConvertName(name,node->mName); + ioprintf(io,"%s \n" + "%s\t \n" + "%s\t\t%0 6f %0 6f %0 6f %0 6f\n" + "%s\t\t%0 6f %0 6f %0 6f %0 6f\n" + "%s\t\t%0 6f %0 6f %0 6f %0 6f\n" + "%s\t\t%0 6f %0 6f %0 6f %0 6f\n" + "%s\t \n", + prefix,name.data,prefix, + prefix,m.a1,m.a2,m.a3,m.a4, + prefix,m.b1,m.b2,m.b3,m.b4, + prefix,m.c1,m.c2,m.c3,m.c4, + prefix,m.d1,m.d2,m.d3,m.d4,prefix); + + if (node->mNumMeshes) { + ioprintf(io, "%s\t\n%s\t", + prefix,node->mNumMeshes,prefix); + + for (unsigned int i = 0; i < node->mNumMeshes;++i) { + ioprintf(io,"%i ",node->mMeshes[i]); + } + ioprintf(io,"\n%s\t\n",prefix); + } + + if (node->mNumChildren) { + ioprintf(io,"%s\t\n", + prefix,node->mNumChildren); + + for (unsigned int i = 0; i < node->mNumChildren;++i) { + WriteNode(node->mChildren[i],io,depth+2); + } + ioprintf(io,"%s\t\n",prefix); + } + ioprintf(io,"%s\n",prefix); +} + + +// ----------------------------------------------------------------------------------- +// Some chuncks of text will need to be encoded for XML +// http://stackoverflow.com/questions/5665231/most-efficient-way-to-escape-xml-html-in-c-string#5665377 +static std::string encodeXML(const std::string& data) { + std::string buffer; + buffer.reserve(data.size()); + for(size_t pos = 0; pos != data.size(); ++pos) { + switch(data[pos]) { + case '&': buffer.append("&"); break; + case '\"': buffer.append("""); break; + case '\'': buffer.append("'"); break; + case '<': buffer.append("<"); break; + case '>': buffer.append(">"); break; + default: buffer.append(&data[pos], 1); break; + } + } + return buffer; +} + +// ----------------------------------------------------------------------------------- +// Write a text model dump +static +void WriteDump(const aiScene* scene, IOStream* io, bool shortened) { + time_t tt = ::time( NULL ); + tm* p = ::gmtime( &tt ); + ai_assert( nullptr != p ); + + // write header + std::string header( + "\n" + "\n\n" + "" + " \n\n" + "\n" + ); + + const unsigned int majorVersion( aiGetVersionMajor() ); + const unsigned int minorVersion( aiGetVersionMinor() ); + const unsigned int rev( aiGetVersionRevision() ); + const char *curtime( asctime( p ) ); + ioprintf( io, header.c_str(), majorVersion, minorVersion, rev, curtime, scene->mFlags, 0 ); + + // write the node graph + WriteNode(scene->mRootNode, io, 0); + +#if 0 + // write cameras + for (unsigned int i = 0; i < scene->mNumCameras;++i) { + aiCamera* cam = scene->mCameras[i]; + ConvertName(name,cam->mName); + + // camera header + ioprintf(io,"\t\n" + "\t\t %0 8f %0 8f %0 8f \n" + "\t\t %0 8f %0 8f %0 8f \n" + "\t\t %0 8f %0 8f %0 8f \n" + "\t\t %f \n" + "\t\t %f \n" + "\t\t %f \n" + "\t\t %f \n" + "\t\n", + name.data, + cam->mUp.x,cam->mUp.y,cam->mUp.z, + cam->mLookAt.x,cam->mLookAt.y,cam->mLookAt.z, + cam->mPosition.x,cam->mPosition.y,cam->mPosition.z, + cam->mHorizontalFOV,cam->mAspect,cam->mClipPlaneNear,cam->mClipPlaneFar,i); + } + + // write lights + for (unsigned int i = 0; i < scene->mNumLights;++i) { + aiLight* l = scene->mLights[i]; + ConvertName(name,l->mName); + + // light header + ioprintf(io,"\t type=\"%s\"\n" + "\t\t %0 8f %0 8f %0 8f \n" + "\t\t %0 8f %0 8f %0 8f \n" + "\t\t %0 8f %0 8f %0 8f \n", + name.data, + (l->mType == aiLightSource_DIRECTIONAL ? "directional" : + (l->mType == aiLightSource_POINT ? "point" : "spot" )), + l->mColorDiffuse.r, l->mColorDiffuse.g, l->mColorDiffuse.b, + l->mColorSpecular.r,l->mColorSpecular.g,l->mColorSpecular.b, + l->mColorAmbient.r, l->mColorAmbient.g, l->mColorAmbient.b); + + if (l->mType != aiLightSource_DIRECTIONAL) { + ioprintf(io, + "\t\t %0 8f %0 8f %0 8f \n" + "\t\t %f \n" + "\t\t %f \n" + "\t\t %f \n", + l->mPosition.x,l->mPosition.y,l->mPosition.z, + l->mAttenuationConstant,l->mAttenuationLinear,l->mAttenuationQuadratic); + } + + if (l->mType != aiLightSource_POINT) { + ioprintf(io, + "\t\t %0 8f %0 8f %0 8f \n", + l->mDirection.x,l->mDirection.y,l->mDirection.z); + } + + if (l->mType == aiLightSource_SPOT) { + ioprintf(io, + "\t\t %f \n" + "\t\t %f \n", + l->mAngleOuterCone,l->mAngleInnerCone); + } + ioprintf(io,"\t\n"); + } +#endif + aiString name; + + // write textures + if (scene->mNumTextures) { + ioprintf(io,"\n",scene->mNumTextures); + for (unsigned int i = 0; i < scene->mNumTextures;++i) { + aiTexture* tex = scene->mTextures[i]; + bool compressed = (tex->mHeight == 0); + + // mesh header + ioprintf(io,"\t \n", + (compressed ? -1 : tex->mWidth),(compressed ? -1 : tex->mHeight), + (compressed ? "true" : "false")); + + if (compressed) { + ioprintf(io,"\t\t \n",tex->mWidth); + + if (!shortened) { + for (unsigned int n = 0; n < tex->mWidth;++n) { + ioprintf(io,"\t\t\t%2x",reinterpret_cast(tex->pcData)[n]); + if (n && !(n % 50)) { + ioprintf(io,"\n"); + } + } + } + } + else if (!shortened){ + ioprintf(io,"\t\t \n",tex->mWidth*tex->mHeight*4); + + // const unsigned int width = (unsigned int)log10((double)std::max(tex->mHeight,tex->mWidth))+1; + for (unsigned int y = 0; y < tex->mHeight;++y) { + for (unsigned int x = 0; x < tex->mWidth;++x) { + aiTexel* tx = tex->pcData + y*tex->mWidth+x; + unsigned int r = tx->r,g=tx->g,b=tx->b,a=tx->a; + ioprintf(io,"\t\t\t%2x %2x %2x %2x",r,g,b,a); + + // group by four for readability + if ( 0 == ( x + y*tex->mWidth ) % 4 ) { + ioprintf( io, "\n" ); + } + } + } + } + ioprintf(io,"\t\t\n\t\n"); + } + ioprintf(io,"\n"); + } + + // write materials + if (scene->mNumMaterials) { + ioprintf(io,"\n",scene->mNumMaterials); + for (unsigned int i = 0; i< scene->mNumMaterials; ++i) { + const aiMaterial* mat = scene->mMaterials[i]; + + ioprintf(io,"\t\n"); + ioprintf(io,"\t\t\n",mat->mNumProperties); + for (unsigned int n = 0; n < mat->mNumProperties;++n) { + + const aiMaterialProperty* prop = mat->mProperties[n]; + const char* sz = ""; + if (prop->mType == aiPTI_Float) { + sz = "float"; + } + else if (prop->mType == aiPTI_Integer) { + sz = "integer"; + } + else if (prop->mType == aiPTI_String) { + sz = "string"; + } + else if (prop->mType == aiPTI_Buffer) { + sz = "binary_buffer"; + } + + ioprintf(io,"\t\t\tmKey.data, sz, + ::TextureTypeToString((aiTextureType)prop->mSemantic),prop->mIndex); + + if (prop->mType == aiPTI_Float) { + ioprintf(io," size=\"%i\">\n\t\t\t\t", + static_cast(prop->mDataLength/sizeof(float))); + + for (unsigned int p = 0; p < prop->mDataLength/sizeof(float);++p) { + ioprintf(io,"%f ",*((float*)(prop->mData+p*sizeof(float)))); + } + } + else if (prop->mType == aiPTI_Integer) { + ioprintf(io," size=\"%i\">\n\t\t\t\t", + static_cast(prop->mDataLength/sizeof(int))); + + for (unsigned int p = 0; p < prop->mDataLength/sizeof(int);++p) { + ioprintf(io,"%i ",*((int*)(prop->mData+p*sizeof(int)))); + } + } + else if (prop->mType == aiPTI_Buffer) { + ioprintf(io," size=\"%i\">\n\t\t\t\t", + static_cast(prop->mDataLength)); + + for (unsigned int p = 0; p < prop->mDataLength;++p) { + ioprintf(io,"%2x ",prop->mData[p]); + if (p && 0 == p%30) { + ioprintf(io,"\n\t\t\t\t"); + } + } + } + else if (prop->mType == aiPTI_String) { + ioprintf(io,">\n\t\t\t\t\"%s\"",encodeXML(prop->mData+4).c_str() /* skip length */); + } + ioprintf(io,"\n\t\t\t\n"); + } + ioprintf(io,"\t\t\n"); + ioprintf(io,"\t\n"); + } + ioprintf(io,"\n"); + } + + // write animations + if (scene->mNumAnimations) { + ioprintf(io,"\n",scene->mNumAnimations); + for (unsigned int i = 0; i < scene->mNumAnimations;++i) { + aiAnimation* anim = scene->mAnimations[i]; + + // anim header + ConvertName(name,anim->mName); + ioprintf(io,"\t\n", + name.data, anim->mDuration, anim->mTicksPerSecond); + + // write bone animation channels + if (anim->mNumChannels) { + ioprintf(io,"\t\t\n",anim->mNumChannels); + for (unsigned int n = 0; n < anim->mNumChannels;++n) { + aiNodeAnim* nd = anim->mChannels[n]; + + // node anim header + ConvertName(name,nd->mNodeName); + ioprintf(io,"\t\t\t\n",name.data); + + if (!shortened) { + // write position keys + if (nd->mNumPositionKeys) { + ioprintf(io,"\t\t\t\t\n",nd->mNumPositionKeys); + for (unsigned int a = 0; a < nd->mNumPositionKeys;++a) { + aiVectorKey* vc = nd->mPositionKeys+a; + ioprintf(io,"\t\t\t\t\t\n" + "\t\t\t\t\t\t%0 8f %0 8f %0 8f\n\t\t\t\t\t\n", + vc->mTime,vc->mValue.x,vc->mValue.y,vc->mValue.z); + } + ioprintf(io,"\t\t\t\t\n"); + } + + // write scaling keys + if (nd->mNumScalingKeys) { + ioprintf(io,"\t\t\t\t\n",nd->mNumScalingKeys); + for (unsigned int a = 0; a < nd->mNumScalingKeys;++a) { + aiVectorKey* vc = nd->mScalingKeys+a; + ioprintf(io,"\t\t\t\t\t\n" + "\t\t\t\t\t\t%0 8f %0 8f %0 8f\n\t\t\t\t\t\n", + vc->mTime,vc->mValue.x,vc->mValue.y,vc->mValue.z); + } + ioprintf(io,"\t\t\t\t\n"); + } + + // write rotation keys + if (nd->mNumRotationKeys) { + ioprintf(io,"\t\t\t\t\n",nd->mNumRotationKeys); + for (unsigned int a = 0; a < nd->mNumRotationKeys;++a) { + aiQuatKey* vc = nd->mRotationKeys+a; + ioprintf(io,"\t\t\t\t\t\n" + "\t\t\t\t\t\t%0 8f %0 8f %0 8f %0 8f\n\t\t\t\t\t\n", + vc->mTime,vc->mValue.x,vc->mValue.y,vc->mValue.z,vc->mValue.w); + } + ioprintf(io,"\t\t\t\t\n"); + } + } + ioprintf(io,"\t\t\t\n"); + } + ioprintf(io,"\t\t\n"); + } + ioprintf(io,"\t\n"); + } + ioprintf(io,"\n"); + } + + // write meshes + if (scene->mNumMeshes) { + ioprintf(io,"\n",scene->mNumMeshes); + for (unsigned int i = 0; i < scene->mNumMeshes;++i) { + aiMesh* mesh = scene->mMeshes[i]; + // const unsigned int width = (unsigned int)log10((double)mesh->mNumVertices)+1; + + // mesh header + ioprintf(io,"\t\n", + (mesh->mPrimitiveTypes & aiPrimitiveType_POINT ? "points" : ""), + (mesh->mPrimitiveTypes & aiPrimitiveType_LINE ? "lines" : ""), + (mesh->mPrimitiveTypes & aiPrimitiveType_TRIANGLE ? "triangles" : ""), + (mesh->mPrimitiveTypes & aiPrimitiveType_POLYGON ? "polygons" : ""), + mesh->mMaterialIndex); + + // bones + if (mesh->mNumBones) { + ioprintf(io,"\t\t\n",mesh->mNumBones); + + for (unsigned int n = 0; n < mesh->mNumBones;++n) { + aiBone* bone = mesh->mBones[n]; + + ConvertName(name,bone->mName); + // bone header + ioprintf(io,"\t\t\t\n" + "\t\t\t\t \n" + "\t\t\t\t\t%0 6f %0 6f %0 6f %0 6f\n" + "\t\t\t\t\t%0 6f %0 6f %0 6f %0 6f\n" + "\t\t\t\t\t%0 6f %0 6f %0 6f %0 6f\n" + "\t\t\t\t\t%0 6f %0 6f %0 6f %0 6f\n" + "\t\t\t\t \n", + name.data, + bone->mOffsetMatrix.a1,bone->mOffsetMatrix.a2,bone->mOffsetMatrix.a3,bone->mOffsetMatrix.a4, + bone->mOffsetMatrix.b1,bone->mOffsetMatrix.b2,bone->mOffsetMatrix.b3,bone->mOffsetMatrix.b4, + bone->mOffsetMatrix.c1,bone->mOffsetMatrix.c2,bone->mOffsetMatrix.c3,bone->mOffsetMatrix.c4, + bone->mOffsetMatrix.d1,bone->mOffsetMatrix.d2,bone->mOffsetMatrix.d3,bone->mOffsetMatrix.d4); + + if (!shortened && bone->mNumWeights) { + ioprintf(io,"\t\t\t\t\n",bone->mNumWeights); + + // bone weights + for (unsigned int a = 0; a < bone->mNumWeights;++a) { + aiVertexWeight* wght = bone->mWeights+a; + + ioprintf(io,"\t\t\t\t\t\n\t\t\t\t\t\t%f\n\t\t\t\t\t\n", + wght->mVertexId,wght->mWeight); + } + ioprintf(io,"\t\t\t\t\n"); + } + ioprintf(io,"\t\t\t\n"); + } + ioprintf(io,"\t\t\n"); + } + + // faces + if (!shortened && mesh->mNumFaces) { + ioprintf(io,"\t\t\n",mesh->mNumFaces); + for (unsigned int n = 0; n < mesh->mNumFaces; ++n) { + aiFace& f = mesh->mFaces[n]; + ioprintf(io,"\t\t\t\n" + "\t\t\t\t",f.mNumIndices); + + for (unsigned int j = 0; j < f.mNumIndices;++j) + ioprintf(io,"%i ",f.mIndices[j]); + + ioprintf(io,"\n\t\t\t\n"); + } + ioprintf(io,"\t\t\n"); + } + + // vertex positions + if (mesh->HasPositions()) { + ioprintf(io,"\t\t \n",mesh->mNumVertices); + if (!shortened) { + for (unsigned int n = 0; n < mesh->mNumVertices; ++n) { + ioprintf(io,"\t\t%0 8f %0 8f %0 8f\n", + mesh->mVertices[n].x, + mesh->mVertices[n].y, + mesh->mVertices[n].z); + } + } + ioprintf(io,"\t\t\n"); + } + + // vertex normals + if (mesh->HasNormals()) { + ioprintf(io,"\t\t \n",mesh->mNumVertices); + if (!shortened) { + for (unsigned int n = 0; n < mesh->mNumVertices; ++n) { + ioprintf(io,"\t\t%0 8f %0 8f %0 8f\n", + mesh->mNormals[n].x, + mesh->mNormals[n].y, + mesh->mNormals[n].z); + } + } + else { + } + ioprintf(io,"\t\t\n"); + } + + // vertex tangents and bitangents + if (mesh->HasTangentsAndBitangents()) { + ioprintf(io,"\t\t \n",mesh->mNumVertices); + if (!shortened) { + for (unsigned int n = 0; n < mesh->mNumVertices; ++n) { + ioprintf(io,"\t\t%0 8f %0 8f %0 8f\n", + mesh->mTangents[n].x, + mesh->mTangents[n].y, + mesh->mTangents[n].z); + } + } + ioprintf(io,"\t\t\n"); + + ioprintf(io,"\t\t \n",mesh->mNumVertices); + if (!shortened) { + for (unsigned int n = 0; n < mesh->mNumVertices; ++n) { + ioprintf(io,"\t\t%0 8f %0 8f %0 8f\n", + mesh->mBitangents[n].x, + mesh->mBitangents[n].y, + mesh->mBitangents[n].z); + } + } + ioprintf(io,"\t\t\n"); + } + + // texture coordinates + for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a) { + if (!mesh->mTextureCoords[a]) + break; + + ioprintf(io,"\t\t \n",mesh->mNumVertices, + a,mesh->mNumUVComponents[a]); + + if (!shortened) { + if (mesh->mNumUVComponents[a] == 3) { + for (unsigned int n = 0; n < mesh->mNumVertices; ++n) { + ioprintf(io,"\t\t%0 8f %0 8f %0 8f\n", + mesh->mTextureCoords[a][n].x, + mesh->mTextureCoords[a][n].y, + mesh->mTextureCoords[a][n].z); + } + } + else { + for (unsigned int n = 0; n < mesh->mNumVertices; ++n) { + ioprintf(io,"\t\t%0 8f %0 8f\n", + mesh->mTextureCoords[a][n].x, + mesh->mTextureCoords[a][n].y); + } + } + } + ioprintf(io,"\t\t\n"); + } + + // vertex colors + for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; ++a) { + if (!mesh->mColors[a]) + break; + ioprintf(io,"\t\t \n",mesh->mNumVertices,a); + if (!shortened) { + for (unsigned int n = 0; n < mesh->mNumVertices; ++n) { + ioprintf(io,"\t\t%0 8f %0 8f %0 8f %0 8f\n", + mesh->mColors[a][n].r, + mesh->mColors[a][n].g, + mesh->mColors[a][n].b, + mesh->mColors[a][n].a); + } + } + ioprintf(io,"\t\t\n"); + } + ioprintf(io,"\t\n"); + } + ioprintf(io,"\n"); + } + ioprintf(io,"\n"); +} + +} // end of namespace AssxmlExport + +void ExportSceneAssxml(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* pProperties) +{ + IOStream * out = pIOSystem->Open( pFile, "wt" ); + if (!out) return; + + bool shortened = false; + AssxmlExport::WriteDump( pScene, out, shortened ); + + pIOSystem->Close( out ); +} + +} // end of namespace Assimp + +#endif // ASSIMP_BUILD_NO_ASSXML_EXPORTER +#endif // ASSIMP_BUILD_NO_EXPORT diff --git a/src/3rdparty/assimp/code/AssxmlExporter.h b/src/3rdparty/assimp/code/AssxmlExporter.h new file mode 100644 index 000000000..ba9921f70 --- /dev/null +++ b/src/3rdparty/assimp/code/AssxmlExporter.h @@ -0,0 +1,49 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2016, assimp team +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the +following conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +---------------------------------------------------------------------- +*/ + +/** @file AssxmlExporter.h + * ASSXML Exporter Main Header + */ +#ifndef AI_ASSXMLEXPORTER_H_INC +#define AI_ASSXMLEXPORTER_H_INC + +// nothing really needed here - reserved for future use like properties + +#endif diff --git a/src/3rdparty/assimp/code/B3DImporter.cpp b/src/3rdparty/assimp/code/B3DImporter.cpp index a2908d446..1b9ba1433 100644 --- a/src/3rdparty/assimp/code/B3DImporter.cpp +++ b/src/3rdparty/assimp/code/B3DImporter.cpp @@ -3,12 +3,12 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2012, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above @@ -25,16 +25,16 @@ conditions are met: derived from this software without specific prior written permission of the assimp team. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --------------------------------------------------------------------------- */ @@ -43,32 +43,39 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * @brief Implementation of the b3d importer class */ -#include "AssimpPCH.h" + #ifndef ASSIMP_BUILD_NO_B3D_IMPORTER // internal headers #include "B3DImporter.h" #include "TextureTransform.h" #include "ConvertToLHProcess.h" +#include "StringUtils.h" +#include +#include +#include +#include +#include + using namespace Assimp; using namespace std; static const aiImporterDesc desc = { - "BlitzBasic 3D Importer", - "", - "", - "http://www.blitzbasic.com/", - aiImporterFlags_SupportBinaryFlavour, - 0, - 0, - 0, - 0, - "b3d" + "BlitzBasic 3D Importer", + "", + "", + "http://www.blitzbasic.com/", + aiImporterFlags_SupportBinaryFlavour, + 0, + 0, + 0, + 0, + "b3d" }; // (fixme, Aramis) quick workaround to get rid of all those signed to unsigned warnings -#ifdef _MSC_VER +#ifdef _MSC_VER # pragma warning (disable: 4018) #endif @@ -77,611 +84,613 @@ static const aiImporterDesc desc = { // ------------------------------------------------------------------------------------------------ bool B3DImporter::CanRead( const std::string& pFile, IOSystem* /*pIOHandler*/, bool /*checkSig*/) const{ - size_t pos=pFile.find_last_of( '.' ); - if( pos==string::npos ) return false; + size_t pos=pFile.find_last_of( '.' ); + if( pos==string::npos ) return false; - string ext=pFile.substr( pos+1 ); - if( ext.size()!=3 ) return false; + string ext=pFile.substr( pos+1 ); + if( ext.size()!=3 ) return false; - return (ext[0]=='b' || ext[0]=='B') && (ext[1]=='3') && (ext[2]=='d' || ext[2]=='D'); + return (ext[0]=='b' || ext[0]=='B') && (ext[1]=='3') && (ext[2]=='d' || ext[2]=='D'); } // ------------------------------------------------------------------------------------------------ // Loader meta information const aiImporterDesc* B3DImporter::GetInfo () const { - return &desc; + return &desc; } #ifdef DEBUG_B3D - extern "C"{ void _stdcall AllocConsole(); } + extern "C"{ void _stdcall AllocConsole(); } #endif // ------------------------------------------------------------------------------------------------ void B3DImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler){ #ifdef DEBUG_B3D - AllocConsole(); - freopen( "conin$","r",stdin ); - freopen( "conout$","w",stdout ); - freopen( "conout$","w",stderr ); - cout<<"Hello world from the B3DImporter!"< file( pIOHandler->Open( pFile)); + std::unique_ptr file( pIOHandler->Open( pFile)); - // Check whether we can read from the file - if( file.get() == NULL) - throw DeadlyImportError( "Failed to open B3D file " + pFile + "."); + // Check whether we can read from the file + if( file.get() == NULL) + throw DeadlyImportError( "Failed to open B3D file " + pFile + "."); - // check whether the .b3d file is large enough to contain - // at least one chunk. - size_t fileSize = file->FileSize(); - if( fileSize<8 ) throw DeadlyImportError( "B3D File is too small."); + // check whether the .b3d file is large enough to contain + // at least one chunk. + size_t fileSize = file->FileSize(); + if( fileSize<8 ) throw DeadlyImportError( "B3D File is too small."); - _pos=0; - _buf.resize( fileSize ); - file->Read( &_buf[0],1,fileSize ); - _stack.clear(); + _pos=0; + _buf.resize( fileSize ); + file->Read( &_buf[0],1,fileSize ); + _stack.clear(); - ReadBB3D( pScene ); + ReadBB3D( pScene ); } // ------------------------------------------------------------------------------------------------ -void B3DImporter::Oops(){ - throw DeadlyImportError( "B3D Importer - INTERNAL ERROR" ); +AI_WONT_RETURN void B3DImporter::Oops(){ + throw DeadlyImportError( "B3D Importer - INTERNAL ERROR" ); } // ------------------------------------------------------------------------------------------------ -void B3DImporter::Fail( string str ){ +AI_WONT_RETURN void B3DImporter::Fail( string str ){ #ifdef DEBUG_B3D - cout<<"Error in B3D file data: "< T *B3DImporter::to_array( const vector &v ){ - if( !v.size() ) return 0; - T *p=new T[v.size()]; - for( size_t i=0;i8 ){ - Fail( "Bad texture count" ); - } - while( ChunkSize() ){ - string name=ReadString(); - aiVector3D color=ReadVec3(); - float alpha=ReadFloat(); - float shiny=ReadFloat(); - /*int blend=**/ReadInt(); - int fx=ReadInt(); - - aiMaterial *mat=new aiMaterial; - _materials.push_back( mat ); - - // Name - aiString ainame( name ); - mat->AddProperty( &ainame,AI_MATKEY_NAME ); - - // Diffuse color - mat->AddProperty( &color,1,AI_MATKEY_COLOR_DIFFUSE ); - - // Opacity - mat->AddProperty( &alpha,1,AI_MATKEY_OPACITY ); - - // Specular color - aiColor3D speccolor( shiny,shiny,shiny ); - mat->AddProperty( &speccolor,1,AI_MATKEY_COLOR_SPECULAR ); - - // Specular power - float specpow=shiny*128; - mat->AddProperty( &specpow,1,AI_MATKEY_SHININESS ); - - // Double sided - if( fx & 0x10 ){ - int i=1; - mat->AddProperty( &i,1,AI_MATKEY_TWOSIDED ); - } - - //Textures - for( int i=0;i=0 && texid>=static_cast(_textures.size())) ){ - Fail( "Bad texture id" ); - } - if( i==0 && texid>=0 ){ - aiString texname( _textures[texid] ); - mat->AddProperty( &texname,AI_MATKEY_TEXTURE_DIFFUSE(0) ); - } - } - } + int n_texs=ReadInt(); + if( n_texs<0 || n_texs>8 ){ + Fail( "Bad texture count" ); + } + while( ChunkSize() ){ + string name=ReadString(); + aiVector3D color=ReadVec3(); + float alpha=ReadFloat(); + float shiny=ReadFloat(); + /*int blend=**/ReadInt(); + int fx=ReadInt(); + + aiMaterial *mat=new aiMaterial; + _materials.push_back( mat ); + + // Name + aiString ainame( name ); + mat->AddProperty( &ainame,AI_MATKEY_NAME ); + + // Diffuse color + mat->AddProperty( &color,1,AI_MATKEY_COLOR_DIFFUSE ); + + // Opacity + mat->AddProperty( &alpha,1,AI_MATKEY_OPACITY ); + + // Specular color + aiColor3D speccolor( shiny,shiny,shiny ); + mat->AddProperty( &speccolor,1,AI_MATKEY_COLOR_SPECULAR ); + + // Specular power + float specpow=shiny*128; + mat->AddProperty( &specpow,1,AI_MATKEY_SHININESS ); + + // Double sided + if( fx & 0x10 ){ + int i=1; + mat->AddProperty( &i,1,AI_MATKEY_TWOSIDED ); + } + + //Textures + for( int i=0;i=0 && texid>=static_cast(_textures.size())) ){ + Fail( "Bad texture id" ); + } + if( i==0 && texid>=0 ){ + aiString texname( _textures[texid] ); + mat->AddProperty( &texname,AI_MATKEY_TEXTURE_DIFFUSE(0) ); + } + } + } } // ------------------------------------------------------------------------------------------------ void B3DImporter::ReadVRTS(){ - _vflags=ReadInt(); - _tcsets=ReadInt(); - _tcsize=ReadInt(); - if( _tcsets<0 || _tcsets>4 || _tcsize<0 || _tcsize>4 ){ - Fail( "Bad texcoord data" ); - } + _vflags=ReadInt(); + _tcsets=ReadInt(); + _tcsize=ReadInt(); + if( _tcsets<0 || _tcsets>4 || _tcsize<0 || _tcsize>4 ){ + Fail( "Bad texcoord data" ); + } - int sz=12+(_vflags&1?12:0)+(_vflags&2?16:0)+(_tcsets*_tcsize*4); - int n_verts=ChunkSize()/sz; + int sz=12+(_vflags&1?12:0)+(_vflags&2?16:0)+(_tcsets*_tcsize*4); + int n_verts=ChunkSize()/sz; - int v0=_vertices.size(); - _vertices.resize( v0+n_verts ); + int v0=_vertices.size(); + _vertices.resize( v0+n_verts ); - for( int i=0;i=(int)_materials.size() ){ + int matid=ReadInt(); + if( matid==-1 ){ + matid=0; + }else if( matid<0 || matid>=(int)_materials.size() ){ #ifdef DEBUG_B3D - cout<<"material id="<mMaterialIndex=matid; - mesh->mNumFaces=0; - mesh->mPrimitiveTypes=aiPrimitiveType_TRIANGLE; + mesh->mMaterialIndex=matid; + mesh->mNumFaces=0; + mesh->mPrimitiveTypes=aiPrimitiveType_TRIANGLE; - int n_tris=ChunkSize()/12; - aiFace *face=mesh->mFaces=new aiFace[n_tris]; + int n_tris=ChunkSize()/12; + aiFace *face=mesh->mFaces=new aiFace[n_tris]; - for( int i=0;i=(int)_vertices.size() || i1<0 || i1>=(int)_vertices.size() || i2<0 || i2>=(int)_vertices.size() ){ + for( int i=0;i=(int)_vertices.size() || i1<0 || i1>=(int)_vertices.size() || i2<0 || i2>=(int)_vertices.size() ){ #ifdef DEBUG_B3D - cout<<"Bad triangle index: i0="<mNumIndices=3; - face->mIndices=new unsigned[3]; - face->mIndices[0]=i0; - face->mIndices[1]=i1; - face->mIndices[2]=i2; - ++mesh->mNumFaces; - ++face; - } + Fail( "Bad triangle index" ); + continue; + } + face->mNumIndices=3; + face->mIndices=new unsigned[3]; + face->mIndices[0]=i0; + face->mIndices[1]=i1; + face->mIndices[2]=i2; + ++mesh->mNumFaces; + ++face; + } } // ------------------------------------------------------------------------------------------------ void B3DImporter::ReadMESH(){ - /*int matid=*/ReadInt(); - - int v0=_vertices.size(); - - while( ChunkSize() ){ - string t=ReadChunk(); - if( t=="VRTS" ){ - ReadVRTS(); - }else if( t=="TRIS" ){ - ReadTRIS( v0 ); - } - ExitChunk(); - } + /*int matid=*/ReadInt(); + + int v0=_vertices.size(); + + while( ChunkSize() ){ + string t=ReadChunk(); + if( t=="VRTS" ){ + ReadVRTS(); + }else if( t=="TRIS" ){ + ReadTRIS( v0 ); + } + ExitChunk(); + } } // ------------------------------------------------------------------------------------------------ void B3DImporter::ReadBONE( int id ){ - while( ChunkSize() ){ - int vertex=ReadInt(); - float weight=ReadFloat(); - if( vertex<0 || vertex>=(int)_vertices.size() ){ - Fail( "Bad vertex index" ); - } - - Vertex &v=_vertices[vertex]; - int i; - for( i=0;i<4;++i ){ - if( !v.weights[i] ){ - v.bones[i]=id; - v.weights[i]=weight; - break; - } - } + while( ChunkSize() ){ + int vertex=ReadInt(); + float weight=ReadFloat(); + if( vertex<0 || vertex>=(int)_vertices.size() ){ + Fail( "Bad vertex index" ); + } + + Vertex &v=_vertices[vertex]; + int i; + for( i=0;i<4;++i ){ + if( !v.weights[i] ){ + v.bones[i]=id; + v.weights[i]=weight; + break; + } + } #ifdef DEBUG_B3D - if( i==4 ){ - cout<<"Too many bone weights"< trans,scale; - vector rot; - int flags=ReadInt(); - while( ChunkSize() ){ - int frame=ReadInt(); - if( flags & 1 ){ - trans.push_back( aiVectorKey( frame,ReadVec3() ) ); - } - if( flags & 2 ){ - scale.push_back( aiVectorKey( frame,ReadVec3() ) ); - } - if( flags & 4 ){ - rot.push_back( aiQuatKey( frame,ReadQuat() ) ); - } - } - - if( flags & 1 ){ - nodeAnim->mNumPositionKeys=trans.size(); - nodeAnim->mPositionKeys=to_array( trans ); - } - - if( flags & 2 ){ - nodeAnim->mNumScalingKeys=scale.size(); - nodeAnim->mScalingKeys=to_array( scale ); - } - - if( flags & 4 ){ - nodeAnim->mNumRotationKeys=rot.size(); - nodeAnim->mRotationKeys=to_array( rot ); - } + vector trans,scale; + vector rot; + int flags=ReadInt(); + while( ChunkSize() ){ + int frame=ReadInt(); + if( flags & 1 ){ + trans.push_back( aiVectorKey( frame,ReadVec3() ) ); + } + if( flags & 2 ){ + scale.push_back( aiVectorKey( frame,ReadVec3() ) ); + } + if( flags & 4 ){ + rot.push_back( aiQuatKey( frame,ReadQuat() ) ); + } + } + + if( flags & 1 ){ + nodeAnim->mNumPositionKeys=trans.size(); + nodeAnim->mPositionKeys=to_array( trans ); + } + + if( flags & 2 ){ + nodeAnim->mNumScalingKeys=scale.size(); + nodeAnim->mScalingKeys=to_array( scale ); + } + + if( flags & 4 ){ + nodeAnim->mNumRotationKeys=rot.size(); + nodeAnim->mRotationKeys=to_array( rot ); + } } // ------------------------------------------------------------------------------------------------ void B3DImporter::ReadANIM(){ - /*int flags=*/ReadInt(); - int frames=ReadInt(); - float fps=ReadFloat(); + /*int flags=*/ReadInt(); + int frames=ReadInt(); + float fps=ReadFloat(); - aiAnimation *anim=new aiAnimation; - _animations.push_back( anim ); + aiAnimation *anim=new aiAnimation; + _animations.push_back( anim ); - anim->mDuration=frames; - anim->mTicksPerSecond=fps; + anim->mDuration=frames; + anim->mTicksPerSecond=fps; } // ------------------------------------------------------------------------------------------------ aiNode *B3DImporter::ReadNODE( aiNode *parent ){ - string name=ReadString(); - aiVector3D t=ReadVec3(); - aiVector3D s=ReadVec3(); - aiQuaternion r=ReadQuat(); - - aiMatrix4x4 trans,scale,rot; - - aiMatrix4x4::Translation( t,trans ); - aiMatrix4x4::Scaling( s,scale ); - rot=aiMatrix4x4( r.GetMatrix() ); - - aiMatrix4x4 tform=trans * rot * scale; - - int nodeid=_nodes.size(); - - aiNode *node=new aiNode( name ); - _nodes.push_back( node ); - - node->mParent=parent; - node->mTransformation=tform; - - aiNodeAnim *nodeAnim=0; - vector meshes; - vector children; - - while( ChunkSize() ){ - string t=ReadChunk(); - if( t=="MESH" ){ - int n=_meshes.size(); - ReadMESH(); - for( int i=n;i<(int)_meshes.size();++i ){ - meshes.push_back( i ); - } - }else if( t=="BONE" ){ - ReadBONE( nodeid ); - }else if( t=="ANIM" ){ - ReadANIM(); - }else if( t=="KEYS" ){ - if( !nodeAnim ){ - nodeAnim=new aiNodeAnim; - _nodeAnims.push_back( nodeAnim ); - nodeAnim->mNodeName=node->mName; - } - ReadKEYS( nodeAnim ); - }else if( t=="NODE" ){ - aiNode *child=ReadNODE( node ); - children.push_back( child ); - } - ExitChunk(); - } - - node->mNumMeshes=meshes.size(); - node->mMeshes=to_array( meshes ); - - node->mNumChildren=children.size(); - node->mChildren=to_array( children ); - - return node; + string name=ReadString(); + aiVector3D t=ReadVec3(); + aiVector3D s=ReadVec3(); + aiQuaternion r=ReadQuat(); + + aiMatrix4x4 trans,scale,rot; + + aiMatrix4x4::Translation( t,trans ); + aiMatrix4x4::Scaling( s,scale ); + rot=aiMatrix4x4( r.GetMatrix() ); + + aiMatrix4x4 tform=trans * rot * scale; + + int nodeid=_nodes.size(); + + aiNode *node=new aiNode( name ); + _nodes.push_back( node ); + + node->mParent=parent; + node->mTransformation=tform; + + aiNodeAnim *nodeAnim=0; + vector meshes; + vector children; + + while( ChunkSize() ){ + string t=ReadChunk(); + if( t=="MESH" ){ + int n=_meshes.size(); + ReadMESH(); + for( int i=n;i<(int)_meshes.size();++i ){ + meshes.push_back( i ); + } + }else if( t=="BONE" ){ + ReadBONE( nodeid ); + }else if( t=="ANIM" ){ + ReadANIM(); + }else if( t=="KEYS" ){ + if( !nodeAnim ){ + nodeAnim=new aiNodeAnim; + _nodeAnims.push_back( nodeAnim ); + nodeAnim->mNodeName=node->mName; + } + ReadKEYS( nodeAnim ); + }else if( t=="NODE" ){ + aiNode *child=ReadNODE( node ); + children.push_back( child ); + } + ExitChunk(); + } + + node->mNumMeshes=meshes.size(); + node->mMeshes=to_array( meshes ); + + node->mNumChildren=children.size(); + node->mChildren=to_array( children ); + + return node; } // ------------------------------------------------------------------------------------------------ void B3DImporter::ReadBB3D( aiScene *scene ){ - _textures.clear(); - _materials.size(); - - _vertices.clear(); - _meshes.clear(); - - _nodes.clear(); - _nodeAnims.clear(); - _animations.clear(); - - string t=ReadChunk(); - if( t=="BB3D" ){ - int version=ReadInt(); - - if (!DefaultLogger::isNullLogger()) { - char dmp[128]; - sprintf(dmp,"B3D file format version: %i",version); - DefaultLogger::get()->info(dmp); - } - - while( ChunkSize() ){ - string t=ReadChunk(); - if( t=="TEXS" ){ - ReadTEXS(); - }else if( t=="BRUS" ){ - ReadBRUS(); - }else if( t=="NODE" ){ - ReadNODE( 0 ); - } - ExitChunk(); - } - } - ExitChunk(); - - if( !_nodes.size() ) Fail( "No nodes" ); - - if( !_meshes.size() ) Fail( "No meshes" ); - - //Fix nodes/meshes/bones - for(size_t i=0;i<_nodes.size();++i ){ - aiNode *node=_nodes[i]; - - for( size_t j=0;jmNumMeshes;++j ){ - aiMesh *mesh=_meshes[node->mMeshes[j]]; - - int n_tris=mesh->mNumFaces; - int n_verts=mesh->mNumVertices=n_tris * 3; - - aiVector3D *mv=mesh->mVertices=new aiVector3D[ n_verts ],*mn=0,*mc=0; - if( _vflags & 1 ) mn=mesh->mNormals=new aiVector3D[ n_verts ]; - if( _tcsets ) mc=mesh->mTextureCoords[0]=new aiVector3D[ n_verts ]; - - aiFace *face=mesh->mFaces; - - vector< vector > vweights( _nodes.size() ); - - for( int i=0;imIndices[j]]; - - *mv++=v.vertex; - if( mn ) *mn++=v.normal; - if( mc ) *mc++=v.texcoords; - - face->mIndices[j]=i+j; - - for( int k=0;k<4;++k ){ - if( !v.weights[k] ) break; - - int bone=v.bones[k]; - float weight=v.weights[k]; - - vweights[bone].push_back( aiVertexWeight(i+j,weight) ); - } - } - ++face; - } - - vector bones; - for(size_t i=0;i &weights=vweights[i]; - if( !weights.size() ) continue; - - aiBone *bone=new aiBone; - bones.push_back( bone ); - - aiNode *bnode=_nodes[i]; - - bone->mName=bnode->mName; - bone->mNumWeights=weights.size(); - bone->mWeights=to_array( weights ); - - aiMatrix4x4 mat=bnode->mTransformation; - while( bnode->mParent ){ - bnode=bnode->mParent; - mat=bnode->mTransformation * mat; - } - bone->mOffsetMatrix=mat.Inverse(); - } - mesh->mNumBones=bones.size(); - mesh->mBones=to_array( bones ); - } - } - - //nodes - scene->mRootNode=_nodes[0]; - - //material - if( !_materials.size() ){ - _materials.push_back( new aiMaterial ); - } - scene->mNumMaterials=_materials.size(); - scene->mMaterials=to_array( _materials ); - - //meshes - scene->mNumMeshes=_meshes.size(); - scene->mMeshes=to_array( _meshes ); - - //animations - if( _animations.size()==1 && _nodeAnims.size() ){ - - aiAnimation *anim=_animations.back(); - anim->mNumChannels=_nodeAnims.size(); - anim->mChannels=to_array( _nodeAnims ); - - scene->mNumAnimations=_animations.size(); - scene->mAnimations=to_array( _animations ); - } + _textures.clear(); + _materials.clear(); + + _vertices.clear(); + _meshes.clear(); + + _nodes.clear(); + _nodeAnims.clear(); + _animations.clear(); + + string t=ReadChunk(); + if( t=="BB3D" ){ + int version=ReadInt(); + + if (!DefaultLogger::isNullLogger()) { + char dmp[128]; + ai_snprintf(dmp, 128, "B3D file format version: %i",version); + DefaultLogger::get()->info(dmp); + } + + while( ChunkSize() ){ + string t=ReadChunk(); + if( t=="TEXS" ){ + ReadTEXS(); + }else if( t=="BRUS" ){ + ReadBRUS(); + }else if( t=="NODE" ){ + ReadNODE( 0 ); + } + ExitChunk(); + } + } + ExitChunk(); + + if( !_nodes.size() ) Fail( "No nodes" ); + + if( !_meshes.size() ) Fail( "No meshes" ); + + //Fix nodes/meshes/bones + for(size_t i=0;i<_nodes.size();++i ){ + aiNode *node=_nodes[i]; + + for( size_t j=0;jmNumMeshes;++j ){ + aiMesh *mesh=_meshes[node->mMeshes[j]]; + + int n_tris=mesh->mNumFaces; + int n_verts=mesh->mNumVertices=n_tris * 3; + + aiVector3D *mv=mesh->mVertices=new aiVector3D[ n_verts ],*mn=0,*mc=0; + if( _vflags & 1 ) mn=mesh->mNormals=new aiVector3D[ n_verts ]; + if( _tcsets ) mc=mesh->mTextureCoords[0]=new aiVector3D[ n_verts ]; + + aiFace *face=mesh->mFaces; + + vector< vector > vweights( _nodes.size() ); + + for( int i=0;imIndices[j]]; + + *mv++=v.vertex; + if( mn ) *mn++=v.normal; + if( mc ) *mc++=v.texcoords; + + face->mIndices[j]=i+j; + + for( int k=0;k<4;++k ){ + if( !v.weights[k] ) break; + + int bone=v.bones[k]; + float weight=v.weights[k]; + + vweights[bone].push_back( aiVertexWeight(i+j,weight) ); + } + } + ++face; + } + + vector bones; + for(size_t i=0;i &weights=vweights[i]; + if( !weights.size() ) continue; + + aiBone *bone=new aiBone; + bones.push_back( bone ); + + aiNode *bnode=_nodes[i]; + + bone->mName=bnode->mName; + bone->mNumWeights=weights.size(); + bone->mWeights=to_array( weights ); + + aiMatrix4x4 mat=bnode->mTransformation; + while( bnode->mParent ){ + bnode=bnode->mParent; + mat=bnode->mTransformation * mat; + } + bone->mOffsetMatrix=mat.Inverse(); + } + mesh->mNumBones=bones.size(); + mesh->mBones=to_array( bones ); + } + } + + //nodes + scene->mRootNode=_nodes[0]; + + //material + if( !_materials.size() ){ + _materials.push_back( new aiMaterial ); + } + scene->mNumMaterials=_materials.size(); + scene->mMaterials=to_array( _materials ); + + //meshes + scene->mNumMeshes=_meshes.size(); + scene->mMeshes=to_array( _meshes ); + + //animations + if( _animations.size()==1 && _nodeAnims.size() ){ + + aiAnimation *anim=_animations.back(); + anim->mNumChannels=_nodeAnims.size(); + anim->mChannels=to_array( _nodeAnims ); + + scene->mNumAnimations=_animations.size(); + scene->mAnimations=to_array( _animations ); + } - // convert to RH - MakeLeftHandedProcess makeleft; - makeleft.Execute( scene ); + // convert to RH + MakeLeftHandedProcess makeleft; + makeleft.Execute( scene ); - FlipWindingOrderProcess flip; - flip.Execute( scene ); + FlipWindingOrderProcess flip; + flip.Execute( scene ); } #endif // !! ASSIMP_BUILD_NO_B3D_IMPORTER diff --git a/src/3rdparty/assimp/code/B3DImporter.h b/src/3rdparty/assimp/code/B3DImporter.h index 7587f6dc7..92ddc0272 100644 --- a/src/3rdparty/assimp/code/B3DImporter.h +++ b/src/3rdparty/assimp/code/B3DImporter.h @@ -1,13 +1,12 @@ - /* Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2012, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above @@ -24,16 +23,16 @@ following conditions are met: derived from this software without specific prior written permission of the assimp team. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- @@ -44,81 +43,86 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_B3DIMPORTER_H_INC #define AI_B3DIMPORTER_H_INC -#include "../include/assimp/types.h" -#include "../include/assimp/mesh.h" -#include "../include/assimp/material.h" +#include +#include +#include +#include "BaseImporter.h" #include #include +struct aiNodeAnim; +struct aiNode; +struct aiAnimation; + namespace Assimp{ class B3DImporter : public BaseImporter{ public: - virtual bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const; + virtual bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const; protected: - virtual const aiImporterDesc* GetInfo () const; - virtual void InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler); + virtual const aiImporterDesc* GetInfo () const; + virtual void InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler); private: - int ReadByte(); - int ReadInt(); - float ReadFloat(); - aiVector2D ReadVec2(); - aiVector3D ReadVec3(); - aiQuaternion ReadQuat(); - std::string ReadString(); - std::string ReadChunk(); - void ExitChunk(); - unsigned ChunkSize(); - - template - T *to_array( const std::vector &v ); - - struct Vertex{ - aiVector3D vertex; - aiVector3D normal; - aiVector3D texcoords; - unsigned char bones[4]; - float weights[4]; - }; - - void Oops(); - void Fail( std::string str ); - - void ReadTEXS(); - void ReadBRUS(); - - void ReadVRTS(); - void ReadTRIS( int v0 ); - void ReadMESH(); - void ReadBONE( int id ); - void ReadKEYS( aiNodeAnim *nodeAnim ); - void ReadANIM(); - - aiNode *ReadNODE( aiNode *parent ); - - void ReadBB3D( aiScene *scene ); - - unsigned _pos; -// unsigned _size; - std::vector _buf; - std::vector _stack; - - std::vector _textures; - std::vector _materials; - - int _vflags,_tcsets,_tcsize; - std::vector _vertices; - - std::vector _nodes; - std::vector _meshes; - std::vector _nodeAnims; - std::vector _animations; + int ReadByte(); + int ReadInt(); + float ReadFloat(); + aiVector2D ReadVec2(); + aiVector3D ReadVec3(); + aiQuaternion ReadQuat(); + std::string ReadString(); + std::string ReadChunk(); + void ExitChunk(); + unsigned ChunkSize(); + + template + T *to_array( const std::vector &v ); + + struct Vertex{ + aiVector3D vertex; + aiVector3D normal; + aiVector3D texcoords; + unsigned char bones[4]; + float weights[4]; + }; + + AI_WONT_RETURN void Oops() AI_WONT_RETURN_SUFFIX; + AI_WONT_RETURN void Fail( std::string str ) AI_WONT_RETURN_SUFFIX; + + void ReadTEXS(); + void ReadBRUS(); + + void ReadVRTS(); + void ReadTRIS( int v0 ); + void ReadMESH(); + void ReadBONE( int id ); + void ReadKEYS( aiNodeAnim *nodeAnim ); + void ReadANIM(); + + aiNode *ReadNODE( aiNode *parent ); + + void ReadBB3D( aiScene *scene ); + + unsigned _pos; +// unsigned _size; + std::vector _buf; + std::vector _stack; + + std::vector _textures; + std::vector _materials; + + int _vflags,_tcsets,_tcsize; + std::vector _vertices; + + std::vector _nodes; + std::vector _meshes; + std::vector _nodeAnims; + std::vector _animations; }; } diff --git a/src/3rdparty/assimp/code/BVHLoader.cpp b/src/3rdparty/assimp/code/BVHLoader.cpp index 35a3e20ef..ca6c5d36c 100644 --- a/src/3rdparty/assimp/code/BVHLoader.cpp +++ b/src/3rdparty/assimp/code/BVHLoader.cpp @@ -4,12 +4,12 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2012, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above @@ -26,46 +26,55 @@ contributors may be used to endorse or promote products derived from this software without specific prior written permission of the assimp team. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --------------------------------------------------------------------------- */ -#include "AssimpPCH.h" + #ifndef ASSIMP_BUILD_NO_BVH_IMPORTER #include "BVHLoader.h" #include "fast_atof.h" #include "SkeletonMeshBuilder.h" +#include +#include +#include "TinyFormatter.h" +#include +#include using namespace Assimp; +using namespace Assimp::Formatter; static const aiImporterDesc desc = { - "BVH Importer (MoCap)", - "", - "", - "", - aiImporterFlags_SupportTextFlavour, - 0, - 0, - 0, - 0, - "bvh" + "BVH Importer (MoCap)", + "", + "", + "", + aiImporterFlags_SupportTextFlavour, + 0, + 0, + 0, + 0, + "bvh" }; // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer BVHLoader::BVHLoader() -: noSkeletonMesh() + : mLine(), + mAnimTickDuration(), + mAnimNumFrames(), + noSkeletonMesh() {} // ------------------------------------------------------------------------------------------------ @@ -74,461 +83,461 @@ BVHLoader::~BVHLoader() {} // ------------------------------------------------------------------------------------------------ -// Returns whether the class can handle the format of the given file. +// Returns whether the class can handle the format of the given file. bool BVHLoader::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool cs) const { - // check file extension - const std::string extension = GetExtension(pFile); - - if( extension == "bvh") - return true; - - if ((!extension.length() || cs) && pIOHandler) { - const char* tokens[] = {"HIERARCHY"}; - return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1); - } - return false; + // check file extension + const std::string extension = GetExtension(pFile); + + if( extension == "bvh") + return true; + + if ((!extension.length() || cs) && pIOHandler) { + const char* tokens[] = {"HIERARCHY"}; + return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1); + } + return false; } // ------------------------------------------------------------------------------------------------ void BVHLoader::SetupProperties(const Importer* pImp) { - noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES,0) != 0; + noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES,0) != 0; } // ------------------------------------------------------------------------------------------------ // Loader meta information const aiImporterDesc* BVHLoader::GetInfo () const { - return &desc; + return &desc; } // ------------------------------------------------------------------------------------------------ -// Imports the given file into the given scene structure. +// Imports the given file into the given scene structure. void BVHLoader::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) { - mFileName = pFile; + mFileName = pFile; - // read file into memory - boost::scoped_ptr file( pIOHandler->Open( pFile)); - if( file.get() == NULL) - throw DeadlyImportError( "Failed to open file " + pFile + "."); + // read file into memory + std::unique_ptr file( pIOHandler->Open( pFile)); + if( file.get() == NULL) + throw DeadlyImportError( "Failed to open file " + pFile + "."); - size_t fileSize = file->FileSize(); - if( fileSize == 0) - throw DeadlyImportError( "File is too small."); + size_t fileSize = file->FileSize(); + if( fileSize == 0) + throw DeadlyImportError( "File is too small."); - mBuffer.resize( fileSize); - file->Read( &mBuffer.front(), 1, fileSize); + mBuffer.resize( fileSize); + file->Read( &mBuffer.front(), 1, fileSize); - // start reading - mReader = mBuffer.begin(); - mLine = 1; - ReadStructure( pScene); + // start reading + mReader = mBuffer.begin(); + mLine = 1; + ReadStructure( pScene); - if (!noSkeletonMesh) { - // build a dummy mesh for the skeleton so that we see something at least - SkeletonMeshBuilder meshBuilder( pScene); - } + if (!noSkeletonMesh) { + // build a dummy mesh for the skeleton so that we see something at least + SkeletonMeshBuilder meshBuilder( pScene); + } - // construct an animation from all the motion data we read - CreateAnimation( pScene); + // construct an animation from all the motion data we read + CreateAnimation( pScene); } // ------------------------------------------------------------------------------------------------ // Reads the file void BVHLoader::ReadStructure( aiScene* pScene) { - // first comes hierarchy - std::string header = GetNextToken(); - if( header != "HIERARCHY") - ThrowException( "Expected header string \"HIERARCHY\"."); - ReadHierarchy( pScene); - - // then comes the motion data - std::string motion = GetNextToken(); - if( motion != "MOTION") - ThrowException( "Expected beginning of motion data \"MOTION\"."); - ReadMotion( pScene); + // first comes hierarchy + std::string header = GetNextToken(); + if( header != "HIERARCHY") + ThrowException( "Expected header string \"HIERARCHY\"."); + ReadHierarchy( pScene); + + // then comes the motion data + std::string motion = GetNextToken(); + if( motion != "MOTION") + ThrowException( "Expected beginning of motion data \"MOTION\"."); + ReadMotion( pScene); } // ------------------------------------------------------------------------------------------------ // Reads the hierarchy void BVHLoader::ReadHierarchy( aiScene* pScene) { - std::string root = GetNextToken(); - if( root != "ROOT") - ThrowException( "Expected root node \"ROOT\"."); + std::string root = GetNextToken(); + if( root != "ROOT") + ThrowException( "Expected root node \"ROOT\"."); - // Go read the hierarchy from here - pScene->mRootNode = ReadNode(); + // Go read the hierarchy from here + pScene->mRootNode = ReadNode(); } // ------------------------------------------------------------------------------------------------ // Reads a node and recursively its childs and returns the created node; aiNode* BVHLoader::ReadNode() { - // first token is name - std::string nodeName = GetNextToken(); - if( nodeName.empty() || nodeName == "{") - ThrowException( boost::str( boost::format( "Expected node name, but found \"%s\".") % nodeName)); - - // then an opening brace should follow - std::string openBrace = GetNextToken(); - if( openBrace != "{") - ThrowException( boost::str( boost::format( "Expected opening brace \"{\", but found \"%s\".") % openBrace)); - - // Create a node - aiNode* node = new aiNode( nodeName); - std::vector childNodes; - - // and create an bone entry for it - mNodes.push_back( Node( node)); - Node& internNode = mNodes.back(); - - // now read the node's contents - while( 1) - { - std::string token = GetNextToken(); - - // node offset to parent node - if( token == "OFFSET") - ReadNodeOffset( node); - else if( token == "CHANNELS") - ReadNodeChannels( internNode); - else if( token == "JOINT") - { - // child node follows - aiNode* child = ReadNode(); - child->mParent = node; - childNodes.push_back( child); - } - else if( token == "End") - { - // The real symbol is "End Site". Second part comes in a separate token - std::string siteToken = GetNextToken(); - if( siteToken != "Site") - ThrowException( boost::str( boost::format( "Expected \"End Site\" keyword, but found \"%s %s\".") % token % siteToken)); - - aiNode* child = ReadEndSite( nodeName); - child->mParent = node; - childNodes.push_back( child); - } - else if( token == "}") - { - // we're done with that part of the hierarchy - break; - } else - { - // everything else is a parse error - ThrowException( boost::str( boost::format( "Unknown keyword \"%s\".") % token)); - } - } - - // add the child nodes if there are any - if( childNodes.size() > 0) - { - node->mNumChildren = childNodes.size(); - node->mChildren = new aiNode*[node->mNumChildren]; - std::copy( childNodes.begin(), childNodes.end(), node->mChildren); - } - - // and return the sub-hierarchy we built here - return node; + // first token is name + std::string nodeName = GetNextToken(); + if( nodeName.empty() || nodeName == "{") + ThrowException( format() << "Expected node name, but found \"" << nodeName << "\"." ); + + // then an opening brace should follow + std::string openBrace = GetNextToken(); + if( openBrace != "{") + ThrowException( format() << "Expected opening brace \"{\", but found \"" << openBrace << "\"." ); + + // Create a node + aiNode* node = new aiNode( nodeName); + std::vector childNodes; + + // and create an bone entry for it + mNodes.push_back( Node( node)); + Node& internNode = mNodes.back(); + + // now read the node's contents + while( 1) + { + std::string token = GetNextToken(); + + // node offset to parent node + if( token == "OFFSET") + ReadNodeOffset( node); + else if( token == "CHANNELS") + ReadNodeChannels( internNode); + else if( token == "JOINT") + { + // child node follows + aiNode* child = ReadNode(); + child->mParent = node; + childNodes.push_back( child); + } + else if( token == "End") + { + // The real symbol is "End Site". Second part comes in a separate token + std::string siteToken = GetNextToken(); + if( siteToken != "Site") + ThrowException( format() << "Expected \"End Site\" keyword, but found \"" << token << " " << siteToken << "\"." ); + + aiNode* child = ReadEndSite( nodeName); + child->mParent = node; + childNodes.push_back( child); + } + else if( token == "}") + { + // we're done with that part of the hierarchy + break; + } else + { + // everything else is a parse error + ThrowException( format() << "Unknown keyword \"" << token << "\"." ); + } + } + + // add the child nodes if there are any + if( childNodes.size() > 0) + { + node->mNumChildren = childNodes.size(); + node->mChildren = new aiNode*[node->mNumChildren]; + std::copy( childNodes.begin(), childNodes.end(), node->mChildren); + } + + // and return the sub-hierarchy we built here + return node; } // ------------------------------------------------------------------------------------------------ // Reads an end node and returns the created node. aiNode* BVHLoader::ReadEndSite( const std::string& pParentName) { - // check opening brace - std::string openBrace = GetNextToken(); - if( openBrace != "{") - ThrowException( boost::str( boost::format( "Expected opening brace \"{\", but found \"%s\".") % openBrace)); - - // Create a node - aiNode* node = new aiNode( "EndSite_" + pParentName); - - // now read the node's contents. Only possible entry is "OFFSET" - while( 1) - { - std::string token = GetNextToken(); - - // end node's offset - if( token == "OFFSET") - { - ReadNodeOffset( node); - } - else if( token == "}") - { - // we're done with the end node - break; - } else - { - // everything else is a parse error - ThrowException( boost::str( boost::format( "Unknown keyword \"%s\".") % token)); - } - } - - // and return the sub-hierarchy we built here - return node; + // check opening brace + std::string openBrace = GetNextToken(); + if( openBrace != "{") + ThrowException( format() << "Expected opening brace \"{\", but found \"" << openBrace << "\"."); + + // Create a node + aiNode* node = new aiNode( "EndSite_" + pParentName); + + // now read the node's contents. Only possible entry is "OFFSET" + while( 1) + { + std::string token = GetNextToken(); + + // end node's offset + if( token == "OFFSET") + { + ReadNodeOffset( node); + } + else if( token == "}") + { + // we're done with the end node + break; + } else + { + // everything else is a parse error + ThrowException( format() << "Unknown keyword \"" << token << "\"." ); + } + } + + // and return the sub-hierarchy we built here + return node; } // ------------------------------------------------------------------------------------------------ // Reads a node offset for the given node void BVHLoader::ReadNodeOffset( aiNode* pNode) { - // Offset consists of three floats to read - aiVector3D offset; - offset.x = GetNextTokenAsFloat(); - offset.y = GetNextTokenAsFloat(); - offset.z = GetNextTokenAsFloat(); - - // build a transformation matrix from it - pNode->mTransformation = aiMatrix4x4( 1.0f, 0.0f, 0.0f, offset.x, 0.0f, 1.0f, 0.0f, offset.y, - 0.0f, 0.0f, 1.0f, offset.z, 0.0f, 0.0f, 0.0f, 1.0f); + // Offset consists of three floats to read + aiVector3D offset; + offset.x = GetNextTokenAsFloat(); + offset.y = GetNextTokenAsFloat(); + offset.z = GetNextTokenAsFloat(); + + // build a transformation matrix from it + pNode->mTransformation = aiMatrix4x4( 1.0f, 0.0f, 0.0f, offset.x, 0.0f, 1.0f, 0.0f, offset.y, + 0.0f, 0.0f, 1.0f, offset.z, 0.0f, 0.0f, 0.0f, 1.0f); } // ------------------------------------------------------------------------------------------------ // Reads the animation channels for the given node void BVHLoader::ReadNodeChannels( BVHLoader::Node& pNode) { - // number of channels. Use the float reader because we're lazy - float numChannelsFloat = GetNextTokenAsFloat(); - unsigned int numChannels = (unsigned int) numChannelsFloat; - - for( unsigned int a = 0; a < numChannels; a++) - { - std::string channelToken = GetNextToken(); - - if( channelToken == "Xposition") - pNode.mChannels.push_back( Channel_PositionX); - else if( channelToken == "Yposition") - pNode.mChannels.push_back( Channel_PositionY); - else if( channelToken == "Zposition") - pNode.mChannels.push_back( Channel_PositionZ); - else if( channelToken == "Xrotation") - pNode.mChannels.push_back( Channel_RotationX); - else if( channelToken == "Yrotation") - pNode.mChannels.push_back( Channel_RotationY); - else if( channelToken == "Zrotation") - pNode.mChannels.push_back( Channel_RotationZ); - else - ThrowException( boost::str( boost::format( "Invalid channel specifier \"%s\".") % channelToken)); - } + // number of channels. Use the float reader because we're lazy + float numChannelsFloat = GetNextTokenAsFloat(); + unsigned int numChannels = (unsigned int) numChannelsFloat; + + for( unsigned int a = 0; a < numChannels; a++) + { + std::string channelToken = GetNextToken(); + + if( channelToken == "Xposition") + pNode.mChannels.push_back( Channel_PositionX); + else if( channelToken == "Yposition") + pNode.mChannels.push_back( Channel_PositionY); + else if( channelToken == "Zposition") + pNode.mChannels.push_back( Channel_PositionZ); + else if( channelToken == "Xrotation") + pNode.mChannels.push_back( Channel_RotationX); + else if( channelToken == "Yrotation") + pNode.mChannels.push_back( Channel_RotationY); + else if( channelToken == "Zrotation") + pNode.mChannels.push_back( Channel_RotationZ); + else + ThrowException( format() << "Invalid channel specifier \"" << channelToken << "\"." ); + } } // ------------------------------------------------------------------------------------------------ // Reads the motion data void BVHLoader::ReadMotion( aiScene* /*pScene*/) { - // Read number of frames - std::string tokenFrames = GetNextToken(); - if( tokenFrames != "Frames:") - ThrowException( boost::str( boost::format( "Expected frame count \"Frames:\", but found \"%s\".") % tokenFrames)); - - float numFramesFloat = GetNextTokenAsFloat(); - mAnimNumFrames = (unsigned int) numFramesFloat; - - // Read frame duration - std::string tokenDuration1 = GetNextToken(); - std::string tokenDuration2 = GetNextToken(); - if( tokenDuration1 != "Frame" || tokenDuration2 != "Time:") - ThrowException( boost::str( boost::format( "Expected frame duration \"Frame Time:\", but found \"%s %s\".") % tokenDuration1 % tokenDuration2)); - - mAnimTickDuration = GetNextTokenAsFloat(); - - // resize value vectors for each node - for( std::vector::iterator it = mNodes.begin(); it != mNodes.end(); ++it) - it->mChannelValues.reserve( it->mChannels.size() * mAnimNumFrames); - - // now read all the data and store it in the corresponding node's value vector - for( unsigned int frame = 0; frame < mAnimNumFrames; ++frame) - { - // on each line read the values for all nodes - for( std::vector::iterator it = mNodes.begin(); it != mNodes.end(); ++it) - { - // get as many values as the node has channels - for( unsigned int c = 0; c < it->mChannels.size(); ++c) - it->mChannelValues.push_back( GetNextTokenAsFloat()); - } - - // after one frame worth of values for all nodes there should be a newline, but we better don't rely on it - } + // Read number of frames + std::string tokenFrames = GetNextToken(); + if( tokenFrames != "Frames:") + ThrowException( format() << "Expected frame count \"Frames:\", but found \"" << tokenFrames << "\"."); + + float numFramesFloat = GetNextTokenAsFloat(); + mAnimNumFrames = (unsigned int) numFramesFloat; + + // Read frame duration + std::string tokenDuration1 = GetNextToken(); + std::string tokenDuration2 = GetNextToken(); + if( tokenDuration1 != "Frame" || tokenDuration2 != "Time:") + ThrowException( format() << "Expected frame duration \"Frame Time:\", but found \"" << tokenDuration1 << " " << tokenDuration2 << "\"." ); + + mAnimTickDuration = GetNextTokenAsFloat(); + + // resize value vectors for each node + for( std::vector::iterator it = mNodes.begin(); it != mNodes.end(); ++it) + it->mChannelValues.reserve( it->mChannels.size() * mAnimNumFrames); + + // now read all the data and store it in the corresponding node's value vector + for( unsigned int frame = 0; frame < mAnimNumFrames; ++frame) + { + // on each line read the values for all nodes + for( std::vector::iterator it = mNodes.begin(); it != mNodes.end(); ++it) + { + // get as many values as the node has channels + for( unsigned int c = 0; c < it->mChannels.size(); ++c) + it->mChannelValues.push_back( GetNextTokenAsFloat()); + } + + // after one frame worth of values for all nodes there should be a newline, but we better don't rely on it + } } // ------------------------------------------------------------------------------------------------ // Retrieves the next token std::string BVHLoader::GetNextToken() { - // skip any preceeding whitespace - while( mReader != mBuffer.end()) - { - if( !isspace( *mReader)) - break; - - // count lines - if( *mReader == '\n') - mLine++; - - ++mReader; - } - - // collect all chars till the next whitespace. BVH is easy in respect to that. - std::string token; - while( mReader != mBuffer.end()) - { - if( isspace( *mReader)) - break; - - token.push_back( *mReader); - ++mReader; - - // little extra logic to make sure braces are counted correctly - if( token == "{" || token == "}") - break; - } - - // empty token means end of file, which is just fine - return token; + // skip any preceding whitespace + while( mReader != mBuffer.end()) + { + if( !isspace( *mReader)) + break; + + // count lines + if( *mReader == '\n') + mLine++; + + ++mReader; + } + + // collect all chars till the next whitespace. BVH is easy in respect to that. + std::string token; + while( mReader != mBuffer.end()) + { + if( isspace( *mReader)) + break; + + token.push_back( *mReader); + ++mReader; + + // little extra logic to make sure braces are counted correctly + if( token == "{" || token == "}") + break; + } + + // empty token means end of file, which is just fine + return token; } // ------------------------------------------------------------------------------------------------ // Reads the next token as a float float BVHLoader::GetNextTokenAsFloat() { - std::string token = GetNextToken(); - if( token.empty()) - ThrowException( "Unexpected end of file while trying to read a float"); + std::string token = GetNextToken(); + if( token.empty()) + ThrowException( "Unexpected end of file while trying to read a float"); - // check if the float is valid by testing if the atof() function consumed every char of the token - const char* ctoken = token.c_str(); - float result = 0.0f; - ctoken = fast_atoreal_move( ctoken, result); + // check if the float is valid by testing if the atof() function consumed every char of the token + const char* ctoken = token.c_str(); + float result = 0.0f; + ctoken = fast_atoreal_move( ctoken, result); - if( ctoken != token.c_str() + token.length()) - ThrowException( boost::str( boost::format( "Expected a floating point number, but found \"%s\".") % token)); + if( ctoken != token.c_str() + token.length()) + ThrowException( format() << "Expected a floating point number, but found \"" << token << "\"." ); - return result; + return result; } // ------------------------------------------------------------------------------------------------ // Aborts the file reading with an exception -void BVHLoader::ThrowException( const std::string& pError) +AI_WONT_RETURN void BVHLoader::ThrowException( const std::string& pError) { - throw DeadlyImportError( boost::str( boost::format( "%s:%d - %s") % mFileName % mLine % pError)); + throw DeadlyImportError( format() << mFileName << ":" << mLine << " - " << pError); } // ------------------------------------------------------------------------------------------------ // Constructs an animation for the motion data and stores it in the given scene void BVHLoader::CreateAnimation( aiScene* pScene) { - // create the animation - pScene->mNumAnimations = 1; - pScene->mAnimations = new aiAnimation*[1]; - aiAnimation* anim = new aiAnimation; - pScene->mAnimations[0] = anim; - - // put down the basic parameters - anim->mName.Set( "Motion"); - anim->mTicksPerSecond = 1.0 / double( mAnimTickDuration); - anim->mDuration = double( mAnimNumFrames - 1); - - // now generate the tracks for all nodes - anim->mNumChannels = mNodes.size(); - anim->mChannels = new aiNodeAnim*[anim->mNumChannels]; - - // FIX: set the array elements to NULL to ensure proper deletion if an exception is thrown - for (unsigned int i = 0; i < anim->mNumChannels;++i) - anim->mChannels[i] = NULL; - - for( unsigned int a = 0; a < anim->mNumChannels; a++) - { - const Node& node = mNodes[a]; - const std::string nodeName = std::string( node.mNode->mName.data ); - aiNodeAnim* nodeAnim = new aiNodeAnim; - anim->mChannels[a] = nodeAnim; - nodeAnim->mNodeName.Set( nodeName); - - // translational part, if given - if( node.mChannels.size() == 6) - { - nodeAnim->mNumPositionKeys = mAnimNumFrames; - nodeAnim->mPositionKeys = new aiVectorKey[mAnimNumFrames]; - aiVectorKey* poskey = nodeAnim->mPositionKeys; - for( unsigned int fr = 0; fr < mAnimNumFrames; ++fr) - { - poskey->mTime = double( fr); - - // Now compute all translations in the right order - for( unsigned int channel = 0; channel < 3; ++channel) - { - switch( node.mChannels[channel]) - { - case Channel_PositionX: poskey->mValue.x = node.mChannelValues[fr * node.mChannels.size() + channel]; break; - case Channel_PositionY: poskey->mValue.y = node.mChannelValues[fr * node.mChannels.size() + channel]; break; - case Channel_PositionZ: poskey->mValue.z = node.mChannelValues[fr * node.mChannels.size() + channel]; break; - default: throw DeadlyImportError( "Unexpected animation channel setup at node " + nodeName ); - } - } - ++poskey; - } - } else - { - // if no translation part is given, put a default sequence - aiVector3D nodePos( node.mNode->mTransformation.a4, node.mNode->mTransformation.b4, node.mNode->mTransformation.c4); - nodeAnim->mNumPositionKeys = 1; - nodeAnim->mPositionKeys = new aiVectorKey[1]; - nodeAnim->mPositionKeys[0].mTime = 0.0; - nodeAnim->mPositionKeys[0].mValue = nodePos; - } - - // rotation part. Always present. First find value offsets - { - unsigned int rotOffset = 0; - if( node.mChannels.size() == 6) - { - // Offset all further calculations - rotOffset = 3; - } - - // Then create the number of rotation keys - nodeAnim->mNumRotationKeys = mAnimNumFrames; - nodeAnim->mRotationKeys = new aiQuatKey[mAnimNumFrames]; - aiQuatKey* rotkey = nodeAnim->mRotationKeys; - for( unsigned int fr = 0; fr < mAnimNumFrames; ++fr) - { - aiMatrix4x4 temp; - aiMatrix3x3 rotMatrix; - - for( unsigned int channel = 0; channel < 3; ++channel) - { - // translate ZXY euler angels into a quaternion - const float angle = node.mChannelValues[fr * node.mChannels.size() + rotOffset + channel] * float( AI_MATH_PI) / 180.0f; - - // Compute rotation transformations in the right order - switch (node.mChannels[rotOffset+channel]) - { - case Channel_RotationX: aiMatrix4x4::RotationX( angle, temp); rotMatrix *= aiMatrix3x3( temp); break; - case Channel_RotationY: aiMatrix4x4::RotationY( angle, temp); rotMatrix *= aiMatrix3x3( temp); break; - case Channel_RotationZ: aiMatrix4x4::RotationZ( angle, temp); rotMatrix *= aiMatrix3x3( temp); break; - default: throw DeadlyImportError( "Unexpected animation channel setup at node " + nodeName ); - } - } - - rotkey->mTime = double( fr); - rotkey->mValue = aiQuaternion( rotMatrix); - ++rotkey; - } - } - - // scaling part. Always just a default track - { - nodeAnim->mNumScalingKeys = 1; - nodeAnim->mScalingKeys = new aiVectorKey[1]; - nodeAnim->mScalingKeys[0].mTime = 0.0; - nodeAnim->mScalingKeys[0].mValue.Set( 1.0f, 1.0f, 1.0f); - } - } + // create the animation + pScene->mNumAnimations = 1; + pScene->mAnimations = new aiAnimation*[1]; + aiAnimation* anim = new aiAnimation; + pScene->mAnimations[0] = anim; + + // put down the basic parameters + anim->mName.Set( "Motion"); + anim->mTicksPerSecond = 1.0 / double( mAnimTickDuration); + anim->mDuration = double( mAnimNumFrames - 1); + + // now generate the tracks for all nodes + anim->mNumChannels = mNodes.size(); + anim->mChannels = new aiNodeAnim*[anim->mNumChannels]; + + // FIX: set the array elements to NULL to ensure proper deletion if an exception is thrown + for (unsigned int i = 0; i < anim->mNumChannels;++i) + anim->mChannels[i] = NULL; + + for( unsigned int a = 0; a < anim->mNumChannels; a++) + { + const Node& node = mNodes[a]; + const std::string nodeName = std::string( node.mNode->mName.data ); + aiNodeAnim* nodeAnim = new aiNodeAnim; + anim->mChannels[a] = nodeAnim; + nodeAnim->mNodeName.Set( nodeName); + + // translational part, if given + if( node.mChannels.size() == 6) + { + nodeAnim->mNumPositionKeys = mAnimNumFrames; + nodeAnim->mPositionKeys = new aiVectorKey[mAnimNumFrames]; + aiVectorKey* poskey = nodeAnim->mPositionKeys; + for( unsigned int fr = 0; fr < mAnimNumFrames; ++fr) + { + poskey->mTime = double( fr); + + // Now compute all translations in the right order + for( unsigned int channel = 0; channel < 3; ++channel) + { + switch( node.mChannels[channel]) + { + case Channel_PositionX: poskey->mValue.x = node.mChannelValues[fr * node.mChannels.size() + channel]; break; + case Channel_PositionY: poskey->mValue.y = node.mChannelValues[fr * node.mChannels.size() + channel]; break; + case Channel_PositionZ: poskey->mValue.z = node.mChannelValues[fr * node.mChannels.size() + channel]; break; + default: throw DeadlyImportError( "Unexpected animation channel setup at node " + nodeName ); + } + } + ++poskey; + } + } else + { + // if no translation part is given, put a default sequence + aiVector3D nodePos( node.mNode->mTransformation.a4, node.mNode->mTransformation.b4, node.mNode->mTransformation.c4); + nodeAnim->mNumPositionKeys = 1; + nodeAnim->mPositionKeys = new aiVectorKey[1]; + nodeAnim->mPositionKeys[0].mTime = 0.0; + nodeAnim->mPositionKeys[0].mValue = nodePos; + } + + // rotation part. Always present. First find value offsets + { + unsigned int rotOffset = 0; + if( node.mChannels.size() == 6) + { + // Offset all further calculations + rotOffset = 3; + } + + // Then create the number of rotation keys + nodeAnim->mNumRotationKeys = mAnimNumFrames; + nodeAnim->mRotationKeys = new aiQuatKey[mAnimNumFrames]; + aiQuatKey* rotkey = nodeAnim->mRotationKeys; + for( unsigned int fr = 0; fr < mAnimNumFrames; ++fr) + { + aiMatrix4x4 temp; + aiMatrix3x3 rotMatrix; + + for( unsigned int channel = 0; channel < 3; ++channel) + { + // translate ZXY euler angels into a quaternion + const float angle = node.mChannelValues[fr * node.mChannels.size() + rotOffset + channel] * float( AI_MATH_PI) / 180.0f; + + // Compute rotation transformations in the right order + switch (node.mChannels[rotOffset+channel]) + { + case Channel_RotationX: aiMatrix4x4::RotationX( angle, temp); rotMatrix *= aiMatrix3x3( temp); break; + case Channel_RotationY: aiMatrix4x4::RotationY( angle, temp); rotMatrix *= aiMatrix3x3( temp); break; + case Channel_RotationZ: aiMatrix4x4::RotationZ( angle, temp); rotMatrix *= aiMatrix3x3( temp); break; + default: throw DeadlyImportError( "Unexpected animation channel setup at node " + nodeName ); + } + } + + rotkey->mTime = double( fr); + rotkey->mValue = aiQuaternion( rotMatrix); + ++rotkey; + } + } + + // scaling part. Always just a default track + { + nodeAnim->mNumScalingKeys = 1; + nodeAnim->mScalingKeys = new aiVectorKey[1]; + nodeAnim->mScalingKeys[0].mTime = 0.0; + nodeAnim->mScalingKeys[0].mValue.Set( 1.0f, 1.0f, 1.0f); + } + } } #endif // !! ASSIMP_BUILD_NO_BVH_IMPORTER diff --git a/src/3rdparty/assimp/code/BVHLoader.h b/src/3rdparty/assimp/code/BVHLoader.h index 279f6bf1e..8a163d1e7 100644 --- a/src/3rdparty/assimp/code/BVHLoader.h +++ b/src/3rdparty/assimp/code/BVHLoader.h @@ -4,11 +4,11 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2012, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above @@ -25,16 +25,16 @@ contributors may be used to endorse or promote products derived from this software without specific prior written permission of the assimp team. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- @@ -49,11 +49,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "BaseImporter.h" +struct aiNode; + namespace Assimp { // -------------------------------------------------------------------------------- -/** Loader class to read Motion Capturing data from a .bvh file. +/** Loader class to read Motion Capturing data from a .bvh file. * * This format only contains a hierarchy of joints and a series of keyframes for * the hierarchy. It contains no actual mesh data, but we generate a dummy mesh @@ -62,106 +64,106 @@ namespace Assimp class BVHLoader : public BaseImporter { - /** Possible animation channels for which the motion data holds the values */ - enum ChannelType - { - Channel_PositionX, - Channel_PositionY, - Channel_PositionZ, - Channel_RotationX, - Channel_RotationY, - Channel_RotationZ - }; - - /** Collected list of node. Will be bones of the dummy mesh some day, addressed by their array index */ - struct Node - { - const aiNode* mNode; - std::vector mChannels; - std::vector mChannelValues; // motion data values for that node. Of size NumChannels * NumFrames - - Node() { } - Node( const aiNode* pNode) : mNode( pNode) { } - }; + /** Possible animation channels for which the motion data holds the values */ + enum ChannelType + { + Channel_PositionX, + Channel_PositionY, + Channel_PositionZ, + Channel_RotationX, + Channel_RotationY, + Channel_RotationZ + }; + + /** Collected list of node. Will be bones of the dummy mesh some day, addressed by their array index */ + struct Node + { + const aiNode* mNode; + std::vector mChannels; + std::vector mChannelValues; // motion data values for that node. Of size NumChannels * NumFrames + + Node() { } + explicit Node( const aiNode* pNode) : mNode( pNode) { } + }; public: - BVHLoader(); - ~BVHLoader(); + BVHLoader(); + ~BVHLoader(); public: - /** Returns whether the class can handle the format of the given file. - * See BaseImporter::CanRead() for details. */ - bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool cs) const; + /** Returns whether the class can handle the format of the given file. + * See BaseImporter::CanRead() for details. */ + bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool cs) const; - void SetupProperties(const Importer* pImp); - const aiImporterDesc* GetInfo () const; + void SetupProperties(const Importer* pImp); + const aiImporterDesc* GetInfo () const; protected: - /** Imports the given file into the given scene structure. - * See BaseImporter::InternReadFile() for details - */ - void InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler); + /** Imports the given file into the given scene structure. + * See BaseImporter::InternReadFile() for details + */ + void InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler); protected: - /** Reads the file */ - void ReadStructure( aiScene* pScene); + /** Reads the file */ + void ReadStructure( aiScene* pScene); - /** Reads the hierarchy */ - void ReadHierarchy( aiScene* pScene); + /** Reads the hierarchy */ + void ReadHierarchy( aiScene* pScene); - /** Reads a node and recursively its childs and returns the created node. */ - aiNode* ReadNode(); + /** Reads a node and recursively its childs and returns the created node. */ + aiNode* ReadNode(); - /** Reads an end node and returns the created node. */ - aiNode* ReadEndSite( const std::string& pParentName); + /** Reads an end node and returns the created node. */ + aiNode* ReadEndSite( const std::string& pParentName); - /** Reads a node offset for the given node */ - void ReadNodeOffset( aiNode* pNode); + /** Reads a node offset for the given node */ + void ReadNodeOffset( aiNode* pNode); - /** Reads the animation channels into the given node */ - void ReadNodeChannels( BVHLoader::Node& pNode); + /** Reads the animation channels into the given node */ + void ReadNodeChannels( BVHLoader::Node& pNode); - /** Reads the motion data */ - void ReadMotion( aiScene* pScene); + /** Reads the motion data */ + void ReadMotion( aiScene* pScene); - /** Retrieves the next token */ - std::string GetNextToken(); + /** Retrieves the next token */ + std::string GetNextToken(); - /** Reads the next token as a float */ - float GetNextTokenAsFloat(); + /** Reads the next token as a float */ + float GetNextTokenAsFloat(); - /** Aborts the file reading with an exception */ - void ThrowException( const std::string& pError); + /** Aborts the file reading with an exception */ + AI_WONT_RETURN void ThrowException( const std::string& pError) AI_WONT_RETURN_SUFFIX; - /** Constructs an animation for the motion data and stores it in the given scene */ - void CreateAnimation( aiScene* pScene); + /** Constructs an animation for the motion data and stores it in the given scene */ + void CreateAnimation( aiScene* pScene); protected: - /** Filename, for a verbose error message */ - std::string mFileName; + /** Filename, for a verbose error message */ + std::string mFileName; - /** Buffer to hold the loaded file */ - std::vector mBuffer; + /** Buffer to hold the loaded file */ + std::vector mBuffer; - /** Next char to read from the buffer */ - std::vector::const_iterator mReader; + /** Next char to read from the buffer */ + std::vector::const_iterator mReader; - /** Current line, for error messages */ - unsigned int mLine; + /** Current line, for error messages */ + unsigned int mLine; - /** Collected list of nodes. Will be bones of the dummy mesh some day, addressed by their array index. - * Also contain the motion data for the node's channels - */ - std::vector mNodes; + /** Collected list of nodes. Will be bones of the dummy mesh some day, addressed by their array index. + * Also contain the motion data for the node's channels + */ + std::vector mNodes; - /** basic Animation parameters */ - float mAnimTickDuration; - unsigned int mAnimNumFrames; + /** basic Animation parameters */ + float mAnimTickDuration; + unsigned int mAnimNumFrames; - bool noSkeletonMesh; + bool noSkeletonMesh; }; } // end of namespace Assimp diff --git a/src/3rdparty/assimp/code/BaseImporter.cpp b/src/3rdparty/assimp/code/BaseImporter.cpp index 4b7163dd5..aa615e592 100644 --- a/src/3rdparty/assimp/code/BaseImporter.cpp +++ b/src/3rdparty/assimp/code/BaseImporter.cpp @@ -3,12 +3,12 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2012, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above @@ -25,264 +25,280 @@ conditions are met: derived from this software without specific prior written permission of the assimp team. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --------------------------------------------------------------------------- */ /** @file BaseImporter.cpp - * @brief Implementation of BaseImporter + * @brief Implementation of BaseImporter */ -#include "AssimpPCH.h" #include "BaseImporter.h" #include "FileSystemFilter.h" - #include "Importer.h" +#include "ByteSwapper.h" +#include +#include +#include +#include +#include +#include +#include +#include + using namespace Assimp; // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer BaseImporter::BaseImporter() -: progress() +: m_progress() { - // nothing to do here + // nothing to do here } // ------------------------------------------------------------------------------------------------ // Destructor, private as well BaseImporter::~BaseImporter() { - // nothing to do here + // nothing to do here } // ------------------------------------------------------------------------------------------------ // Imports the given file and returns the imported data. aiScene* BaseImporter::ReadFile(const Importer* pImp, const std::string& pFile, IOSystem* pIOHandler) { - progress = pImp->GetProgressHandler(); - ai_assert(progress); + m_progress = pImp->GetProgressHandler(); + ai_assert(m_progress); - // Gather configuration properties for this run - SetupProperties( pImp ); + // Gather configuration properties for this run + SetupProperties( pImp ); - // Construct a file system filter to improve our success ratio at reading external files - FileSystemFilter filter(pFile,pIOHandler); + // Construct a file system filter to improve our success ratio at reading external files + FileSystemFilter filter(pFile,pIOHandler); - // create a scene object to hold the data - ScopeGuard sc(new aiScene()); + // create a scene object to hold the data + ScopeGuard sc(new aiScene()); - // dispatch importing - try - { - InternReadFile( pFile, sc, &filter); + // dispatch importing + try + { + InternReadFile( pFile, sc, &filter); - } catch( const std::exception& err ) { - // extract error description - mErrorText = err.what(); - DefaultLogger::get()->error(mErrorText); - return NULL; - } + } catch( const std::exception& err ) { + // extract error description + m_ErrorText = err.what(); + DefaultLogger::get()->error(m_ErrorText); + return NULL; + } - // return what we gathered from the import. - sc.dismiss(); - return sc; + // return what we gathered from the import. + sc.dismiss(); + return sc; } // ------------------------------------------------------------------------------------------------ void BaseImporter::SetupProperties(const Importer* /*pImp*/) { - // the default implementation does nothing + // the default implementation does nothing } // ------------------------------------------------------------------------------------------------ void BaseImporter::GetExtensionList(std::set& extensions) { - const aiImporterDesc* desc = GetInfo(); - ai_assert(desc != NULL); - - const char* ext = desc->mFileExtensions; - ai_assert(ext != NULL); - - const char* last = ext; - do { - if (!*ext || *ext == ' ') { - extensions.insert(std::string(last,ext-last)); - ai_assert(ext-last > 0); - last = ext; - while(*last == ' ') { - ++last; - } - } - } - while(*ext++); + const aiImporterDesc* desc = GetInfo(); + ai_assert(desc != NULL); + + const char* ext = desc->mFileExtensions; + ai_assert(ext != NULL); + + const char* last = ext; + do { + if (!*ext || *ext == ' ') { + extensions.insert(std::string(last,ext-last)); + ai_assert(ext-last > 0); + last = ext; + while(*last == ' ') { + ++last; + } + } + } + while(*ext++); } // ------------------------------------------------------------------------------------------------ /*static*/ bool BaseImporter::SearchFileHeaderForToken(IOSystem* pIOHandler, - const std::string& pFile, - const char** tokens, - unsigned int numTokens, - unsigned int searchBytes /* = 200 */, - bool tokensSol /* false */) + const std::string& pFile, + const char** tokens, + unsigned int numTokens, + unsigned int searchBytes /* = 200 */, + bool tokensSol /* false */) { - ai_assert(NULL != tokens && 0 != numTokens && 0 != searchBytes); - if (!pIOHandler) - return false; - - boost::scoped_ptr pStream (pIOHandler->Open(pFile)); - if (pStream.get() ) { - // read 200 characters from the file - boost::scoped_array _buffer (new char[searchBytes+1 /* for the '\0' */]); - char* buffer = _buffer.get(); - - const unsigned int read = pStream->Read(buffer,1,searchBytes); - if (!read) - return false; - - for (unsigned int i = 0; i < read;++i) - buffer[i] = ::tolower(buffer[i]); - - // It is not a proper handling of unicode files here ... - // ehm ... but it works in most cases. - char* cur = buffer,*cur2 = buffer,*end = &buffer[read]; - while (cur != end) { - if (*cur) - *cur2++ = *cur; - ++cur; - } - *cur2 = '\0'; - - for (unsigned int i = 0; i < numTokens;++i) { - ai_assert(NULL != tokens[i]); - - - const char* r = strstr(buffer,tokens[i]); - if (!r) - continue; - // We got a match, either we don't care where it is, or it happens to - // be in the beginning of the file / line - if (!tokensSol || r == buffer || r[-1] == '\r' || r[-1] == '\n') { - DefaultLogger::get()->debug(std::string("Found positive match for header keyword: ") + tokens[i]); - return true; - } - } - } - return false; + ai_assert(NULL != tokens && 0 != numTokens && 0 != searchBytes); + if (!pIOHandler) + return false; + + std::unique_ptr pStream (pIOHandler->Open(pFile)); + if (pStream.get() ) { + // read 200 characters from the file + std::unique_ptr _buffer (new char[searchBytes+1 /* for the '\0' */]); + char* buffer = _buffer.get(); + if( NULL == buffer ) { + return false; + } + + const size_t read = pStream->Read(buffer,1,searchBytes); + if( !read ) { + return false; + } + + for( size_t i = 0; i < read; ++i ) { + buffer[ i ] = ::tolower( buffer[ i ] ); + } + + // It is not a proper handling of unicode files here ... + // ehm ... but it works in most cases. + char* cur = buffer,*cur2 = buffer,*end = &buffer[read]; + while (cur != end) { + if( *cur ) { + *cur2++ = *cur; + } + ++cur; + } + *cur2 = '\0'; + + for (unsigned int i = 0; i < numTokens;++i) { + ai_assert(NULL != tokens[i]); + + + const char* r = strstr(buffer,tokens[i]); + if( !r ) { + continue; + } + // We got a match, either we don't care where it is, or it happens to + // be in the beginning of the file / line + if (!tokensSol || r == buffer || r[-1] == '\r' || r[-1] == '\n') { + DefaultLogger::get()->debug(std::string("Found positive match for header keyword: ") + tokens[i]); + return true; + } + } + } + + return false; } // ------------------------------------------------------------------------------------------------ // Simple check for file extension -/*static*/ bool BaseImporter::SimpleExtensionCheck (const std::string& pFile, - const char* ext0, - const char* ext1, - const char* ext2) +/*static*/ bool BaseImporter::SimpleExtensionCheck (const std::string& pFile, + const char* ext0, + const char* ext1, + const char* ext2) { - std::string::size_type pos = pFile.find_last_of('.'); + std::string::size_type pos = pFile.find_last_of('.'); + + // no file extension - can't read + if( pos == std::string::npos) + return false; - // no file extension - can't read - if( pos == std::string::npos) - return false; - - const char* ext_real = & pFile[ pos+1 ]; - if( !ASSIMP_stricmp(ext_real,ext0) ) - return true; + const char* ext_real = & pFile[ pos+1 ]; + if( !ASSIMP_stricmp(ext_real,ext0) ) + return true; - // check for other, optional, file extensions - if (ext1 && !ASSIMP_stricmp(ext_real,ext1)) - return true; + // check for other, optional, file extensions + if (ext1 && !ASSIMP_stricmp(ext_real,ext1)) + return true; - if (ext2 && !ASSIMP_stricmp(ext_real,ext2)) - return true; + if (ext2 && !ASSIMP_stricmp(ext_real,ext2)) + return true; - return false; + return false; } // ------------------------------------------------------------------------------------------------ // Get file extension from path /*static*/ std::string BaseImporter::GetExtension (const std::string& pFile) { - std::string::size_type pos = pFile.find_last_of('.'); + std::string::size_type pos = pFile.find_last_of('.'); - // no file extension at all - if( pos == std::string::npos) - return ""; + // no file extension at all + if( pos == std::string::npos) + return ""; - std::string ret = pFile.substr(pos+1); - std::transform(ret.begin(),ret.end(),ret.begin(),::tolower); // thanks to Andy Maloney for the hint - return ret; + std::string ret = pFile.substr(pos+1); + std::transform(ret.begin(),ret.end(),ret.begin(),::tolower); // thanks to Andy Maloney for the hint + return ret; } // ------------------------------------------------------------------------------------------------ // Check for magic bytes at the beginning of the file. -/* static */ bool BaseImporter::CheckMagicToken(IOSystem* pIOHandler, const std::string& pFile, - const void* _magic, unsigned int num, unsigned int offset, unsigned int size) +/* static */ bool BaseImporter::CheckMagicToken(IOSystem* pIOHandler, const std::string& pFile, + const void* _magic, unsigned int num, unsigned int offset, unsigned int size) { - ai_assert(size <= 16 && _magic); - - if (!pIOHandler) { - return false; - } - union { - const char* magic; - const uint16_t* magic_u16; - const uint32_t* magic_u32; - }; - magic = reinterpret_cast(_magic); - boost::scoped_ptr pStream (pIOHandler->Open(pFile)); - if (pStream.get() ) { - - // skip to offset - pStream->Seek(offset,aiOrigin_SET); - - // read 'size' characters from the file - union { - char data[16]; - uint16_t data_u16[8]; - uint32_t data_u32[4]; - }; - if(size != pStream->Read(data,1,size)) { - return false; - } - - for (unsigned int i = 0; i < num; ++i) { - // also check against big endian versions of tokens with size 2,4 - // that's just for convinience, the chance that we cause conflicts - // is quite low and it can save some lines and prevent nasty bugs - if (2 == size) { - uint16_t rev = *magic_u16; - ByteSwap::Swap(&rev); - if (data_u16[0] == *magic_u16 || data_u16[0] == rev) { - return true; - } - } - else if (4 == size) { - uint32_t rev = *magic_u32; - ByteSwap::Swap(&rev); - if (data_u32[0] == *magic_u32 || data_u32[0] == rev) { - return true; - } - } - else { - // any length ... just compare - if(!memcmp(magic,data,size)) { - return true; - } - } - magic += size; - } - } - return false; + ai_assert(size <= 16 && _magic); + + if (!pIOHandler) { + return false; + } + union { + const char* magic; + const uint16_t* magic_u16; + const uint32_t* magic_u32; + }; + magic = reinterpret_cast(_magic); + std::unique_ptr pStream (pIOHandler->Open(pFile)); + if (pStream.get() ) { + + // skip to offset + pStream->Seek(offset,aiOrigin_SET); + + // read 'size' characters from the file + union { + char data[16]; + uint16_t data_u16[8]; + uint32_t data_u32[4]; + }; + if(size != pStream->Read(data,1,size)) { + return false; + } + + for (unsigned int i = 0; i < num; ++i) { + // also check against big endian versions of tokens with size 2,4 + // that's just for convenience, the chance that we cause conflicts + // is quite low and it can save some lines and prevent nasty bugs + if (2 == size) { + uint16_t rev = *magic_u16; + ByteSwap::Swap(&rev); + if (data_u16[0] == *magic_u16 || data_u16[0] == rev) { + return true; + } + } + else if (4 == size) { + uint32_t rev = *magic_u32; + ByteSwap::Swap(&rev); + if (data_u32[0] == *magic_u32 || data_u32[0] == rev) { + return true; + } + } + else { + // any length ... just compare + if(!memcmp(magic,data,size)) { + return true; + } + } + magic += size; + } + } + return false; } #include "../contrib/ConvertUTF/ConvertUTF.h" @@ -290,309 +306,312 @@ void BaseImporter::GetExtensionList(std::set& extensions) // ------------------------------------------------------------------------------------------------ void ReportResult(ConversionResult res) { - if(res == sourceExhausted) { - DefaultLogger::get()->error("Source ends with incomplete character sequence, transformation to UTF-8 fails"); - } - else if(res == sourceIllegal) { - DefaultLogger::get()->error("Source contains illegal character sequence, transformation to UTF-8 fails"); - } + if(res == sourceExhausted) { + DefaultLogger::get()->error("Source ends with incomplete character sequence, transformation to UTF-8 fails"); + } + else if(res == sourceIllegal) { + DefaultLogger::get()->error("Source contains illegal character sequence, transformation to UTF-8 fails"); + } } // ------------------------------------------------------------------------------------------------ // Convert to UTF8 data void BaseImporter::ConvertToUTF8(std::vector& data) { - ConversionResult result; - if(data.size() < 8) { - throw DeadlyImportError("File is too small"); - } - - // UTF 8 with BOM - if((uint8_t)data[0] == 0xEF && (uint8_t)data[1] == 0xBB && (uint8_t)data[2] == 0xBF) { - DefaultLogger::get()->debug("Found UTF-8 BOM ..."); - - std::copy(data.begin()+3,data.end(),data.begin()); - data.resize(data.size()-3); - return; - } - - // UTF 32 BE with BOM - if(*((uint32_t*)&data.front()) == 0xFFFE0000) { - - // swap the endianess .. - for(uint32_t* p = (uint32_t*)&data.front(), *end = (uint32_t*)&data.back(); p <= end; ++p) { - AI_SWAP4P(p); - } - } - - // UTF 32 LE with BOM - if(*((uint32_t*)&data.front()) == 0x0000FFFE) { - DefaultLogger::get()->debug("Found UTF-32 BOM ..."); - - const uint32_t* sstart = (uint32_t*)&data.front()+1, *send = (uint32_t*)&data.back()+1; - char* dstart,*dend; - std::vector output; - do { - output.resize(output.size()?output.size()*3/2:data.size()/2); - dstart = &output.front(),dend = &output.back()+1; - - result = ConvertUTF32toUTF8((const UTF32**)&sstart,(const UTF32*)send,(UTF8**)&dstart,(UTF8*)dend,lenientConversion); - } while(result == targetExhausted); - - ReportResult(result); - - // copy to output buffer. - const size_t outlen = (size_t)(dstart-&output.front()); - data.assign(output.begin(),output.begin()+outlen); - return; - } - - // UTF 16 BE with BOM - if(*((uint16_t*)&data.front()) == 0xFFFE) { - - // swap the endianess .. - for(uint16_t* p = (uint16_t*)&data.front(), *end = (uint16_t*)&data.back(); p <= end; ++p) { - ByteSwap::Swap2(p); - } - } - - // UTF 16 LE with BOM - if(*((uint16_t*)&data.front()) == 0xFEFF) { - DefaultLogger::get()->debug("Found UTF-16 BOM ..."); - - const uint16_t* sstart = (uint16_t*)&data.front()+1, *send = (uint16_t*)(&data.back()+1); - char* dstart,*dend; - std::vector output; - do { - output.resize(output.size()?output.size()*3/2:data.size()*3/4); - dstart = &output.front(),dend = &output.back()+1; - - result = ConvertUTF16toUTF8((const UTF16**)&sstart,(const UTF16*)send,(UTF8**)&dstart,(UTF8*)dend,lenientConversion); - } while(result == targetExhausted); - - ReportResult(result); - - // copy to output buffer. - const size_t outlen = (size_t)(dstart-&output.front()); - data.assign(output.begin(),output.begin()+outlen); - return; - } + ConversionResult result; + if(data.size() < 8) { + throw DeadlyImportError("File is too small"); + } + + // UTF 8 with BOM + if((uint8_t)data[0] == 0xEF && (uint8_t)data[1] == 0xBB && (uint8_t)data[2] == 0xBF) { + DefaultLogger::get()->debug("Found UTF-8 BOM ..."); + + std::copy(data.begin()+3,data.end(),data.begin()); + data.resize(data.size()-3); + return; + } + + // UTF 32 BE with BOM + if(*((uint32_t*)&data.front()) == 0xFFFE0000) { + + // swap the endianness .. + for(uint32_t* p = (uint32_t*)&data.front(), *end = (uint32_t*)&data.back(); p <= end; ++p) { + AI_SWAP4P(p); + } + } + + // UTF 32 LE with BOM + if(*((uint32_t*)&data.front()) == 0x0000FFFE) { + DefaultLogger::get()->debug("Found UTF-32 BOM ..."); + + const uint32_t* sstart = (uint32_t*)&data.front()+1, *send = (uint32_t*)&data.back()+1; + char* dstart,*dend; + std::vector output; + do { + output.resize(output.size()?output.size()*3/2:data.size()/2); + dstart = &output.front(),dend = &output.back()+1; + + result = ConvertUTF32toUTF8((const UTF32**)&sstart,(const UTF32*)send,(UTF8**)&dstart,(UTF8*)dend,lenientConversion); + } while(result == targetExhausted); + + ReportResult(result); + + // copy to output buffer. + const size_t outlen = (size_t)(dstart-&output.front()); + data.assign(output.begin(),output.begin()+outlen); + return; + } + + // UTF 16 BE with BOM + if(*((uint16_t*)&data.front()) == 0xFFFE) { + + // swap the endianness .. + for(uint16_t* p = (uint16_t*)&data.front(), *end = (uint16_t*)&data.back(); p <= end; ++p) { + ByteSwap::Swap2(p); + } + } + + // UTF 16 LE with BOM + if(*((uint16_t*)&data.front()) == 0xFEFF) { + DefaultLogger::get()->debug("Found UTF-16 BOM ..."); + + const uint16_t* sstart = (uint16_t*)&data.front()+1, *send = (uint16_t*)(&data.back()+1); + char* dstart,*dend; + std::vector output; + do { + output.resize(output.size()?output.size()*3/2:data.size()*3/4); + dstart = &output.front(),dend = &output.back()+1; + + result = ConvertUTF16toUTF8((const UTF16**)&sstart,(const UTF16*)send,(UTF8**)&dstart,(UTF8*)dend,lenientConversion); + } while(result == targetExhausted); + + ReportResult(result); + + // copy to output buffer. + const size_t outlen = (size_t)(dstart-&output.front()); + data.assign(output.begin(),output.begin()+outlen); + return; + } } // ------------------------------------------------------------------------------------------------ // Convert to UTF8 data to ISO-8859-1 void BaseImporter::ConvertUTF8toISO8859_1(std::string& data) { - unsigned int size = data.size(); - unsigned int i = 0, j = 0; + size_t size = data.size(); + size_t i = 0, j = 0; - while(i < size) { - if((unsigned char) data[i] < 0x80) { - data[j] = data[i]; - } else if(i < size - 1) { - if((unsigned char) data[i] == 0xC2) { - data[j] = data[++i]; - } else if((unsigned char) data[i] == 0xC3) { - data[j] = ((unsigned char) data[++i] + 0x40); - } else { - std::stringstream stream; + while(i < size) { + if ((unsigned char) data[i] < (size_t) 0x80) { + data[j] = data[i]; + } else if(i < size - 1) { + if((unsigned char) data[i] == 0xC2) { + data[j] = data[++i]; + } else if((unsigned char) data[i] == 0xC3) { + data[j] = ((unsigned char) data[++i] + 0x40); + } else { + std::stringstream stream; - stream << "UTF8 code " << std::hex << data[i] << data[i + 1] << " can not be converted into ISA-8859-1."; + stream << "UTF8 code " << std::hex << data[i] << data[i + 1] << " can not be converted into ISA-8859-1."; - DefaultLogger::get()->error(stream.str()); + DefaultLogger::get()->error(stream.str()); - data[j++] = data[i++]; - data[j] = data[i]; - } - } else { - DefaultLogger::get()->error("UTF8 code but only one character remaining"); + data[j++] = data[i++]; + data[j] = data[i]; + } + } else { + DefaultLogger::get()->error("UTF8 code but only one character remaining"); - data[j] = data[i]; - } + data[j] = data[i]; + } - i++; j++; - } + i++; j++; + } - data.resize(j); + data.resize(j); } // ------------------------------------------------------------------------------------------------ void BaseImporter::TextFileToBuffer(IOStream* stream, - std::vector& data) + std::vector& data, + TextFileMode mode) { - ai_assert(NULL != stream); - - const size_t fileSize = stream->FileSize(); - if(!fileSize) { - throw DeadlyImportError("File is empty"); - } - - data.reserve(fileSize+1); - data.resize(fileSize); - if(fileSize != stream->Read( &data[0], 1, fileSize)) { - throw DeadlyImportError("File read error"); - } - - ConvertToUTF8(data); - - // append a binary zero to simplify string parsing - data.push_back(0); + ai_assert(NULL != stream); + + const size_t fileSize = stream->FileSize(); + if (mode == FORBID_EMPTY) { + if(!fileSize) { + throw DeadlyImportError("File is empty"); + } + } + + data.reserve(fileSize+1); + data.resize(fileSize); + if(fileSize > 0) { + if(fileSize != stream->Read( &data[0], 1, fileSize)) { + throw DeadlyImportError("File read error"); + } + + ConvertToUTF8(data); + } + + // append a binary zero to simplify string parsing + data.push_back(0); } // ------------------------------------------------------------------------------------------------ namespace Assimp { - // Represents an import request - struct LoadRequest - { - LoadRequest(const std::string& _file, unsigned int _flags,const BatchLoader::PropertyMap* _map, unsigned int _id) - : file(_file), flags(_flags), refCnt(1),scene(NULL), loaded(false), id(_id) - { - if (_map) - map = *_map; - } - - const std::string file; - unsigned int flags; - unsigned int refCnt; - aiScene* scene; - bool loaded; - BatchLoader::PropertyMap map; - unsigned int id; - - bool operator== (const std::string& f) { - return file == f; - } - }; + // Represents an import request + struct LoadRequest + { + LoadRequest(const std::string& _file, unsigned int _flags,const BatchLoader::PropertyMap* _map, unsigned int _id) + : file(_file), flags(_flags), refCnt(1),scene(NULL), loaded(false), id(_id) + { + if (_map) + map = *_map; + } + + const std::string file; + unsigned int flags; + unsigned int refCnt; + aiScene* scene; + bool loaded; + BatchLoader::PropertyMap map; + unsigned int id; + + bool operator== (const std::string& f) { + return file == f; + } + }; } // ------------------------------------------------------------------------------------------------ // BatchLoader::pimpl data structure struct Assimp::BatchData { - BatchData() - : next_id(0xffff) - {} + BatchData() + : pIOSystem() + , pImporter() + , next_id(0xffff) + {} - // IO system to be used for all imports - IOSystem* pIOSystem; + // IO system to be used for all imports + IOSystem* pIOSystem; - // Importer used to load all meshes - Importer* pImporter; + // Importer used to load all meshes + Importer* pImporter; - // List of all imports - std::list requests; + // List of all imports + std::list requests; - // Base path - std::string pathBase; + // Base path + std::string pathBase; - // Id for next item - unsigned int next_id; + // Id for next item + unsigned int next_id; }; // ------------------------------------------------------------------------------------------------ BatchLoader::BatchLoader(IOSystem* pIO) { - ai_assert(NULL != pIO); + ai_assert(NULL != pIO); - data = new BatchData(); - data->pIOSystem = pIO; + data = new BatchData(); + data->pIOSystem = pIO; - data->pImporter = new Importer(); - data->pImporter->SetIOHandler(data->pIOSystem); + data->pImporter = new Importer(); + data->pImporter->SetIOHandler(data->pIOSystem); } // ------------------------------------------------------------------------------------------------ BatchLoader::~BatchLoader() { - // delete all scenes wthat have not been polled by the user - for (std::list::iterator it = data->requests.begin();it != data->requests.end(); ++it) { - - delete (*it).scene; - } - data->pImporter->SetIOHandler(NULL); /* get pointer back into our posession */ - delete data->pImporter; - delete data; + // delete all scenes wthat have not been polled by the user + for (std::list::iterator it = data->requests.begin();it != data->requests.end(); ++it) { + + delete (*it).scene; + } + data->pImporter->SetIOHandler(NULL); /* get pointer back into our possession */ + delete data->pImporter; + delete data; } // ------------------------------------------------------------------------------------------------ -unsigned int BatchLoader::AddLoadRequest (const std::string& file, - unsigned int steps /*= 0*/, const PropertyMap* map /*= NULL*/) +unsigned int BatchLoader::AddLoadRequest (const std::string& file, + unsigned int steps /*= 0*/, const PropertyMap* map /*= NULL*/) { - ai_assert(!file.empty()); - - // check whether we have this loading request already - std::list::iterator it; - for (it = data->requests.begin();it != data->requests.end(); ++it) { - - // Call IOSystem's path comparison function here - if (data->pIOSystem->ComparePaths((*it).file,file)) { - - if (map) { - if (!((*it).map == *map)) - continue; - } - else if (!(*it).map.empty()) - continue; - - (*it).refCnt++; - return (*it).id; - } - } - - // no, we don't have it. So add it to the queue ... - data->requests.push_back(LoadRequest(file,steps,map,data->next_id)); - return data->next_id++; + ai_assert(!file.empty()); + + // check whether we have this loading request already + std::list::iterator it; + for (it = data->requests.begin();it != data->requests.end(); ++it) { + + // Call IOSystem's path comparison function here + if (data->pIOSystem->ComparePaths((*it).file,file)) { + + if (map) { + if (!((*it).map == *map)) + continue; + } + else if (!(*it).map.empty()) + continue; + + (*it).refCnt++; + return (*it).id; + } + } + + // no, we don't have it. So add it to the queue ... + data->requests.push_back(LoadRequest(file,steps,map,data->next_id)); + return data->next_id++; } // ------------------------------------------------------------------------------------------------ -aiScene* BatchLoader::GetImport (unsigned int which) +aiScene* BatchLoader::GetImport (unsigned int which) { - for (std::list::iterator it = data->requests.begin();it != data->requests.end(); ++it) { - - if ((*it).id == which && (*it).loaded) { - - aiScene* sc = (*it).scene; - if (!(--(*it).refCnt)) { - data->requests.erase(it); - } - return sc; - } - } - return NULL; + for (std::list::iterator it = data->requests.begin();it != data->requests.end(); ++it) { + + if ((*it).id == which && (*it).loaded) { + + aiScene* sc = (*it).scene; + if (!(--(*it).refCnt)) { + data->requests.erase(it); + } + return sc; + } + } + return NULL; } // ------------------------------------------------------------------------------------------------ void BatchLoader::LoadAll() { - // no threaded implementation for the moment - for (std::list::iterator it = data->requests.begin();it != data->requests.end(); ++it) { - // force validation in debug builds - unsigned int pp = (*it).flags; + // no threaded implementation for the moment + for (std::list::iterator it = data->requests.begin();it != data->requests.end(); ++it) { + // force validation in debug builds + unsigned int pp = (*it).flags; #ifdef ASSIMP_BUILD_DEBUG - pp |= aiProcess_ValidateDataStructure; + pp |= aiProcess_ValidateDataStructure; #endif - // setup config properties if necessary - ImporterPimpl* pimpl = data->pImporter->Pimpl(); - pimpl->mFloatProperties = (*it).map.floats; - pimpl->mIntProperties = (*it).map.ints; - pimpl->mStringProperties = (*it).map.strings; - pimpl->mMatrixProperties = (*it).map.matrices; - - if (!DefaultLogger::isNullLogger()) - { - DefaultLogger::get()->info("%%% BEGIN EXTERNAL FILE %%%"); - DefaultLogger::get()->info("File: " + (*it).file); - } - data->pImporter->ReadFile((*it).file,pp); - (*it).scene = data->pImporter->GetOrphanedScene(); - (*it).loaded = true; - - DefaultLogger::get()->info("%%% END EXTERNAL FILE %%%"); - } + // setup config properties if necessary + ImporterPimpl* pimpl = data->pImporter->Pimpl(); + pimpl->mFloatProperties = (*it).map.floats; + pimpl->mIntProperties = (*it).map.ints; + pimpl->mStringProperties = (*it).map.strings; + pimpl->mMatrixProperties = (*it).map.matrices; + + if (!DefaultLogger::isNullLogger()) + { + DefaultLogger::get()->info("%%% BEGIN EXTERNAL FILE %%%"); + DefaultLogger::get()->info("File: " + (*it).file); + } + data->pImporter->ReadFile((*it).file,pp); + (*it).scene = data->pImporter->GetOrphanedScene(); + (*it).loaded = true; + + DefaultLogger::get()->info("%%% END EXTERNAL FILE %%%"); + } } - - - - diff --git a/src/3rdparty/assimp/code/BaseImporter.h b/src/3rdparty/assimp/code/BaseImporter.h index 491c9cea1..5c9ddfa5e 100644 --- a/src/3rdparty/assimp/code/BaseImporter.h +++ b/src/3rdparty/assimp/code/BaseImporter.h @@ -2,11 +2,11 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2012, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above @@ -23,16 +23,16 @@ following conditions are met: derived from this software without specific prior written permission of the assimp team. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- @@ -47,318 +47,350 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include -#include "./../include/assimp/types.h" +#include +#include +#include struct aiScene; -namespace Assimp { +namespace Assimp { -class IOSystem; class Importer; -class BaseImporter; +class IOSystem; class BaseProcess; class SharedPostProcessInfo; class IOStream; + // utility to do char4 to uint32 in a portable manner #define AI_MAKE_MAGIC(string) ((uint32_t)((string[0] << 24) + \ - (string[1] << 16) + (string[2] << 8) + string[3])) + (string[1] << 16) + (string[2] << 8) + string[3])) // --------------------------------------------------------------------------- template struct ScopeGuard { - ScopeGuard(T* obj) : obj(obj), mdismiss() {} - ~ScopeGuard () throw() { - if (!mdismiss) { - delete obj; - } - obj = NULL; - } - - T* dismiss() { - mdismiss=true; - return obj; - } - - operator T*() { - return obj; - } - - T* operator -> () { - return obj; - } + explicit ScopeGuard(T* obj) : obj(obj), mdismiss() {} + ~ScopeGuard () throw() { + if (!mdismiss) { + delete obj; + } + obj = NULL; + } + + T* dismiss() { + mdismiss=true; + return obj; + } + + operator T*() { + return obj; + } + + T* operator -> () { + return obj; + } private: - T* obj; - bool mdismiss; + // no copying allowed. + ScopeGuard(); + ScopeGuard( const ScopeGuard & ); + ScopeGuard &operator = ( const ScopeGuard & ); + + T* obj; + bool mdismiss; }; // --------------------------------------------------------------------------- -/** FOR IMPORTER PLUGINS ONLY: The BaseImporter defines a common interface +/** FOR IMPORTER PLUGINS ONLY: The BaseImporter defines a common interface * for all importer worker classes. * - * The interface defines two functions: CanRead() is used to check if the - * importer can handle the format of the given file. If an implementation of - * this function returns true, the importer then calls ReadFile() which - * imports the given file. ReadFile is not overridable, it just calls + * The interface defines two functions: CanRead() is used to check if the + * importer can handle the format of the given file. If an implementation of + * this function returns true, the importer then calls ReadFile() which + * imports the given file. ReadFile is not overridable, it just calls * InternReadFile() and catches any ImportErrorException that might occur. */ class ASSIMP_API BaseImporter { - friend class Importer; + friend class Importer; public: - /** Constructor to be privately used by #Importer */ - BaseImporter(); + /** Constructor to be privately used by #Importer */ + BaseImporter(); - /** Destructor, private as well */ - virtual ~BaseImporter(); + /** Destructor, private as well */ + virtual ~BaseImporter(); public: - // ------------------------------------------------------------------- - /** Returns whether the class can handle the format of the given file. - * - * The implementation should be as quick as possible. A check for - * the file extension is enough. If no suitable loader is found with - * this strategy, CanRead() is called again, the 'checkSig' parameter - * set to true this time. Now the implementation is expected to - * perform a full check of the file structure, possibly searching the - * first bytes of the file for magic identifiers or keywords. - * - * @param pFile Path and file name of the file to be examined. - * @param pIOHandler The IO handler to use for accessing any file. - * @param checkSig Set to true if this method is called a second time. - * This time, the implementation may take more time to examine the - * contents of the file to be loaded for magic bytes, keywords, etc - * to be able to load files with unknown/not existent file extensions. - * @return true if the class can read this file, false if not. - */ - virtual bool CanRead( - const std::string& pFile, - IOSystem* pIOHandler, - bool checkSig - ) const = 0; - - // ------------------------------------------------------------------- - /** Imports the given file and returns the imported data. - * If the import succeeds, ownership of the data is transferred to - * the caller. If the import fails, NULL is returned. The function - * takes care that any partially constructed data is destroyed - * beforehand. - * - * @param pImp #Importer object hosting this loader. - * @param pFile Path of the file to be imported. - * @param pIOHandler IO-Handler used to open this and possible other files. - * @return The imported data or NULL if failed. If it failed a - * human-readable error description can be retrieved by calling - * GetErrorText() - * - * @note This function is not intended to be overridden. Implement - * InternReadFile() to do the import. If an exception is thrown somewhere - * in InternReadFile(), this function will catch it and transform it into - * a suitable response to the caller. - */ - aiScene* ReadFile( - const Importer* pImp, - const std::string& pFile, - IOSystem* pIOHandler - ); - - // ------------------------------------------------------------------- - /** Returns the error description of the last error that occured. - * @return A description of the last error that occured. An empty - * string if there was no error. - */ - const std::string& GetErrorText() const { - return mErrorText; - } - - // ------------------------------------------------------------------- - /** Called prior to ReadFile(). - * The function is a request to the importer to update its configuration - * basing on the Importer's configuration property list. - * @param pImp Importer instance - */ - virtual void SetupProperties( - const Importer* pImp - ); - - - // ------------------------------------------------------------------- - /** Called by #Importer::GetImporterInfo to get a description of - * some loader features. Importers must provide this information. */ - virtual const aiImporterDesc* GetInfo() const = 0; - - - - // ------------------------------------------------------------------- - /** Called by #Importer::GetExtensionList for each loaded importer. - * Take the extension list contained in the structure returned by - * #GetInfo and insert all file extensions into the given set. - * @param extension set to collect file extensions in*/ - void GetExtensionList(std::set& extensions); + // ------------------------------------------------------------------- + /** Returns whether the class can handle the format of the given file. + * + * The implementation should be as quick as possible. A check for + * the file extension is enough. If no suitable loader is found with + * this strategy, CanRead() is called again, the 'checkSig' parameter + * set to true this time. Now the implementation is expected to + * perform a full check of the file structure, possibly searching the + * first bytes of the file for magic identifiers or keywords. + * + * @param pFile Path and file name of the file to be examined. + * @param pIOHandler The IO handler to use for accessing any file. + * @param checkSig Set to true if this method is called a second time. + * This time, the implementation may take more time to examine the + * contents of the file to be loaded for magic bytes, keywords, etc + * to be able to load files with unknown/not existent file extensions. + * @return true if the class can read this file, false if not. + */ + virtual bool CanRead( + const std::string& pFile, + IOSystem* pIOHandler, + bool checkSig + ) const = 0; + + // ------------------------------------------------------------------- + /** Imports the given file and returns the imported data. + * If the import succeeds, ownership of the data is transferred to + * the caller. If the import fails, NULL is returned. The function + * takes care that any partially constructed data is destroyed + * beforehand. + * + * @param pImp #Importer object hosting this loader. + * @param pFile Path of the file to be imported. + * @param pIOHandler IO-Handler used to open this and possible other files. + * @return The imported data or NULL if failed. If it failed a + * human-readable error description can be retrieved by calling + * GetErrorText() + * + * @note This function is not intended to be overridden. Implement + * InternReadFile() to do the import. If an exception is thrown somewhere + * in InternReadFile(), this function will catch it and transform it into + * a suitable response to the caller. + */ + aiScene* ReadFile( + const Importer* pImp, + const std::string& pFile, + IOSystem* pIOHandler + ); + + // ------------------------------------------------------------------- + /** Returns the error description of the last error that occurred. + * @return A description of the last error that occurred. An empty + * string if there was no error. + */ + const std::string& GetErrorText() const { + return m_ErrorText; + } + + // ------------------------------------------------------------------- + /** Called prior to ReadFile(). + * The function is a request to the importer to update its configuration + * basing on the Importer's configuration property list. + * @param pImp Importer instance + */ + virtual void SetupProperties( + const Importer* pImp + ); + + + // ------------------------------------------------------------------- + /** Called by #Importer::GetImporterInfo to get a description of + * some loader features. Importers must provide this information. */ + virtual const aiImporterDesc* GetInfo() const = 0; + + + + // ------------------------------------------------------------------- + /** Called by #Importer::GetExtensionList for each loaded importer. + * Take the extension list contained in the structure returned by + * #GetInfo and insert all file extensions into the given set. + * @param extension set to collect file extensions in*/ + void GetExtensionList(std::set& extensions); protected: - // ------------------------------------------------------------------- - /** Imports the given file into the given scene structure. The - * function is expected to throw an ImportErrorException if there is - * an error. If it terminates normally, the data in aiScene is - * expected to be correct. Override this function to implement the - * actual importing. - *
- * The output scene must meet the following requirements:
- *
    - *
  • At least a root node must be there, even if its only purpose - * is to reference one mesh.
  • - *
  • aiMesh::mPrimitiveTypes may be 0. The types of primitives - * in the mesh are determined automatically in this case.
  • - *
  • the vertex data is stored in a pseudo-indexed "verbose" format. - * In fact this means that every vertex that is referenced by - * a face is unique. Or the other way round: a vertex index may - * not occur twice in a single aiMesh.
  • - *
  • aiAnimation::mDuration may be -1. Assimp determines the length - * of the animation automatically in this case as the length of - * the longest animation channel.
  • - *
  • aiMesh::mBitangents may be NULL if tangents and normals are - * given. In this case bitangents are computed as the cross product - * between normal and tangent.
  • - *
  • There needn't be a material. If none is there a default material - * is generated. However, it is recommended practice for loaders - * to generate a default material for yourself that matches the - * default material setting for the file format better than Assimp's - * generic default material. Note that default materials *should* - * be named AI_DEFAULT_MATERIAL_NAME if they're just color-shaded - * or AI_DEFAULT_TEXTURED_MATERIAL_NAME if they define a (dummy) - * texture.
  • - *
- * If the AI_SCENE_FLAGS_INCOMPLETE-Flag is not set:
    - *
  • at least one mesh must be there
  • - *
  • there may be no meshes with 0 vertices or faces
  • - *
- * This won't be checked (except by the validation step): Assimp will - * crash if one of the conditions is not met! - * - * @param pFile Path of the file to be imported. - * @param pScene The scene object to hold the imported data. - * NULL is not a valid parameter. - * @param pIOHandler The IO handler to use for any file access. - * NULL is not a valid parameter. */ - virtual void InternReadFile( - const std::string& pFile, - aiScene* pScene, - IOSystem* pIOHandler - ) = 0; + // ------------------------------------------------------------------- + /** Imports the given file into the given scene structure. The + * function is expected to throw an ImportErrorException if there is + * an error. If it terminates normally, the data in aiScene is + * expected to be correct. Override this function to implement the + * actual importing. + *
+ * The output scene must meet the following requirements:
+ *
    + *
  • At least a root node must be there, even if its only purpose + * is to reference one mesh.
  • + *
  • aiMesh::mPrimitiveTypes may be 0. The types of primitives + * in the mesh are determined automatically in this case.
  • + *
  • the vertex data is stored in a pseudo-indexed "verbose" format. + * In fact this means that every vertex that is referenced by + * a face is unique. Or the other way round: a vertex index may + * not occur twice in a single aiMesh.
  • + *
  • aiAnimation::mDuration may be -1. Assimp determines the length + * of the animation automatically in this case as the length of + * the longest animation channel.
  • + *
  • aiMesh::mBitangents may be NULL if tangents and normals are + * given. In this case bitangents are computed as the cross product + * between normal and tangent.
  • + *
  • There needn't be a material. If none is there a default material + * is generated. However, it is recommended practice for loaders + * to generate a default material for yourself that matches the + * default material setting for the file format better than Assimp's + * generic default material. Note that default materials *should* + * be named AI_DEFAULT_MATERIAL_NAME if they're just color-shaded + * or AI_DEFAULT_TEXTURED_MATERIAL_NAME if they define a (dummy) + * texture.
  • + *
+ * If the AI_SCENE_FLAGS_INCOMPLETE-Flag is not set:
    + *
  • at least one mesh must be there
  • + *
  • there may be no meshes with 0 vertices or faces
  • + *
+ * This won't be checked (except by the validation step): Assimp will + * crash if one of the conditions is not met! + * + * @param pFile Path of the file to be imported. + * @param pScene The scene object to hold the imported data. + * NULL is not a valid parameter. + * @param pIOHandler The IO handler to use for any file access. + * NULL is not a valid parameter. */ + virtual void InternReadFile( + const std::string& pFile, + aiScene* pScene, + IOSystem* pIOHandler + ) = 0; public: // static utilities - // ------------------------------------------------------------------- - /** A utility for CanRead(). - * - * The function searches the header of a file for a specific token - * and returns true if this token is found. This works for text - * files only. There is a rudimentary handling of UNICODE files. - * The comparison is case independent. - * - * @param pIOSystem IO System to work with - * @param file File name of the file - * @param tokens List of tokens to search for - * @param numTokens Size of the token array - * @param searchBytes Number of bytes to be searched for the tokens. - */ - static bool SearchFileHeaderForToken( - IOSystem* pIOSystem, - const std::string& file, - const char** tokens, - unsigned int numTokens, - unsigned int searchBytes = 200, - bool tokensSol = false); - - // ------------------------------------------------------------------- - /** @brief Check whether a file has a specific file extension - * @param pFile Input file - * @param ext0 Extension to check for. Lowercase characters only, no dot! - * @param ext1 Optional second extension - * @param ext2 Optional third extension - * @note Case-insensitive - */ - static bool SimpleExtensionCheck ( - const std::string& pFile, - const char* ext0, - const char* ext1 = NULL, - const char* ext2 = NULL); - - // ------------------------------------------------------------------- - /** @brief Extract file extension from a string - * @param pFile Input file - * @return Extension without trailing dot, all lowercase - */ - static std::string GetExtension ( - const std::string& pFile); - - // ------------------------------------------------------------------- - /** @brief Check whether a file starts with one or more magic tokens - * @param pFile Input file - * @param pIOHandler IO system to be used - * @param magic n magic tokens - * @params num Size of magic - * @param offset Offset from file start where tokens are located - * @param Size of one token, in bytes. Maximally 16 bytes. - * @return true if one of the given tokens was found - * - * @note For convinence, the check is also performed for the - * byte-swapped variant of all tokens (big endian). Only for - * tokens of size 2,4. - */ - static bool CheckMagicToken( - IOSystem* pIOHandler, - const std::string& pFile, - const void* magic, - unsigned int num, - unsigned int offset = 0, - unsigned int size = 4); - - // ------------------------------------------------------------------- - /** An utility for all text file loaders. It converts a file to our - * UTF8 character set. Errors are reported, but ignored. - * - * @param data File buffer to be converted to UTF8 data. The buffer - * is resized as appropriate. */ - static void ConvertToUTF8( - std::vector& data); - - // ------------------------------------------------------------------- - /** An utility for all text file loaders. It converts a file from our - * UTF8 character set back to ISO-8859-1. Errors are reported, but ignored. - * - * @param data File buffer to be converted from UTF8 to ISO-8859-1. The buffer - * is resized as appropriate. */ - static void ConvertUTF8toISO8859_1( - std::string& data); - - // ------------------------------------------------------------------- - /** Utility for text file loaders which copies the contents of the - * file into a memory buffer and converts it to our UTF8 - * representation. - * @param stream Stream to read from. - * @param data Output buffer to be resized and filled with the - * converted text file data. The buffer is terminated with - * a binary 0. */ - static void TextFileToBuffer( - IOStream* stream, - std::vector& data); + // ------------------------------------------------------------------- + /** A utility for CanRead(). + * + * The function searches the header of a file for a specific token + * and returns true if this token is found. This works for text + * files only. There is a rudimentary handling of UNICODE files. + * The comparison is case independent. + * + * @param pIOSystem IO System to work with + * @param file File name of the file + * @param tokens List of tokens to search for + * @param numTokens Size of the token array + * @param searchBytes Number of bytes to be searched for the tokens. + */ + static bool SearchFileHeaderForToken( + IOSystem* pIOSystem, + const std::string& file, + const char** tokens, + unsigned int numTokens, + unsigned int searchBytes = 200, + bool tokensSol = false); + + // ------------------------------------------------------------------- + /** @brief Check whether a file has a specific file extension + * @param pFile Input file + * @param ext0 Extension to check for. Lowercase characters only, no dot! + * @param ext1 Optional second extension + * @param ext2 Optional third extension + * @note Case-insensitive + */ + static bool SimpleExtensionCheck ( + const std::string& pFile, + const char* ext0, + const char* ext1 = NULL, + const char* ext2 = NULL); + + // ------------------------------------------------------------------- + /** @brief Extract file extension from a string + * @param pFile Input file + * @return Extension without trailing dot, all lowercase + */ + static std::string GetExtension ( + const std::string& pFile); + + // ------------------------------------------------------------------- + /** @brief Check whether a file starts with one or more magic tokens + * @param pFile Input file + * @param pIOHandler IO system to be used + * @param magic n magic tokens + * @params num Size of magic + * @param offset Offset from file start where tokens are located + * @param Size of one token, in bytes. Maximally 16 bytes. + * @return true if one of the given tokens was found + * + * @note For convinence, the check is also performed for the + * byte-swapped variant of all tokens (big endian). Only for + * tokens of size 2,4. + */ + static bool CheckMagicToken( + IOSystem* pIOHandler, + const std::string& pFile, + const void* magic, + unsigned int num, + unsigned int offset = 0, + unsigned int size = 4); + + // ------------------------------------------------------------------- + /** An utility for all text file loaders. It converts a file to our + * UTF8 character set. Errors are reported, but ignored. + * + * @param data File buffer to be converted to UTF8 data. The buffer + * is resized as appropriate. */ + static void ConvertToUTF8( + std::vector& data); + + // ------------------------------------------------------------------- + /** An utility for all text file loaders. It converts a file from our + * UTF8 character set back to ISO-8859-1. Errors are reported, but ignored. + * + * @param data File buffer to be converted from UTF8 to ISO-8859-1. The buffer + * is resized as appropriate. */ + static void ConvertUTF8toISO8859_1( + std::string& data); + + enum TextFileMode { ALLOW_EMPTY, FORBID_EMPTY }; + + // ------------------------------------------------------------------- + /** Utility for text file loaders which copies the contents of the + * file into a memory buffer and converts it to our UTF8 + * representation. + * @param stream Stream to read from. + * @param data Output buffer to be resized and filled with the + * converted text file data. The buffer is terminated with + * a binary 0. + * @param mode Whether it is OK to load empty text files. */ + static void TextFileToBuffer( + IOStream* stream, + std::vector& data, + TextFileMode mode = FORBID_EMPTY); + + // ------------------------------------------------------------------- + /** Utility function to move a std::vector into a aiScene array + * @param vec The vector to be moved + * @param out The output pointer to the allocated array. + * @param numOut The output count of elements copied. */ + template + AI_FORCE_INLINE + static void CopyVector( + std::vector& vec, + T*& out, + unsigned int& outLength) + { + outLength = unsigned(vec.size()); + if (outLength) { + out = new T[outLength]; + std::swap_ranges(vec.begin(), vec.end(), out); + } + } + + protected: - /** Error description in case there was one. */ - std::string mErrorText; + /** Error description in case there was one. */ + std::string m_ErrorText; - /** Currently set progress handler */ - ProgressHandler* progress; + /** Currently set progress handler */ + ProgressHandler* m_progress; }; diff --git a/src/3rdparty/assimp/code/BaseProcess.cpp b/src/3rdparty/assimp/code/BaseProcess.cpp index 9bac9ec89..580f89cdb 100644 --- a/src/3rdparty/assimp/code/BaseProcess.cpp +++ b/src/3rdparty/assimp/code/BaseProcess.cpp @@ -3,12 +3,12 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2012, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above @@ -25,26 +25,26 @@ conditions are met: derived from this software without specific prior written permission of the assimp team. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --------------------------------------------------------------------------- */ /** @file Implementation of BaseProcess */ -#include "AssimpPCH.h" #include "BaseImporter.h" #include "BaseProcess.h" - +#include +#include #include "Importer.h" using namespace Assimp; @@ -61,45 +61,45 @@ BaseProcess::BaseProcess() // Destructor, private as well BaseProcess::~BaseProcess() { - // nothing to do here + // nothing to do here } // ------------------------------------------------------------------------------------------------ void BaseProcess::ExecuteOnScene( Importer* pImp) { - ai_assert(NULL != pImp && NULL != pImp->Pimpl()->mScene); + ai_assert(NULL != pImp && NULL != pImp->Pimpl()->mScene); - progress = pImp->GetProgressHandler(); - ai_assert(progress); + progress = pImp->GetProgressHandler(); + ai_assert(progress); - SetupProperties( pImp ); + SetupProperties( pImp ); - // catch exceptions thrown inside the PostProcess-Step - try - { - Execute(pImp->Pimpl()->mScene); + // catch exceptions thrown inside the PostProcess-Step + try + { + Execute(pImp->Pimpl()->mScene); - } catch( const std::exception& err ) { + } catch( const std::exception& err ) { - // extract error description - pImp->Pimpl()->mErrorString = err.what(); - DefaultLogger::get()->error(pImp->Pimpl()->mErrorString); + // extract error description + pImp->Pimpl()->mErrorString = err.what(); + DefaultLogger::get()->error(pImp->Pimpl()->mErrorString); - // and kill the partially imported data - delete pImp->Pimpl()->mScene; - pImp->Pimpl()->mScene = NULL; - } + // and kill the partially imported data + delete pImp->Pimpl()->mScene; + pImp->Pimpl()->mScene = NULL; + } } // ------------------------------------------------------------------------------------------------ void BaseProcess::SetupProperties(const Importer* /*pImp*/) { - // the default implementation does nothing + // the default implementation does nothing } // ------------------------------------------------------------------------------------------------ bool BaseProcess::RequireVerboseFormat() const { - return true; + return true; } diff --git a/src/3rdparty/assimp/code/BaseProcess.h b/src/3rdparty/assimp/code/BaseProcess.h index 3bae1899d..148f07284 100644 --- a/src/3rdparty/assimp/code/BaseProcess.h +++ b/src/3rdparty/assimp/code/BaseProcess.h @@ -2,11 +2,11 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2012, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above @@ -23,16 +23,16 @@ following conditions are met: derived from this software without specific prior written permission of the assimp team. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- @@ -44,12 +44,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include -#include "../include/assimp/types.h" +#include #include "GenericProperty.h" struct aiScene; -namespace Assimp { +namespace Assimp { class Importer; @@ -64,121 +64,121 @@ class SharedPostProcessInfo { public: - struct Base - { - virtual ~Base() - {} - }; - - //! Represents data that is allocated on the heap, thus needs to be deleted - template - struct THeapData : public Base - { - THeapData(T* in) - : data (in) - {} - - ~THeapData() - { - delete data; - } - T* data; - }; - - //! Represents static, by-value data not allocated on the heap - template - struct TStaticData : public Base - { - TStaticData(T in) - : data (in) - {} - - ~TStaticData() - {} - - T data; - }; - - // some typedefs for cleaner code - typedef unsigned int KeyType; - typedef std::map PropertyMap; + struct Base + { + virtual ~Base() + {} + }; + + //! Represents data that is allocated on the heap, thus needs to be deleted + template + struct THeapData : public Base + { + explicit THeapData(T* in) + : data (in) + {} + + ~THeapData() + { + delete data; + } + T* data; + }; + + //! Represents static, by-value data not allocated on the heap + template + struct TStaticData : public Base + { + explicit TStaticData(T in) + : data (in) + {} + + ~TStaticData() + {} + + T data; + }; + + // some typedefs for cleaner code + typedef unsigned int KeyType; + typedef std::map PropertyMap; public: - //! Destructor - ~SharedPostProcessInfo() - { - Clean(); - } - - //! Remove all stored properties from the table - void Clean() - { - // invoke the virtual destructor for all stored properties - for (PropertyMap::iterator it = pmap.begin(), end = pmap.end(); - it != end; ++it) - { - delete (*it).second; - } - pmap.clear(); - } - - //! Add a heap property to the list - template - void AddProperty( const char* name, T* in ){ - AddProperty(name,(Base*)new THeapData(in)); - } - - //! Add a static by-value property to the list - template - void AddProperty( const char* name, T in ){ - AddProperty(name,(Base*)new TStaticData(in)); - } - - - //! Get a heap property - template - bool GetProperty( const char* name, T*& out ) const - { - THeapData* t = (THeapData*)GetPropertyInternal(name); - if(!t) - { - out = NULL; - return false; - } - out = t->data; - return true; - } - - //! Get a static, by-value property - template - bool GetProperty( const char* name, T& out ) const - { - TStaticData* t = (TStaticData*)GetPropertyInternal(name); - if(!t)return false; - out = t->data; - return true; - } - - //! Remove a property of a specific type - void RemoveProperty( const char* name) { - SetGenericPropertyPtr(pmap,name,NULL); - } + //! Destructor + ~SharedPostProcessInfo() + { + Clean(); + } + + //! Remove all stored properties from the table + void Clean() + { + // invoke the virtual destructor for all stored properties + for (PropertyMap::iterator it = pmap.begin(), end = pmap.end(); + it != end; ++it) + { + delete (*it).second; + } + pmap.clear(); + } + + //! Add a heap property to the list + template + void AddProperty( const char* name, T* in ){ + AddProperty(name,(Base*)new THeapData(in)); + } + + //! Add a static by-value property to the list + template + void AddProperty( const char* name, T in ){ + AddProperty(name,(Base*)new TStaticData(in)); + } + + + //! Get a heap property + template + bool GetProperty( const char* name, T*& out ) const + { + THeapData* t = (THeapData*)GetPropertyInternal(name); + if(!t) + { + out = NULL; + return false; + } + out = t->data; + return true; + } + + //! Get a static, by-value property + template + bool GetProperty( const char* name, T& out ) const + { + TStaticData* t = (TStaticData*)GetPropertyInternal(name); + if(!t)return false; + out = t->data; + return true; + } + + //! Remove a property of a specific type + void RemoveProperty( const char* name) { + SetGenericPropertyPtr(pmap,name,NULL); + } private: - void AddProperty( const char* name, Base* data) { - SetGenericPropertyPtr(pmap,name,data); - } + void AddProperty( const char* name, Base* data) { + SetGenericPropertyPtr(pmap,name,data); + } - Base* GetPropertyInternal( const char* name) const { - return GetGenericProperty(pmap,name,NULL); - } + Base* GetPropertyInternal( const char* name) const { + return GetGenericProperty(pmap,name,NULL); + } private: - //! Map of all stored properties - PropertyMap pmap; + //! Map of all stored properties + PropertyMap pmap; }; #if 0 @@ -188,12 +188,12 @@ private: * * For future use. */ - struct PPDependencyTable + struct PPDependencyTable { - unsigned int execute_me_before_these; - unsigned int execute_me_after_these; - unsigned int only_if_these_are_not_specified; - unsigned int mutually_exclusive_with; + unsigned int execute_me_before_these; + unsigned int execute_me_after_these; + unsigned int only_if_these_are_not_specified; + unsigned int mutually_exclusive_with; }; #endif @@ -204,88 +204,88 @@ private: // --------------------------------------------------------------------------- /** The BaseProcess defines a common interface for all post processing steps. * A post processing step is run after a successful import if the caller - * specified the corresponding flag when calling ReadFile(). - * Enum #aiPostProcessSteps defines which flags are available. - * After a successful import the Importer iterates over its internal array - * of processes and calls IsActive() on each process to evaluate if the step - * should be executed. If the function returns true, the class' Execute() + * specified the corresponding flag when calling ReadFile(). + * Enum #aiPostProcessSteps defines which flags are available. + * After a successful import the Importer iterates over its internal array + * of processes and calls IsActive() on each process to evaluate if the step + * should be executed. If the function returns true, the class' Execute() * function is called subsequently. */ -class ASSIMP_API_WINONLY BaseProcess +class ASSIMP_API_WINONLY BaseProcess { - friend class Importer; + friend class Importer; public: - /** Constructor to be privately used by Importer */ - BaseProcess(); + /** Constructor to be privately used by Importer */ + BaseProcess(); - /** Destructor, private as well */ - virtual ~BaseProcess(); + /** Destructor, private as well */ + virtual ~BaseProcess(); public: - // ------------------------------------------------------------------- - /** Returns whether the processing step is present in the given flag. - * @param pFlags The processing flags the importer was called with. A - * bitwise combination of #aiPostProcessSteps. - * @return true if the process is present in this flag fields, - * false if not. - */ - virtual bool IsActive( unsigned int pFlags) const = 0; - - // ------------------------------------------------------------------- - /** Check whether this step expects its input vertex data to be - * in verbose format. */ - virtual bool RequireVerboseFormat() const; - - // ------------------------------------------------------------------- - /** Executes the post processing step on the given imported data. - * The function deletes the scene if the postprocess step fails ( - * the object pointer will be set to NULL). - * @param pImp Importer instance (pImp->mScene must be valid) - */ - void ExecuteOnScene( Importer* pImp); - - // ------------------------------------------------------------------- - /** Called prior to ExecuteOnScene(). - * The function is a request to the process to update its configuration - * basing on the Importer's configuration property list. - */ - virtual void SetupProperties(const Importer* pImp); - - // ------------------------------------------------------------------- - /** Executes the post processing step on the given imported data. - * A process should throw an ImportErrorException* if it fails. - * This method must be implemented by deriving classes. - * @param pScene The imported data to work at. - */ - virtual void Execute( aiScene* pScene) = 0; - - - // ------------------------------------------------------------------- - /** Assign a new SharedPostProcessInfo to the step. This object - * allows multiple postprocess steps to share data. - * @param sh May be NULL - */ - inline void SetSharedData(SharedPostProcessInfo* sh) { - shared = sh; - } - - // ------------------------------------------------------------------- - /** Get the shared data that is assigned to the step. - */ - inline SharedPostProcessInfo* GetSharedData() { - return shared; - } + // ------------------------------------------------------------------- + /** Returns whether the processing step is present in the given flag. + * @param pFlags The processing flags the importer was called with. A + * bitwise combination of #aiPostProcessSteps. + * @return true if the process is present in this flag fields, + * false if not. + */ + virtual bool IsActive( unsigned int pFlags) const = 0; + + // ------------------------------------------------------------------- + /** Check whether this step expects its input vertex data to be + * in verbose format. */ + virtual bool RequireVerboseFormat() const; + + // ------------------------------------------------------------------- + /** Executes the post processing step on the given imported data. + * The function deletes the scene if the postprocess step fails ( + * the object pointer will be set to NULL). + * @param pImp Importer instance (pImp->mScene must be valid) + */ + void ExecuteOnScene( Importer* pImp); + + // ------------------------------------------------------------------- + /** Called prior to ExecuteOnScene(). + * The function is a request to the process to update its configuration + * basing on the Importer's configuration property list. + */ + virtual void SetupProperties(const Importer* pImp); + + // ------------------------------------------------------------------- + /** Executes the post processing step on the given imported data. + * A process should throw an ImportErrorException* if it fails. + * This method must be implemented by deriving classes. + * @param pScene The imported data to work at. + */ + virtual void Execute( aiScene* pScene) = 0; + + + // ------------------------------------------------------------------- + /** Assign a new SharedPostProcessInfo to the step. This object + * allows multiple postprocess steps to share data. + * @param sh May be NULL + */ + inline void SetSharedData(SharedPostProcessInfo* sh) { + shared = sh; + } + + // ------------------------------------------------------------------- + /** Get the shared data that is assigned to the step. + */ + inline SharedPostProcessInfo* GetSharedData() { + return shared; + } protected: - /** See the doc of #SharedPostProcessInfo for more details */ - SharedPostProcessInfo* shared; + /** See the doc of #SharedPostProcessInfo for more details */ + SharedPostProcessInfo* shared; - /** Currently active progress handler */ - ProgressHandler* progress; + /** Currently active progress handler */ + ProgressHandler* progress; }; diff --git a/src/3rdparty/assimp/code/Bitmap.cpp b/src/3rdparty/assimp/code/Bitmap.cpp index 30b5744ad..ae6d62083 100644 --- a/src/3rdparty/assimp/code/Bitmap.cpp +++ b/src/3rdparty/assimp/code/Bitmap.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2012, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. @@ -45,101 +45,108 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * Used for file formats which embed their textures into the model file. */ -#include "AssimpPCH.h" #include "Bitmap.h" +#include +#include +#include "ByteSwapper.h" namespace Assimp { - void Bitmap::Save(aiTexture* texture, IOStream* file) { - if(file != NULL) { - Header header; - DIB dib; - - dib.size = DIB::dib_size; - dib.width = texture->mWidth; - dib.height = texture->mHeight; - dib.planes = 1; - dib.bits_per_pixel = 8 * mBytesPerPixel; - dib.compression = 0; - dib.image_size = (((dib.width * mBytesPerPixel) + 3) & 0x0000FFFC) * dib.height; - dib.x_resolution = 0; - dib.y_resolution = 0; - dib.nb_colors = 0; - dib.nb_important_colors = 0; - - header.type = 0x4D42; // 'BM' - header.offset = Header::header_size + DIB::dib_size; - header.size = header.offset + dib.image_size; - header.reserved1 = 0; - header.reserved2 = 0; - - WriteHeader(header, file); - WriteDIB(dib, file); - WriteData(texture, file); - } - } - - template - inline std::size_t Copy(uint8_t* data, T& field) { - std::memcpy(data, &AI_BE(field), sizeof(field)); return sizeof(field); - } - - void Bitmap::WriteHeader(Header& header, IOStream* file) { - uint8_t data[Header::header_size]; - - std::size_t offset = 0; - - offset += Copy(&data[offset], header.type); - offset += Copy(&data[offset], header.size); - offset += Copy(&data[offset], header.reserved1); - offset += Copy(&data[offset], header.reserved2); - offset += Copy(&data[offset], header.offset); - - file->Write(data, Header::header_size, 1); - } - - void Bitmap::WriteDIB(DIB& dib, IOStream* file) { - uint8_t data[DIB::dib_size]; - - std::size_t offset = 0; - - offset += Copy(&data[offset], dib.size); - offset += Copy(&data[offset], dib.width); - offset += Copy(&data[offset], dib.height); - offset += Copy(&data[offset], dib.planes); - offset += Copy(&data[offset], dib.bits_per_pixel); - offset += Copy(&data[offset], dib.compression); - offset += Copy(&data[offset], dib.image_size); - offset += Copy(&data[offset], dib.x_resolution); - offset += Copy(&data[offset], dib.y_resolution); - offset += Copy(&data[offset], dib.nb_colors); - offset += Copy(&data[offset], dib.nb_important_colors); - - file->Write(data, DIB::dib_size, 1); - } - - void Bitmap::WriteData(aiTexture* texture, IOStream* file) { - static const std::size_t padding_offset = 4; - static const uint8_t padding_data[padding_offset] = {0x0, 0x0, 0x0, 0x0}; - - unsigned int padding = (padding_offset - ((mBytesPerPixel * texture->mWidth) % padding_offset)) % padding_offset; - uint8_t pixel[mBytesPerPixel]; - - for(std::size_t i = 0; i < texture->mHeight; ++i) { - for(std::size_t j = 0; j < texture->mWidth; ++j) { - const aiTexel& texel = texture->pcData[(texture->mHeight - i - 1) * texture->mWidth + j]; // Bitmap files are stored in bottom-up format - - pixel[0] = texel.r; - pixel[1] = texel.g; - pixel[2] = texel.b; - pixel[3] = texel.a; - - file->Write(pixel, mBytesPerPixel, 1); - } - - file->Write(padding_data, padding, 1); - } - } + void Bitmap::Save(aiTexture* texture, IOStream* file) { + if(file != NULL) { + Header header; + DIB dib; + + dib.size = DIB::dib_size; + dib.width = texture->mWidth; + dib.height = texture->mHeight; + dib.planes = 1; + dib.bits_per_pixel = 8 * mBytesPerPixel; + dib.compression = 0; + dib.image_size = (((dib.width * mBytesPerPixel) + 3) & 0x0000FFFC) * dib.height; + dib.x_resolution = 0; + dib.y_resolution = 0; + dib.nb_colors = 0; + dib.nb_important_colors = 0; + + header.type = 0x4D42; // 'BM' + header.offset = Header::header_size + DIB::dib_size; + header.size = header.offset + dib.image_size; + header.reserved1 = 0; + header.reserved2 = 0; + + WriteHeader(header, file); + WriteDIB(dib, file); + WriteData(texture, file); + } + } + + template + inline std::size_t Copy(uint8_t* data, T& field) { +#ifdef AI_BUILD_BIG_ENDIAN + T field_swapped=AI_BE(field); + std::memcpy(data, &field_swapped, sizeof(field)); return sizeof(field); +#else + std::memcpy(data, &AI_BE(field), sizeof(field)); return sizeof(field); +#endif + } + + void Bitmap::WriteHeader(Header& header, IOStream* file) { + uint8_t data[Header::header_size]; + + std::size_t offset = 0; + + offset += Copy(&data[offset], header.type); + offset += Copy(&data[offset], header.size); + offset += Copy(&data[offset], header.reserved1); + offset += Copy(&data[offset], header.reserved2); + offset += Copy(&data[offset], header.offset); + + file->Write(data, Header::header_size, 1); + } + + void Bitmap::WriteDIB(DIB& dib, IOStream* file) { + uint8_t data[DIB::dib_size]; + + std::size_t offset = 0; + + offset += Copy(&data[offset], dib.size); + offset += Copy(&data[offset], dib.width); + offset += Copy(&data[offset], dib.height); + offset += Copy(&data[offset], dib.planes); + offset += Copy(&data[offset], dib.bits_per_pixel); + offset += Copy(&data[offset], dib.compression); + offset += Copy(&data[offset], dib.image_size); + offset += Copy(&data[offset], dib.x_resolution); + offset += Copy(&data[offset], dib.y_resolution); + offset += Copy(&data[offset], dib.nb_colors); + offset += Copy(&data[offset], dib.nb_important_colors); + + file->Write(data, DIB::dib_size, 1); + } + + void Bitmap::WriteData(aiTexture* texture, IOStream* file) { + static const std::size_t padding_offset = 4; + static const uint8_t padding_data[padding_offset] = {0x0, 0x0, 0x0, 0x0}; + + unsigned int padding = (padding_offset - ((mBytesPerPixel * texture->mWidth) % padding_offset)) % padding_offset; + uint8_t pixel[mBytesPerPixel]; + + for(std::size_t i = 0; i < texture->mHeight; ++i) { + for(std::size_t j = 0; j < texture->mWidth; ++j) { + const aiTexel& texel = texture->pcData[(texture->mHeight - i - 1) * texture->mWidth + j]; // Bitmap files are stored in bottom-up format + + pixel[0] = texel.r; + pixel[1] = texel.g; + pixel[2] = texel.b; + pixel[3] = texel.a; + + file->Write(pixel, mBytesPerPixel, 1); + } + + file->Write(padding_data, padding, 1); + } + } } diff --git a/src/3rdparty/assimp/code/Bitmap.h b/src/3rdparty/assimp/code/Bitmap.h index 36f80363e..ad29783ce 100644 --- a/src/3rdparty/assimp/code/Bitmap.h +++ b/src/3rdparty/assimp/code/Bitmap.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2012, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. @@ -48,89 +48,94 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_BITMAP_H_INC #define AI_BITMAP_H_INC +#include +#include +struct aiTexture; + namespace Assimp { +class IOStream; class Bitmap { - protected: + protected: - struct Header { + struct Header { - uint16_t type; + uint16_t type; - uint32_t size; + uint32_t size; - uint16_t reserved1; + uint16_t reserved1; - uint16_t reserved2; + uint16_t reserved2; - uint32_t offset; + uint32_t offset; - // We define the struct size because sizeof(Header) might return a wrong result because of structure padding. - // Moreover, we must use this ugly and error prone syntax because Visual Studio neither support constexpr or sizeof(name_of_field). - static const std::size_t header_size = - sizeof(uint16_t) + // type - sizeof(uint32_t) + // size - sizeof(uint16_t) + // reserved1 - sizeof(uint16_t) + // reserved2 - sizeof(uint32_t); // offset + // We define the struct size because sizeof(Header) might return a wrong result because of structure padding. + // Moreover, we must use this ugly and error prone syntax because Visual Studio neither support constexpr or sizeof(name_of_field). + static const std::size_t header_size = + sizeof(uint16_t) + // type + sizeof(uint32_t) + // size + sizeof(uint16_t) + // reserved1 + sizeof(uint16_t) + // reserved2 + sizeof(uint32_t); // offset - }; + }; - struct DIB { + struct DIB { - uint32_t size; + uint32_t size; - int32_t width; + int32_t width; - int32_t height; + int32_t height; - uint16_t planes; + uint16_t planes; - uint16_t bits_per_pixel; + uint16_t bits_per_pixel; - uint32_t compression; + uint32_t compression; - uint32_t image_size; + uint32_t image_size; - int32_t x_resolution; + int32_t x_resolution; - int32_t y_resolution; + int32_t y_resolution; - uint32_t nb_colors; + uint32_t nb_colors; - uint32_t nb_important_colors; + uint32_t nb_important_colors; - // We define the struct size because sizeof(DIB) might return a wrong result because of structure padding. - // Moreover, we must use this ugly and error prone syntax because Visual Studio neither support constexpr or sizeof(name_of_field). - static const std::size_t dib_size = - sizeof(uint32_t) + // size - sizeof(int32_t) + // width - sizeof(int32_t) + // height - sizeof(uint16_t) + // planes - sizeof(uint16_t) + // bits_per_pixel - sizeof(uint32_t) + // compression - sizeof(uint32_t) + // image_size - sizeof(int32_t) + // x_resolution - sizeof(int32_t) + // y_resolution - sizeof(uint32_t) + // nb_colors - sizeof(uint32_t); // nb_important_colors + // We define the struct size because sizeof(DIB) might return a wrong result because of structure padding. + // Moreover, we must use this ugly and error prone syntax because Visual Studio neither support constexpr or sizeof(name_of_field). + static const std::size_t dib_size = + sizeof(uint32_t) + // size + sizeof(int32_t) + // width + sizeof(int32_t) + // height + sizeof(uint16_t) + // planes + sizeof(uint16_t) + // bits_per_pixel + sizeof(uint32_t) + // compression + sizeof(uint32_t) + // image_size + sizeof(int32_t) + // x_resolution + sizeof(int32_t) + // y_resolution + sizeof(uint32_t) + // nb_colors + sizeof(uint32_t); // nb_important_colors - }; + }; - static const std::size_t mBytesPerPixel = 4; + static const std::size_t mBytesPerPixel = 4; - public: + public: - static void Save(aiTexture* texture, IOStream* file); + static void Save(aiTexture* texture, IOStream* file); - protected: + protected: - static void WriteHeader(Header& header, IOStream* file); + static void WriteHeader(Header& header, IOStream* file); - static void WriteDIB(DIB& dib, IOStream* file); + static void WriteDIB(DIB& dib, IOStream* file); - static void WriteData(aiTexture* texture, IOStream* file); + static void WriteData(aiTexture* texture, IOStream* file); }; diff --git a/src/3rdparty/assimp/code/BlenderBMesh.cpp b/src/3rdparty/assimp/code/BlenderBMesh.cpp index 0e517f4c8..bf27a9396 100644 --- a/src/3rdparty/assimp/code/BlenderBMesh.cpp +++ b/src/3rdparty/assimp/code/BlenderBMesh.cpp @@ -5,8 +5,8 @@ Open Asset Import Library (assimp) Copyright (c) 2006-2013, assimp team All rights reserved. -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above @@ -23,16 +23,16 @@ following conditions are met: derived from this software without specific prior written permission of the assimp team. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- @@ -42,7 +42,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * @brief Conversion of Blender's new BMesh stuff */ -#include "AssimpPCH.h" #ifndef ASSIMP_BUILD_NO_BLEND_IMPORTER @@ -53,7 +52,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. namespace Assimp { - template< > const std::string LogFunctions< BlenderBMeshConverter >::log_prefix = "BLEND_BMESH: "; + template< > const std::string LogFunctions< BlenderBMeshConverter >::log_prefix = "BLEND_BMESH: "; } using namespace Assimp; @@ -62,115 +61,142 @@ using namespace Assimp::Formatter; // ------------------------------------------------------------------------------------------------ BlenderBMeshConverter::BlenderBMeshConverter( const Mesh* mesh ): - BMesh( mesh ), - triMesh( NULL ) + BMesh( mesh ), + triMesh( NULL ) { - AssertValidMesh( ); } // ------------------------------------------------------------------------------------------------ BlenderBMeshConverter::~BlenderBMeshConverter( ) { - DestroyTriMesh( ); + DestroyTriMesh( ); } // ------------------------------------------------------------------------------------------------ bool BlenderBMeshConverter::ContainsBMesh( ) const { - // TODO - Should probably do some additional verification here - return BMesh->totpoly && BMesh->totloop && BMesh->totvert; + // TODO - Should probably do some additional verification here + return BMesh->totpoly && BMesh->totloop && BMesh->totvert; } // ------------------------------------------------------------------------------------------------ const Mesh* BlenderBMeshConverter::TriangulateBMesh( ) { - AssertValidMesh( ); - AssertValidSizes( ); - PrepareTriMesh( ); + AssertValidMesh( ); + AssertValidSizes( ); + PrepareTriMesh( ); - for ( int i = 0; i < BMesh->totpoly; ++i ) - { - const MPoly& poly = BMesh->mpoly[ i ]; - ConvertPolyToFaces( poly ); - } + for ( int i = 0; i < BMesh->totpoly; ++i ) + { + const MPoly& poly = BMesh->mpoly[ i ]; + ConvertPolyToFaces( poly ); + } - return triMesh; + return triMesh; } // ------------------------------------------------------------------------------------------------ void BlenderBMeshConverter::AssertValidMesh( ) { - if ( !ContainsBMesh( ) ) - { - ThrowException( "BlenderBMeshConverter requires a BMesh with \"polygons\" - please call BlenderBMeshConverter::ContainsBMesh to check this first" ); - } + if ( !ContainsBMesh( ) ) + { + ThrowException( "BlenderBMeshConverter requires a BMesh with \"polygons\" - please call BlenderBMeshConverter::ContainsBMesh to check this first" ); + } } // ------------------------------------------------------------------------------------------------ void BlenderBMeshConverter::AssertValidSizes( ) { - if ( BMesh->totpoly != static_cast( BMesh->mpoly.size( ) ) ) - { - ThrowException( "BMesh poly array has incorrect size" ); - } - if ( BMesh->totloop != static_cast( BMesh->mloop.size( ) ) ) - { - ThrowException( "BMesh loop array has incorrect size" ); - } + if ( BMesh->totpoly != static_cast( BMesh->mpoly.size( ) ) ) + { + ThrowException( "BMesh poly array has incorrect size" ); + } + if ( BMesh->totloop != static_cast( BMesh->mloop.size( ) ) ) + { + ThrowException( "BMesh loop array has incorrect size" ); + } } // ------------------------------------------------------------------------------------------------ void BlenderBMeshConverter::PrepareTriMesh( ) { - if ( triMesh ) - { - DestroyTriMesh( ); - } - - triMesh = new Mesh( *BMesh ); - triMesh->totface = 0; - triMesh->mface.clear( ); + if ( triMesh ) + { + DestroyTriMesh( ); + } + + triMesh = new Mesh( *BMesh ); + triMesh->totface = 0; + triMesh->mface.clear( ); } // ------------------------------------------------------------------------------------------------ void BlenderBMeshConverter::DestroyTriMesh( ) { - delete triMesh; - triMesh = NULL; + delete triMesh; + triMesh = NULL; } // ------------------------------------------------------------------------------------------------ void BlenderBMeshConverter::ConvertPolyToFaces( const MPoly& poly ) { - const MLoop* polyLoop = &BMesh->mloop[ poly.loopstart ]; - if ( poly.totloop == 3 || poly.totloop == 4 ) - { - AddFace( polyLoop[ 0 ].v, polyLoop[ 1 ].v, polyLoop[ 2 ].v, poly.totloop == 4 ? polyLoop[ 3 ].v : 0 ); - } - else if ( poly.totloop > 4 ) - { + const MLoop* polyLoop = &BMesh->mloop[ poly.loopstart ]; + + if ( poly.totloop == 3 || poly.totloop == 4 ) + { + AddFace( polyLoop[ 0 ].v, polyLoop[ 1 ].v, polyLoop[ 2 ].v, poly.totloop == 4 ? polyLoop[ 3 ].v : 0 ); + + // UVs are optional, so only convert when present. + if ( BMesh->mloopuv.size() ) + { + if ( (poly.loopstart + poly.totloop ) > static_cast( BMesh->mloopuv.size() ) ) + { + ThrowException( "BMesh uv loop array has incorrect size" ); + } + const MLoopUV* loopUV = &BMesh->mloopuv[ poly.loopstart ]; + AddTFace( loopUV[ 0 ].uv, loopUV[ 1 ].uv, loopUV[ 2 ].uv, poly.totloop == 4 ? loopUV[ 3 ].uv : 0 ); + } + } + else if ( poly.totloop > 4 ) + { #if ASSIMP_BLEND_WITH_GLU_TESSELLATE - BlenderTessellatorGL tessGL( *this ); - tessGL.Tessellate( polyLoop, poly.totloop, triMesh->mvert ); + BlenderTessellatorGL tessGL( *this ); + tessGL.Tessellate( polyLoop, poly.totloop, triMesh->mvert ); #elif ASSIMP_BLEND_WITH_POLY_2_TRI - BlenderTessellatorP2T tessP2T( *this ); - tessP2T.Tessellate( polyLoop, poly.totloop, triMesh->mvert ); + BlenderTessellatorP2T tessP2T( *this ); + tessP2T.Tessellate( polyLoop, poly.totloop, triMesh->mvert ); #endif - } + } } // ------------------------------------------------------------------------------------------------ void BlenderBMeshConverter::AddFace( int v1, int v2, int v3, int v4 ) { - MFace face; - face.v1 = v1; - face.v2 = v2; - face.v3 = v3; - face.v4 = v4; - // TODO - Work out how materials work - face.mat_nr = 0; - triMesh->mface.push_back( face ); - triMesh->totface = triMesh->mface.size( ); + MFace face; + face.v1 = v1; + face.v2 = v2; + face.v3 = v3; + face.v4 = v4; + // TODO - Work out how materials work + face.mat_nr = 0; + triMesh->mface.push_back( face ); + triMesh->totface = triMesh->mface.size( ); +} + +// ------------------------------------------------------------------------------------------------ +void BlenderBMeshConverter::AddTFace( const float* uv1, const float *uv2, const float *uv3, const float* uv4 ) +{ + MTFace mtface; + memcpy( &mtface.uv[ 0 ], uv1, sizeof(float) * 2 ); + memcpy( &mtface.uv[ 1 ], uv2, sizeof(float) * 2 ); + memcpy( &mtface.uv[ 2 ], uv3, sizeof(float) * 2 ); + + if ( uv4 ) + { + memcpy( &mtface.uv[ 3 ], uv4, sizeof(float) * 2 ); + } + + triMesh->mtface.push_back( mtface ); } #endif // ASSIMP_BUILD_NO_BLEND_IMPORTER diff --git a/src/3rdparty/assimp/code/BlenderBMesh.h b/src/3rdparty/assimp/code/BlenderBMesh.h index 47afbf437..0d58b818c 100644 --- a/src/3rdparty/assimp/code/BlenderBMesh.h +++ b/src/3rdparty/assimp/code/BlenderBMesh.h @@ -5,8 +5,8 @@ Open Asset Import Library (assimp) Copyright (c) 2006-2013, assimp team All rights reserved. -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above @@ -23,16 +23,16 @@ following conditions are met: derived from this software without specific prior written permission of the assimp team. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- @@ -48,45 +48,46 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. namespace Assimp { - // TinyFormatter.h - namespace Formatter - { - template < typename T,typename TR, typename A > class basic_formatter; - typedef class basic_formatter< char, std::char_traits< char >, std::allocator< char > > format; - } - - // BlenderScene.h - namespace Blender - { - struct Mesh; - struct MPoly; - struct MLoop; - } - - class BlenderBMeshConverter: public LogFunctions< BlenderBMeshConverter > - { - public: - BlenderBMeshConverter( const Blender::Mesh* mesh ); - ~BlenderBMeshConverter( ); - - bool ContainsBMesh( ) const; - - const Blender::Mesh* TriangulateBMesh( ); - - private: - void AssertValidMesh( ); - void AssertValidSizes( ); - void PrepareTriMesh( ); - void DestroyTriMesh( ); - void ConvertPolyToFaces( const Blender::MPoly& poly ); - void AddFace( int v1, int v2, int v3, int v4 = 0 ); - - const Blender::Mesh* BMesh; - Blender::Mesh* triMesh; - - friend class BlenderTessellatorGL; - friend class BlenderTessellatorP2T; - }; + // TinyFormatter.h + namespace Formatter + { + template < typename T,typename TR, typename A > class basic_formatter; + typedef class basic_formatter< char, std::char_traits< char >, std::allocator< char > > format; + } + + // BlenderScene.h + namespace Blender + { + struct Mesh; + struct MPoly; + struct MLoop; + } + + class BlenderBMeshConverter: public LogFunctions< BlenderBMeshConverter > + { + public: + BlenderBMeshConverter( const Blender::Mesh* mesh ); + ~BlenderBMeshConverter( ); + + bool ContainsBMesh( ) const; + + const Blender::Mesh* TriangulateBMesh( ); + + private: + void AssertValidMesh( ); + void AssertValidSizes( ); + void PrepareTriMesh( ); + void DestroyTriMesh( ); + void ConvertPolyToFaces( const Blender::MPoly& poly ); + void AddFace( int v1, int v2, int v3, int v4 = 0 ); + void AddTFace( const float* uv1, const float* uv2, const float *uv3, const float* uv4 = 0 ); + + const Blender::Mesh* BMesh; + Blender::Mesh* triMesh; + + friend class BlenderTessellatorGL; + friend class BlenderTessellatorP2T; + }; } // end of namespace Assimp diff --git a/src/3rdparty/assimp/code/BlenderDNA.cpp b/src/3rdparty/assimp/code/BlenderDNA.cpp index b380fbe8d..18ec9f2b4 100644 --- a/src/3rdparty/assimp/code/BlenderDNA.cpp +++ b/src/3rdparty/assimp/code/BlenderDNA.cpp @@ -2,11 +2,11 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2012, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above @@ -23,16 +23,16 @@ following conditions are met: derived from this software without specific prior written permission of the assimp team. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- @@ -42,7 +42,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * @brief Implementation of the Blender `DNA`, that is its own * serialized set of data structures. */ -#include "AssimpPCH.h" + #ifndef ASSIMP_BUILD_NO_BLEND_IMPORTER #include "BlenderDNA.h" @@ -53,170 +53,169 @@ using namespace Assimp; using namespace Assimp::Blender; using namespace Assimp::Formatter; -#define for_each BOOST_FOREACH bool match4(StreamReaderAny& stream, const char* string) { - char tmp[] = { - (stream).GetI1(), - (stream).GetI1(), - (stream).GetI1(), - (stream).GetI1() - }; - return (tmp[0]==string[0] && tmp[1]==string[1] && tmp[2]==string[2] && tmp[3]==string[3]); + char tmp[] = { + (stream).GetI1(), + (stream).GetI1(), + (stream).GetI1(), + (stream).GetI1() + }; + return (tmp[0]==string[0] && tmp[1]==string[1] && tmp[2]==string[2] && tmp[3]==string[3]); } struct Type { - size_t size; - std::string name; + size_t size; + std::string name; }; // ------------------------------------------------------------------------------------------------ -void DNAParser :: Parse () +void DNAParser :: Parse () { - StreamReaderAny& stream = *db.reader.get(); - DNA& dna = db.dna; - - if(!match4(stream,"SDNA")) { - throw DeadlyImportError("BlenderDNA: Expected SDNA chunk"); - } - - // name dictionary - if(!match4(stream,"NAME")) { - throw DeadlyImportError("BlenderDNA: Expected NAME field"); - } - - std::vector names (stream.GetI4()); - for_each(std::string& s, names) { - while (char c = stream.GetI1()) { - s += c; - } - } - - // type dictionary - for (;stream.GetCurrentPos() & 0x3; stream.GetI1()); - if(!match4(stream,"TYPE")) { - throw DeadlyImportError("BlenderDNA: Expected TYPE field"); - } - - std::vector types (stream.GetI4()); - for_each(Type& s, types) { - while (char c = stream.GetI1()) { - s.name += c; - } - } - - // type length dictionary - for (;stream.GetCurrentPos() & 0x3; stream.GetI1()); - if(!match4(stream,"TLEN")) { - throw DeadlyImportError("BlenderDNA: Expected TLEN field"); - } - - for_each(Type& s, types) { - s.size = stream.GetI2(); - } - - // structures dictionary - for (;stream.GetCurrentPos() & 0x3; stream.GetI1()); - if(!match4(stream,"STRC")) { - throw DeadlyImportError("BlenderDNA: Expected STRC field"); - } - - size_t end = stream.GetI4(), fields = 0; - - dna.structures.reserve(end); - for(size_t i = 0; i != end; ++i) { - - uint16_t n = stream.GetI2(); - if (n >= types.size()) { - throw DeadlyImportError((format(), - "BlenderDNA: Invalid type index in structure name" ,n, - " (there are only ", types.size(), " entries)" - )); - } - - // maintain separate indexes - dna.indices[types[n].name] = dna.structures.size(); - - dna.structures.push_back(Structure()); - Structure& s = dna.structures.back(); - s.name = types[n].name; - //s.index = dna.structures.size()-1; - - n = stream.GetI2(); - s.fields.reserve(n); - - size_t offset = 0; - for (size_t m = 0; m < n; ++m, ++fields) { - - uint16_t j = stream.GetI2(); - if (j >= types.size()) { - throw DeadlyImportError((format(), - "BlenderDNA: Invalid type index in structure field ", j, - " (there are only ", types.size(), " entries)" - )); - } - s.fields.push_back(Field()); - Field& f = s.fields.back(); - f.offset = offset; - - f.type = types[j].name; - f.size = types[j].size; - - j = stream.GetI2(); - if (j >= names.size()) { - throw DeadlyImportError((format(), - "BlenderDNA: Invalid name index in structure field ", j, - " (there are only ", names.size(), " entries)" - )); - } - - f.name = names[j]; - f.flags = 0u; - - // pointers always specify the size of the pointee instead of their own. - // The pointer asterisk remains a property of the lookup name. - if (f.name[0] == '*') { - f.size = db.i64bit ? 8 : 4; - f.flags |= FieldFlag_Pointer; - } - - // arrays, however, specify the size of a single element so we - // need to parse the (possibly multi-dimensional) array declaration - // in order to obtain the actual size of the array in the file. - // Also we need to alter the lookup name to include no array - // brackets anymore or size fixup won't work (if our size does - // not match the size read from the DNA). - if (*f.name.rbegin() == ']') { - const std::string::size_type rb = f.name.find('['); - if (rb == std::string::npos) { - throw DeadlyImportError((format(), - "BlenderDNA: Encountered invalid array declaration ", - f.name - )); - } - - f.flags |= FieldFlag_Array; - DNA::ExtractArraySize(f.name,f.array_sizes); - f.name = f.name.substr(0,rb); - - f.size *= f.array_sizes[0] * f.array_sizes[1]; - } - - // maintain separate indexes - s.indices[f.name] = s.fields.size()-1; - offset += f.size; - } - s.size = offset; - } - - DefaultLogger::get()->debug((format(),"BlenderDNA: Got ",dna.structures.size(), - " structures with totally ",fields," fields")); + StreamReaderAny& stream = *db.reader.get(); + DNA& dna = db.dna; + + if(!match4(stream,"SDNA")) { + throw DeadlyImportError("BlenderDNA: Expected SDNA chunk"); + } + + // name dictionary + if(!match4(stream,"NAME")) { + throw DeadlyImportError("BlenderDNA: Expected NAME field"); + } + + std::vector names (stream.GetI4()); + for(std::string& s : names) { + while (char c = stream.GetI1()) { + s += c; + } + } + + // type dictionary + for (;stream.GetCurrentPos() & 0x3; stream.GetI1()); + if(!match4(stream,"TYPE")) { + throw DeadlyImportError("BlenderDNA: Expected TYPE field"); + } + + std::vector types (stream.GetI4()); + for(Type& s : types) { + while (char c = stream.GetI1()) { + s.name += c; + } + } + + // type length dictionary + for (;stream.GetCurrentPos() & 0x3; stream.GetI1()); + if(!match4(stream,"TLEN")) { + throw DeadlyImportError("BlenderDNA: Expected TLEN field"); + } + + for(Type& s : types) { + s.size = stream.GetI2(); + } + + // structures dictionary + for (;stream.GetCurrentPos() & 0x3; stream.GetI1()); + if(!match4(stream,"STRC")) { + throw DeadlyImportError("BlenderDNA: Expected STRC field"); + } + + size_t end = stream.GetI4(), fields = 0; + + dna.structures.reserve(end); + for(size_t i = 0; i != end; ++i) { + + uint16_t n = stream.GetI2(); + if (n >= types.size()) { + throw DeadlyImportError((format(), + "BlenderDNA: Invalid type index in structure name" ,n, + " (there are only ", types.size(), " entries)" + )); + } + + // maintain separate indexes + dna.indices[types[n].name] = dna.structures.size(); + + dna.structures.push_back(Structure()); + Structure& s = dna.structures.back(); + s.name = types[n].name; + //s.index = dna.structures.size()-1; + + n = stream.GetI2(); + s.fields.reserve(n); + + size_t offset = 0; + for (size_t m = 0; m < n; ++m, ++fields) { + + uint16_t j = stream.GetI2(); + if (j >= types.size()) { + throw DeadlyImportError((format(), + "BlenderDNA: Invalid type index in structure field ", j, + " (there are only ", types.size(), " entries)" + )); + } + s.fields.push_back(Field()); + Field& f = s.fields.back(); + f.offset = offset; + + f.type = types[j].name; + f.size = types[j].size; + + j = stream.GetI2(); + if (j >= names.size()) { + throw DeadlyImportError((format(), + "BlenderDNA: Invalid name index in structure field ", j, + " (there are only ", names.size(), " entries)" + )); + } + + f.name = names[j]; + f.flags = 0u; + + // pointers always specify the size of the pointee instead of their own. + // The pointer asterisk remains a property of the lookup name. + if (f.name[0] == '*') { + f.size = db.i64bit ? 8 : 4; + f.flags |= FieldFlag_Pointer; + } + + // arrays, however, specify the size of a single element so we + // need to parse the (possibly multi-dimensional) array declaration + // in order to obtain the actual size of the array in the file. + // Also we need to alter the lookup name to include no array + // brackets anymore or size fixup won't work (if our size does + // not match the size read from the DNA). + if (*f.name.rbegin() == ']') { + const std::string::size_type rb = f.name.find('['); + if (rb == std::string::npos) { + throw DeadlyImportError((format(), + "BlenderDNA: Encountered invalid array declaration ", + f.name + )); + } + + f.flags |= FieldFlag_Array; + DNA::ExtractArraySize(f.name,f.array_sizes); + f.name = f.name.substr(0,rb); + + f.size *= f.array_sizes[0] * f.array_sizes[1]; + } + + // maintain separate indexes + s.indices[f.name] = s.fields.size()-1; + offset += f.size; + } + s.size = offset; + } + + DefaultLogger::get()->debug((format(),"BlenderDNA: Got ",dna.structures.size(), + " structures with totally ",fields," fields")); #ifdef ASSIMP_BUILD_BLENDER_DEBUG - dna.DumpToFile(); + dna.DumpToFile(); #endif - dna.AddPrimitiveStructures(); - dna.RegisterConverters(); + dna.AddPrimitiveStructures(); + dna.RegisterConverters(); } @@ -226,144 +225,146 @@ void DNAParser :: Parse () // ------------------------------------------------------------------------------------------------ void DNA :: DumpToFile() { - // we dont't bother using the VFS here for this is only for debugging. - // (and all your bases are belong to us). - - std::ofstream f("dna.txt"); - if (f.fail()) { - DefaultLogger::get()->error("Could not dump dna to dna.txt"); - return; - } - f << "Field format: type name offset size" << "\n"; - f << "Structure format: name size" << "\n"; - - for_each(const Structure& s, structures) { - f << s.name << " " << s.size << "\n\n"; - for_each(const Field& ff, s.fields) { - f << "\t" << ff.type << " " << ff.name << " " << ff.offset << " " << ff.size << std::endl; - } - f << std::endl; - } - DefaultLogger::get()->info("BlenderDNA: Dumped dna to dna.txt"); + // we dont't bother using the VFS here for this is only for debugging. + // (and all your bases are belong to us). + + std::ofstream f("dna.txt"); + if (f.fail()) { + DefaultLogger::get()->error("Could not dump dna to dna.txt"); + return; + } + f << "Field format: type name offset size" << "\n"; + f << "Structure format: name size" << "\n"; + + for(const Structure& s : structures) { + f << s.name << " " << s.size << "\n\n"; + for(const Field& ff : s.fields) { + f << "\t" << ff.type << " " << ff.name << " " << ff.offset << " " << ff.size << "\n"; + } + f << "\n"; + } + f << std::flush; + + DefaultLogger::get()->info("BlenderDNA: Dumped dna to dna.txt"); } #endif // ------------------------------------------------------------------------------------------------ /*static*/ void DNA :: ExtractArraySize( - const std::string& out, - size_t array_sizes[2] + const std::string& out, + size_t array_sizes[2] ) { - array_sizes[0] = array_sizes[1] = 1; - std::string::size_type pos = out.find('['); - if (pos++ == std::string::npos) { - return; - } - array_sizes[0] = strtoul10(&out[pos]); - - pos = out.find('[',pos); - if (pos++ == std::string::npos) { - return; - } - array_sizes[1] = strtoul10(&out[pos]); + array_sizes[0] = array_sizes[1] = 1; + std::string::size_type pos = out.find('['); + if (pos++ == std::string::npos) { + return; + } + array_sizes[0] = strtoul10(&out[pos]); + + pos = out.find('[',pos); + if (pos++ == std::string::npos) { + return; + } + array_sizes[1] = strtoul10(&out[pos]); } // ------------------------------------------------------------------------------------------------ -boost::shared_ptr< ElemBase > DNA :: ConvertBlobToStructure( - const Structure& structure, - const FileDatabase& db -) const +std::shared_ptr< ElemBase > DNA :: ConvertBlobToStructure( + const Structure& structure, + const FileDatabase& db +) const { - std::map::const_iterator it = converters.find(structure.name); - if (it == converters.end()) { - return boost::shared_ptr< ElemBase >(); - } - - boost::shared_ptr< ElemBase > ret = (structure.*((*it).second.first))(); - (structure.*((*it).second.second))(ret,db); - - return ret; + std::map::const_iterator it = converters.find(structure.name); + if (it == converters.end()) { + return std::shared_ptr< ElemBase >(); + } + + std::shared_ptr< ElemBase > ret = (structure.*((*it).second.first))(); + (structure.*((*it).second.second))(ret,db); + + return ret; } // ------------------------------------------------------------------------------------------------ DNA::FactoryPair DNA :: GetBlobToStructureConverter( - const Structure& structure, - const FileDatabase& /*db*/ -) const + const Structure& structure, + const FileDatabase& /*db*/ +) const { - std::map::const_iterator it = converters.find(structure.name); - return it == converters.end() ? FactoryPair() : (*it).second; + std::map::const_iterator it = converters.find(structure.name); + return it == converters.end() ? FactoryPair() : (*it).second; } // basing on http://www.blender.org/development/architecture/notes-on-sdna/ // ------------------------------------------------------------------------------------------------ void DNA :: AddPrimitiveStructures() { - // NOTE: these are just dummies. Their presence enforces - // Structure::Convert to be called on these - // empty structures. These converters are special - // overloads which scan the name of the structure and - // perform the required data type conversion if one - // of these special names is found in the structure - // in question. + // NOTE: these are just dummies. Their presence enforces + // Structure::Convert to be called on these + // empty structures. These converters are special + // overloads which scan the name of the structure and + // perform the required data type conversion if one + // of these special names is found in the structure + // in question. - indices["int"] = structures.size(); - structures.push_back( Structure() ); - structures.back().name = "int"; - structures.back().size = 4; + indices["int"] = structures.size(); + structures.push_back( Structure() ); + structures.back().name = "int"; + structures.back().size = 4; - indices["short"] = structures.size(); - structures.push_back( Structure() ); - structures.back().name = "short"; - structures.back().size = 2; + indices["short"] = structures.size(); + structures.push_back( Structure() ); + structures.back().name = "short"; + structures.back().size = 2; - indices["char"] = structures.size(); - structures.push_back( Structure() ); - structures.back().name = "char"; - structures.back().size = 1; + indices["char"] = structures.size(); + structures.push_back( Structure() ); + structures.back().name = "char"; + structures.back().size = 1; - indices["float"] = structures.size(); - structures.push_back( Structure() ); - structures.back().name = "float"; - structures.back().size = 4; + indices["float"] = structures.size(); + structures.push_back( Structure() ); + structures.back().name = "float"; + structures.back().size = 4; - indices["double"] = structures.size(); - structures.push_back( Structure() ); - structures.back().name = "double"; - structures.back().size = 8; + indices["double"] = structures.size(); + structures.push_back( Structure() ); + structures.back().name = "double"; + structures.back().size = 8; - // no long, seemingly. + // no long, seemingly. } // ------------------------------------------------------------------------------------------------ void SectionParser :: Next() { - stream.SetCurrentPos(current.start + current.size); + stream.SetCurrentPos(current.start + current.size); - const char tmp[] = { - stream.GetI1(), - stream.GetI1(), - stream.GetI1(), - stream.GetI1() - }; - current.id = std::string(tmp,tmp[3]?4:tmp[2]?3:tmp[1]?2:1); + const char tmp[] = { + stream.GetI1(), + stream.GetI1(), + stream.GetI1(), + stream.GetI1() + }; + current.id = std::string(tmp,tmp[3]?4:tmp[2]?3:tmp[1]?2:1); - current.size = stream.GetI4(); - current.address.val = ptr64 ? stream.GetU8() : stream.GetU4(); + current.size = stream.GetI4(); + current.address.val = ptr64 ? stream.GetU8() : stream.GetU4(); - current.dna_index = stream.GetI4(); - current.num = stream.GetI4(); + current.dna_index = stream.GetI4(); + current.num = stream.GetI4(); - current.start = stream.GetCurrentPos(); - if (stream.GetRemainingSizeToLimit() < current.size) { - throw DeadlyImportError("BLEND: invalid size of file block"); - } + current.start = stream.GetCurrentPos(); + if (stream.GetRemainingSizeToLimit() < current.size) { + throw DeadlyImportError("BLEND: invalid size of file block"); + } #ifdef ASSIMP_BUILD_BLENDER_DEBUG - DefaultLogger::get()->debug(current.id); + DefaultLogger::get()->debug(current.id); #endif } diff --git a/src/3rdparty/assimp/code/BlenderDNA.h b/src/3rdparty/assimp/code/BlenderDNA.h index c52eb28a3..801d68fce 100644 --- a/src/3rdparty/assimp/code/BlenderDNA.h +++ b/src/3rdparty/assimp/code/BlenderDNA.h @@ -2,11 +2,11 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2012, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above @@ -23,23 +23,23 @@ following conditions are met: derived from this software without specific prior written permission of the assimp team. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- */ /** @file BlenderDNA.h - * @brief Blender `DNA` (file format specification embedded in + * @brief Blender `DNA` (file format specification embedded in * blend file itself) loader. */ #ifndef INCLUDED_AI_BLEND_DNA_H @@ -47,24 +47,29 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "BaseImporter.h" #include "TinyFormatter.h" +#include "StreamReader.h" +#include +#include +#include + // enable verbose log output. really verbose, so be careful. #ifdef ASSIMP_BUILD_DEBUG -# define ASSIMP_BUILD_BLENDER_DEBUG +# define ASSIMP_BUILD_BLENDER_DEBUG #endif // #define ASSIMP_BUILD_BLENDER_NO_STATS -namespace Assimp { - template class StreamReader; - typedef StreamReader StreamReaderAny; +namespace Assimp { + template class StreamReader; + typedef StreamReader StreamReaderAny; - namespace Blender { - class FileDatabase; - struct FileBlockHead; + namespace Blender { + class FileDatabase; + struct FileBlockHead; - template