From c72b821b5911842757a3929fb287471ad5d457ea Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Fri, 24 Mar 2017 14:54:24 +0100 Subject: [PATCH] Add the Vulkan cube example Features a little bit more than a cube, though. Change-Id: I636d4875ba9ccf722ed3caab97f14570be785748 Reviewed-by: Andy Nichols --- .../vulkan/doc/images/hellovulkancubes.png | Bin 0 -> 98495 bytes examples/vulkan/doc/src/hellovulkancubes.qdoc | 58 + examples/vulkan/hellovulkancubes/camera.cpp | 112 + examples/vulkan/hellovulkancubes/camera.h | 80 + examples/vulkan/hellovulkancubes/color.frag | 12 + examples/vulkan/hellovulkancubes/color.vert | 14 + .../vulkan/hellovulkancubes/color_frag.spv | Bin 0 -> 616 bytes .../vulkan/hellovulkancubes/color_phong.frag | 39 + .../vulkan/hellovulkancubes/color_phong.vert | 32 + .../hellovulkancubes/color_phong_frag.spv | Bin 0 -> 3364 bytes .../hellovulkancubes/color_phong_vert.spv | Bin 0 -> 2268 bytes .../vulkan/hellovulkancubes/color_vert.spv | Bin 0 -> 744 bytes .../hellovulkancubes/hellovulkancubes.pro | 24 + .../hellovulkancubes/hellovulkancubes.qrc | 10 + examples/vulkan/hellovulkancubes/main.cpp | 92 + .../vulkan/hellovulkancubes/mainwindow.cpp | 117 + examples/vulkan/hellovulkancubes/mainwindow.h | 83 + examples/vulkan/hellovulkancubes/mesh.cpp | 98 + examples/vulkan/hellovulkancubes/mesh.h | 79 + examples/vulkan/hellovulkancubes/renderer.cpp | 1048 ++++++ examples/vulkan/hellovulkancubes/renderer.h | 158 + examples/vulkan/hellovulkancubes/shader.cpp | 94 + examples/vulkan/hellovulkancubes/shader.h | 77 + .../vulkan/hellovulkancubes/vulkanwindow.cpp | 134 + .../vulkan/hellovulkancubes/vulkanwindow.h | 85 + examples/vulkan/shared/block.buf | Bin 0 -> 4256 bytes examples/vulkan/shared/block.txt | 100 + examples/vulkan/shared/objconvert.js | 241 ++ examples/vulkan/shared/qt_logo.buf | Bin 0 -> 125600 bytes examples/vulkan/shared/qt_logo.txt | 2912 +++++++++++++++++ examples/vulkan/vulkan.pro | 5 +- 31 files changed, 5703 insertions(+), 1 deletion(-) create mode 100644 examples/vulkan/doc/images/hellovulkancubes.png create mode 100644 examples/vulkan/doc/src/hellovulkancubes.qdoc create mode 100644 examples/vulkan/hellovulkancubes/camera.cpp create mode 100644 examples/vulkan/hellovulkancubes/camera.h create mode 100644 examples/vulkan/hellovulkancubes/color.frag create mode 100644 examples/vulkan/hellovulkancubes/color.vert create mode 100644 examples/vulkan/hellovulkancubes/color_frag.spv create mode 100644 examples/vulkan/hellovulkancubes/color_phong.frag create mode 100644 examples/vulkan/hellovulkancubes/color_phong.vert create mode 100644 examples/vulkan/hellovulkancubes/color_phong_frag.spv create mode 100644 examples/vulkan/hellovulkancubes/color_phong_vert.spv create mode 100644 examples/vulkan/hellovulkancubes/color_vert.spv create mode 100644 examples/vulkan/hellovulkancubes/hellovulkancubes.pro create mode 100644 examples/vulkan/hellovulkancubes/hellovulkancubes.qrc create mode 100644 examples/vulkan/hellovulkancubes/main.cpp create mode 100644 examples/vulkan/hellovulkancubes/mainwindow.cpp create mode 100644 examples/vulkan/hellovulkancubes/mainwindow.h create mode 100644 examples/vulkan/hellovulkancubes/mesh.cpp create mode 100644 examples/vulkan/hellovulkancubes/mesh.h create mode 100644 examples/vulkan/hellovulkancubes/renderer.cpp create mode 100644 examples/vulkan/hellovulkancubes/renderer.h create mode 100644 examples/vulkan/hellovulkancubes/shader.cpp create mode 100644 examples/vulkan/hellovulkancubes/shader.h create mode 100644 examples/vulkan/hellovulkancubes/vulkanwindow.cpp create mode 100644 examples/vulkan/hellovulkancubes/vulkanwindow.h create mode 100644 examples/vulkan/shared/block.buf create mode 100644 examples/vulkan/shared/block.txt create mode 100644 examples/vulkan/shared/objconvert.js create mode 100644 examples/vulkan/shared/qt_logo.buf create mode 100644 examples/vulkan/shared/qt_logo.txt diff --git a/examples/vulkan/doc/images/hellovulkancubes.png b/examples/vulkan/doc/images/hellovulkancubes.png new file mode 100644 index 0000000000000000000000000000000000000000..c3d819c047f10f2443b3c035abdd205df7e1f572 GIT binary patch literal 98495 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 z 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

(kR&jq6Qm+Q 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 literal 0 HcmV?d00001 diff --git a/examples/vulkan/doc/src/hellovulkancubes.qdoc b/examples/vulkan/doc/src/hellovulkancubes.qdoc new file mode 100644 index 00000000000..934d2015a1a --- /dev/null +++ b/examples/vulkan/doc/src/hellovulkancubes.qdoc @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +/*! + \example hellovulkancubes + \title Hello Vulkan Cubes Example + \ingroup examples-vulkan + \brief Shows the basics of using QVulkanWindow + + The \e{Hello Vulkan Cubes Example} shows more advanced usage of QVulkanWindow. + + \image hellovulkancubes.png + + In this example there is a mesh loaded from a file and two different + materials and corresponding graphics pipelines. The rounded cubes are drawn + using instancing and feature a Phong lighting model with a single + directional light. + + Unlike hellovulkantexture and hellovulkantriangle, the uniform buffer + handling takes an alternative approach here: dynamic uniform buffers are + used instead of multiple descriptor sets. + + The example requires QtConcurrent since it demonstrates simple usage of + QtConcurrent::run(), QFuture, and QFutureWatcher in combination of + QVulkanWindow. Mesh and shader data loading, the potentially expensive + graphics pipeline construction, and the building of the frame command buffer + are all done in separate worker threads. + + The scene is embedded into a widget-based user interface. The QVulkanWindow + subclass handles mouse and keyboard input as well since it provides a + first-person style camera in order to allow moving around in the scene. + + \include examples-run.qdocinc +*/ diff --git a/examples/vulkan/hellovulkancubes/camera.cpp b/examples/vulkan/hellovulkancubes/camera.cpp new file mode 100644 index 00000000000..64dee031548 --- /dev/null +++ b/examples/vulkan/hellovulkancubes/camera.cpp @@ -0,0 +1,112 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples 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 "camera.h" + +Camera::Camera(const QVector3D &pos) + : m_forward(0.0f, 0.0f, -1.0f), + m_right(1.0f, 0.0f, 0.0f), + m_up(0.0f, 1.0f, 0.0f), + m_pos(pos), + m_yaw(0.0f), + m_pitch(0.0f) +{ +} + +static inline void clamp360(float *v) +{ + if (*v > 360.0f) + *v -= 360.0f; + if (*v < -360.0f) + *v += 360.0f; +} + +void Camera::yaw(float degrees) +{ + m_yaw += degrees; + clamp360(&m_yaw); + m_yawMatrix.setToIdentity(); + m_yawMatrix.rotate(m_yaw, 0, 1, 0); + + QMatrix4x4 rotMat = m_pitchMatrix * m_yawMatrix; + m_forward = (QVector4D(0.0f, 0.0f, -1.0f, 0.0f) * rotMat).toVector3D(); + m_right = (QVector4D(1.0f, 0.0f, 0.0f, 0.0f) * rotMat).toVector3D(); +} + +void Camera::pitch(float degrees) +{ + m_pitch += degrees; + clamp360(&m_pitch); + m_pitchMatrix.setToIdentity(); + m_pitchMatrix.rotate(m_pitch, 1, 0, 0); + + QMatrix4x4 rotMat = m_pitchMatrix * m_yawMatrix; + m_forward = (QVector4D(0.0f, 0.0f, -1.0f, 0.0f) * rotMat).toVector3D(); + m_up = (QVector4D(0.0f, 1.0f, 0.0f, 0.0f) * rotMat).toVector3D(); +} + +void Camera::walk(float amount) +{ + m_pos[0] += amount * m_forward.x(); + m_pos[2] += amount * m_forward.z(); +} + +void Camera::strafe(float amount) +{ + m_pos[0] += amount * m_right.x(); + m_pos[2] += amount * m_right.z(); +} + +QMatrix4x4 Camera::viewMatrix() const +{ + QMatrix4x4 m = m_pitchMatrix * m_yawMatrix; + m.translate(-m_pos); + return m; +} diff --git a/examples/vulkan/hellovulkancubes/camera.h b/examples/vulkan/hellovulkancubes/camera.h new file mode 100644 index 00000000000..c5c579f0663 --- /dev/null +++ b/examples/vulkan/hellovulkancubes/camera.h @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples 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 CAMERA_H +#define CAMERA_H + +#include +#include + +class Camera +{ +public: + Camera(const QVector3D &pos); + + void yaw(float degrees); + void pitch(float degrees); + void walk(float amount); + void strafe(float amount); + + QMatrix4x4 viewMatrix() const; + +private: + QVector3D m_forward; + QVector3D m_right; + QVector3D m_up; + QVector3D m_pos; + float m_yaw; + float m_pitch; + QMatrix4x4 m_yawMatrix; + QMatrix4x4 m_pitchMatrix; +}; + +#endif diff --git a/examples/vulkan/hellovulkancubes/color.frag b/examples/vulkan/hellovulkancubes/color.frag new file mode 100644 index 00000000000..3b049559639 --- /dev/null +++ b/examples/vulkan/hellovulkancubes/color.frag @@ -0,0 +1,12 @@ +#version 440 + +layout(push_constant) uniform PC { + layout(offset = 64) vec3 color; +} pc; + +layout(location = 0) out vec4 fragColor; + +void main() +{ + fragColor = vec4(pc.color, 1.0); +} diff --git a/examples/vulkan/hellovulkancubes/color.vert b/examples/vulkan/hellovulkancubes/color.vert new file mode 100644 index 00000000000..19bf8158199 --- /dev/null +++ b/examples/vulkan/hellovulkancubes/color.vert @@ -0,0 +1,14 @@ +#version 440 + +layout(location = 0) in vec4 position; + +out gl_PerVertex { vec4 gl_Position; }; + +layout(push_constant) uniform PC { + mat4 mvp; +} pc; + +void main() +{ + gl_Position = pc.mvp * position; +} diff --git a/examples/vulkan/hellovulkancubes/color_frag.spv b/examples/vulkan/hellovulkancubes/color_frag.spv new file mode 100644 index 0000000000000000000000000000000000000000..bd72984ffe82090cf6f53d857b07dc1bc2887130 GIT binary patch literal 616 zcmYk2%T5A85Jd~dK@{a70Dsv3tX_k_yq)`F;Ow-2l!cjni~_(8An4; zZdcXqTh+HGDfZVR3Vh|*i{I6VB6UP1N?9CFZYP7c_q)O2(NIM-l1!+khGvZ@o@b9Q z9&CU*8aalOB}|O?q#=b})uu4&@0YWO(c)>bBu~*-h|^IpJU(pDyqJf=P*2?DjT* z_c`+nrE_+G{0$oC?dBZepKIluzW#LWob%2pf5ZRL0rso+TyN(%(X(gYyzB)00GFB@ Aj{pDw literal 0 HcmV?d00001 diff --git a/examples/vulkan/hellovulkancubes/color_phong.frag b/examples/vulkan/hellovulkancubes/color_phong.frag new file mode 100644 index 00000000000..8b0c715f3b8 --- /dev/null +++ b/examples/vulkan/hellovulkancubes/color_phong.frag @@ -0,0 +1,39 @@ +#version 440 + +layout(location = 0) in vec3 vECVertNormal; +layout(location = 1) in vec3 vECVertPos; +layout(location = 2) flat in vec3 vDiffuseAdjust; + +layout(std140, binding = 1) uniform buf { + vec3 ECCameraPosition; + vec3 ka; + vec3 kd; + vec3 ks; + // Have one light only for now. + vec3 ECLightPosition; + vec3 attenuation; + vec3 color; + float intensity; + float specularExp; +} ubuf; + +layout(location = 0) out vec4 fragColor; + +void main() +{ + vec3 unnormL = ubuf.ECLightPosition - vECVertPos; + float dist = length(unnormL); + float att = 1.0 / (ubuf.attenuation.x + ubuf.attenuation.y * dist + ubuf.attenuation.z * dist * dist); + + vec3 N = normalize(vECVertNormal); + vec3 L = normalize(unnormL); + float NL = max(0.0, dot(N, L)); + vec3 dColor = att * ubuf.intensity * ubuf.color * NL; + + vec3 R = reflect(-L, N); + vec3 V = normalize(ubuf.ECCameraPosition - vECVertPos); + float RV = max(0.0, dot(R, V)); + vec3 sColor = att * ubuf.intensity * ubuf.color * pow(RV, ubuf.specularExp); + + fragColor = vec4(ubuf.ka + (ubuf.kd + vDiffuseAdjust) * dColor + ubuf.ks * sColor, 1.0); +} diff --git a/examples/vulkan/hellovulkancubes/color_phong.vert b/examples/vulkan/hellovulkancubes/color_phong.vert new file mode 100644 index 00000000000..a1d15526858 --- /dev/null +++ b/examples/vulkan/hellovulkancubes/color_phong.vert @@ -0,0 +1,32 @@ +#version 440 + +layout(location = 0) in vec4 position; +layout(location = 1) in vec3 normal; + +// Instanced attributes to variate the translation of the model and the diffuse +// color of the material. +layout(location = 2) in vec3 instTranslate; +layout(location = 3) in vec3 instDiffuseAdjust; + +out gl_PerVertex { vec4 gl_Position; }; +layout(location = 0) out vec3 vECVertNormal; +layout(location = 1) out vec3 vECVertPos; +layout(location = 2) flat out vec3 vDiffuseAdjust; + +layout(std140, binding = 0) uniform buf { + mat4 vp; + mat4 model; + mat3 modelNormal; +} ubuf; + +void main() +{ + vECVertNormal = normalize(ubuf.modelNormal * normal); + mat4 t = mat4(1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + instTranslate.x, instTranslate.y, instTranslate.z, 1); + vECVertPos = vec3(t * ubuf.model * position); + vDiffuseAdjust = instDiffuseAdjust; + gl_Position = ubuf.vp * t * ubuf.model * position; +} diff --git a/examples/vulkan/hellovulkancubes/color_phong_frag.spv b/examples/vulkan/hellovulkancubes/color_phong_frag.spv new file mode 100644 index 0000000000000000000000000000000000000000..a1a413533bcbd909281c9ab88713b3b389d3cc2b GIT binary patch literal 3364 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 literal 0 HcmV?d00001 diff --git a/examples/vulkan/hellovulkancubes/hellovulkancubes.pro b/examples/vulkan/hellovulkancubes/hellovulkancubes.pro new file mode 100644 index 00000000000..f9a9c3cff13 --- /dev/null +++ b/examples/vulkan/hellovulkancubes/hellovulkancubes.pro @@ -0,0 +1,24 @@ +QT += widgets concurrent + +HEADERS += \ + mainwindow.h \ + vulkanwindow.h \ + renderer.h \ + mesh.h \ + shader.h \ + camera.h + +SOURCES += \ + main.cpp \ + mainwindow.cpp \ + vulkanwindow.cpp \ + renderer.cpp \ + mesh.cpp \ + shader.cpp \ + camera.cpp + +RESOURCES += hellovulkancubes.qrc + +# install +target.path = $$[QT_INSTALL_EXAMPLES]/vulkan/hellovulkancubes +INSTALLS += target diff --git a/examples/vulkan/hellovulkancubes/hellovulkancubes.qrc b/examples/vulkan/hellovulkancubes/hellovulkancubes.qrc new file mode 100644 index 00000000000..7b085e18754 --- /dev/null +++ b/examples/vulkan/hellovulkancubes/hellovulkancubes.qrc @@ -0,0 +1,10 @@ + + + ../shared/block.buf + ../shared/qt_logo.buf + color_phong_vert.spv + color_phong_frag.spv + color_vert.spv + color_frag.spv + + diff --git a/examples/vulkan/hellovulkancubes/main.cpp b/examples/vulkan/hellovulkancubes/main.cpp new file mode 100644 index 00000000000..4ec4d486455 --- /dev/null +++ b/examples/vulkan/hellovulkancubes/main.cpp @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples 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 "mainwindow.h" +#include "vulkanwindow.h" + +int main(int argc, char **argv) +{ + QApplication app(argc, argv); + + const bool dbg = qEnvironmentVariableIntValue("QT_VK_DEBUG"); + + QVulkanInstance inst; + + if (dbg) { + QLoggingCategory::setFilterRules(QStringLiteral("qt.vulkan=true")); + +#ifndef Q_OS_ANDROID + inst.setLayers(QByteArrayList() << "VK_LAYER_LUNARG_standard_validation"); +#else + inst.setLayers(QByteArrayList() + << "VK_LAYER_GOOGLE_threading" + << "VK_LAYER_LUNARG_parameter_validation" + << "VK_LAYER_LUNARG_object_tracker" + << "VK_LAYER_LUNARG_core_validation" + << "VK_LAYER_LUNARG_image" + << "VK_LAYER_LUNARG_swapchain" + << "VK_LAYER_GOOGLE_unique_objects"); +#endif + } + + if (!inst.create()) + qFatal("Failed to create Vulkan instance: %d", inst.errorCode()); + + VulkanWindow *vulkanWindow = new VulkanWindow(dbg); + vulkanWindow->setVulkanInstance(&inst); + + MainWindow mainWindow(vulkanWindow); + mainWindow.resize(1024, 768); + mainWindow.show(); + + return app.exec(); +} diff --git a/examples/vulkan/hellovulkancubes/mainwindow.cpp b/examples/vulkan/hellovulkancubes/mainwindow.cpp new file mode 100644 index 00000000000..2be7d237af2 --- /dev/null +++ b/examples/vulkan/hellovulkancubes/mainwindow.cpp @@ -0,0 +1,117 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples 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 "mainwindow.h" +#include "vulkanwindow.h" +#include +#include +#include +#include +#include +#include + +MainWindow::MainWindow(VulkanWindow *vulkanWindow) +{ + QWidget *wrapper = QWidget::createWindowContainer(vulkanWindow); + wrapper->setFocusPolicy(Qt::StrongFocus); + wrapper->setFocus(); + + infoLabel = new QLabel; + infoLabel->setFrameStyle(QFrame::Box | QFrame::Raised); + infoLabel->setAlignment(Qt::AlignCenter); + infoLabel->setText(tr("This example demonstrates instanced drawing\nof a mesh loaded from a file.\n" + "Uses a Phong material with a single light.\n" + "Also demonstrates dynamic uniform buffers\nand a bit of threading with QtConcurrent.\n" + "Uses 4x MSAA when available.\n" + "Comes with an FPS camera.\n" + "Hit [Shift+]WASD to walk and strafe.\nPress and move mouse to look around.\n" + "Click Add New to increase the number of instances.")); + + meshSwitch = new QCheckBox(tr("&Use Qt logo")); + meshSwitch->setFocusPolicy(Qt::NoFocus); // do not interfere with vulkanWindow's keyboard input + + counterLcd = new QLCDNumber(5); + counterLcd->setSegmentStyle(QLCDNumber::Filled); + counterLcd->display(m_count); + + newButton = new QPushButton(tr("&Add new")); + newButton->setFocusPolicy(Qt::NoFocus); + quitButton = new QPushButton(tr("&Quit")); + quitButton->setFocusPolicy(Qt::NoFocus); + pauseButton = new QPushButton(tr("&Pause")); + pauseButton->setFocusPolicy(Qt::NoFocus); + + connect(quitButton, &QPushButton::clicked, qApp, &QCoreApplication::quit); + connect(newButton, &QPushButton::clicked, vulkanWindow, [=] { + vulkanWindow->addNew(); + m_count = vulkanWindow->instanceCount(); + counterLcd->display(m_count); + }); + connect(pauseButton, &QPushButton::clicked, vulkanWindow, &VulkanWindow::togglePaused); + connect(meshSwitch, &QCheckBox::clicked, vulkanWindow, &VulkanWindow::meshSwitched); + + QGridLayout *layout = new QGridLayout; + layout->addWidget(infoLabel, 0, 2); + layout->addWidget(meshSwitch, 1, 2); + layout->addWidget(createLabel(tr("INSTANCES")), 2, 2); + layout->addWidget(counterLcd, 3, 2); + layout->addWidget(newButton, 4, 2); + layout->addWidget(pauseButton, 5, 2); + layout->addWidget(quitButton, 6, 2); + layout->addWidget(wrapper, 0, 0, 7, 2); + setLayout(layout); +} + +QLabel *MainWindow::createLabel(const QString &text) +{ + QLabel *lbl = new QLabel(text); + lbl->setAlignment(Qt::AlignHCenter | Qt::AlignBottom); + return lbl; +} diff --git a/examples/vulkan/hellovulkancubes/mainwindow.h b/examples/vulkan/hellovulkancubes/mainwindow.h new file mode 100644 index 00000000000..4109709959c --- /dev/null +++ b/examples/vulkan/hellovulkancubes/mainwindow.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples 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 MAINWINDOW_H +#define MAINWINDOW_H + +#include + +QT_BEGIN_NAMESPACE +class QLCDNumber; +class QLabel; +class QPushButton; +class QCheckBox; +QT_END_NAMESPACE + +class VulkanWindow; + +class MainWindow : public QWidget +{ +public: + MainWindow(VulkanWindow *vulkanWindow); + +private: + QLabel *createLabel(const QString &text); + + QLabel *infoLabel; + QCheckBox *meshSwitch; + QLCDNumber *counterLcd; + QPushButton *newButton; + QPushButton *quitButton; + QPushButton *pauseButton; + + int m_count = 128; +}; + +#endif diff --git a/examples/vulkan/hellovulkancubes/mesh.cpp b/examples/vulkan/hellovulkancubes/mesh.cpp new file mode 100644 index 00000000000..fcc45bfd573 --- /dev/null +++ b/examples/vulkan/hellovulkancubes/mesh.cpp @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples 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 "mesh.h" +#include +#include + +void Mesh::load(const QString &fn) +{ + reset(); + m_maybeRunning = true; + m_future = QtConcurrent::run([fn]() { + MeshData md; + QFile f(fn); + if (!f.open(QIODevice::ReadOnly)) { + qWarning("Failed to open %s", qPrintable(fn)); + return md; + } + QByteArray buf = f.readAll(); + const char *p = buf.constData(); + quint32 format; + memcpy(&format, p, 4); + if (format != 1) { + qWarning("Invalid format in %s", qPrintable(fn)); + return md; + } + int ofs = 4; + memcpy(&md.vertexCount, p + ofs, 4); + ofs += 4; + memcpy(md.aabb, p + ofs, 6 * 4); + ofs += 6 * 4; + const int byteCount = md.vertexCount * 8 * 4; + md.geom.resize(byteCount); + memcpy(md.geom.data(), p + ofs, byteCount); + return md; + }); +} + +MeshData *Mesh::data() +{ + if (m_maybeRunning && !m_data.isValid()) + m_data = m_future.result(); + + return &m_data; +} + +void Mesh::reset() +{ + *data() = MeshData(); + m_maybeRunning = false; +} diff --git a/examples/vulkan/hellovulkancubes/mesh.h b/examples/vulkan/hellovulkancubes/mesh.h new file mode 100644 index 00000000000..cb6ee9c8300 --- /dev/null +++ b/examples/vulkan/hellovulkancubes/mesh.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples 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 MESH_H +#define MESH_H + +#include +#include + +struct MeshData +{ + bool isValid() const { return vertexCount > 0; } + int vertexCount = 0; + float aabb[6]; + QByteArray geom; // x, y, z, u, v, nx, ny, nz +}; + +class Mesh +{ +public: + void load(const QString &fn); + MeshData *data(); + bool isValid() { return data()->isValid(); } + void reset(); + +private: + bool m_maybeRunning = false; + QFuture m_future; + MeshData m_data; +}; + +#endif diff --git a/examples/vulkan/hellovulkancubes/renderer.cpp b/examples/vulkan/hellovulkancubes/renderer.cpp new file mode 100644 index 00000000000..96ae6020a7f --- /dev/null +++ b/examples/vulkan/hellovulkancubes/renderer.cpp @@ -0,0 +1,1048 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples 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 "renderer.h" +#include +#include +#include + +static float quadVert[] = { + -1, -1, 0, + -1, 1, 0, + 1, -1, 0, + 1, 1, 0 +}; + +#define DBG Q_UNLIKELY(m_window->isDebugEnabled()) + +const int MAX_INSTANCES = 16384; +const VkDeviceSize PER_INSTANCE_DATA_SIZE = 6 * sizeof(float); // instTranslate, instDiffuseAdjust + +static inline VkDeviceSize aligned(VkDeviceSize v, VkDeviceSize byteAlign) +{ + return (v + byteAlign - 1) & ~(byteAlign - 1); +} + +Renderer::Renderer(VulkanWindow *w, int initialCount) + : m_window(w), + // Have the light positioned just behind the default camera position, looking forward. + m_lightPos(0.0f, 0.0f, 25.0f), + m_cam(QVector3D(0.0f, 0.0f, 20.0f)), // starting camera position + m_instCount(initialCount) +{ + qsrand(QTime(0, 0, 0).secsTo(QTime::currentTime())); + + m_floorModel.translate(0, -5, 0); + m_floorModel.rotate(-90, 1, 0, 0); + m_floorModel.scale(20, 100, 1); + + m_blockMesh.load(QStringLiteral(":/block.buf")); + m_logoMesh.load(QStringLiteral(":/qt_logo.buf")); + + QObject::connect(&m_frameWatcher, &QFutureWatcherBase::finished, [this] { + if (m_framePending) { + m_framePending = false; + m_window->frameReady(); + m_window->requestUpdate(); + } + }); +} + +void Renderer::preInitResources() +{ + QSet sampleCounts = m_window->supportedSampleCounts(); + if (DBG) + qDebug() << "Supported sample counts:" << sampleCounts; + if (sampleCounts.contains(4)) { + if (DBG) + qDebug("Requesting 4x MSAA"); + m_window->setSampleCount(4); + } +} + +void Renderer::initResources() +{ + if (DBG) + qDebug("Renderer init"); + + m_animating = true; + m_framePending = false; + + QVulkanInstance *inst = m_window->vulkanInstance(); + VkDevice dev = m_window->device(); + const VkPhysicalDeviceLimits *pdevLimits = &m_window->physicalDeviceProperties()->limits; + const VkDeviceSize uniAlign = pdevLimits->minUniformBufferOffsetAlignment; + + m_devFuncs = inst->deviceFunctions(dev); + + // Note the std140 packing rules. A vec3 still has an alignment of 16, + // while a mat3 is like 3 * vec3. + m_itemMaterial.vertUniSize = aligned(2 * 64 + 48, uniAlign); // see color_phong.vert + m_itemMaterial.fragUniSize = aligned(6 * 16 + 12 + 2 * 4, uniAlign); // see color_phong.frag + + if (!m_itemMaterial.vs.isValid()) + m_itemMaterial.vs.load(inst, dev, QStringLiteral(":/color_phong_vert.spv")); + if (!m_itemMaterial.fs.isValid()) + m_itemMaterial.fs.load(inst, dev, QStringLiteral(":/color_phong_frag.spv")); + + if (!m_floorMaterial.vs.isValid()) + m_floorMaterial.vs.load(inst, dev, QStringLiteral(":/color_vert.spv")); + if (!m_floorMaterial.fs.isValid()) + m_floorMaterial.fs.load(inst, dev, QStringLiteral(":/color_frag.spv")); + + m_pipelinesFuture = QtConcurrent::run(this, &Renderer::createPipelines); +} + +void Renderer::createPipelines() +{ + VkDevice dev = m_window->device(); + + VkPipelineCacheCreateInfo pipelineCacheInfo; + memset(&pipelineCacheInfo, 0, sizeof(pipelineCacheInfo)); + pipelineCacheInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO; + VkResult err = m_devFuncs->vkCreatePipelineCache(dev, &pipelineCacheInfo, nullptr, &m_pipelineCache); + if (err != VK_SUCCESS) + qFatal("Failed to create pipeline cache: %d", err); + + createItemPipeline(); + createFloorPipeline(); +} + +void Renderer::createItemPipeline() +{ + VkDevice dev = m_window->device(); + + // Vertex layout. + VkVertexInputBindingDescription vertexBindingDesc[] = { + { + 0, // binding + 8 * sizeof(float), + VK_VERTEX_INPUT_RATE_VERTEX + }, + { + 1, + 6 * sizeof(float), + VK_VERTEX_INPUT_RATE_INSTANCE + } + }; + VkVertexInputAttributeDescription vertexAttrDesc[] = { + { // position + 0, // location + 0, // binding + VK_FORMAT_R32G32B32_SFLOAT, + 0 // offset + }, + { // normal + 1, + 0, + VK_FORMAT_R32G32B32_SFLOAT, + 5 * sizeof(float) + }, + { // instTranslate + 2, + 1, + VK_FORMAT_R32G32B32_SFLOAT, + 0 + }, + { // instDiffuseAdjust + 3, + 1, + VK_FORMAT_R32G32B32_SFLOAT, + 3 * sizeof(float) + } + }; + + VkPipelineVertexInputStateCreateInfo vertexInputInfo; + vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; + vertexInputInfo.pNext = nullptr; + vertexInputInfo.flags = 0; + vertexInputInfo.vertexBindingDescriptionCount = sizeof(vertexBindingDesc) / sizeof(vertexBindingDesc[0]); + vertexInputInfo.pVertexBindingDescriptions = vertexBindingDesc; + vertexInputInfo.vertexAttributeDescriptionCount = sizeof(vertexAttrDesc) / sizeof(vertexAttrDesc[0]); + vertexInputInfo.pVertexAttributeDescriptions = vertexAttrDesc; + + // Descriptor set layout. + VkDescriptorPoolSize descPoolSizes[] = { + { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 2 } + }; + VkDescriptorPoolCreateInfo descPoolInfo; + memset(&descPoolInfo, 0, sizeof(descPoolInfo)); + descPoolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; + descPoolInfo.maxSets = 1; // a single set is enough due to the dynamic uniform buffer + descPoolInfo.poolSizeCount = sizeof(descPoolSizes) / sizeof(descPoolSizes[0]); + descPoolInfo.pPoolSizes = descPoolSizes; + VkResult err = m_devFuncs->vkCreateDescriptorPool(dev, &descPoolInfo, nullptr, &m_itemMaterial.descPool); + if (err != VK_SUCCESS) + qFatal("Failed to create descriptor pool: %d", err); + + VkDescriptorSetLayoutBinding layoutBindings[] = + { + { + 0, // binding + VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, + 1, // descriptorCount + VK_SHADER_STAGE_VERTEX_BIT, + nullptr + }, + { + 1, + VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, + 1, + VK_SHADER_STAGE_FRAGMENT_BIT, + nullptr + } + }; + VkDescriptorSetLayoutCreateInfo descLayoutInfo = { + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, + nullptr, + 0, + sizeof(layoutBindings) / sizeof(layoutBindings[0]), + layoutBindings + }; + err = m_devFuncs->vkCreateDescriptorSetLayout(dev, &descLayoutInfo, nullptr, &m_itemMaterial.descSetLayout); + if (err != VK_SUCCESS) + qFatal("Failed to create descriptor set layout: %d", err); + + VkDescriptorSetAllocateInfo descSetAllocInfo = { + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, + nullptr, + m_itemMaterial.descPool, + 1, + &m_itemMaterial.descSetLayout + }; + err = m_devFuncs->vkAllocateDescriptorSets(dev, &descSetAllocInfo, &m_itemMaterial.descSet); + if (err != VK_SUCCESS) + qFatal("Failed to allocate descriptor set: %d", err); + + // Graphics pipeline. + VkPipelineLayoutCreateInfo pipelineLayoutInfo; + memset(&pipelineLayoutInfo, 0, sizeof(pipelineLayoutInfo)); + pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + pipelineLayoutInfo.setLayoutCount = 1; + pipelineLayoutInfo.pSetLayouts = &m_itemMaterial.descSetLayout; + + err = m_devFuncs->vkCreatePipelineLayout(dev, &pipelineLayoutInfo, nullptr, &m_itemMaterial.pipelineLayout); + if (err != VK_SUCCESS) + qFatal("Failed to create pipeline layout: %d", err); + + VkGraphicsPipelineCreateInfo pipelineInfo; + memset(&pipelineInfo, 0, sizeof(pipelineInfo)); + pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + + VkPipelineShaderStageCreateInfo shaderStages[2] = { + { + VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + nullptr, + 0, + VK_SHADER_STAGE_VERTEX_BIT, + m_itemMaterial.vs.data()->shaderModule, + "main", + nullptr + }, + { + VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + nullptr, + 0, + VK_SHADER_STAGE_FRAGMENT_BIT, + m_itemMaterial.fs.data()->shaderModule, + "main", + nullptr + } + }; + pipelineInfo.stageCount = 2; + pipelineInfo.pStages = shaderStages; + + pipelineInfo.pVertexInputState = &vertexInputInfo; + + VkPipelineInputAssemblyStateCreateInfo ia; + memset(&ia, 0, sizeof(ia)); + ia.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; + ia.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + pipelineInfo.pInputAssemblyState = &ia; + + VkPipelineViewportStateCreateInfo vp; + memset(&vp, 0, sizeof(vp)); + vp.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; + vp.viewportCount = 1; + vp.scissorCount = 1; + pipelineInfo.pViewportState = &vp; + + VkPipelineRasterizationStateCreateInfo rs; + memset(&rs, 0, sizeof(rs)); + rs.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; + rs.polygonMode = VK_POLYGON_MODE_FILL; + rs.cullMode = VK_CULL_MODE_BACK_BIT; + rs.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; + rs.lineWidth = 1.0f; + pipelineInfo.pRasterizationState = &rs; + + VkPipelineMultisampleStateCreateInfo ms; + memset(&ms, 0, sizeof(ms)); + ms.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; + ms.rasterizationSamples = m_window->sampleCountFlagBits(); + pipelineInfo.pMultisampleState = &ms; + + VkPipelineDepthStencilStateCreateInfo ds; + memset(&ds, 0, sizeof(ds)); + ds.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; + ds.depthTestEnable = VK_TRUE; + ds.depthWriteEnable = VK_TRUE; + ds.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL; + pipelineInfo.pDepthStencilState = &ds; + + VkPipelineColorBlendStateCreateInfo cb; + memset(&cb, 0, sizeof(cb)); + cb.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; + VkPipelineColorBlendAttachmentState att; + memset(&att, 0, sizeof(att)); + att.colorWriteMask = 0xF; + cb.attachmentCount = 1; + cb.pAttachments = &att; + pipelineInfo.pColorBlendState = &cb; + + VkDynamicState dynEnable[] = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR }; + VkPipelineDynamicStateCreateInfo dyn; + memset(&dyn, 0, sizeof(dyn)); + dyn.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; + dyn.dynamicStateCount = sizeof(dynEnable) / sizeof(VkDynamicState); + dyn.pDynamicStates = dynEnable; + pipelineInfo.pDynamicState = &dyn; + + pipelineInfo.layout = m_itemMaterial.pipelineLayout; + pipelineInfo.renderPass = m_window->defaultRenderPass(); + + err = m_devFuncs->vkCreateGraphicsPipelines(dev, m_pipelineCache, 1, &pipelineInfo, nullptr, &m_itemMaterial.pipeline); + if (err != VK_SUCCESS) + qFatal("Failed to create graphics pipeline: %d", err); +} + +void Renderer::createFloorPipeline() +{ + VkDevice dev = m_window->device(); + + // Vertex layout. + VkVertexInputBindingDescription vertexBindingDesc = { + 0, // binding + 3 * sizeof(float), + VK_VERTEX_INPUT_RATE_VERTEX + }; + VkVertexInputAttributeDescription vertexAttrDesc[] = { + { // position + 0, // location + 0, // binding + VK_FORMAT_R32G32B32_SFLOAT, + 0 // offset + }, + }; + + VkPipelineVertexInputStateCreateInfo vertexInputInfo; + vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; + vertexInputInfo.pNext = nullptr; + vertexInputInfo.flags = 0; + vertexInputInfo.vertexBindingDescriptionCount = 1; + vertexInputInfo.pVertexBindingDescriptions = &vertexBindingDesc; + vertexInputInfo.vertexAttributeDescriptionCount = sizeof(vertexAttrDesc) / sizeof(vertexAttrDesc[0]); + vertexInputInfo.pVertexAttributeDescriptions = vertexAttrDesc; + + // Do not bother with uniform buffers and descriptors, all the data fits + // into the spec mandated minimum of 128 bytes for push constants. + VkPushConstantRange pcr[] = { + // mvp + { + VK_SHADER_STAGE_VERTEX_BIT, + 0, + 64 + }, + // color + { + VK_SHADER_STAGE_FRAGMENT_BIT, + 64, + 12 + } + }; + + VkPipelineLayoutCreateInfo pipelineLayoutInfo; + memset(&pipelineLayoutInfo, 0, sizeof(pipelineLayoutInfo)); + pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + pipelineLayoutInfo.pushConstantRangeCount = sizeof(pcr) / sizeof(pcr[0]); + pipelineLayoutInfo.pPushConstantRanges = pcr; + + VkResult err = m_devFuncs->vkCreatePipelineLayout(dev, &pipelineLayoutInfo, nullptr, &m_floorMaterial.pipelineLayout); + if (err != VK_SUCCESS) + qFatal("Failed to create pipeline layout: %d", err); + + VkGraphicsPipelineCreateInfo pipelineInfo; + memset(&pipelineInfo, 0, sizeof(pipelineInfo)); + pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + + VkPipelineShaderStageCreateInfo shaderStages[2] = { + { + VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + nullptr, + 0, + VK_SHADER_STAGE_VERTEX_BIT, + m_floorMaterial.vs.data()->shaderModule, + "main", + nullptr + }, + { + VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + nullptr, + 0, + VK_SHADER_STAGE_FRAGMENT_BIT, + m_floorMaterial.fs.data()->shaderModule, + "main", + nullptr + } + }; + pipelineInfo.stageCount = 2; + pipelineInfo.pStages = shaderStages; + + pipelineInfo.pVertexInputState = &vertexInputInfo; + + VkPipelineInputAssemblyStateCreateInfo ia; + memset(&ia, 0, sizeof(ia)); + ia.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; + ia.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP; + pipelineInfo.pInputAssemblyState = &ia; + + VkPipelineViewportStateCreateInfo vp; + memset(&vp, 0, sizeof(vp)); + vp.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; + vp.viewportCount = 1; + vp.scissorCount = 1; + pipelineInfo.pViewportState = &vp; + + VkPipelineRasterizationStateCreateInfo rs; + memset(&rs, 0, sizeof(rs)); + rs.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; + rs.polygonMode = VK_POLYGON_MODE_FILL; + rs.cullMode = VK_CULL_MODE_BACK_BIT; + rs.frontFace = VK_FRONT_FACE_CLOCKWISE; + rs.lineWidth = 1.0f; + pipelineInfo.pRasterizationState = &rs; + + VkPipelineMultisampleStateCreateInfo ms; + memset(&ms, 0, sizeof(ms)); + ms.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; + ms.rasterizationSamples = m_window->sampleCountFlagBits(); + pipelineInfo.pMultisampleState = &ms; + + VkPipelineDepthStencilStateCreateInfo ds; + memset(&ds, 0, sizeof(ds)); + ds.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; + ds.depthTestEnable = VK_TRUE; + ds.depthWriteEnable = VK_TRUE; + ds.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL; + pipelineInfo.pDepthStencilState = &ds; + + VkPipelineColorBlendStateCreateInfo cb; + memset(&cb, 0, sizeof(cb)); + cb.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; + VkPipelineColorBlendAttachmentState att; + memset(&att, 0, sizeof(att)); + att.colorWriteMask = 0xF; + cb.attachmentCount = 1; + cb.pAttachments = &att; + pipelineInfo.pColorBlendState = &cb; + + VkDynamicState dynEnable[] = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR }; + VkPipelineDynamicStateCreateInfo dyn; + memset(&dyn, 0, sizeof(dyn)); + dyn.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; + dyn.dynamicStateCount = sizeof(dynEnable) / sizeof(VkDynamicState); + dyn.pDynamicStates = dynEnable; + pipelineInfo.pDynamicState = &dyn; + + pipelineInfo.layout = m_floorMaterial.pipelineLayout; + pipelineInfo.renderPass = m_window->defaultRenderPass(); + + err = m_devFuncs->vkCreateGraphicsPipelines(dev, m_pipelineCache, 1, &pipelineInfo, nullptr, &m_floorMaterial.pipeline); + if (err != VK_SUCCESS) + qFatal("Failed to create graphics pipeline: %d", err); +} + +void Renderer::initSwapChainResources() +{ + m_proj = *m_window->clipCorrectionMatrix(); + const QSize sz = m_window->swapChainImageSize(); + m_proj.perspective(45.0f, sz.width() / (float) sz.height(), 0.01f, 1000.0f); + markViewProjDirty(); +} + +void Renderer::releaseSwapChainResources() +{ + // It is important to finish the pending frame right here since this is the + // last opportunity to act with all resources intact. + m_frameWatcher.waitForFinished(); + // Cannot count on the finished() signal being emitted before returning + // from here. + if (m_framePending) { + m_framePending = false; + m_window->frameReady(); + } +} + +void Renderer::releaseResources() +{ + if (DBG) + qDebug("Renderer release"); + + m_pipelinesFuture.waitForFinished(); + + VkDevice dev = m_window->device(); + + if (m_itemMaterial.descSetLayout) { + m_devFuncs->vkDestroyDescriptorSetLayout(dev, m_itemMaterial.descSetLayout, nullptr); + m_itemMaterial.descSetLayout = VK_NULL_HANDLE; + } + + if (m_itemMaterial.descPool) { + m_devFuncs->vkDestroyDescriptorPool(dev, m_itemMaterial.descPool, nullptr); + m_itemMaterial.descPool = VK_NULL_HANDLE; + } + + if (m_itemMaterial.pipeline) { + m_devFuncs->vkDestroyPipeline(dev, m_itemMaterial.pipeline, nullptr); + m_itemMaterial.pipeline = VK_NULL_HANDLE; + } + + if (m_itemMaterial.pipelineLayout) { + m_devFuncs->vkDestroyPipelineLayout(dev, m_itemMaterial.pipelineLayout, nullptr); + m_itemMaterial.pipelineLayout = VK_NULL_HANDLE; + } + + if (m_floorMaterial.pipeline) { + m_devFuncs->vkDestroyPipeline(dev, m_floorMaterial.pipeline, nullptr); + m_floorMaterial.pipeline = VK_NULL_HANDLE; + } + + if (m_floorMaterial.pipelineLayout) { + m_devFuncs->vkDestroyPipelineLayout(dev, m_floorMaterial.pipelineLayout, nullptr); + m_floorMaterial.pipelineLayout = VK_NULL_HANDLE; + } + + if (m_pipelineCache) { + m_devFuncs->vkDestroyPipelineCache(dev, m_pipelineCache, nullptr); + m_pipelineCache = VK_NULL_HANDLE; + } + + if (m_blockVertexBuf) { + m_devFuncs->vkDestroyBuffer(dev, m_blockVertexBuf, nullptr); + m_blockVertexBuf = VK_NULL_HANDLE; + } + + if (m_logoVertexBuf) { + m_devFuncs->vkDestroyBuffer(dev, m_logoVertexBuf, nullptr); + m_logoVertexBuf = VK_NULL_HANDLE; + } + + if (m_floorVertexBuf) { + m_devFuncs->vkDestroyBuffer(dev, m_floorVertexBuf, nullptr); + m_floorVertexBuf = VK_NULL_HANDLE; + } + + if (m_uniBuf) { + m_devFuncs->vkDestroyBuffer(dev, m_uniBuf, nullptr); + m_uniBuf = VK_NULL_HANDLE; + } + + if (m_bufMem) { + m_devFuncs->vkFreeMemory(dev, m_bufMem, nullptr); + m_bufMem = VK_NULL_HANDLE; + } + + if (m_instBuf) { + m_devFuncs->vkDestroyBuffer(dev, m_instBuf, nullptr); + m_instBuf = VK_NULL_HANDLE; + } + + if (m_instBufMem) { + m_devFuncs->vkFreeMemory(dev, m_instBufMem, nullptr); + m_instBufMem = VK_NULL_HANDLE; + } + + if (m_itemMaterial.vs.isValid()) { + m_devFuncs->vkDestroyShaderModule(dev, m_itemMaterial.vs.data()->shaderModule, nullptr); + m_itemMaterial.vs.reset(); + } + if (m_itemMaterial.fs.isValid()) { + m_devFuncs->vkDestroyShaderModule(dev, m_itemMaterial.fs.data()->shaderModule, nullptr); + m_itemMaterial.fs.reset(); + } + + if (m_floorMaterial.vs.isValid()) { + m_devFuncs->vkDestroyShaderModule(dev, m_floorMaterial.vs.data()->shaderModule, nullptr); + m_floorMaterial.vs.reset(); + } + if (m_floorMaterial.fs.isValid()) { + m_devFuncs->vkDestroyShaderModule(dev, m_floorMaterial.fs.data()->shaderModule, nullptr); + m_floorMaterial.fs.reset(); + } +} + +void Renderer::ensureBuffers() +{ + if (m_blockVertexBuf) + return; + + VkDevice dev = m_window->device(); + const int concurrentFrameCount = m_window->concurrentFrameCount(); + + // Vertex buffer for the block. + VkBufferCreateInfo bufInfo; + memset(&bufInfo, 0, sizeof(bufInfo)); + bufInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + const int blockMeshByteCount = m_blockMesh.data()->vertexCount * 8 * sizeof(float); + bufInfo.size = blockMeshByteCount; + bufInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; + VkResult err = m_devFuncs->vkCreateBuffer(dev, &bufInfo, nullptr, &m_blockVertexBuf); + if (err != VK_SUCCESS) + qFatal("Failed to create vertex buffer: %d", err); + + VkMemoryRequirements blockVertMemReq; + m_devFuncs->vkGetBufferMemoryRequirements(dev, m_blockVertexBuf, &blockVertMemReq); + + // Vertex buffer for the logo. + const int logoMeshByteCount = m_logoMesh.data()->vertexCount * 8 * sizeof(float); + bufInfo.size = logoMeshByteCount; + bufInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; + err = m_devFuncs->vkCreateBuffer(dev, &bufInfo, nullptr, &m_logoVertexBuf); + if (err != VK_SUCCESS) + qFatal("Failed to create vertex buffer: %d", err); + + VkMemoryRequirements logoVertMemReq; + m_devFuncs->vkGetBufferMemoryRequirements(dev, m_logoVertexBuf, &logoVertMemReq); + + // Vertex buffer for the floor. + bufInfo.size = sizeof(quadVert); + err = m_devFuncs->vkCreateBuffer(dev, &bufInfo, nullptr, &m_floorVertexBuf); + if (err != VK_SUCCESS) + qFatal("Failed to create vertex buffer: %d", err); + + VkMemoryRequirements floorVertMemReq; + m_devFuncs->vkGetBufferMemoryRequirements(dev, m_floorVertexBuf, &floorVertMemReq); + + // Uniform buffer. Instead of using multiple descriptor sets, we take a + // different approach: have a single dynamic uniform buffer and specify the + // active-frame-specific offset at the time of binding the descriptor set. + bufInfo.size = (m_itemMaterial.vertUniSize + m_itemMaterial.fragUniSize) * concurrentFrameCount; + bufInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; + err = m_devFuncs->vkCreateBuffer(dev, &bufInfo, nullptr, &m_uniBuf); + if (err != VK_SUCCESS) + qFatal("Failed to create uniform buffer: %d", err); + + VkMemoryRequirements uniMemReq; + m_devFuncs->vkGetBufferMemoryRequirements(dev, m_uniBuf, &uniMemReq); + + // Allocate memory for everything at once. + VkDeviceSize logoVertStartOffset = aligned(0 + blockVertMemReq.size, logoVertMemReq.alignment); + VkDeviceSize floorVertStartOffset = aligned(logoVertStartOffset + logoVertMemReq.size, floorVertMemReq.alignment); + m_itemMaterial.uniMemStartOffset = aligned(floorVertStartOffset + floorVertMemReq.size, uniMemReq.alignment); + VkMemoryAllocateInfo memAllocInfo = { + VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, + nullptr, + m_itemMaterial.uniMemStartOffset + uniMemReq.size, + m_window->hostVisibleMemoryIndex() + }; + err = m_devFuncs->vkAllocateMemory(dev, &memAllocInfo, nullptr, &m_bufMem); + if (err != VK_SUCCESS) + qFatal("Failed to allocate memory: %d", err); + + err = m_devFuncs->vkBindBufferMemory(dev, m_blockVertexBuf, m_bufMem, 0); + if (err != VK_SUCCESS) + qFatal("Failed to bind vertex buffer memory: %d", err); + err = m_devFuncs->vkBindBufferMemory(dev, m_logoVertexBuf, m_bufMem, logoVertStartOffset); + if (err != VK_SUCCESS) + qFatal("Failed to bind vertex buffer memory: %d", err); + err = m_devFuncs->vkBindBufferMemory(dev, m_floorVertexBuf, m_bufMem, floorVertStartOffset); + if (err != VK_SUCCESS) + qFatal("Failed to bind vertex buffer memory: %d", err); + err = m_devFuncs->vkBindBufferMemory(dev, m_uniBuf, m_bufMem, m_itemMaterial.uniMemStartOffset); + if (err != VK_SUCCESS) + qFatal("Failed to bind uniform buffer memory: %d", err); + + // Copy vertex data. + quint8 *p; + err = m_devFuncs->vkMapMemory(dev, m_bufMem, 0, m_itemMaterial.uniMemStartOffset, 0, reinterpret_cast(&p)); + if (err != VK_SUCCESS) + qFatal("Failed to map memory: %d", err); + memcpy(p, m_blockMesh.data()->geom.constData(), blockMeshByteCount); + memcpy(p + logoVertStartOffset, m_logoMesh.data()->geom.constData(), logoMeshByteCount); + memcpy(p + floorVertStartOffset, quadVert, sizeof(quadVert)); + m_devFuncs->vkUnmapMemory(dev, m_bufMem); + + // Write descriptors for the uniform buffers in the vertex and fragment shaders. + VkDescriptorBufferInfo vertUni = { m_uniBuf, 0, m_itemMaterial.vertUniSize }; + VkDescriptorBufferInfo fragUni = { m_uniBuf, m_itemMaterial.vertUniSize, m_itemMaterial.fragUniSize }; + + VkWriteDescriptorSet descWrite[2]; + memset(descWrite, 0, sizeof(descWrite)); + descWrite[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + descWrite[0].dstSet = m_itemMaterial.descSet; + descWrite[0].dstBinding = 0; + descWrite[0].descriptorCount = 1; + descWrite[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; + descWrite[0].pBufferInfo = &vertUni; + + descWrite[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + descWrite[1].dstSet = m_itemMaterial.descSet; + descWrite[1].dstBinding = 1; + descWrite[1].descriptorCount = 1; + descWrite[1].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; + descWrite[1].pBufferInfo = &fragUni; + + m_devFuncs->vkUpdateDescriptorSets(dev, 2, descWrite, 0, nullptr); +} + +void Renderer::ensureInstanceBuffer() +{ + if (m_instCount == m_preparedInstCount && m_instBuf) + return; + + Q_ASSERT(m_instCount <= MAX_INSTANCES); + + VkDevice dev = m_window->device(); + + // allocate only once, for the maximum instance count + if (!m_instBuf) { + VkBufferCreateInfo bufInfo; + memset(&bufInfo, 0, sizeof(bufInfo)); + bufInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + bufInfo.size = MAX_INSTANCES * PER_INSTANCE_DATA_SIZE; + bufInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; + + // Keep a copy of the data since we may lose all graphics resources on + // unexpose, and reinitializing to new random positions afterwards + // would not be nice. + m_instData.resize(bufInfo.size); + + VkResult err = m_devFuncs->vkCreateBuffer(dev, &bufInfo, nullptr, &m_instBuf); + if (err != VK_SUCCESS) + qFatal("Failed to create instance buffer: %d", err); + + VkMemoryRequirements memReq; + m_devFuncs->vkGetBufferMemoryRequirements(dev, m_instBuf, &memReq); + if (DBG) + qDebug("Allocating %u bytes for instance data", uint32_t(memReq.size)); + + VkMemoryAllocateInfo memAllocInfo = { + VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, + nullptr, + memReq.size, + m_window->hostVisibleMemoryIndex() + }; + err = m_devFuncs->vkAllocateMemory(dev, &memAllocInfo, nullptr, &m_instBufMem); + if (err != VK_SUCCESS) + qFatal("Failed to allocate memory: %d", err); + + err = m_devFuncs->vkBindBufferMemory(dev, m_instBuf, m_instBufMem, 0); + if (err != VK_SUCCESS) + qFatal("Failed to bind instance buffer memory: %d", err); + } + + if (m_instCount != m_preparedInstCount) { + if (DBG) + qDebug("Preparing instances %d..%d", m_preparedInstCount, m_instCount - 1); + char *p = m_instData.data(); + p += m_preparedInstCount * PER_INSTANCE_DATA_SIZE; + auto gen = [](float a, float b) { return float((qrand() % int(b - a + 1)) + a); }; + for (int i = m_preparedInstCount; i < m_instCount; ++i) { + // Apply a random translation to each instance of the mesh. + float t[] = { gen(-5, 5), gen(-4, 6), gen(-30, 5) }; + memcpy(p, t, 12); + // Apply a random adjustment to the diffuse color for each instance. (default is 0.7) + float d[] = { gen(-6, 3) / 10.0f, gen(-6, 3) / 10.0f, gen(-6, 3) / 10.0f }; + memcpy(p + 12, d, 12); + p += PER_INSTANCE_DATA_SIZE; + } + m_preparedInstCount = m_instCount; + } + + quint8 *p; + VkResult err = m_devFuncs->vkMapMemory(dev, m_instBufMem, 0, m_instCount * PER_INSTANCE_DATA_SIZE, 0, + reinterpret_cast(&p)); + if (err != VK_SUCCESS) + qFatal("Failed to map memory: %d", err); + memcpy(p, m_instData.constData(), m_instData.size()); + m_devFuncs->vkUnmapMemory(dev, m_instBufMem); +} + +void Renderer::getMatrices(QMatrix4x4 *vp, QMatrix4x4 *model, QMatrix3x3 *modelNormal, QVector3D *eyePos) +{ + model->setToIdentity(); + if (m_useLogo) + model->rotate(90, 1, 0, 0); + model->rotate(m_rotation, 1, 1, 0); + + *modelNormal = model->normalMatrix(); + + QMatrix4x4 view = m_cam.viewMatrix(); + *vp = m_proj * view; + + *eyePos = view.inverted().column(3).toVector3D(); +} + +void Renderer::writeFragUni(quint8 *p, const QVector3D &eyePos) +{ + float ECCameraPosition[] = { eyePos.x(), eyePos.y(), eyePos.z() }; + memcpy(p, ECCameraPosition, 12); + p += 16; + + // Material + float ka[] = { 0.05f, 0.05f, 0.05f }; + memcpy(p, ka, 12); + p += 16; + + float kd[] = { 0.7f, 0.7f, 0.7f }; + memcpy(p, kd, 12); + p += 16; + + float ks[] = { 0.66f, 0.66f, 0.66f }; + memcpy(p, ks, 12); + p += 16; + + // Light parameters + float ECLightPosition[] = { m_lightPos.x(), m_lightPos.y(), m_lightPos.z() }; + memcpy(p, ECLightPosition, 12); + p += 16; + + float att[] = { 1, 0, 0 }; + memcpy(p, att, 12); + p += 16; + + float color[] = { 1.0f, 1.0f, 1.0f }; + memcpy(p, color, 12); + p += 12; // next we have two floats which have an alignment of 4, hence 12 only + + float intensity = 0.8f; + memcpy(p, &intensity, 4); + p += 4; + + float specularExp = 150.0f; + memcpy(p, &specularExp, 4); + p += 4; +} + +void Renderer::startNextFrame() +{ + // For demonstration purposes offload the command buffer generation onto a + // worker thread and continue with the frame submission only when it has + // finished. + Q_ASSERT(!m_framePending); + m_framePending = true; + QFuture future = QtConcurrent::run(this, &Renderer::buildFrame); + m_frameWatcher.setFuture(future); +} + +void Renderer::buildFrame() +{ + QMutexLocker locker(&m_guiMutex); + + ensureBuffers(); + ensureInstanceBuffer(); + m_pipelinesFuture.waitForFinished(); + + VkCommandBuffer cb = m_window->currentCommandBuffer(); + const QSize sz = m_window->swapChainImageSize(); + + VkClearColorValue clearColor = { 0.67f, 0.84f, 0.9f, 1.0f }; + VkClearDepthStencilValue clearDS = { 1, 0 }; + VkClearValue clearValues[3]; + memset(clearValues, 0, sizeof(clearValues)); + clearValues[0].color = clearValues[2].color = clearColor; + clearValues[1].depthStencil = clearDS; + + VkRenderPassBeginInfo rpBeginInfo; + memset(&rpBeginInfo, 0, sizeof(rpBeginInfo)); + rpBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + rpBeginInfo.renderPass = m_window->defaultRenderPass(); + rpBeginInfo.framebuffer = m_window->currentFramebuffer(); + rpBeginInfo.renderArea.extent.width = sz.width(); + rpBeginInfo.renderArea.extent.height = sz.height(); + rpBeginInfo.clearValueCount = m_window->sampleCountFlagBits() > VK_SAMPLE_COUNT_1_BIT ? 3 : 2; + rpBeginInfo.pClearValues = clearValues; + VkCommandBuffer cmdBuf = m_window->currentCommandBuffer(); + m_devFuncs->vkCmdBeginRenderPass(cmdBuf, &rpBeginInfo, VK_SUBPASS_CONTENTS_INLINE); + + VkViewport viewport = { + 0, 0, + float(sz.width()), float(sz.height()), + 0, 1 + }; + m_devFuncs->vkCmdSetViewport(cb, 0, 1, &viewport); + + VkRect2D scissor = { + { 0, 0 }, + { uint32_t(sz.width()), uint32_t(sz.height()) } + }; + m_devFuncs->vkCmdSetScissor(cb, 0, 1, &scissor); + + buildDrawCallsForFloor(); + buildDrawCallsForItems(); + + m_devFuncs->vkCmdEndRenderPass(cmdBuf); +} + +void Renderer::buildDrawCallsForItems() +{ + VkDevice dev = m_window->device(); + VkCommandBuffer cb = m_window->currentCommandBuffer(); + + m_devFuncs->vkCmdBindPipeline(cb, VK_PIPELINE_BIND_POINT_GRAPHICS, m_itemMaterial.pipeline); + + VkDeviceSize vbOffset = 0; + m_devFuncs->vkCmdBindVertexBuffers(cb, 0, 1, m_useLogo ? &m_logoVertexBuf : &m_blockVertexBuf, &vbOffset); + m_devFuncs->vkCmdBindVertexBuffers(cb, 1, 1, &m_instBuf, &vbOffset); + + // Now provide offsets so that the two dynamic buffers point to the + // beginning of the vertex and fragment uniform data for the current frame. + uint32_t frameUniOffset = m_window->currentFrame() * (m_itemMaterial.vertUniSize + m_itemMaterial.fragUniSize); + uint32_t frameUniOffsets[] = { frameUniOffset, frameUniOffset }; + m_devFuncs->vkCmdBindDescriptorSets(cb, VK_PIPELINE_BIND_POINT_GRAPHICS, m_itemMaterial.pipelineLayout, 0, 1, + &m_itemMaterial.descSet, 2, frameUniOffsets); + + if (m_animating) + m_rotation += 0.5; + + if (m_animating || m_vpDirty) { + if (m_vpDirty) + --m_vpDirty; + QMatrix4x4 vp, model; + QMatrix3x3 modelNormal; + QVector3D eyePos; + getMatrices(&vp, &model, &modelNormal, &eyePos); + + // Map the uniform data for the current frame, ignore the geometry data at + // the beginning and the uniforms for other frames. + quint8 *p; + VkResult err = m_devFuncs->vkMapMemory(dev, m_bufMem, + m_itemMaterial.uniMemStartOffset + frameUniOffset, + m_itemMaterial.vertUniSize + m_itemMaterial.fragUniSize, + 0, reinterpret_cast(&p)); + if (err != VK_SUCCESS) + qFatal("Failed to map memory: %d", err); + + // Vertex shader uniforms + memcpy(p, vp.constData(), 64); + memcpy(p + 64, model.constData(), 64); + const float *mnp = modelNormal.constData(); + memcpy(p + 128, mnp, 12); + memcpy(p + 128 + 16, mnp + 3, 12); + memcpy(p + 128 + 32, mnp + 6, 12); + + // Fragment shader uniforms + p += m_itemMaterial.vertUniSize; + writeFragUni(p, eyePos); + + m_devFuncs->vkUnmapMemory(dev, m_bufMem); + } + + m_devFuncs->vkCmdDraw(cb, (m_useLogo ? m_logoMesh.data() : m_blockMesh.data())->vertexCount, m_instCount, 0, 0); +} + +void Renderer::buildDrawCallsForFloor() +{ + VkCommandBuffer cb = m_window->currentCommandBuffer(); + + m_devFuncs->vkCmdBindPipeline(cb, VK_PIPELINE_BIND_POINT_GRAPHICS, m_floorMaterial.pipeline); + + VkDeviceSize vbOffset = 0; + m_devFuncs->vkCmdBindVertexBuffers(cb, 0, 1, &m_floorVertexBuf, &vbOffset); + + QMatrix4x4 mvp = m_proj * m_cam.viewMatrix() * m_floorModel; + m_devFuncs->vkCmdPushConstants(cb, m_floorMaterial.pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, 64, mvp.constData()); + float color[] = { 0.67f, 1.0f, 0.2f }; + m_devFuncs->vkCmdPushConstants(cb, m_floorMaterial.pipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 64, 12, color); + + m_devFuncs->vkCmdDraw(cb, 4, 1, 0, 0); +} + +void Renderer::addNew() +{ + QMutexLocker locker(&m_guiMutex); + m_instCount = qMin(m_instCount + 16, MAX_INSTANCES); +} + +void Renderer::yaw(float degrees) +{ + QMutexLocker locker(&m_guiMutex); + m_cam.yaw(degrees); + markViewProjDirty(); +} + +void Renderer::pitch(float degrees) +{ + QMutexLocker locker(&m_guiMutex); + m_cam.pitch(degrees); + markViewProjDirty(); +} + +void Renderer::walk(float amount) +{ + QMutexLocker locker(&m_guiMutex); + m_cam.walk(amount); + markViewProjDirty(); +} + +void Renderer::strafe(float amount) +{ + QMutexLocker locker(&m_guiMutex); + m_cam.strafe(amount); + markViewProjDirty(); +} + +void Renderer::setUseLogo(bool b) +{ + QMutexLocker locker(&m_guiMutex); + m_useLogo = b; + if (!m_animating) + m_window->requestUpdate(); +} diff --git a/examples/vulkan/hellovulkancubes/renderer.h b/examples/vulkan/hellovulkancubes/renderer.h new file mode 100644 index 00000000000..60bb48377eb --- /dev/null +++ b/examples/vulkan/hellovulkancubes/renderer.h @@ -0,0 +1,158 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples 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 RENDERER_H +#define RENDERER_H + +#include "vulkanwindow.h" +#include "mesh.h" +#include "shader.h" +#include "camera.h" +#include +#include + +class Renderer : public QVulkanWindowRenderer +{ +public: + Renderer(VulkanWindow *w, int initialCount); + + void preInitResources() override; + void initResources() override; + void initSwapChainResources() override; + void releaseSwapChainResources() override; + void releaseResources() override; + + void startNextFrame() override; + + bool animating() const { return m_animating; } + void setAnimating(bool a) { m_animating = a; } + + int instanceCount() const { return m_instCount; } + void addNew(); + + void yaw(float degrees); + void pitch(float degrees); + void walk(float amount); + void strafe(float amount); + + void setUseLogo(bool b); + +private: + void createPipelines(); + void createItemPipeline(); + void createFloorPipeline(); + void ensureBuffers(); + void ensureInstanceBuffer(); + void getMatrices(QMatrix4x4 *mvp, QMatrix4x4 *model, QMatrix3x3 *modelNormal, QVector3D *eyePos); + void writeFragUni(quint8 *p, const QVector3D &eyePos); + void buildFrame(); + void buildDrawCallsForItems(); + void buildDrawCallsForFloor(); + + void markViewProjDirty() { m_vpDirty = m_window->concurrentFrameCount(); } + + VulkanWindow *m_window; + QVulkanDeviceFunctions *m_devFuncs; + + bool m_useLogo = false; + Mesh m_blockMesh; + Mesh m_logoMesh; + VkBuffer m_blockVertexBuf = VK_NULL_HANDLE; + VkBuffer m_logoVertexBuf = VK_NULL_HANDLE; + struct { + VkDeviceSize vertUniSize; + VkDeviceSize fragUniSize; + VkDeviceSize uniMemStartOffset; + Shader vs; + Shader fs; + VkDescriptorPool descPool = VK_NULL_HANDLE; + VkDescriptorSetLayout descSetLayout = VK_NULL_HANDLE; + VkDescriptorSet descSet; + VkPipelineLayout pipelineLayout = VK_NULL_HANDLE; + VkPipeline pipeline = VK_NULL_HANDLE; + } m_itemMaterial; + + VkBuffer m_floorVertexBuf = VK_NULL_HANDLE; + struct { + Shader vs; + Shader fs; + VkPipelineLayout pipelineLayout = VK_NULL_HANDLE; + VkPipeline pipeline = VK_NULL_HANDLE; + } m_floorMaterial; + + VkDeviceMemory m_bufMem = VK_NULL_HANDLE; + VkBuffer m_uniBuf = VK_NULL_HANDLE; + + VkPipelineCache m_pipelineCache = VK_NULL_HANDLE; + QFuture m_pipelinesFuture; + + QVector3D m_lightPos; + Camera m_cam; + + QMatrix4x4 m_proj; + int m_vpDirty = 0; + QMatrix4x4 m_floorModel; + + bool m_animating; + float m_rotation = 0.0f; + + int m_instCount; + int m_preparedInstCount = 0; + QByteArray m_instData; + VkBuffer m_instBuf = VK_NULL_HANDLE; + VkDeviceMemory m_instBufMem = VK_NULL_HANDLE; + + QFutureWatcher m_frameWatcher; + bool m_framePending; + + QMutex m_guiMutex; +}; + +#endif diff --git a/examples/vulkan/hellovulkancubes/shader.cpp b/examples/vulkan/hellovulkancubes/shader.cpp new file mode 100644 index 00000000000..e1c01c68426 --- /dev/null +++ b/examples/vulkan/hellovulkancubes/shader.cpp @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples 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 "shader.h" +#include +#include +#include + +void Shader::load(QVulkanInstance *inst, VkDevice dev, const QString &fn) +{ + reset(); + m_maybeRunning = true; + m_future = QtConcurrent::run([inst, dev, fn]() { + ShaderData sd; + QFile f(fn); + if (!f.open(QIODevice::ReadOnly)) { + qWarning("Failed to open %s", qPrintable(fn)); + return sd; + } + QByteArray blob = f.readAll(); + VkShaderModuleCreateInfo shaderInfo; + memset(&shaderInfo, 0, sizeof(shaderInfo)); + shaderInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + shaderInfo.codeSize = blob.size(); + shaderInfo.pCode = reinterpret_cast(blob.constData()); + VkResult err = inst->deviceFunctions(dev)->vkCreateShaderModule(dev, &shaderInfo, nullptr, &sd.shaderModule); + if (err != VK_SUCCESS) { + qWarning("Failed to create shader module: %d", err); + return sd; + } + return sd; + }); +} + +ShaderData *Shader::data() +{ + if (m_maybeRunning && !m_data.isValid()) + m_data = m_future.result(); + + return &m_data; +} + +void Shader::reset() +{ + *data() = ShaderData(); + m_maybeRunning = false; +} diff --git a/examples/vulkan/hellovulkancubes/shader.h b/examples/vulkan/hellovulkancubes/shader.h new file mode 100644 index 00000000000..265868d2b0e --- /dev/null +++ b/examples/vulkan/hellovulkancubes/shader.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples 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 SHADER_H +#define SHADER_H + +#include +#include + +struct ShaderData +{ + bool isValid() const { return shaderModule != VK_NULL_HANDLE; } + VkShaderModule shaderModule = VK_NULL_HANDLE; +}; + +class Shader +{ +public: + void load(QVulkanInstance *inst, VkDevice dev, const QString &fn); + ShaderData *data(); + bool isValid() { return data()->isValid(); } + void reset(); + +private: + bool m_maybeRunning = false; + QFuture m_future; + ShaderData m_data; +}; + +#endif diff --git a/examples/vulkan/hellovulkancubes/vulkanwindow.cpp b/examples/vulkan/hellovulkancubes/vulkanwindow.cpp new file mode 100644 index 00000000000..9a4eaf19011 --- /dev/null +++ b/examples/vulkan/hellovulkancubes/vulkanwindow.cpp @@ -0,0 +1,134 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples 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 "vulkanwindow.h" +#include "renderer.h" +#include +#include + +VulkanWindow::VulkanWindow(bool dbg) + : m_debug(dbg) +{ +} + +QVulkanWindowRenderer *VulkanWindow::createRenderer() +{ + m_renderer = new Renderer(this, 128); + return m_renderer; +} + +void VulkanWindow::addNew() +{ + m_renderer->addNew(); +} + +void VulkanWindow::togglePaused() +{ + m_renderer->setAnimating(!m_renderer->animating()); +} + +void VulkanWindow::meshSwitched(bool enable) +{ + m_renderer->setUseLogo(enable); +} + +void VulkanWindow::mousePressEvent(QMouseEvent *e) +{ + m_pressed = true; + m_lastPos = e->pos(); +} + +void VulkanWindow::mouseReleaseEvent(QMouseEvent *) +{ + m_pressed = false; +} + +void VulkanWindow::mouseMoveEvent(QMouseEvent *e) +{ + if (!m_pressed) + return; + + int dx = e->pos().x() - m_lastPos.x(); + int dy = e->pos().y() - m_lastPos.y(); + + if (dy) + m_renderer->pitch(dy / 10.0f); + + if (dx) + m_renderer->yaw(dx / 10.0f); + + m_lastPos = e->pos(); +} + +void VulkanWindow::keyPressEvent(QKeyEvent *e) +{ + const float amount = e->modifiers().testFlag(Qt::ShiftModifier) ? 1.0f : 0.1f; + switch (e->key()) { + case Qt::Key_W: + m_renderer->walk(amount); + break; + case Qt::Key_S: + m_renderer->walk(-amount); + break; + case Qt::Key_A: + m_renderer->strafe(-amount); + break; + case Qt::Key_D: + m_renderer->strafe(amount); + break; + default: + break; + } +} + +int VulkanWindow::instanceCount() const +{ + return m_renderer->instanceCount(); +} diff --git a/examples/vulkan/hellovulkancubes/vulkanwindow.h b/examples/vulkan/hellovulkancubes/vulkanwindow.h new file mode 100644 index 00000000000..d085c0bde7a --- /dev/null +++ b/examples/vulkan/hellovulkancubes/vulkanwindow.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples 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 VULKANWINDOW_H +#define VULKANWINDOW_H + +#include + +class Renderer; + +class VulkanWindow : public QVulkanWindow +{ +public: + VulkanWindow(bool dbg); + + QVulkanWindowRenderer *createRenderer() override; + + bool isDebugEnabled() const { return m_debug; } + int instanceCount() const; + +public slots: + void addNew(); + void togglePaused(); + void meshSwitched(bool enable); + +private: + void mousePressEvent(QMouseEvent *) override; + void mouseReleaseEvent(QMouseEvent *) override; + void mouseMoveEvent(QMouseEvent *) override; + void keyPressEvent(QKeyEvent *) override; + + bool m_debug; + Renderer *m_renderer; + bool m_pressed = false; + QPoint m_lastPos; +}; + +#endif diff --git a/examples/vulkan/shared/block.buf b/examples/vulkan/shared/block.buf new file mode 100644 index 0000000000000000000000000000000000000000..28ec2620bd5a5069e15d80b56991ec419ee46cde GIT binary patch literal 4256 zcma);(QVu?5JWFPI&dxd^>yPe0x&@8@_pwoRpd7}lkR~-K6|_Ii)D=+k2RQkEdQ<#PX6l8jM=p{cRl@~$=YXJ>-H&qoDcb( zZ8~4p&E@ZRWT$_R8teH#eEw#dtuG!657-&kdiI#&_#$lt+Gi%hwqx$b$de~Mk z?(lQ*2h+Z|J^Z6~@}{Ro z4stb)?{q$F(w?5Z@~!+zA1t#k`7#?dTK4jHHn{YDM<`9UuBR_*RDa&n{If^aJ@7D( zwM%{Q%(-fHpW0sE-f;Sh34P^Tx%SXg4mck)+aI4CouifaR&Q_ZDZM;KEZ~pFSh(AM3mu)L#9IU+GnQdcXYJBp4&J&GnDpE(boI z?HMOu?8}_muW69C|9)d%8&8}b+cxT(Em`L4Ru&! zY`8N#ac9?D+#a!De=_8NZTM8*9A9Ot{=|l6pV8zWg*wM$%eDScjh>J58gbcw&A0N& zKe8ov_FkVNWaom5ReuY2_AQUSnZ5hFcJn8D={KD0XBM!oe&-WMkpPtXc>2IpP z^0?1)V4Y#_ aabb[0][1]) // max x + aabb[0][1] = v[0]; + if (aabb[1][0] === null || v[1] < aabb[1][0]) // min y + aabb[1][0] = v[1]; + if (aabb[1][1] === null || v[1] > aabb[1][1]) // max y + aabb[1][1] = v[1]; + if (aabb[2][0] === null || v[2] < aabb[2][0]) // min z + aabb[2][0] = v[2]; + if (aabb[2][1] === null || v[2] > aabb[2][1]) // max z + aabb[2][1] = v[2]; + }, + getBuffer: function() { + var aabb = metadata.aabb; + console.log(metadata.vertexCount + " vertices"); + console.log("AABB: " + aabb[0][0] + ".." + aabb[0][1] + + ", " + aabb[1][0] + ".." + aabb[1][1] + + ", " + aabb[2][0] + ".." + aabb[2][1]); + var buf = new Buffer((2 + 6) * 4); + var format = 1, p = 0; + buf.writeUInt32LE(format, p++); + buf.writeUInt32LE(metadata.vertexCount, p++ * 4); + for (var i = 0; i < 3; ++i) { + buf.writeFloatLE(aabb[i][0], p++ * 4); + buf.writeFloatLE(aabb[i][1], p++ * 4); + } + return buf; + } +}; + +function makeVec(s, n) { + var v = []; + s.split(' ').forEach(function (coordStr) { + var coord = parseFloat(coordStr); + if (!isNaN(coord)) + v.push(coord); + }); + if (v.length != n) { + console.error("Wrong vector size, expected " + n + ", got " + v.length); + process.exit(); + } + return v; +} + +function parseObj(filename, callback) { + fs.readFile(filename, "ascii", function (err, data) { + if (err) + throw err; + var groupCount = 0; + var parsed = { 'vertices': [], 'normals': [], 'texcoords': [], 'links': [] }; + var missingTexCount = 0, missingNormCount = 0; + data.split('\n').forEach(function (line) { + var s = line.trim(); + if (!s.length || groupCount > 1) + return; + if (s[0] === '#') + return; + if (s[0] === 'g') { + ++groupCount; + } else if (s.substr(0, 2) === "v ") { + parsed.vertices.push(makeVec(s, 3)); + } else if (s.substr(0, 3) === "vn ") { + parsed.normals.push(makeVec(s, 3)); + } else if (s.substr(0, 3) === "vt ") { + parsed.texcoords.push(makeVec(s, 2)); + } else if (s.substr(0, 2) === "f ") { + var refs = s.split(' '); + var vertCount = refs.length - 1; + if (vertCount != 3) + console.warn("Face " + parsed.links.length / 3 + " has " + vertCount + " vertices! (not triangulated?)"); + for (var i = 1, ie = Math.min(4, refs.length); i < ie; ++i) { + var refComps = refs[i].split('/'); + var vertIndex = parseInt(refComps[0]) - 1; + var texIndex = -1; + if (refComps.length >= 2 && refComps[1].length) + texIndex = parseInt(refComps[1]) - 1; + var normIndex = -1; + if (refComps.length >= 3 && refComps[2].length) + normIndex = parseInt(refComps[2]) - 1; + parsed.links.push([vertIndex, texIndex, normIndex]); + if (texIndex == -1) + ++missingTexCount; + if (normIndex == -1) + ++missingNormCount; + } + } + }); + console.log(missingTexCount + " missing texture coordinates, " + missingNormCount + " missing normals"); + callback(parsed); + }); +} + +function fillVert(src, index, dst, elemCount, isVertexCoord) { + var vertex = []; + if (index >= 0) { + for (var i = 0; i < elemCount; ++i) { + var elem = src[index][i]; + if (isVertexCoord) + vertex.push(elem); + dst.buf.writeFloatLE(elem, dst.bufptr++ * 4); + } + if (vertex.length == 3) + metadata.emitVertex(vertex); + } else { + if (isVertexCoord) { + console.error("Missing vertex"); + process.exit(); + } + for (var i = 0; i < elemCount; ++i) + dst.buf.writeFloatLE(0, dst.bufptr++ * 4); + } + return vertex; +} + +function normalize(v) { + var len = v[0] * v[0] + v[1] * v[1] + v[2] * v[2]; + if (len == 0.0 || len == 1.0) + return; + len = Math.sqrt(len); + return [ v[0] / len, v[1] / len, v[2] / len ]; +} + +function surfaceNormal(a, b, c) { + var u = [ b[0] - a[0], b[1] - a[1], b[2] - a[2] ]; + var v = [ c[0] - a[0], c[1] - a[1], c[2] - a[2] ]; + var result = [ u[1] * v[2] - u[2] * v[1], + u[2] * v[0] - u[0] * v[2], + u[0] * v[1] - u[1] * v[0] ]; + return normalize(result); +} + +function objDataToBuf(parsed) { + var floatCount = parsed.links.length * (3 + 2 + 3); + var buf = new Buffer(floatCount * 4); + var dst = { 'buf': buf, 'bufptr': 0 }; + var tri = []; + var genNormals = false; + var genNormCount = 0; + for (var i = 0; i < parsed.links.length; ++i) { + var link = parsed.links[i]; + var vertIndex = link[0], texIndex = link[1], normIndex = link[2]; + tri.push(fillVert(parsed.vertices, vertIndex, dst, 3, true)); + fillVert(parsed.texcoords, texIndex, dst, 2); + fillVert(parsed.normals, normIndex, dst, 3); + if (normIndex == -1) + genNormals = true; + if (tri.length == 3) { + if (genNormals) { + var norm = surfaceNormal(tri[0], tri[1], tri[2]); + for (var nvIdx = 0; nvIdx < 3; ++nvIdx) { + dst.buf.writeFloatLE(norm[0], (dst.bufptr - 3 - nvIdx * 8) * 4); + dst.buf.writeFloatLE(norm[1], (dst.bufptr - 2 - nvIdx * 8) * 4); + dst.buf.writeFloatLE(norm[2], (dst.bufptr - 1 - nvIdx * 8) * 4); + } + genNormCount += 3; + } + tri = []; + } + } + if (genNormCount) + console.log("Generated " + genNormCount + " normals"); + return buf; +} + +var inFilename = process.argv[2]; +var outFilename = process.argv[3]; + +if (process.argv.length < 4) { + console.log("Usage: objconvert file.obj file.buf"); + process.exit(); +} + +parseObj(inFilename, function (parsed) { + var buf = objDataToBuf(parsed); + var f = fs.createWriteStream(outFilename); + f.on("error", function (e) { console.error(e); }); + f.write(metadata.getBuffer()); + f.write(buf); + f.end(); + console.log("Written to " + outFilename + ", format is:"); + console.log(" uint32 version, uint32 vertex_count, float32 aabb[6], vertex_count * (float32 vertex[3], float32 texcoord[2], float32 normal[3])"); +}); diff --git a/examples/vulkan/shared/qt_logo.buf b/examples/vulkan/shared/qt_logo.buf new file mode 100644 index 0000000000000000000000000000000000000000..316ec41aeed3867c3dd4b91ffa2cd600c8f744aa GIT binary patch literal 125600 zcmbuI37izg`To~iyii2(3_%1jC?E=m^zINr1rbjI2#N2Gtd8;_~(DAQGeFZI#S;~CtVuqU!y`3 z*hjmSq)+`H_<6AC_q;TC{;Bc!q5jWJI9K#v9e7Sj`Kdpxe_EfdZrx6f-@EUy^U?W- zj{mbiSty^U`#)jVcik;JR@8Lp*S&}~G`=;+s$@yh$D^q`dk8kAoel^hk+=S%so0&`P{+~U)hv>I{;E0m+DIe)~ znE$@yFV&y)yYKRf=r2G1aC3a*|M|o}NPR;6NuTnO{>P)7r2Nk9Y5*yE%f=V{RLBHe1F=?_NUKhRG)Fb&X@W(T+_@PAJuQ= z%x01=)SvVzAL-AVI7jl|xxA^FpZp(rvz6oz^(TGGNBW;NzE1LI4{c)RC;!{0Mv_0& zpY$mo>A(EOc*)_9U=`OnH7E%`(JNuToNc3dmR@4H{`Yv!ZlmyUlrem|%)UB=h{ zJlmg+Z>rCn#>1rk8;`DUj*sd$dr&9I7wS*?l#lewUhE_Jdu`a;%uoIoT-R0dhx(H~ zy)(fa8*;|3XD z{X4cW{b_xj{L$&s|BKn%n*FIhRA176V6SE}zx8e{&41tKXG;EuUjNO!e@gn4kMxIZ z(LnM~c%d}^JLlJz^>cX3|CsqZ)_Y9aLx2C$`lJ4|K1rX}=NISSB=hskPoJ3MqxJje zre{n4^Y;0|>`(Ql`6K-n&GwM_9sbMbCHWUSzu9KvOnsWa^#02aSN+xOpPwK3{vdS! zKkXk{U(wsi{lP)C*P8lNAF40uZPlx`}zwxh+nEk0fRA17cKmA)5e?Gl(N@@OGwiqD!pZ{jI znVfh$W&Za-j&w$B; zr2gIJoo@E0`cQpI|LtR5llu4ks7FcuRR8qzTj=^l^HZ#Ty-p{a`N=>1{^z2vZYj^t zwfB=eKb3y|2z`D@`%`;JKW|vn=bw=N-aV4HiWfk@-FI!%k*?@-Mdj3zl8I&|1Ig z{D$Ud&Z=bnubw;MD62o^r}6J{NV0x*oBHL`mVTNql%K{=>t{jFWc~EIbxAwRpVk-E zC!N1m$F47_e#O@3&;`duR(`7Aq!*8o<9Fpb6*cw`=~KQ#`y}h<)87Z0`cxmPFX_Lu zUvhnX?aIqb@~8E4&zH&P&vWKJZ|c+fYIJ$>`FYQ5*6g3oU#R{xf5qzW`^`rs`LDYr z`TYE2*?VSxsz1#i>3`57`TV@@U^_qgzhB;7*8hx4cP_8#_zBgA>PzeA&GKaZY zra!H(!zU(xKTfTzZ}zA9P<=`Nng^1*1AEEhqcJD~$x8d5h zHTDnbQ@;KOC-+Yte6p*lPxYbtlD?af+&@`+%_$}M)A}qwHn~6c(ue`3KCRzk>;K;R zex`mpzoGfruuB`6UpJ%X{vmzJH}b0F{@%JKSD5*z{xpB2Kk)r;re}(*)9MMFpKt#)`F^wi-yb&hY5i7CI6&t2h!Y+#`=|8{)t~0CSp7lA z-cyqQO)n?!N40wGUbBC`el^~IOYiT6##cT&`Tn;-&&N%DnqOKUq~EfvuB@Lo8$4N( zf3fu+)A>GAKb`;J{Cttr|M#ySHTzTjY5pkxKL1SKkLa<(v!;KVKQz9I|LiU6|L5a! zW`EMBe02OC@?`S-%%>NbG`Q%JtmPu_1GcH2%B z`ML0ZlKbm4f7CxOSmX7D^z;2|{C;89UCHyA^TvN_j*reC7i_bwtpBM`ePH&d^+W6L z!cM2j`m6QfyQV(XkLGXgZ{1~mzB+K7sZZ;N)*tDYJU857l@2gcD``TwD2nrasLttq;;~I;gj-pV3o(D#`!&&)3ND zHEohTe^h^(zx)52)PLV+?0i&zn!j$tI!pcQw%@|MzEXXtzNDX+=}5joF{p53N7aKW&?FvOZVrW!I1VZ+o$)%FYNxLPx+`mkM+J^&OZa%mR3K? zzj*ir8DH(kOB)~QzkS3c>x7+i=1=SnOWcMe1%186N-K%vg;`2x4 zJ%2FkNAurv{yN!z@5D#{X!a+4%18P$qI#15mTeoA)s zllm+>t+Cmk^3(W9|C?|2mikOy@~4vg|MBCovVY@|cQiHolRo96`nTCeKj|^y@G68P>U#*`M?&AL+lix}oG>GT_LP{Qt4=F3I2ij<#lh(x-ehzoS+R zk@;=ZyWI4r`KSC%e>h0$^UUs%sZZnk%TIHpK5xE!l-Zy3Dc|vr{7v*5?^RKfKIJ3* zzfM0y>eIPjrX+uw-%C#GEAxBjwjE4;n*SLu50v`MZf*Cc{4{>jpK$kKQlHCuA8qC* zf6^b_s*UJZ{?yUbCx5E{wBLJ3{qOtwI8&eI=iFuoOZ`t@)7k7#`Dy&5e?j|lsZXN{ zJ3sk9+2MNWKX~M^X8wHrYP`RS_h&zzCi+btxAT!c<)iwPE$JZs{SUV1hw3+f-W2J- z)yhsK)u)WdU*q#{Z@$_k8-KoNxAzIAKds+eubU|Oe|gy+Kh>YcPxYU? zewv>zW?v)yyUh>uhxJM0KWO(S<@4>;kDp@Zqx>}fJC~1>{5ucrV(L@E?^*?!D^8M;br*}2;)BLnuIZW!`=Xkq6)t|qkCcjrG~` zkOQPXXVvOv>QnuWxIHWWPrOxHej0y=CC`ig{yk1J^HF^$-|&-P68+1Tm8MVmK574| z=pT8QU0=#i`DlJmy}6Fe?{!W8V%Cr5f3I0@O8)aEmzJN#->B!iqW{d>rRh_?+GGDM z`a}1!$4~XAe4p1{FZ$0PUz$GUqxntwh$l?3{b~L?*8NWMe?8RhPxYbkw;212=x-Qb znm*;D@l$@vNA)Lt%6IULhvfeJur+%M~U;6&grMF&Nl0N05`ci!;Uphab^+*0`|IqqK+e7-4 zpZvF8wnDDoo9pMD^LrGA^^^8+zN9_RXRb*<2l_e4ms9?;Gx*6d&pQ5zk3VPdDWyH{ zALk49SN?Obo%D;y7oVR>)-NKT=o|d$qUw_$Uyb>cKkN+t^#7zE%BR;iXYi**zX*RC zzqA|tThS-~v_7HyX?sXt`OwbbSN~7`A${dHJA+>>`sA;CW@qrHr9Z9zV&^B6U-`|> z;8%-3jZgW^&frfMmA{Db*SLO^|LhEYwfNKclt1hY{&Z3KY5clBiZl4rqEGp0ee3?q z&fq_YKKYY=+HQP)P4XxF>!5$yKeYZRpYofX!LKf=e#&Qd27g-m=kw)ix_;66p!~|O zbq2p${Aqm3-*pCmx~Tj#e&rK7gFjtO-}ro7tvz)8SAMiJ_|wwASpSf|@}r%>pB8=c zr}>`s7df$)EJo{-Ns&Lm+Y^6V`uQA zB|qs?KGIkIamoI)ev}{V41TqYkJgv+ft|shE^7VI`cpo$Gx*V>PxYbtlD_hrOZHd( zu`~G5lArV`AL%P!xnzG@Kg#!Y2ESUyN9#-Zz0TlI7qxz9{ZW0C-|P&2wfIy0ln?C; z{jaUp`F2> zmj0wq`AA>+$Ijqa7v-;fWoPiGr9bIYK3YG@KXwMcTKs8!Dc{&N-kd)z{pt9n^+)wl z{;@Oo)kW1$`O41VPfLH&r+id@<;yyQUoHMLKgy4F27kJ!`qTVTeUu;U41RS{^;15v zGx*cepY$nT`uQz%{i6EQ{H6K^e^~O9e%e2jFa3NG`uvf8KVGKbv{4_txZ*~TMTJn=VYw%x%^&4gey}t6)kTdj^$+D& z{;@Oo)kTd@`M}QLPfLGVKeYbR`7!v@qEGdq`lj_U_{5@5^-24O>YKKQ^p$_?41RS{ z{!}036FY-nT~z&)KkN+twDc!^%BOr_XYi**pVkkpKdQg-kDbA<7Jr(bRNvtDN`KN% z`-j#C)nEC?&fr%UH9yK%b_Rc1`jbBA6Mmix)kpcn&fr%URX^qTI)gtg{b~Ks`lI?N z|JWJ)>Z0nWd}U|wr=>sXQ@(V48T?_7Q@;H8YyAFE`Nz)SSBpR0 zpQHIz{;o6l)uK=HuY6x;@Ta9e=~KS6eg>cUf2x0I{;2-SKXwMcTKs8#l&|Xy{`CKp zKQw;QS3a>b_|--ED?ip5{AuY=$8QnGe~s&3`Nz)SSBpQ*53Nt-6FY-nE&8;6m4ECE z{aToXXYi|wnjhr{ zJA*$h{YjtlDSycs{Atlw{;@Oo)zVJ$L-R}iq_6x~XYi*bADtiQ{6gzT_t$U+zgqlh zebM-pf9wo?by4#}>qq&-`S%Mq<5!D5tuN&tJA*$h{YjtlDZkel{Atmr`qTVT{gr?0 z41Trv)BI3=<>NYoUtQGrsQ$_ib_Tz?sQFPou`~G7(x3DxAJt#^%Ff_di$Bee@>iX~ zpO*e~exUP<@^78NpB8Ei>jaUd!50bmj0wq`KUh1Z*~U1TKuVg z%9nKpe_Hy}{L=cM{K_YG2ESVTX?&Dl`MA#DR~I!t<(E2xKP~;~{6^xDPO+6HQwJ-K8iE=)#6Y3%71nSf4Zpr zG=AkXJA*%6ls@I7<4gIY&fr&zKOKL{hjs>kx~Tj#e$rPyu{(Hkesxj)%4c;3e_Hxe zeW7w*0pYoxd!JjTlpYoBu@|B&zuP(}8`OnVaPfLH&r+mtXb_RbsSMSN! zo~lVdZm%g{+z$FjD!sXQ$EsHezP<9)kXO$AKDrGY3Wb;l#le4f9wo?by5DxS9S(}TKbbd<)ihf{9tGB ztHqzzukw4H!Jn4?^!b@Se^Y&w-|P&2by4+GKD0CV)6$>xDIe*l`>z@N>Z1IW5A6*8 zwDhO>rS(Dj%2##znc`zu6i5>Y~P{{A6eF zr=>sXQ$EsHzOpm;)kXO$KiL`l>7wdS^QZh|XYi**pYqfANniQO&fr%U<*)oL zKeRrS5A6*8wCGcQ8b9ePAKDrG>Z1HfU-`<;;8%-2`71x!8T@JKPx_Qk`Nq!RPm4ay zFRc&Cul!?Y@T-d&pYorb!Jn4?q)+*jpX?0&bW!@0Px-yh;7=D-f0{qaul!nP@T-d& zpYoHP!Jn4?q)++s>#xT9tICIV2ESVT>HaI}E5F$p{A$rBf8`rHgFjtVeW<>aU-`|> z;8%-3jZgWs&frfc{guBE+Ml+F^QD1W^;dqgGx*iw zPvfKf$~Scezq+{b!SSX1W@qrLMW4o}d}e3xr=>sTr}0z$mEY_Pezo}1_>^z#4E}Uc z`Dy%=U-`|>;8%-3jZgWy&frf=|Ga-L=BI>?-y)9x8joM)H#>u0E&en<Xox!gzYJQYY=nVd}^jChfGx*igu6$}|@TsL;`NPiOPfI)1hw4lD zl@IL>`s7dg%7=CazgqOkpY)aA>Nnmi{!qv_2@m z@}ZrS3a~e_|>9M{-m$`W@qrLMW6gr{-VL3mi{!qv_2@m z@}Zrr}~jU=~Mm5Ki|K`>x=TCox!h``q1@<^p)T241Trf zlfUw7-RAtZ1IMonM1bEc!J6lwbMKu5xpJwdm9MNMHHT&fr&z zKKYY=`u>!`uNHmsCw-b9@~8gk{DszU+8&yJ%AfWR=~KS2eqK4xr&d0+ar`CiVgIBZ z^kcrX@S!))Fa1+Kb;v(n1M&GSs?HZJu<2tFIsaAX2XEFMQMuU22*pYj1eJOlHawpSZ}T-)SF z<|!A?uV0_BTep&9KmSi$pOi1}Bl^{kzvSAYA>#IG_3{1F{-Jznd-eMxo9lyrMD0Ew zHNQTjKKb>TRsT)y&ur!&h4SU+U-Os#y(OX@Q*_6%5RT+{a8Es858sC zH{-|q{*+Jo?LmF@H~8>zf-&*=sUlu~p?vv&DYI#Nye{M3@j40fGL0v|9r`HquYu8XPuhmtmhwmf6AxN-$efNJ)<(mi2mJ&G|XAg zpZNZiPoGbU{O8XOY;vOLcUf95XFdPp`%^xBel7B!Z~p19?xMe2>z#7e^HIJ(<|4WPiX07M5eSgZQ?`KB- z`?q`SKS1QPz4t)c2=+`uQ~S_jmZm|6MHl zpYDHe)_T9&_osZiKSbp3pYqu0mx=y&^=D+$&&MHu%BTCUME?Fe8`h2x{rK4)Ykvyg zpYrMcQ<1;F)x+zq5d8-R^vPQLzxe)?Pxr@){Qc4DUwxJ64_RE1wf4XA{VAXBe;4`t z>%H>wNYNj0XoIY^KbP-M`E-B2$lu@a+t){l{tXkh$y)pG`Tmqo_h*c%?T>lgXwfg< z;jKm1{(!ze<ol6#3`-}Si zlu!5Hjr{$Q|M+^Mf6Ivd7Fql2`u>zp_jiu`{jWd%HqqbitXa<5|JV1Ye7Zk)RDFN* z+F#oDr+m7~*xU+>Z|D0{KIMN#K3_JsOY-;KbM=-~SbRs{pYkc6 zHuCw?16@C{3+jU*Y|O;e%Z!u1^uZ__LuyB*z@>|`n!-n{3+jt*++=}@aNAj z=+A!PpYr?ECPOmn??V2R@BAP8iT+)C4=U*Y-r*Mc{rbHw&8WW%`BT0&-KL0s^Sg%@ z^e;GIu>3w@&nq(O??V2RZ_Hcwihi&2FD~dmzoCiz-emO1jQYEfKjqtgo5iC4<(b0@ z`tj$&_&A$7b96@iUC5vEb$a*TqCa=?r3L-*bGnNDiu)=v>hD7Sluy5Zi%$KzO26Kd zr?idp$M?_G--Y}s->ji^^qQ7Qp)%t(o;i016 z>Z{8$>hD7Sl<%TOT||G?j{^(qXX&h4MZfV!!!qjcLjIKRh4wu}|C5`l&Of_<`>g11 z{psM0`n!-n<$G?zxuXB-z^e1-jcujQYEfKjl;YP}K9%s`LMy4QplM`Mvp1 zJu~W`-@noJr+i1>JY4dReYEQO)qR)!MgORV$7fRhQOKY2J>R!d^j9{iy8h1Fy@lxC z_(t1|`n!-n<@<5|IMJW@M#sYXSv>8}qW|1A2W8aXh5RYshvgGQ|BENu74%O$_hivO z>7lwA^>-nE%6HlDNus}g>0t%^Q`Ynr{kXHiecOieur~LEij<0qp=zlQ#V$t7Y|9KVa z??V2RPx;l6&u8Cz>*1n*!F5wBEdILhPx+J&9Ql0hU3*?3`ft{{pu*y3`~H+q`L~hJ zFK+$HRigj<8%I`Hd}809@+luR^7*`LCyf&QJqPYwVexl;f6Ax)&&cPuevln4`rmxN ztlZ+W`u>zp`GJwoC;f6{rRWd6b8NZAANBnypYrP>pKqAIew_J$7GKBrr+mtnh8nzi=-_5CTI?%x*q`*X&B zSI3{*4ls5_osZizeVKlFZX=EUZQ`%-?qtF`^WkIlu!33i2VIG&f4xo(Vz2G zy_~hbhVM`L^!@wD-#_7%b`{C_^Z2GYYkvgapYrMZ>yf`dz|UVa75&@pFV9);|NH)w zPv4)8{P*iWKV>h`@09DBv)-Tg{VAWmzZ?1QcQ>fNwdmi}p?A)Df7|z`eENQB-$qaeg7%)-+y$MUN8E` zHo7clz2E5jQ$BsaB=X6e(#4XbJqI_zCYzl@2~jJ z&v!X}+bCY2m;6+jv!0Ll{VAV5KOXtdug{;{+ok&H{hyFO<H8Ux|9;5q!|xFN{O7}*^?rr#Px^ zoYbf8=$!R_i|gv`u-}O_v;S$ZMf(!xa9Jj_5PUe zPx$& zpYI=)NuDq2xok$(dVbyar+oT;K;*xlu-%H&b8&r|PS`e+KED+5r+oT;L*&0-;p{?_};Mtd-y?q3u6`{Vfi zt^HMu_Fz8UKPd9|C-VDS`{x+#!F;;EQRMHhGxAwm_+JpIY|K`ZwAKUM*{?+#9Hrj*vbpPha-(TAAZ|xs#v_oUzqH@q+CSQ859ZVTl_P(DX}`aAcTKhZu`jk)icaHr1ouB@7yY%nVjI}?suTS}Of9S~HU;E4<$H?Co`M<9-*8bAo z-^XctFrV&k9{KyHuh{!F(QkeK=!~^LweL^)bpQIu-+zDqBa`nUU%PH(#@b)q_osZy zhlqUs#8q{ZXBAHV_416hf4=We`IKJ~`TUHDug{UcFLpm?SjOU0`2Lhn`5TeX7kOsQ zGSR2y}c;(z%5lu!9Ek{!q(Lnu&hjFOSMtd>Y@M@+rS4^7%|B{oz>A|E~T48H?ZJ`%^yUJ4HTU zYRd7wM1M=SO~&FU`Tmqo`Bah5C)@6<3q=31rK>9}zLf7z`IK)K`TVxoFI*)09e;kH z!s283{*+JoZ;{W>J7Txw`QeNAomye>)qH=-r~JLh=Occ7^%au8`Fs5;EdHGDPx+Lu z82Nn4xl5Agw+Gj1TVe74e1FQPe9Oq^kDl5&dHy{A{B4EBcl7-!pYls1pD#Q7q~!Ve z4*RVyxA>aAKjl+?aOCrY*Z!2~AF>AXHTh!pC7*Ht6K{C@q4$i{>0b&w6pm1zCYzl^?$hP zukx8B*7e>G&uP00`KSFu?QN#sDEUbr+M`f=s^6ydFIN7Hwma${YEQ>U`p_PQ+Ee{? zE32MA^y;5U>reed?dxvYQR=^men#iHpub7GtgrYzY|5AFZ{lCj*LJsw{-*6wsJ&yo z$I9dNPx{av?4Rmqn~n3=Pns{M?JlIB_7AnE^&x#|k3#LKe!Wg77xKr?ZO8K)|D^S& z{?vZd`rT{P2mgrLyDz*)zOzeGZ=N6gBWho;?COPycKqL)>w|wp?T0QnPW~nhLlst@>6zUaO6{c6+)|A^X$pFFWfeekDzn_ho6JHEg_ zqV_?@-cw`#O|Gw-`cuAWOy~PH)6YNOxG+6GfPWNf-{+sn^`*xS&ldFa-@8k`ivPUh zQho3b=4;=4C%JyTHEDH0|G=4v{-nS4TcrLjuZ#mDviDWCF-BA>r@^sCA9;d8#4khS<~zCYztzEI@zmAfKIQX7KL5ynzR=f6Ax)mdNMVjC$}`(J#BOLC)gS`2Lhn`6rRjm$`h$BSinVA6n%sevI!= z`IH|L`FxhYZTm;je`m#UIg7vI`%^yUZ$v)dWUI?}6#cL7?VhvvCB8r9Q~pNe^Fi|K zMxKB8?~Ui?EdGb@Px+Kz5&3+OPxpUO^iNqcC};6Me1FQP{D;WrYpm*ehv@fQc1h0S zXZZe3rc-6k+JE2o zr+mschtUy5osK1R;T@w!?0Xy;t~&pLPSpR@Q$zCY#D=VOA; zzgYYy-=Fdg*`k5$KQQ5i-{hEzbLZbrm(M4IYdxKPV6SFzyQ_EWwo{@c%=omGDq@~3CA^H1m>da-nE$~Wtmk3|26KC=t@x80xoefrFxT3PjXA%DvE{knHVzt8IN1^xKBhj^XL+kNFC z^>-nE%J=p$uZe!okCJO*tb6NUlE2@#t#iX7^>-nE%2&7Ha?#KAYgovi|9(jFFP+tH zk@~xkKjpjZvKK{vL65f!_doOdi;4a}`akN_--Y}s-!IV;(LeLUP6d7c{-^r8kU!;1 z+glyG{;0V2@sF23Qhyinr+hE%m(>5YD=#nH|Mco#p5_nvQ@#&cB--Y}s-!%^;>wj*WhUH0h%F5F9zv8}E%hlh7{3)NCksQBkuQ{clf9NC0@q0p> zS{3T=LjII*;QQam`Z;go$SQq3|NOCUvkLWhA%Dtuz~VAFe@JzxShW7W7ZA*I&**yS09|Lj7IH zpYoMG&{p)%TKQo?e|7gWM1NJ+Ei>xxLjII*{e_)H|EUFE7WBK0?<)G!Z_mFcn)thr zKjmvWsJG~kp7K*c|A!`#=>IVD(2V-KkU!J^}&VO&8QGXZm zr+oR(IHJE|uWbwZwP)`x`kysEC8Pc>wUlI4`{nD>LfvLjIKR zxd~flfdp4^0(4woknNW--Y}s-@DE0i~jrFs@6}h4Q;b={(b&=RYv_?$e;54 zbo)V~|J3lR_5bc$V@3a`+ec*7-&y`sp1vw=kF54M-;v{*i~jW8s*c}h2F(-w#nUd% zsJ{#OQ@)#5w-)^i8daTt4nKUA=x19DNc~;NpYq*!OS$MzeYEQQIpd7qMgNgzeKP9r zLjIKRzbiV3{xNQwig-@rpKD&Kn~VQ>_lYNG)Zc~tDPOl?okhQH`>N~L%0~|t{T26R zGV1R_{*-U}gcC*o+RFbcTz@wQ-F#vhVVe;4wne0%M9n&?+t{zXCmfdL7>VDjL4 z8TEG|f66!ax9+0<>cDjc{hcp9L-ObMgwCkH3;9#Nm1BB|{@_M$6!hP?<$Tc}e$x9D z>Yv}g&i1E#H$Hx*=+7OtxS(J8PO|@h>u6Dh`n!-nO1Uq||4?g)J)7--Y}sU;l##i2j35b}i_q`(Kay=MEL> z??V2R@9>EOMSp5#{eu3yyOQUVuU`LJx%#`1Kjm9@%OKJJvFyFV{efLhN}j)+b;6D1 z>hD7Sl<&|!gGK+--v<`-)8~U*N9E<}??V2RZ_cVjfA!o6h5IKxK2P%3-tqBB{awhP z@}>JnTKn7Q_j!F<{awhP@-2NW$v?C0dxiT;Y5t|N7P@qQ%aA|i+q*}if8Xdvi{fim z{1fkc6902q%Z`iG--Y}s-+;-<`sp_B^n!l;y;rRN@7A|0Qhyinr+iNjP1gU#)2=S) zmnpwt!`inNslN;PQ@$=+B**Xb-&Ebd?K(brefSvk%XzzYF{Q9$v0mMR{+K6|{quXat(#MS7xJfk7hKm>^m}dCyP*Hp zo$V$6mbWy?slN;PQ@+`QI*I5?5Q5l?~(nt7X1$U_0Flk3;9#NN8W5D`gbmGTFAe# z!F%%i`VY^~slN;PQ@)k?@6h7=0}akU!;na#dr|UwnGi{=-w& zUMu>e9vq%ie;4wne4kJJgXk|mKH1YJuKyNYlf9a^FTX0M{x0NC`96Dk57BS^z!8P| z{g>3=h5RYsH+^>!{a44fD(L^Re5mNpoL-qze;4wneChp_nM6LjII*evfbD{?#V^%VYgGe|rBXHyOX^$MskLP4gH0DPQ+pUJ-qN z{w^Hbu_DeNuOIc_wEhKu%J=aoC;I;S`>FOs(f|71;W_oMwtjqn$~W%U`J(S1KaXDZ zi0FU(?S(n@ueSbuf66y+;vCWUkN-m-c~A5YdhYz3`d2%CeSgaLS>x+O-#>pfe=pg8 z@{l)r<R;{r>HAZ@IgN*jzJL7~P}W@Z z4|(ILocdQg|NH)wuk6J>qVHe-ew~->KmYrA2j$ei+V#u#r+llYoFMxC_4~(# zD)6BlwFCb($bVLU7ve*w?IC~SKWlq6KC;h`PW40n%7?DTch2|GpD`&Px|)948b60Y z{=|PKzPaWL`scI6{Nrl*{r69`y;^_2o%~aM;6FQR|NrGvhxpLx_`pBNe@^?ae65PF z^1tw_iT|wa)%eIhKbriB|E%rR^z)kf!~AOEQxiX${PRI-bxQuJ zKAfNO&(BQG#+u1b)%&CQ{~hNG`V;?|_|e3#CjK+=qsgE6&%}==f8swAKbriB|4jU7 z@+Uqu@uSI~_|L?TCV%2T6F-{#iT_OeX!0liGx4LzKixkS_|PuYPX5GyCVq6f|7*yf z_|L?TCV%2T6F-{#iT_OeX!0liGx4LzpZL$jk0yWOKNCNi{NFEcUmkxx4DqS8-G$o8 zpZL$jk0yWOKNCNi{E7ce{Altg{xk8T$)EVo#E&L_;y)8Vn*53XO#Eo_C;l_>qsgE6 z&%}==f8swAKbriB|4jU7@+bZ?@uSI~_|L?TCV%2T6F-{#iT_OeX!0liGx4LzpZL$j zk0yWOKNCNi{E7ce{Altg{xk8T$)EVo#E&L_;y)8Vn*53XO#Eo_C;l_>qsgE6&)Od3 zN0UGCpNSt${=|PKel+=~{2$;$yHGp%6aSg`(J8+uqtoa6LjJ^mCVn*e6aSg`(d1A3 zXW~bbKk=WnJ;;wHf8swAKbriB|4jU7@+bZ?@uSI~_|L?TCV%2T6F-{#iT_OeX!0li zGx4LzpZL$jk0yWOKNCNi{E7ce{Altg{xk8T$)EVo#E&L_;y)8Vn*53XO#Eo_C;l_> zqsgE6&%}==f8swAKbriB|4jU7@+bZ?@uSI~_|L?TCV%2T6F-{#iT_OeX!0liGx4Lz zpZL$jk0$>%`;3w2OGA8WZFiw|@+bZ?@uSI~_|L?TCV%2T6F-{#iT_OeX!0liGx4Lz zpZL$jk0yWOKNCNi{E7ce{Altg{xk8T$v?gS1AJ%~YA1iqsgE6 z&%}==f8swAKbriB|4jU7@+bZ?@uSI~_|L?TCV%2T6F-{#iT_OeX!0liGx4LzpZL$j zk0yWOKNCNi{E7ce{Alt|pI-t#v9$)EVt#E&L_;!_hpn*51RP5fx`Cq6atqsgE6&%}==f8sxDdypSZ z{=}!o=cj>RO?+zNM-#uA_|(LYCV%2n6F-{#iBC=ZX!2J+bddk7?LmGt`4gX-_|fD~ zd}`uHlRxpPi62e=#HS{HH2D+%nfTGPGF%%@KI#i4fcPxXP%9OOHb zf69*z=@UOX)rbC@@`t59@q5at{wDn3&DulyX?;Td(|nnE;H$`1{-lYgqeiT`H$)E@FD{xk8T)A5D;Q~eO1In}53kbYX9Q2#VvsGa;% zec(SkY7hCR`oMp7)DHf{e|Er!CV%2TJK#f;Kk=XQ`yc-Q@vDIk?Wi66iT~_?4^95W ze|Er+CV%2TJK#f;Kk=X4Cf8p%|HbFn^!NtDP5#7xCVq6ve};S!@S$C(o&1Ua zO#J9Hf5@Ns&%}==f8swAKbriB|4jU7@+bZ?@uSI~_|L?TCV%2T6F-{#iT_OeX!0li zGx4LzpZL$jk0yWOKNCNi{E7ce{Altg{xk8T$)EVo#E&L_;y)8Vn*53XO#Eo_C;l_> zqsgE6&%}==f8swAKbriB|4jU7@+bZ?@uSI~_|L?TCjXTG1AOQpKbriB|4jVolwTCe zNBn2vN0UGCsfiy={=|PKel+qsgE6&%}==f8swAKbriB|4jU7@+bZ?@uSI~_|MuNG>P-|9{#)8HxY^ literal 0 HcmV?d00001 diff --git a/examples/vulkan/shared/qt_logo.txt b/examples/vulkan/shared/qt_logo.txt new file mode 100644 index 00000000000..167b8a4caf3 --- /dev/null +++ b/examples/vulkan/shared/qt_logo.txt @@ -0,0 +1,2912 @@ +# Blender v2.77 (sub 0) OBJ File: 'qt_logo.blend' +# www.blender.org +o qt_logo_qt_logo_mesh +v 0.500000 0.030000 -0.271909 +v 0.500000 0.030000 -0.234087 +v 0.500000 0.030000 0.229669 +v 0.361282 0.030000 0.368353 +v -0.369121 0.030000 0.368353 +v -0.403885 0.030000 0.368353 +v -0.500000 0.030000 0.368353 +v -0.500000 0.030000 0.272263 +v -0.500000 0.030000 0.234440 +v -0.500000 0.030000 -0.229316 +v -0.361282 0.030000 -0.368000 +v 0.369121 0.030000 -0.368000 +v 0.403886 0.030000 -0.368000 +v 0.500000 0.030000 -0.368000 +v -0.014123 0.030000 0.177038 +v -0.008432 0.030000 0.172481 +v -0.003036 0.030000 0.167611 +v 0.002070 0.030000 0.162429 +v 0.006887 0.030000 0.156934 +v 0.011418 0.030000 0.151127 +v 0.015664 0.030000 0.145008 +v 0.019629 0.030000 0.138577 +v 0.023315 0.030000 0.131833 +v 0.026724 0.030000 0.124776 +v 0.029858 0.030000 0.117408 +v 0.032720 0.030000 0.109727 +v 0.035255 0.030000 0.101769 +v 0.037575 0.030000 0.093399 +v 0.039680 0.030000 0.084618 +v 0.041569 0.030000 0.075425 +v 0.043240 0.030000 0.065820 +v 0.044692 0.030000 0.055804 +v 0.045923 0.030000 0.045375 +v 0.046934 0.030000 0.034535 +v 0.047722 0.030000 0.023284 +v 0.048286 0.030000 0.011620 +v 0.048626 0.030000 -0.000455 +v 0.048739 0.030000 -0.012942 +v 0.048469 0.030000 -0.031775 +v 0.047658 0.030000 -0.049771 +v 0.046305 0.030000 -0.066929 +v 0.044409 0.030000 -0.083249 +v 0.041969 0.030000 -0.098732 +v 0.038983 0.030000 -0.113377 +v 0.035450 0.030000 -0.127184 +v 0.031369 0.030000 -0.140154 +v 0.026739 0.030000 -0.152286 +v 0.021559 0.030000 -0.163580 +v 0.015828 0.030000 -0.174037 +v 0.009543 0.030000 -0.183656 +v 0.002656 0.030000 -0.192551 +v -0.005054 0.030000 -0.200667 +v -0.013585 0.030000 -0.208004 +v -0.022937 0.030000 -0.214563 +v -0.033107 0.030000 -0.220347 +v -0.044095 0.030000 -0.225355 +v -0.055900 0.030000 -0.229590 +v -0.068520 0.030000 -0.233052 +v -0.081954 0.030000 -0.235742 +v -0.096201 0.030000 -0.237663 +v -0.111260 0.030000 -0.238814 +v -0.127130 0.030000 -0.239198 +v -0.143000 0.030000 -0.238808 +v -0.158061 0.030000 -0.237638 +v -0.172312 0.030000 -0.235689 +v -0.185753 0.030000 -0.232963 +v -0.198385 0.030000 -0.229461 +v -0.210208 0.030000 -0.225185 +v -0.221221 0.030000 -0.220134 +v -0.231425 0.030000 -0.214311 +v -0.240819 0.030000 -0.207716 +v -0.249404 0.030000 -0.200351 +v -0.257179 0.030000 -0.192217 +v -0.264144 0.030000 -0.183315 +v -0.270435 0.030000 -0.173618 +v -0.276186 0.030000 -0.163098 +v -0.281394 0.030000 -0.151754 +v -0.286059 0.030000 -0.139586 +v -0.290179 0.030000 -0.126595 +v -0.293754 0.030000 -0.112781 +v -0.296782 0.030000 -0.098143 +v -0.299263 0.030000 -0.082682 +v -0.301194 0.030000 -0.066397 +v -0.302575 0.030000 -0.049288 +v -0.303404 0.030000 -0.031357 +v -0.303681 0.030000 -0.012601 +v -0.303411 0.030000 0.006061 +v -0.302602 0.030000 0.023884 +v -0.301253 0.030000 0.040864 +v -0.299364 0.030000 0.056999 +v -0.296935 0.030000 0.072288 +v -0.293967 0.030000 0.086726 +v -0.290460 0.030000 0.100313 +v -0.286412 0.030000 0.113046 +v -0.281825 0.030000 0.124922 +v -0.276698 0.030000 0.135939 +v -0.271032 0.030000 0.146095 +v -0.264826 0.030000 0.155387 +v -0.257932 0.030000 0.163877 +v -0.250200 0.030000 0.171629 +v -0.241634 0.030000 0.178643 +v -0.232233 0.030000 0.184918 +v -0.221998 0.030000 0.190455 +v -0.210932 0.030000 0.195254 +v -0.199035 0.030000 0.199315 +v -0.186309 0.030000 0.202637 +v -0.172754 0.030000 0.205221 +v -0.158371 0.030000 0.207067 +v -0.143163 0.030000 0.208174 +v -0.127130 0.030000 0.208543 +v -0.122805 0.030000 0.208515 +v -0.118691 0.030000 0.208431 +v -0.114786 0.030000 0.208293 +v -0.111086 0.030000 0.208101 +v -0.107590 0.030000 0.207858 +v -0.104294 0.030000 0.207563 +v -0.101198 0.030000 0.207219 +v -0.098298 0.030000 0.206827 +v -0.095593 0.030000 0.206387 +v -0.093079 0.030000 0.205901 +v -0.090754 0.030000 0.205370 +v -0.088616 0.030000 0.204795 +v -0.032379 0.030000 0.297137 +v 0.032720 0.030000 0.266811 +v 0.027981 0.030000 0.259139 +v 0.022692 0.030000 0.250576 +v 0.017036 0.030000 0.241420 +v 0.011197 0.030000 0.231966 +v 0.005358 0.030000 0.222513 +v -0.000298 0.030000 0.213356 +v -0.005587 0.030000 0.204794 +v -0.010326 0.030000 0.197122 +v -0.014331 0.030000 0.190638 +v -0.017419 0.030000 0.185639 +v -0.019406 0.030000 0.182422 +v -0.020109 0.030000 0.181283 +v 0.291411 0.030000 0.137327 +v 0.286764 0.030000 0.137511 +v 0.281577 0.030000 0.137715 +v 0.276031 0.030000 0.137934 +v 0.270305 0.030000 0.138160 +v 0.264578 0.030000 0.138386 +v 0.259032 0.030000 0.138605 +v 0.253845 0.030000 0.138810 +v 0.249198 0.030000 0.138993 +v 0.245271 0.030000 0.139148 +v 0.242243 0.030000 0.139267 +v 0.240294 0.030000 0.139344 +v 0.239605 0.030000 0.139372 +v 0.235884 0.030000 0.139286 +v 0.232394 0.030000 0.139029 +v 0.229135 0.030000 0.138600 +v 0.226110 0.030000 0.137996 +v 0.223322 0.030000 0.137217 +v 0.220774 0.030000 0.136262 +v 0.218466 0.030000 0.135130 +v 0.216403 0.030000 0.133819 +v 0.214585 0.030000 0.132328 +v 0.213017 0.030000 0.130656 +v 0.211699 0.030000 0.128802 +v 0.210634 0.030000 0.126764 +v 0.209732 0.030000 0.124535 +v 0.208903 0.030000 0.121937 +v 0.208147 0.030000 0.118969 +v 0.207465 0.030000 0.115633 +v 0.206860 0.030000 0.111927 +v 0.206331 0.030000 0.107853 +v 0.205880 0.030000 0.103409 +v 0.205509 0.030000 0.098596 +v 0.205218 0.030000 0.093413 +v 0.205009 0.030000 0.087862 +v 0.204882 0.030000 0.081942 +v 0.204840 0.030000 0.075652 +v 0.204840 0.030000 -0.063713 +v 0.292093 0.030000 -0.063713 +v 0.292093 0.030000 -0.122662 +v 0.204840 0.030000 -0.122662 +v 0.204840 0.030000 -0.214664 +v 0.136333 0.030000 -0.214664 +v 0.136333 0.030000 -0.122662 +v 0.087935 0.030000 -0.122662 +v 0.087935 0.030000 -0.064054 +v 0.136333 0.030000 -0.064054 +v 0.136333 0.030000 -0.050850 +v 0.136333 0.030000 -0.036113 +v 0.136333 0.030000 -0.020353 +v 0.136333 0.030000 -0.004083 +v 0.136333 0.030000 0.012188 +v 0.136333 0.030000 0.027947 +v 0.136333 0.030000 0.042685 +v 0.136333 0.030000 0.055889 +v 0.136333 0.030000 0.067048 +v 0.136333 0.030000 0.075652 +v 0.136333 0.030000 0.081189 +v 0.136333 0.030000 0.083148 +v 0.136475 0.030000 0.094258 +v 0.136899 0.030000 0.104757 +v 0.137605 0.030000 0.114646 +v 0.138592 0.030000 0.123924 +v 0.139858 0.030000 0.132592 +v 0.141403 0.030000 0.140649 +v 0.143224 0.030000 0.148096 +v 0.145321 0.030000 0.154932 +v 0.147692 0.030000 0.161158 +v 0.150337 0.030000 0.166773 +v 0.153254 0.030000 0.171778 +v 0.156442 0.030000 0.176172 +v 0.159999 0.030000 0.180091 +v 0.164025 0.030000 0.183669 +v 0.168520 0.030000 0.186906 +v 0.173483 0.030000 0.189802 +v 0.178915 0.030000 0.192358 +v 0.184816 0.030000 0.194573 +v 0.191185 0.030000 0.196447 +v 0.198023 0.030000 0.197980 +v 0.205330 0.030000 0.199173 +v 0.213105 0.030000 0.200024 +v 0.221349 0.030000 0.200536 +v 0.230061 0.030000 0.200706 +v 0.233945 0.030000 0.200649 +v 0.238099 0.030000 0.200479 +v 0.242523 0.030000 0.200195 +v 0.247217 0.030000 0.199797 +v 0.252180 0.030000 0.199286 +v 0.257413 0.030000 0.198662 +v 0.262916 0.030000 0.197923 +v 0.268689 0.030000 0.197071 +v 0.274732 0.030000 0.196106 +v 0.281044 0.030000 0.195027 +v 0.287626 0.030000 0.193834 +v 0.294479 0.030000 0.192528 +v -0.042504 0.030000 -0.131451 +v -0.039308 0.030000 -0.123910 +v -0.036421 0.030000 -0.115714 +v -0.033843 0.030000 -0.106862 +v -0.031573 0.030000 -0.097352 +v -0.029610 0.030000 -0.087182 +v -0.027952 0.030000 -0.076353 +v -0.026597 0.030000 -0.064862 +v -0.025546 0.030000 -0.052708 +v -0.024797 0.030000 -0.039891 +v -0.024348 0.030000 -0.026409 +v -0.024199 0.030000 -0.012261 +v -0.024348 0.030000 0.001795 +v -0.024794 0.030000 0.015166 +v -0.025536 0.030000 0.027852 +v -0.026572 0.030000 0.039848 +v -0.027902 0.030000 0.051154 +v -0.029525 0.030000 0.061767 +v -0.031438 0.030000 0.071683 +v -0.033641 0.030000 0.080902 +v -0.036133 0.030000 0.089420 +v -0.038913 0.030000 0.097236 +v -0.041979 0.030000 0.104346 +v -0.045331 0.030000 0.110749 +v -0.049179 0.030000 0.116548 +v -0.053569 0.030000 0.121850 +v -0.058501 0.030000 0.126652 +v -0.063975 0.030000 0.130954 +v -0.069995 0.030000 0.134754 +v -0.076559 0.030000 0.138051 +v -0.083671 0.030000 0.140844 +v -0.091330 0.030000 0.143132 +v -0.099539 0.030000 0.144914 +v -0.108298 0.030000 0.146188 +v -0.117608 0.030000 0.146953 +v -0.127471 0.030000 0.147209 +v -0.137341 0.030000 0.146947 +v -0.146670 0.030000 0.146161 +v -0.155456 0.030000 0.144855 +v -0.163700 0.030000 0.143031 +v -0.171399 0.030000 0.140692 +v -0.178553 0.030000 0.137838 +v -0.185160 0.030000 0.134474 +v -0.191219 0.030000 0.130601 +v -0.196729 0.030000 0.126221 +v -0.201689 0.030000 0.121337 +v -0.206097 0.030000 0.115952 +v -0.209952 0.030000 0.110067 +v -0.213382 0.030000 0.103587 +v -0.216513 0.030000 0.096412 +v -0.219346 0.030000 0.088547 +v -0.221881 0.030000 0.079993 +v -0.224118 0.030000 0.070753 +v -0.226057 0.030000 0.060830 +v -0.227697 0.030000 0.050224 +v -0.229039 0.030000 0.038940 +v -0.230083 0.030000 0.026978 +v -0.230828 0.030000 0.014343 +v -0.231276 0.030000 0.001035 +v -0.231425 0.030000 -0.012942 +v -0.231269 0.030000 -0.027005 +v -0.230801 0.030000 -0.040404 +v -0.230024 0.030000 -0.053140 +v -0.228938 0.030000 -0.065215 +v -0.227544 0.030000 -0.076633 +v -0.225844 0.030000 -0.087395 +v -0.223838 0.030000 -0.097504 +v -0.221528 0.030000 -0.106963 +v -0.218915 0.030000 -0.115773 +v -0.216000 0.030000 -0.123937 +v -0.212785 0.030000 -0.131458 +v -0.209271 0.030000 -0.138337 +v -0.205266 0.030000 -0.144620 +v -0.200750 0.030000 -0.150350 +v -0.195723 0.030000 -0.155529 +v -0.190184 0.030000 -0.160157 +v -0.184134 0.030000 -0.164237 +v -0.177573 0.030000 -0.167769 +v -0.170501 0.030000 -0.170754 +v -0.162917 0.030000 -0.173194 +v -0.154823 0.030000 -0.175090 +v -0.146217 0.030000 -0.176442 +v -0.137100 0.030000 -0.177253 +v -0.127471 0.030000 -0.177523 +v -0.117843 0.030000 -0.177253 +v -0.108727 0.030000 -0.176442 +v -0.100125 0.030000 -0.175090 +v -0.092037 0.030000 -0.173194 +v -0.084466 0.030000 -0.170754 +v -0.077411 0.030000 -0.167769 +v -0.070875 0.030000 -0.164237 +v -0.064859 0.030000 -0.160157 +v -0.059363 0.030000 -0.155529 +v -0.054389 0.030000 -0.150350 +v -0.049939 0.030000 -0.144620 +v -0.046012 0.030000 -0.138337 +v 0.500000 -0.030000 -0.271909 +v 0.500000 -0.030000 -0.234087 +v 0.500000 -0.030000 0.229669 +v 0.361282 -0.030000 0.368353 +v -0.369121 -0.030000 0.368353 +v -0.403885 -0.030000 0.368353 +v -0.500000 -0.030000 0.368353 +v -0.500000 -0.030000 0.272263 +v -0.500000 -0.030000 0.234440 +v -0.500000 -0.030000 -0.229316 +v -0.361282 -0.030000 -0.368000 +v 0.369121 -0.030000 -0.368000 +v 0.403886 -0.030000 -0.368000 +v 0.500000 -0.030000 -0.368000 +v -0.014123 -0.030000 0.177038 +v -0.008432 -0.030000 0.172481 +v -0.003036 -0.030000 0.167611 +v 0.002070 -0.030000 0.162429 +v 0.006887 -0.030000 0.156934 +v 0.011418 -0.030000 0.151127 +v 0.015664 -0.030000 0.145008 +v 0.019629 -0.030000 0.138577 +v 0.023315 -0.030000 0.131833 +v 0.026724 -0.030000 0.124776 +v 0.029858 -0.030000 0.117408 +v 0.032720 -0.030000 0.109727 +v 0.035255 -0.030000 0.101769 +v 0.037575 -0.030000 0.093399 +v 0.039680 -0.030000 0.084618 +v 0.041569 -0.030000 0.075425 +v 0.043240 -0.030000 0.065820 +v 0.044692 -0.030000 0.055804 +v 0.045923 -0.030000 0.045375 +v 0.046934 -0.030000 0.034535 +v 0.047722 -0.030000 0.023284 +v 0.048286 -0.030000 0.011620 +v 0.048626 -0.030000 -0.000455 +v 0.048739 -0.030000 -0.012942 +v 0.048469 -0.030000 -0.031775 +v 0.047658 -0.030000 -0.049771 +v 0.046305 -0.030000 -0.066929 +v 0.044409 -0.030000 -0.083249 +v 0.041969 -0.030000 -0.098732 +v 0.038983 -0.030000 -0.113377 +v 0.035450 -0.030000 -0.127184 +v 0.031369 -0.030000 -0.140154 +v 0.026739 -0.030000 -0.152286 +v 0.021559 -0.030000 -0.163580 +v 0.015828 -0.030000 -0.174037 +v 0.009543 -0.030000 -0.183656 +v 0.002656 -0.030000 -0.192551 +v -0.005054 -0.030000 -0.200667 +v -0.013585 -0.030000 -0.208004 +v -0.022937 -0.030000 -0.214563 +v -0.033107 -0.030000 -0.220347 +v -0.044095 -0.030000 -0.225355 +v -0.055900 -0.030000 -0.229590 +v -0.068520 -0.030000 -0.233052 +v -0.081954 -0.030000 -0.235742 +v -0.096201 -0.030000 -0.237663 +v -0.111260 -0.030000 -0.238814 +v -0.127130 -0.030000 -0.239198 +v -0.143000 -0.030000 -0.238808 +v -0.158061 -0.030000 -0.237638 +v -0.172312 -0.030000 -0.235689 +v -0.185753 -0.030000 -0.232963 +v -0.198385 -0.030000 -0.229461 +v -0.210208 -0.030000 -0.225185 +v -0.221221 -0.030000 -0.220134 +v -0.231425 -0.030000 -0.214311 +v -0.240819 -0.030000 -0.207716 +v -0.249404 -0.030000 -0.200351 +v -0.257179 -0.030000 -0.192217 +v -0.264144 -0.030000 -0.183315 +v -0.270435 -0.030000 -0.173618 +v -0.276186 -0.030000 -0.163098 +v -0.281394 -0.030000 -0.151754 +v -0.286059 -0.030000 -0.139586 +v -0.290179 -0.030000 -0.126595 +v -0.293754 -0.030000 -0.112781 +v -0.296782 -0.030000 -0.098143 +v -0.299263 -0.030000 -0.082682 +v -0.301194 -0.030000 -0.066397 +v -0.302575 -0.030000 -0.049288 +v -0.303404 -0.030000 -0.031357 +v -0.303681 -0.030000 -0.012601 +v -0.303411 -0.030000 0.006061 +v -0.302602 -0.030000 0.023884 +v -0.301253 -0.030000 0.040864 +v -0.299364 -0.030000 0.056999 +v -0.296935 -0.030000 0.072288 +v -0.293967 -0.030000 0.086726 +v -0.290460 -0.030000 0.100313 +v -0.286412 -0.030000 0.113046 +v -0.281825 -0.030000 0.124922 +v -0.276698 -0.030000 0.135939 +v -0.271032 -0.030000 0.146095 +v -0.264826 -0.030000 0.155387 +v -0.257932 -0.030000 0.163877 +v -0.250200 -0.030000 0.171629 +v -0.241634 -0.030000 0.178643 +v -0.232233 -0.030000 0.184918 +v -0.221998 -0.030000 0.190455 +v -0.210932 -0.030000 0.195254 +v -0.199035 -0.030000 0.199315 +v -0.186309 -0.030000 0.202637 +v -0.172754 -0.030000 0.205221 +v -0.158371 -0.030000 0.207067 +v -0.143163 -0.030000 0.208174 +v -0.127130 -0.030000 0.208543 +v -0.122805 -0.030000 0.208515 +v -0.118691 -0.030000 0.208431 +v -0.114786 -0.030000 0.208293 +v -0.111086 -0.030000 0.208101 +v -0.107590 -0.030000 0.207858 +v -0.104294 -0.030000 0.207563 +v -0.101198 -0.030000 0.207219 +v -0.098298 -0.030000 0.206827 +v -0.095593 -0.030000 0.206387 +v -0.093079 -0.030000 0.205901 +v -0.090754 -0.030000 0.205370 +v -0.088616 -0.030000 0.204795 +v -0.032379 -0.030000 0.297137 +v 0.032720 -0.030000 0.266811 +v 0.027981 -0.030000 0.259139 +v 0.022692 -0.030000 0.250576 +v 0.017036 -0.030000 0.241420 +v 0.011197 -0.030000 0.231966 +v 0.005358 -0.030000 0.222513 +v -0.000298 -0.030000 0.213356 +v -0.005587 -0.030000 0.204794 +v -0.010326 -0.030000 0.197122 +v -0.014331 -0.030000 0.190638 +v -0.017419 -0.030000 0.185639 +v -0.019406 -0.030000 0.182422 +v -0.020109 -0.030000 0.181283 +v 0.291411 -0.030000 0.137327 +v 0.286764 -0.030000 0.137511 +v 0.281577 -0.030000 0.137715 +v 0.276031 -0.030000 0.137934 +v 0.270305 -0.030000 0.138160 +v 0.264578 -0.030000 0.138386 +v 0.259032 -0.030000 0.138605 +v 0.253845 -0.030000 0.138810 +v 0.249198 -0.030000 0.138993 +v 0.245271 -0.030000 0.139148 +v 0.242243 -0.030000 0.139267 +v 0.240294 -0.030000 0.139344 +v 0.239605 -0.030000 0.139372 +v 0.235884 -0.030000 0.139286 +v 0.232394 -0.030000 0.139029 +v 0.229135 -0.030000 0.138600 +v 0.226110 -0.030000 0.137996 +v 0.223322 -0.030000 0.137217 +v 0.220774 -0.030000 0.136262 +v 0.218466 -0.030000 0.135130 +v 0.216403 -0.030000 0.133819 +v 0.214585 -0.030000 0.132328 +v 0.213017 -0.030000 0.130656 +v 0.211699 -0.030000 0.128802 +v 0.210634 -0.030000 0.126764 +v 0.209732 -0.030000 0.124535 +v 0.208903 -0.030000 0.121937 +v 0.208147 -0.030000 0.118969 +v 0.207465 -0.030000 0.115633 +v 0.206860 -0.030000 0.111927 +v 0.206331 -0.030000 0.107853 +v 0.205880 -0.030000 0.103409 +v 0.205509 -0.030000 0.098596 +v 0.205218 -0.030000 0.093413 +v 0.205009 -0.030000 0.087862 +v 0.204882 -0.030000 0.081942 +v 0.204840 -0.030000 0.075652 +v 0.204840 -0.030000 -0.063713 +v 0.292093 -0.030000 -0.063713 +v 0.292093 -0.030000 -0.122662 +v 0.204840 -0.030000 -0.122662 +v 0.204840 -0.030000 -0.214664 +v 0.136333 -0.030000 -0.214664 +v 0.136333 -0.030000 -0.122662 +v 0.087935 -0.030000 -0.122662 +v 0.087935 -0.030000 -0.064054 +v 0.136333 -0.030000 -0.064054 +v 0.136333 -0.030000 -0.050850 +v 0.136333 -0.030000 -0.036113 +v 0.136333 -0.030000 -0.020353 +v 0.136333 -0.030000 -0.004083 +v 0.136333 -0.030000 0.012188 +v 0.136333 -0.030000 0.027947 +v 0.136333 -0.030000 0.042685 +v 0.136333 -0.030000 0.055889 +v 0.136333 -0.030000 0.067048 +v 0.136333 -0.030000 0.075652 +v 0.136333 -0.030000 0.081189 +v 0.136333 -0.030000 0.083148 +v 0.136475 -0.030000 0.094258 +v 0.136899 -0.030000 0.104757 +v 0.137605 -0.030000 0.114646 +v 0.138592 -0.030000 0.123924 +v 0.139858 -0.030000 0.132592 +v 0.141403 -0.030000 0.140649 +v 0.143224 -0.030000 0.148096 +v 0.145321 -0.030000 0.154932 +v 0.147692 -0.030000 0.161158 +v 0.150337 -0.030000 0.166773 +v 0.153254 -0.030000 0.171778 +v 0.156442 -0.030000 0.176172 +v 0.159999 -0.030000 0.180091 +v 0.164025 -0.030000 0.183669 +v 0.168520 -0.030000 0.186906 +v 0.173483 -0.030000 0.189802 +v 0.178915 -0.030000 0.192358 +v 0.184816 -0.030000 0.194573 +v 0.191185 -0.030000 0.196447 +v 0.198023 -0.030000 0.197980 +v 0.205330 -0.030000 0.199173 +v 0.213105 -0.030000 0.200024 +v 0.221349 -0.030000 0.200536 +v 0.230061 -0.030000 0.200706 +v 0.233945 -0.030000 0.200649 +v 0.238099 -0.030000 0.200479 +v 0.242523 -0.030000 0.200195 +v 0.247217 -0.030000 0.199797 +v 0.252180 -0.030000 0.199286 +v 0.257413 -0.030000 0.198662 +v 0.262916 -0.030000 0.197923 +v 0.268689 -0.030000 0.197071 +v 0.274732 -0.030000 0.196106 +v 0.281044 -0.030000 0.195027 +v 0.287626 -0.030000 0.193834 +v 0.294479 -0.030000 0.192528 +v -0.042504 -0.030000 -0.131451 +v -0.039308 -0.030000 -0.123910 +v -0.036421 -0.030000 -0.115714 +v -0.033843 -0.030000 -0.106862 +v -0.031573 -0.030000 -0.097352 +v -0.029610 -0.030000 -0.087182 +v -0.027952 -0.030000 -0.076353 +v -0.026597 -0.030000 -0.064862 +v -0.025546 -0.030000 -0.052708 +v -0.024797 -0.030000 -0.039891 +v -0.024348 -0.030000 -0.026409 +v -0.024199 -0.030000 -0.012261 +v -0.024348 -0.030000 0.001795 +v -0.024794 -0.030000 0.015166 +v -0.025536 -0.030000 0.027852 +v -0.026572 -0.030000 0.039848 +v -0.027902 -0.030000 0.051154 +v -0.029525 -0.030000 0.061767 +v -0.031438 -0.030000 0.071683 +v -0.033641 -0.030000 0.080902 +v -0.036133 -0.030000 0.089420 +v -0.038913 -0.030000 0.097236 +v -0.041979 -0.030000 0.104346 +v -0.045331 -0.030000 0.110749 +v -0.049179 -0.030000 0.116548 +v -0.053569 -0.030000 0.121850 +v -0.058501 -0.030000 0.126652 +v -0.063975 -0.030000 0.130954 +v -0.069995 -0.030000 0.134754 +v -0.076559 -0.030000 0.138051 +v -0.083671 -0.030000 0.140844 +v -0.091330 -0.030000 0.143132 +v -0.099539 -0.030000 0.144914 +v -0.108298 -0.030000 0.146188 +v -0.117608 -0.030000 0.146953 +v -0.127471 -0.030000 0.147209 +v -0.137341 -0.030000 0.146947 +v -0.146670 -0.030000 0.146161 +v -0.155456 -0.030000 0.144855 +v -0.163700 -0.030000 0.143031 +v -0.171399 -0.030000 0.140692 +v -0.178553 -0.030000 0.137838 +v -0.185160 -0.030000 0.134474 +v -0.191219 -0.030000 0.130601 +v -0.196729 -0.030000 0.126221 +v -0.201689 -0.030000 0.121337 +v -0.206097 -0.030000 0.115952 +v -0.209952 -0.030000 0.110067 +v -0.213382 -0.030000 0.103587 +v -0.216513 -0.030000 0.096412 +v -0.219346 -0.030000 0.088547 +v -0.221881 -0.030000 0.079993 +v -0.224118 -0.030000 0.070753 +v -0.226057 -0.030000 0.060830 +v -0.227697 -0.030000 0.050224 +v -0.229039 -0.030000 0.038940 +v -0.230083 -0.030000 0.026978 +v -0.230828 -0.030000 0.014343 +v -0.231276 -0.030000 0.001035 +v -0.231425 -0.030000 -0.012942 +v -0.231269 -0.030000 -0.027005 +v -0.230801 -0.030000 -0.040404 +v -0.230024 -0.030000 -0.053140 +v -0.228938 -0.030000 -0.065215 +v -0.227544 -0.030000 -0.076633 +v -0.225844 -0.030000 -0.087395 +v -0.223838 -0.030000 -0.097504 +v -0.221528 -0.030000 -0.106963 +v -0.218915 -0.030000 -0.115773 +v -0.216000 -0.030000 -0.123937 +v -0.212785 -0.030000 -0.131458 +v -0.209271 -0.030000 -0.138337 +v -0.205266 -0.030000 -0.144620 +v -0.200750 -0.030000 -0.150350 +v -0.195723 -0.030000 -0.155529 +v -0.190184 -0.030000 -0.160157 +v -0.184134 -0.030000 -0.164237 +v -0.177573 -0.030000 -0.167769 +v -0.170501 -0.030000 -0.170754 +v -0.162917 -0.030000 -0.173194 +v -0.154823 -0.030000 -0.175090 +v -0.146217 -0.030000 -0.176442 +v -0.137100 -0.030000 -0.177253 +v -0.127471 -0.030000 -0.177523 +v -0.117843 -0.030000 -0.177253 +v -0.108727 -0.030000 -0.176442 +v -0.100125 -0.030000 -0.175090 +v -0.092037 -0.030000 -0.173194 +v -0.084466 -0.030000 -0.170754 +v -0.077411 -0.030000 -0.167769 +v -0.070875 -0.030000 -0.164237 +v -0.064859 -0.030000 -0.160157 +v -0.059363 -0.030000 -0.155529 +v -0.054389 -0.030000 -0.150350 +v -0.049939 -0.030000 -0.144620 +v -0.046012 -0.030000 -0.138337 +v 0.500000 -0.030000 -0.271909 +v 0.500000 0.030000 -0.271909 +v 0.500000 -0.030000 -0.234087 +v 0.500000 0.030000 -0.234087 +v 0.500000 -0.030000 0.229669 +v 0.500000 0.030000 0.229669 +v 0.361282 -0.030000 0.368353 +v 0.361282 0.030000 0.368353 +v -0.369121 -0.030000 0.368353 +v -0.369121 0.030000 0.368353 +v -0.403885 -0.030000 0.368353 +v -0.403885 0.030000 0.368353 +v -0.500000 -0.030000 0.368353 +v -0.500000 0.030000 0.368353 +v -0.500000 -0.030000 0.272263 +v -0.500000 0.030000 0.272263 +v -0.500000 -0.030000 0.234440 +v -0.500000 0.030000 0.234440 +v -0.500000 -0.030000 -0.229316 +v -0.500000 0.030000 -0.229316 +v -0.361282 -0.030000 -0.368000 +v -0.361282 0.030000 -0.368000 +v 0.369121 -0.030000 -0.368000 +v 0.369121 0.030000 -0.368000 +v 0.403886 -0.030000 -0.368000 +v 0.403886 0.030000 -0.368000 +v 0.500000 -0.030000 -0.368000 +v 0.500000 0.030000 -0.368000 +v -0.014123 -0.030000 0.177038 +v -0.014123 0.030000 0.177038 +v -0.008432 -0.030000 0.172481 +v -0.008432 0.030000 0.172481 +v -0.003036 -0.030000 0.167611 +v -0.003036 0.030000 0.167611 +v 0.002070 -0.030000 0.162429 +v 0.002070 0.030000 0.162429 +v 0.006887 -0.030000 0.156934 +v 0.006887 0.030000 0.156934 +v 0.011418 -0.030000 0.151127 +v 0.011418 0.030000 0.151127 +v 0.015664 -0.030000 0.145008 +v 0.015664 0.030000 0.145008 +v 0.019629 -0.030000 0.138577 +v 0.019629 0.030000 0.138577 +v 0.023315 -0.030000 0.131833 +v 0.023315 0.030000 0.131833 +v 0.026724 -0.030000 0.124776 +v 0.026724 0.030000 0.124776 +v 0.029858 -0.030000 0.117408 +v 0.029858 0.030000 0.117408 +v 0.032720 -0.030000 0.109727 +v 0.032720 0.030000 0.109727 +v 0.035255 -0.030000 0.101769 +v 0.035255 0.030000 0.101769 +v 0.037575 -0.030000 0.093399 +v 0.037575 0.030000 0.093399 +v 0.039680 -0.030000 0.084618 +v 0.039680 0.030000 0.084618 +v 0.041569 -0.030000 0.075425 +v 0.041569 0.030000 0.075425 +v 0.043240 -0.030000 0.065820 +v 0.043240 0.030000 0.065820 +v 0.044692 -0.030000 0.055804 +v 0.044692 0.030000 0.055804 +v 0.045923 -0.030000 0.045375 +v 0.045923 0.030000 0.045375 +v 0.046934 -0.030000 0.034535 +v 0.046934 0.030000 0.034535 +v 0.047722 -0.030000 0.023284 +v 0.047722 0.030000 0.023284 +v 0.048286 -0.030000 0.011620 +v 0.048286 0.030000 0.011620 +v 0.048626 -0.030000 -0.000455 +v 0.048626 0.030000 -0.000455 +v 0.048739 -0.030000 -0.012942 +v 0.048739 0.030000 -0.012942 +v 0.048469 -0.030000 -0.031775 +v 0.048469 0.030000 -0.031775 +v 0.047658 -0.030000 -0.049771 +v 0.047658 0.030000 -0.049771 +v 0.046305 -0.030000 -0.066929 +v 0.046305 0.030000 -0.066929 +v 0.044409 -0.030000 -0.083249 +v 0.044409 0.030000 -0.083249 +v 0.041969 -0.030000 -0.098732 +v 0.041969 0.030000 -0.098732 +v 0.038983 -0.030000 -0.113377 +v 0.038983 0.030000 -0.113377 +v 0.035450 -0.030000 -0.127184 +v 0.035450 0.030000 -0.127184 +v 0.031369 -0.030000 -0.140154 +v 0.031369 0.030000 -0.140154 +v 0.026739 -0.030000 -0.152286 +v 0.026739 0.030000 -0.152286 +v 0.021559 -0.030000 -0.163580 +v 0.021559 0.030000 -0.163580 +v 0.015828 -0.030000 -0.174037 +v 0.015828 0.030000 -0.174037 +v 0.009543 -0.030000 -0.183656 +v 0.009543 0.030000 -0.183656 +v 0.002656 -0.030000 -0.192551 +v 0.002656 0.030000 -0.192551 +v -0.005054 -0.030000 -0.200667 +v -0.005054 0.030000 -0.200667 +v -0.013585 -0.030000 -0.208004 +v -0.013585 0.030000 -0.208004 +v -0.022937 -0.030000 -0.214563 +v -0.022937 0.030000 -0.214563 +v -0.033107 -0.030000 -0.220347 +v -0.033107 0.030000 -0.220347 +v -0.044095 -0.030000 -0.225355 +v -0.044095 0.030000 -0.225355 +v -0.055900 -0.030000 -0.229590 +v -0.055900 0.030000 -0.229590 +v -0.068520 -0.030000 -0.233052 +v -0.068520 0.030000 -0.233052 +v -0.081954 -0.030000 -0.235742 +v -0.081954 0.030000 -0.235742 +v -0.096201 -0.030000 -0.237663 +v -0.096201 0.030000 -0.237663 +v -0.111260 -0.030000 -0.238814 +v -0.111260 0.030000 -0.238814 +v -0.127130 -0.030000 -0.239198 +v -0.127130 0.030000 -0.239198 +v -0.143000 -0.030000 -0.238808 +v -0.143000 0.030000 -0.238808 +v -0.158061 -0.030000 -0.237638 +v -0.158061 0.030000 -0.237638 +v -0.172312 -0.030000 -0.235689 +v -0.172312 0.030000 -0.235689 +v -0.185753 -0.030000 -0.232963 +v -0.185753 0.030000 -0.232963 +v -0.198385 -0.030000 -0.229461 +v -0.198385 0.030000 -0.229461 +v -0.210208 -0.030000 -0.225185 +v -0.210208 0.030000 -0.225185 +v -0.221221 -0.030000 -0.220134 +v -0.221221 0.030000 -0.220134 +v -0.231425 -0.030000 -0.214311 +v -0.231425 0.030000 -0.214311 +v -0.240819 -0.030000 -0.207716 +v -0.240819 0.030000 -0.207716 +v -0.249404 -0.030000 -0.200351 +v -0.249404 0.030000 -0.200351 +v -0.257179 -0.030000 -0.192217 +v -0.257179 0.030000 -0.192217 +v -0.264144 -0.030000 -0.183315 +v -0.264144 0.030000 -0.183315 +v -0.270435 -0.030000 -0.173618 +v -0.270435 0.030000 -0.173618 +v -0.276186 -0.030000 -0.163098 +v -0.276186 0.030000 -0.163098 +v -0.281394 -0.030000 -0.151754 +v -0.281394 0.030000 -0.151754 +v -0.286059 -0.030000 -0.139586 +v -0.286059 0.030000 -0.139586 +v -0.290179 -0.030000 -0.126595 +v -0.290179 0.030000 -0.126595 +v -0.293754 -0.030000 -0.112781 +v -0.293754 0.030000 -0.112781 +v -0.296782 -0.030000 -0.098143 +v -0.296782 0.030000 -0.098143 +v -0.299263 -0.030000 -0.082682 +v -0.299263 0.030000 -0.082682 +v -0.301194 -0.030000 -0.066397 +v -0.301194 0.030000 -0.066397 +v -0.302575 -0.030000 -0.049288 +v -0.302575 0.030000 -0.049288 +v -0.303404 -0.030000 -0.031357 +v -0.303404 0.030000 -0.031357 +v -0.303681 -0.030000 -0.012601 +v -0.303681 0.030000 -0.012601 +v -0.303411 -0.030000 0.006061 +v -0.303411 0.030000 0.006061 +v -0.302602 -0.030000 0.023884 +v -0.302602 0.030000 0.023884 +v -0.301253 -0.030000 0.040864 +v -0.301253 0.030000 0.040864 +v -0.299364 -0.030000 0.056999 +v -0.299364 0.030000 0.056999 +v -0.296935 -0.030000 0.072288 +v -0.296935 0.030000 0.072288 +v -0.293967 -0.030000 0.086726 +v -0.293967 0.030000 0.086726 +v -0.290460 -0.030000 0.100313 +v -0.290460 0.030000 0.100313 +v -0.286412 -0.030000 0.113046 +v -0.286412 0.030000 0.113046 +v -0.281825 -0.030000 0.124922 +v -0.281825 0.030000 0.124922 +v -0.276698 -0.030000 0.135939 +v -0.276698 0.030000 0.135939 +v -0.271032 -0.030000 0.146095 +v -0.271032 0.030000 0.146095 +v -0.264826 -0.030000 0.155387 +v -0.264826 0.030000 0.155387 +v -0.257932 -0.030000 0.163877 +v -0.257932 0.030000 0.163877 +v -0.250200 -0.030000 0.171629 +v -0.250200 0.030000 0.171629 +v -0.241634 -0.030000 0.178643 +v -0.241634 0.030000 0.178643 +v -0.232233 -0.030000 0.184918 +v -0.232233 0.030000 0.184918 +v -0.221998 -0.030000 0.190455 +v -0.221998 0.030000 0.190455 +v -0.210932 -0.030000 0.195254 +v -0.210932 0.030000 0.195254 +v -0.199035 -0.030000 0.199315 +v -0.199035 0.030000 0.199315 +v -0.186309 -0.030000 0.202637 +v -0.186309 0.030000 0.202637 +v -0.172754 -0.030000 0.205221 +v -0.172754 0.030000 0.205221 +v -0.158371 -0.030000 0.207067 +v -0.158371 0.030000 0.207067 +v -0.143163 -0.030000 0.208174 +v -0.143163 0.030000 0.208174 +v -0.127130 -0.030000 0.208543 +v -0.127130 0.030000 0.208543 +v -0.122805 -0.030000 0.208515 +v -0.122805 0.030000 0.208515 +v -0.118691 -0.030000 0.208431 +v -0.118691 0.030000 0.208431 +v -0.114786 -0.030000 0.208293 +v -0.114786 0.030000 0.208293 +v -0.111086 -0.030000 0.208101 +v -0.111086 0.030000 0.208101 +v -0.107590 -0.030000 0.207858 +v -0.107590 0.030000 0.207858 +v -0.104294 -0.030000 0.207563 +v -0.104294 0.030000 0.207563 +v -0.101198 -0.030000 0.207219 +v -0.101198 0.030000 0.207219 +v -0.098298 -0.030000 0.206827 +v -0.098298 0.030000 0.206827 +v -0.095593 -0.030000 0.206387 +v -0.095593 0.030000 0.206387 +v -0.093079 -0.030000 0.205901 +v -0.093079 0.030000 0.205901 +v -0.090754 -0.030000 0.205370 +v -0.090754 0.030000 0.205370 +v -0.088616 -0.030000 0.204795 +v -0.088616 0.030000 0.204795 +v -0.032379 -0.030000 0.297137 +v -0.032379 0.030000 0.297137 +v 0.032720 -0.030000 0.266811 +v 0.032720 0.030000 0.266811 +v 0.027981 -0.030000 0.259139 +v 0.027981 0.030000 0.259139 +v 0.022692 -0.030000 0.250576 +v 0.022692 0.030000 0.250576 +v 0.017036 -0.030000 0.241420 +v 0.017036 0.030000 0.241420 +v 0.011197 -0.030000 0.231966 +v 0.011197 0.030000 0.231966 +v 0.005358 -0.030000 0.222513 +v 0.005358 0.030000 0.222513 +v -0.000298 -0.030000 0.213356 +v -0.000298 0.030000 0.213356 +v -0.005587 -0.030000 0.204794 +v -0.005587 0.030000 0.204794 +v -0.010326 -0.030000 0.197122 +v -0.010326 0.030000 0.197122 +v -0.014331 -0.030000 0.190638 +v -0.014331 0.030000 0.190638 +v -0.017419 -0.030000 0.185639 +v -0.017419 0.030000 0.185639 +v -0.019406 -0.030000 0.182422 +v -0.019406 0.030000 0.182422 +v -0.020109 -0.030000 0.181283 +v -0.020109 0.030000 0.181283 +v 0.291411 -0.030000 0.137327 +v 0.291411 0.030000 0.137327 +v 0.286764 -0.030000 0.137511 +v 0.286764 0.030000 0.137511 +v 0.281577 -0.030000 0.137715 +v 0.281577 0.030000 0.137715 +v 0.276031 -0.030000 0.137934 +v 0.276031 0.030000 0.137934 +v 0.270305 -0.030000 0.138160 +v 0.270305 0.030000 0.138160 +v 0.264578 -0.030000 0.138386 +v 0.264578 0.030000 0.138386 +v 0.259032 -0.030000 0.138605 +v 0.259032 0.030000 0.138605 +v 0.253845 -0.030000 0.138810 +v 0.253845 0.030000 0.138810 +v 0.249198 -0.030000 0.138993 +v 0.249198 0.030000 0.138993 +v 0.245271 -0.030000 0.139148 +v 0.245271 0.030000 0.139148 +v 0.242243 -0.030000 0.139267 +v 0.242243 0.030000 0.139267 +v 0.240294 -0.030000 0.139344 +v 0.240294 0.030000 0.139344 +v 0.239605 -0.030000 0.139372 +v 0.239605 0.030000 0.139372 +v 0.235884 -0.030000 0.139286 +v 0.235884 0.030000 0.139286 +v 0.232394 -0.030000 0.139029 +v 0.232394 0.030000 0.139029 +v 0.229135 -0.030000 0.138600 +v 0.229135 0.030000 0.138600 +v 0.226110 -0.030000 0.137996 +v 0.226110 0.030000 0.137996 +v 0.223322 -0.030000 0.137217 +v 0.223322 0.030000 0.137217 +v 0.220774 -0.030000 0.136262 +v 0.220774 0.030000 0.136262 +v 0.218466 -0.030000 0.135130 +v 0.218466 0.030000 0.135130 +v 0.216403 -0.030000 0.133819 +v 0.216403 0.030000 0.133819 +v 0.214585 -0.030000 0.132328 +v 0.214585 0.030000 0.132328 +v 0.213017 -0.030000 0.130656 +v 0.213017 0.030000 0.130656 +v 0.211699 -0.030000 0.128802 +v 0.211699 0.030000 0.128802 +v 0.210634 -0.030000 0.126764 +v 0.210634 0.030000 0.126764 +v 0.209732 -0.030000 0.124535 +v 0.209732 0.030000 0.124535 +v 0.208903 -0.030000 0.121937 +v 0.208903 0.030000 0.121937 +v 0.208147 -0.030000 0.118969 +v 0.208147 0.030000 0.118969 +v 0.207465 -0.030000 0.115633 +v 0.207465 0.030000 0.115633 +v 0.206860 -0.030000 0.111927 +v 0.206860 0.030000 0.111927 +v 0.206331 -0.030000 0.107853 +v 0.206331 0.030000 0.107853 +v 0.205880 -0.030000 0.103409 +v 0.205880 0.030000 0.103409 +v 0.205509 -0.030000 0.098596 +v 0.205509 0.030000 0.098596 +v 0.205218 -0.030000 0.093413 +v 0.205218 0.030000 0.093413 +v 0.205009 -0.030000 0.087862 +v 0.205009 0.030000 0.087862 +v 0.204882 -0.030000 0.081942 +v 0.204882 0.030000 0.081942 +v 0.204840 -0.030000 0.075652 +v 0.204840 0.030000 0.075652 +v 0.204840 -0.030000 -0.063713 +v 0.204840 0.030000 -0.063713 +v 0.292093 -0.030000 -0.063713 +v 0.292093 0.030000 -0.063713 +v 0.292093 -0.030000 -0.122662 +v 0.292093 0.030000 -0.122662 +v 0.204840 -0.030000 -0.122662 +v 0.204840 0.030000 -0.122662 +v 0.204840 -0.030000 -0.214664 +v 0.204840 0.030000 -0.214664 +v 0.136333 -0.030000 -0.214664 +v 0.136333 0.030000 -0.214664 +v 0.136333 -0.030000 -0.122662 +v 0.136333 0.030000 -0.122662 +v 0.087935 -0.030000 -0.122662 +v 0.087935 0.030000 -0.122662 +v 0.087935 -0.030000 -0.064054 +v 0.087935 0.030000 -0.064054 +v 0.136333 -0.030000 -0.064054 +v 0.136333 0.030000 -0.064054 +v 0.136333 -0.030000 -0.050850 +v 0.136333 0.030000 -0.050850 +v 0.136333 -0.030000 -0.036113 +v 0.136333 0.030000 -0.036113 +v 0.136333 -0.030000 -0.020353 +v 0.136333 0.030000 -0.020353 +v 0.136333 -0.030000 -0.004083 +v 0.136333 0.030000 -0.004083 +v 0.136333 -0.030000 0.012188 +v 0.136333 0.030000 0.012188 +v 0.136333 -0.030000 0.027947 +v 0.136333 0.030000 0.027947 +v 0.136333 -0.030000 0.042685 +v 0.136333 0.030000 0.042685 +v 0.136333 -0.030000 0.055889 +v 0.136333 0.030000 0.055889 +v 0.136333 -0.030000 0.067048 +v 0.136333 0.030000 0.067048 +v 0.136333 -0.030000 0.075652 +v 0.136333 0.030000 0.075652 +v 0.136333 -0.030000 0.081189 +v 0.136333 0.030000 0.081189 +v 0.136333 -0.030000 0.083148 +v 0.136333 0.030000 0.083148 +v 0.136475 -0.030000 0.094258 +v 0.136475 0.030000 0.094258 +v 0.136899 -0.030000 0.104757 +v 0.136899 0.030000 0.104757 +v 0.137605 -0.030000 0.114646 +v 0.137605 0.030000 0.114646 +v 0.138592 -0.030000 0.123924 +v 0.138592 0.030000 0.123924 +v 0.139858 -0.030000 0.132592 +v 0.139858 0.030000 0.132592 +v 0.141403 -0.030000 0.140649 +v 0.141403 0.030000 0.140649 +v 0.143224 -0.030000 0.148096 +v 0.143224 0.030000 0.148096 +v 0.145321 -0.030000 0.154932 +v 0.145321 0.030000 0.154932 +v 0.147692 -0.030000 0.161158 +v 0.147692 0.030000 0.161158 +v 0.150337 -0.030000 0.166773 +v 0.150337 0.030000 0.166773 +v 0.153254 -0.030000 0.171778 +v 0.153254 0.030000 0.171778 +v 0.156442 -0.030000 0.176172 +v 0.156442 0.030000 0.176172 +v 0.159999 -0.030000 0.180091 +v 0.159999 0.030000 0.180091 +v 0.164025 -0.030000 0.183669 +v 0.164025 0.030000 0.183669 +v 0.168520 -0.030000 0.186906 +v 0.168520 0.030000 0.186906 +v 0.173483 -0.030000 0.189802 +v 0.173483 0.030000 0.189802 +v 0.178915 -0.030000 0.192358 +v 0.178915 0.030000 0.192358 +v 0.184816 -0.030000 0.194573 +v 0.184816 0.030000 0.194573 +v 0.191185 -0.030000 0.196447 +v 0.191185 0.030000 0.196447 +v 0.198023 -0.030000 0.197980 +v 0.198023 0.030000 0.197980 +v 0.205330 -0.030000 0.199173 +v 0.205330 0.030000 0.199173 +v 0.213105 -0.030000 0.200024 +v 0.213105 0.030000 0.200024 +v 0.221349 -0.030000 0.200536 +v 0.221349 0.030000 0.200536 +v 0.230061 -0.030000 0.200706 +v 0.230061 0.030000 0.200706 +v 0.233945 -0.030000 0.200649 +v 0.233945 0.030000 0.200649 +v 0.238099 -0.030000 0.200479 +v 0.238099 0.030000 0.200479 +v 0.242523 -0.030000 0.200195 +v 0.242523 0.030000 0.200195 +v 0.247217 -0.030000 0.199797 +v 0.247217 0.030000 0.199797 +v 0.252180 -0.030000 0.199286 +v 0.252180 0.030000 0.199286 +v 0.257413 -0.030000 0.198662 +v 0.257413 0.030000 0.198662 +v 0.262916 -0.030000 0.197923 +v 0.262916 0.030000 0.197923 +v 0.268689 -0.030000 0.197071 +v 0.268689 0.030000 0.197071 +v 0.274732 -0.030000 0.196106 +v 0.274732 0.030000 0.196106 +v 0.281044 -0.030000 0.195027 +v 0.281044 0.030000 0.195027 +v 0.287626 -0.030000 0.193834 +v 0.287626 0.030000 0.193834 +v 0.294479 -0.030000 0.192528 +v 0.294479 0.030000 0.192528 +v -0.042504 -0.030000 -0.131451 +v -0.042504 0.030000 -0.131451 +v -0.039308 -0.030000 -0.123910 +v -0.039308 0.030000 -0.123910 +v -0.036421 -0.030000 -0.115714 +v -0.036421 0.030000 -0.115714 +v -0.033843 -0.030000 -0.106862 +v -0.033843 0.030000 -0.106862 +v -0.031573 -0.030000 -0.097352 +v -0.031573 0.030000 -0.097352 +v -0.029610 -0.030000 -0.087182 +v -0.029610 0.030000 -0.087182 +v -0.027952 -0.030000 -0.076353 +v -0.027952 0.030000 -0.076353 +v -0.026597 -0.030000 -0.064862 +v -0.026597 0.030000 -0.064862 +v -0.025546 -0.030000 -0.052708 +v -0.025546 0.030000 -0.052708 +v -0.024797 -0.030000 -0.039891 +v -0.024797 0.030000 -0.039891 +v -0.024348 -0.030000 -0.026409 +v -0.024348 0.030000 -0.026409 +v -0.024199 -0.030000 -0.012261 +v -0.024199 0.030000 -0.012261 +v -0.024348 -0.030000 0.001795 +v -0.024348 0.030000 0.001795 +v -0.024794 -0.030000 0.015166 +v -0.024794 0.030000 0.015166 +v -0.025536 -0.030000 0.027852 +v -0.025536 0.030000 0.027852 +v -0.026572 -0.030000 0.039848 +v -0.026572 0.030000 0.039848 +v -0.027902 -0.030000 0.051154 +v -0.027902 0.030000 0.051154 +v -0.029525 -0.030000 0.061767 +v -0.029525 0.030000 0.061767 +v -0.031438 -0.030000 0.071683 +v -0.031438 0.030000 0.071683 +v -0.033641 -0.030000 0.080902 +v -0.033641 0.030000 0.080902 +v -0.036133 -0.030000 0.089420 +v -0.036133 0.030000 0.089420 +v -0.038913 -0.030000 0.097236 +v -0.038913 0.030000 0.097236 +v -0.041979 -0.030000 0.104346 +v -0.041979 0.030000 0.104346 +v -0.045331 -0.030000 0.110749 +v -0.045331 0.030000 0.110749 +v -0.049179 -0.030000 0.116548 +v -0.049179 0.030000 0.116548 +v -0.053569 -0.030000 0.121850 +v -0.053569 0.030000 0.121850 +v -0.058501 -0.030000 0.126652 +v -0.058501 0.030000 0.126652 +v -0.063975 -0.030000 0.130954 +v -0.063975 0.030000 0.130954 +v -0.069995 -0.030000 0.134754 +v -0.069995 0.030000 0.134754 +v -0.076559 -0.030000 0.138051 +v -0.076559 0.030000 0.138051 +v -0.083671 -0.030000 0.140844 +v -0.083671 0.030000 0.140844 +v -0.091330 -0.030000 0.143132 +v -0.091330 0.030000 0.143132 +v -0.099539 -0.030000 0.144914 +v -0.099539 0.030000 0.144914 +v -0.108298 -0.030000 0.146188 +v -0.108298 0.030000 0.146188 +v -0.117608 -0.030000 0.146953 +v -0.117608 0.030000 0.146953 +v -0.127471 -0.030000 0.147209 +v -0.127471 0.030000 0.147209 +v -0.137341 -0.030000 0.146947 +v -0.137341 0.030000 0.146947 +v -0.146670 -0.030000 0.146161 +v -0.146670 0.030000 0.146161 +v -0.155456 -0.030000 0.144855 +v -0.155456 0.030000 0.144855 +v -0.163700 -0.030000 0.143031 +v -0.163700 0.030000 0.143031 +v -0.171399 -0.030000 0.140692 +v -0.171399 0.030000 0.140692 +v -0.178553 -0.030000 0.137838 +v -0.178553 0.030000 0.137838 +v -0.185160 -0.030000 0.134474 +v -0.185160 0.030000 0.134474 +v -0.191219 -0.030000 0.130601 +v -0.191219 0.030000 0.130601 +v -0.196729 -0.030000 0.126221 +v -0.196729 0.030000 0.126221 +v -0.201689 -0.030000 0.121337 +v -0.201689 0.030000 0.121337 +v -0.206097 -0.030000 0.115952 +v -0.206097 0.030000 0.115952 +v -0.209952 -0.030000 0.110067 +v -0.209952 0.030000 0.110067 +v -0.213382 -0.030000 0.103587 +v -0.213382 0.030000 0.103587 +v -0.216513 -0.030000 0.096412 +v -0.216513 0.030000 0.096412 +v -0.219346 -0.030000 0.088547 +v -0.219346 0.030000 0.088547 +v -0.221881 -0.030000 0.079993 +v -0.221881 0.030000 0.079993 +v -0.224118 -0.030000 0.070753 +v -0.224118 0.030000 0.070753 +v -0.226057 -0.030000 0.060830 +v -0.226057 0.030000 0.060830 +v -0.227697 -0.030000 0.050224 +v -0.227697 0.030000 0.050224 +v -0.229039 -0.030000 0.038940 +v -0.229039 0.030000 0.038940 +v -0.230083 -0.030000 0.026978 +v -0.230083 0.030000 0.026978 +v -0.230828 -0.030000 0.014343 +v -0.230828 0.030000 0.014343 +v -0.231276 -0.030000 0.001035 +v -0.231276 0.030000 0.001035 +v -0.231425 -0.030000 -0.012942 +v -0.231425 0.030000 -0.012942 +v -0.231269 -0.030000 -0.027005 +v -0.231269 0.030000 -0.027005 +v -0.230801 -0.030000 -0.040404 +v -0.230801 0.030000 -0.040404 +v -0.230024 -0.030000 -0.053140 +v -0.230024 0.030000 -0.053140 +v -0.228938 -0.030000 -0.065215 +v -0.228938 0.030000 -0.065215 +v -0.227544 -0.030000 -0.076633 +v -0.227544 0.030000 -0.076633 +v -0.225844 -0.030000 -0.087395 +v -0.225844 0.030000 -0.087395 +v -0.223838 -0.030000 -0.097504 +v -0.223838 0.030000 -0.097504 +v -0.221528 -0.030000 -0.106963 +v -0.221528 0.030000 -0.106963 +v -0.218915 -0.030000 -0.115773 +v -0.218915 0.030000 -0.115773 +v -0.216000 -0.030000 -0.123937 +v -0.216000 0.030000 -0.123937 +v -0.212785 -0.030000 -0.131458 +v -0.212785 0.030000 -0.131458 +v -0.209271 -0.030000 -0.138337 +v -0.209271 0.030000 -0.138337 +v -0.205266 -0.030000 -0.144620 +v -0.205266 0.030000 -0.144620 +v -0.200750 -0.030000 -0.150350 +v -0.200750 0.030000 -0.150350 +v -0.195723 -0.030000 -0.155529 +v -0.195723 0.030000 -0.155529 +v -0.190184 -0.030000 -0.160157 +v -0.190184 0.030000 -0.160157 +v -0.184134 -0.030000 -0.164237 +v -0.184134 0.030000 -0.164237 +v -0.177573 -0.030000 -0.167769 +v -0.177573 0.030000 -0.167769 +v -0.170501 -0.030000 -0.170754 +v -0.170501 0.030000 -0.170754 +v -0.162917 -0.030000 -0.173194 +v -0.162917 0.030000 -0.173194 +v -0.154823 -0.030000 -0.175090 +v -0.154823 0.030000 -0.175090 +v -0.146217 -0.030000 -0.176442 +v -0.146217 0.030000 -0.176442 +v -0.137100 -0.030000 -0.177253 +v -0.137100 0.030000 -0.177253 +v -0.127471 -0.030000 -0.177523 +v -0.127471 0.030000 -0.177523 +v -0.117843 -0.030000 -0.177253 +v -0.117843 0.030000 -0.177253 +v -0.108727 -0.030000 -0.176442 +v -0.108727 0.030000 -0.176442 +v -0.100125 -0.030000 -0.175090 +v -0.100125 0.030000 -0.175090 +v -0.092037 -0.030000 -0.173194 +v -0.092037 0.030000 -0.173194 +v -0.084466 -0.030000 -0.170754 +v -0.084466 0.030000 -0.170754 +v -0.077411 -0.030000 -0.167769 +v -0.077411 0.030000 -0.167769 +v -0.070875 -0.030000 -0.164237 +v -0.070875 0.030000 -0.164237 +v -0.064859 -0.030000 -0.160157 +v -0.064859 0.030000 -0.160157 +v -0.059363 -0.030000 -0.155529 +v -0.059363 0.030000 -0.155529 +v -0.054389 -0.030000 -0.150350 +v -0.054389 0.030000 -0.150350 +v -0.049939 -0.030000 -0.144620 +v -0.049939 0.030000 -0.144620 +v -0.046012 -0.030000 -0.138337 +v -0.046012 0.030000 -0.138337 +vn 0.0000 1.0000 0.0000 +vn 0.0000 0.0000 1.0000 +vn 0.0000 0.0000 -1.0000 +vn 0.0000 -1.0000 0.0000 +vn 0.0000 -1.0000 -0.0001 +vn 0.0000 -1.0000 0.0001 +vn 1.0000 0.0000 0.0000 +vn 0.9238 0.0000 0.3827 +vn 0.3826 0.0000 0.9239 +vn -0.7071 0.0000 0.7071 +vn -1.0000 0.0000 0.0000 +vn -0.9238 0.0000 -0.3827 +vn -0.3826 0.0000 -0.9239 +vn 0.7071 0.0000 -0.7071 +vn -0.6478 0.0000 -0.7618 +vn -0.6020 0.0000 -0.7985 +vn -0.6914 0.0000 -0.7224 +vn -0.7324 0.0000 -0.6808 +vn -0.7705 0.0000 -0.6374 +vn -0.8053 0.0000 -0.5929 +vn -0.8367 0.0000 -0.5477 +vn -0.8647 0.0000 -0.5023 +vn -0.8367 0.0000 -0.5476 +vn -0.8892 0.0000 -0.4574 +vn -0.9106 0.0000 -0.4133 +vn -0.9289 0.0000 -0.3704 +vn -0.9452 0.0000 -0.3264 +vn -0.9584 0.0000 -0.2854 +vn -0.9682 0.0000 -0.2502 +vn -0.9761 0.0000 -0.2172 +vn -0.9825 0.0000 -0.1863 +vn -0.9875 0.0000 -0.1574 +vn -0.9915 0.0000 -0.1304 +vn -0.9944 0.0000 -0.1050 +vn -0.9967 0.0000 -0.0813 +vn -0.9982 0.0000 -0.0591 +vn -0.9993 0.0000 -0.0382 +vn -0.9998 0.0000 -0.0186 +vn -1.0000 0.0000 0.0026 +vn -0.9995 0.0000 0.0297 +vn -0.9981 0.0000 0.0618 +vn -0.9953 0.0000 0.0970 +vn -0.9908 0.0000 0.1356 +vn -0.9840 0.0000 0.1778 +vn -0.9746 0.0000 0.2239 +vn -0.9617 0.0000 0.2741 +vn -0.9445 0.0000 0.3285 +vn -0.9221 0.0000 0.3869 +vn -0.8935 0.0000 0.4490 +vn -0.8577 0.0000 0.5142 +vn -0.8146 0.0000 0.5800 +vn -0.7588 0.0000 0.6513 +vn -0.6894 0.0000 0.7244 +vn -0.6139 0.0000 0.7894 +vn -0.5349 0.0000 0.8449 +vn -0.4550 0.0000 0.8905 +vn -0.3765 0.0000 0.9264 +vn -0.3013 0.0000 0.9535 +vn -0.2306 0.0000 0.9730 +vn -0.1650 0.0000 0.9863 +vn -0.1050 0.0000 0.9945 +vn -0.0502 0.0000 0.9987 +vn 0.0002 0.0000 1.0000 +vn 0.0510 0.0000 0.9987 +vn 0.1065 0.0000 0.9943 +vn 0.1672 0.0000 0.9859 +vn 0.2331 0.0000 0.9724 +vn 0.3039 0.0000 0.9527 +vn 0.3788 0.0000 0.9254 +vn 0.4567 0.0000 0.8896 +vn 0.5357 0.0000 0.8444 +vn 0.6135 0.0000 0.7896 +vn 0.6878 0.0000 0.7259 +vn 0.7561 0.0000 0.6544 +vn 0.8140 0.0000 0.5808 +vn 0.8588 0.0000 0.5123 +vn 0.8937 0.0000 0.4487 +vn 0.9217 0.0000 0.3878 +vn 0.9438 0.0000 0.3303 +vn 0.9610 0.0000 0.2765 +vn 0.9740 0.0000 0.2266 +vn 0.9836 0.0000 0.1805 +vn 0.9904 0.0000 0.1381 +vn 0.9951 0.0000 0.0991 +vn 0.9980 0.0000 0.0633 +vn 0.9995 0.0000 0.0305 +vn 1.0000 0.0000 0.0001 +vn 0.9995 0.0000 -0.0299 +vn 0.9980 0.0000 -0.0623 +vn 0.9952 0.0000 -0.0978 +vn 0.9906 0.0000 -0.1366 +vn 0.9838 0.0000 -0.1791 +vn 0.9742 0.0000 -0.2257 +vn 0.9610 0.0000 -0.2766 +vn 0.9434 0.0000 -0.3318 +vn 0.9203 0.0000 -0.3913 +vn 0.8905 0.0000 -0.4548 +vn 0.8531 0.0000 -0.5217 +vn 0.8048 0.0000 -0.5935 +vn 0.7431 0.0000 -0.6691 +vn 0.6716 0.0000 -0.7409 +vn 0.5950 0.0000 -0.8037 +vn 0.5161 0.0000 -0.8565 +vn 0.4372 0.0000 -0.8993 +vn 0.3607 0.0000 -0.9326 +vn 0.2880 0.0000 -0.9576 +vn 0.2200 0.0000 -0.9755 +vn 0.1573 0.0000 -0.9875 +vn 0.1000 0.0000 -0.9950 +vn 0.0478 0.0000 -0.9988 +vn 0.0082 0.0000 -0.9999 +vn -0.0134 0.0000 -0.9999 +vn -0.0279 0.0000 -0.9996 +vn -0.0435 0.0000 -0.9990 +vn -0.0606 0.0000 -0.9981 +vn -0.0792 0.0000 -0.9968 +vn -0.0997 0.0000 -0.9950 +vn -0.1223 0.0000 -0.9925 +vn -0.1473 0.0000 -0.9891 +vn -0.1752 0.0000 -0.9845 +vn -0.2063 0.0000 -0.9785 +vn -0.1751 0.0000 -0.9845 +vn -0.2412 0.0000 -0.9705 +vn 0.3714 0.0000 -0.9284 +vn 0.2897 0.0000 -0.9571 +vn -0.9580 0.0000 -0.2867 +vn -0.8508 0.0000 0.5255 +vn -0.9800 0.0000 -0.1990 +vn 0.0394 0.0000 0.9992 +vn -0.6727 0.0000 0.7399 +vn 0.0395 0.0000 0.9992 +vn 0.0083 0.0000 0.9999 +vn -0.0482 0.0000 0.9988 +vn 0.0082 0.0000 0.9999 +vn -0.1021 0.0000 0.9948 +vn -0.1633 0.0000 0.9866 +vn -0.2325 0.0000 0.9726 +vn -0.3102 0.0000 0.9507 +vn -0.3962 0.0000 0.9181 +vn -0.4892 0.0000 0.8722 +vn -0.5863 0.0000 0.8101 +vn -0.6832 0.0000 0.7302 +vn -0.7739 0.0000 0.6333 +vn -0.8527 0.0000 0.5224 +vn -0.9077 0.0000 0.4195 +vn -0.9405 0.0000 0.3398 +vn -0.9612 0.0000 0.2756 +vn -0.9747 0.0000 0.2235 +vn -0.9835 0.0000 0.1807 +vn -0.9894 0.0000 0.1450 +vn -0.9934 0.0000 0.1148 +vn -0.9960 0.0000 0.0889 +vn -0.9978 0.0000 0.0665 +vn -0.9989 0.0000 0.0468 +vn -0.9995 0.0000 0.0295 +vn -0.9999 0.0000 0.0140 +vn -1.0000 0.0000 0.0034 +vn -0.7071 0.0000 -0.7071 +vn 0.7071 0.0000 0.7071 +vn 1.0000 0.0000 -0.0064 +vn 0.9996 0.0000 -0.0266 +vn 0.9984 0.0000 -0.0558 +vn 0.9961 0.0000 -0.0885 +vn 0.9921 0.0000 -0.1252 +vn 0.9861 0.0000 -0.1664 +vn 0.9771 0.0000 -0.2129 +vn 0.9641 0.0000 -0.2655 +vn 0.9458 0.0000 -0.3248 +vn 0.8852 0.0000 -0.4653 +vn 0.8377 0.0000 -0.5461 +vn 0.7761 0.0000 -0.6306 +vn 0.7033 0.0000 -0.7108 +vn 0.6251 0.0000 -0.7805 +vn 0.5448 0.0000 -0.8385 +vn 0.4653 0.0000 -0.8851 +vn 0.3889 0.0000 -0.9213 +vn 0.3170 0.0000 -0.9484 +vn 0.2506 0.0000 -0.9680 +vn 0.3171 0.0000 -0.9484 +vn 0.1900 0.0000 -0.9817 +vn 0.1350 0.0000 -0.9908 +vn 0.0854 0.0000 -0.9963 +vn 0.0407 0.0000 -0.9991 +vn 0.0024 0.0000 -1.0000 +vn -0.0278 0.0000 -0.9996 +vn -0.0525 0.0000 -0.9986 +vn -0.0742 0.0000 -0.9972 +vn -0.0934 0.0000 -0.9956 +vn -0.1105 0.0000 -0.9939 +vn -0.1257 0.0000 -0.9920 +vn -0.1395 0.0000 -0.9902 +vn -0.1519 0.0000 -0.9884 +vn -0.1631 0.0000 -0.9866 +vn -0.1734 0.0000 -0.9848 +vn -0.1827 0.0000 -0.9832 +vn -0.7879 0.0000 -0.6158 +vn 0.9324 0.0000 -0.3614 +vn 0.9064 0.0000 -0.4223 +vn 0.9520 0.0000 -0.3060 +vn 0.9667 0.0000 -0.2559 +vn 0.9775 0.0000 -0.2109 +vn 0.9854 0.0000 -0.1705 +vn 0.9909 0.0000 -0.1342 +vn 0.9948 0.0000 -0.1016 +vn 0.9974 0.0000 -0.0723 +vn 0.9989 0.0000 -0.0458 +vn 0.9998 0.0000 -0.0219 +vn 0.9998 0.0000 0.0219 +vn 0.9989 0.0000 0.0458 +vn 0.9974 0.0000 0.0722 +vn 0.9948 0.0000 0.1014 +vn 0.9910 0.0000 0.1340 +vn 0.9854 0.0000 0.1703 +vn 0.9775 0.0000 0.2110 +vn 0.9665 0.0000 0.2567 +vn 0.9514 0.0000 0.3081 +vn 0.9307 0.0000 0.3657 +vn 0.9027 0.0000 0.4301 +vn 0.8607 0.0000 0.5090 +vn 0.8028 0.0000 0.5962 +vn 0.7350 0.0000 0.6781 +vn 0.6587 0.0000 0.7524 +vn 0.5766 0.0000 0.8170 +vn 0.4919 0.0000 0.8706 +vn 0.4076 0.0000 0.9131 +vn 0.3262 0.0000 0.9453 +vn 0.2493 0.0000 0.9684 +vn 0.1781 0.0000 0.9840 +vn 0.1130 0.0000 0.9936 +vn 0.0539 0.0000 0.9985 +vn -0.0003 0.0000 1.0000 +vn -0.0552 0.0000 0.9984 +vn -0.1155 0.0000 0.9933 +vn -0.1816 0.0000 0.9834 +vn -0.2536 0.0000 0.9673 +vn -0.1816 0.0000 0.9833 +vn -0.3309 0.0000 0.9436 +vn -0.4125 0.0000 0.9109 +vn -0.4968 0.0000 0.8679 +vn -0.5812 0.0000 0.8137 +vn -0.6629 0.0000 0.7487 +vn -0.7388 0.0000 0.6739 +vn -0.8063 0.0000 0.5915 +vn -0.8611 0.0000 0.5084 +vn -0.9008 0.0000 0.4342 +vn -0.9291 0.0000 0.3696 +vn -0.9502 0.0000 0.3116 +vn -0.9656 0.0000 0.2598 +vn -0.9769 0.0000 0.2135 +vn -0.9850 0.0000 0.1723 +vn -0.9908 0.0000 0.1355 +vn -0.9947 0.0000 0.1025 +vn -0.9973 0.0000 0.0729 +vn -0.9989 0.0000 0.0462 +vn -0.9997 0.0000 0.0221 +vn -1.0000 0.0000 -0.0002 +vn -0.9997 0.0000 -0.0229 +vn -0.9988 0.0000 -0.0479 +vn -0.9972 0.0000 -0.0753 +vn -0.9944 0.0000 -0.1054 +vn -0.9903 0.0000 -0.1386 +vn -0.9845 0.0000 -0.1754 +vn -0.9764 0.0000 -0.2159 +vn -0.9654 0.0000 -0.2608 +vn -0.9506 0.0000 -0.3104 +vn -0.9311 0.0000 -0.3648 +vn -0.9055 0.0000 -0.4243 +vn -0.8679 0.0000 -0.4968 +vn -0.8153 0.0000 -0.5790 +vn -0.7525 0.0000 -0.6586 +vn -0.6803 0.0000 -0.7329 +vn -0.6010 0.0000 -0.7992 +vn -0.5172 0.0000 -0.8559 +vn -0.4319 0.0000 -0.9019 +vn -0.3479 0.0000 -0.9375 +vn -0.2673 0.0000 -0.9636 +vn -0.1917 0.0000 -0.9814 +vn -0.1220 0.0000 -0.9925 +vn -0.0583 0.0000 -0.9983 +vn 0.0583 0.0000 -0.9983 +vn 0.1220 0.0000 -0.9925 +vn 0.1919 0.0000 -0.9814 +vn 0.2677 0.0000 -0.9635 +vn 0.3486 0.0000 -0.9373 +vn 0.4330 0.0000 -0.9014 +vn 0.5190 0.0000 -0.8548 +vn 0.6035 0.0000 -0.7973 +vn 0.6836 0.0000 -0.7298 +vn 0.7565 0.0000 -0.6539 +vn 0.8199 0.0000 -0.5724 +vn 0.8704 0.0000 -0.4924 +s off +f 10//1 12//1 11//1 +f 10//1 13//1 12//1 +f 10//1 14//1 13//1 +f 10//1 1//1 14//1 +f 10//1 63//1 1//1 +f 63//1 62//1 1//1 +f 62//1 2//1 1//1 +f 61//1 2//1 62//1 +f 60//1 2//1 61//1 +f 10//1 64//1 63//1 +f 59//1 2//1 60//1 +f 10//1 65//1 64//1 +f 58//1 2//1 59//1 +f 10//1 66//1 65//1 +f 58//1 178//1 2//1 +f 178//1 176//1 2//1 +f 176//1 3//1 2//1 +f 57//1 178//1 58//1 +f 10//1 67//1 66//1 +f 56//1 178//1 57//1 +f 10//1 68//1 67//1 +f 9//1 75//1 10//1 +f 75//1 74//1 10//1 +f 74//1 73//1 10//1 +f 73//1 72//1 10//1 +f 72//1 71//1 10//1 +f 71//1 70//1 10//1 +f 70//1 69//1 10//1 +f 69//1 68//1 10//1 +f 55//1 178//1 56//1 +f 54//1 179//1 55//1 +f 179//1 178//1 55//1 +f 54//1 180//1 179//1 +f 177//1 176//1 178//1 +f 53//1 180//1 54//1 +f 52//1 180//1 53//1 +f 51//1 180//1 52//1 +f 50//1 180//1 51//1 +f 49//1 180//1 50//1 +f 314//1 316//1 315//1 +f 313//1 316//1 314//1 +f 313//1 317//1 316//1 +f 313//1 318//1 317//1 +f 312//1 318//1 313//1 +f 312//1 319//1 318//1 +f 311//1 319//1 312//1 +f 48//1 180//1 49//1 +f 9//1 76//1 75//1 +f 311//1 320//1 319//1 +f 310//1 320//1 311//1 +f 310//1 321//1 320//1 +f 309//1 321//1 310//1 +f 309//1 322//1 321//1 +f 308//1 322//1 309//1 +f 308//1 323//1 322//1 +f 307//1 323//1 308//1 +f 47//1 180//1 48//1 +f 9//1 77//1 76//1 +f 307//1 324//1 323//1 +f 306//1 324//1 307//1 +f 306//1 325//1 324//1 +f 305//1 325//1 306//1 +f 46//1 180//1 47//1 +f 9//1 78//1 77//1 +f 305//1 326//1 325//1 +f 304//1 326//1 305//1 +f 304//1 327//1 326//1 +f 303//1 327//1 304//1 +f 45//1 180//1 46//1 +f 9//1 79//1 78//1 +f 302//1 327//1 303//1 +f 302//1 232//1 327//1 +f 301//1 232//1 302//1 +f 301//1 233//1 232//1 +f 44//1 181//1 45//1 +f 181//1 180//1 45//1 +f 9//1 80//1 79//1 +f 300//1 233//1 301//1 +f 300//1 234//1 233//1 +f 44//1 182//1 181//1 +f 175//1 3//1 176//1 +f 299//1 234//1 300//1 +f 299//1 235//1 234//1 +f 43//1 182//1 44//1 +f 9//1 81//1 80//1 +f 298//1 235//1 299//1 +f 298//1 236//1 235//1 +f 42//1 182//1 43//1 +f 9//1 82//1 81//1 +f 297//1 236//1 298//1 +f 297//1 237//1 236//1 +f 296//1 237//1 297//1 +f 296//1 238//1 237//1 +f 41//1 182//1 42//1 +f 9//1 83//1 82//1 +f 295//1 238//1 296//1 +f 295//1 239//1 238//1 +f 40//1 182//1 41//1 +f 9//1 84//1 83//1 +f 294//1 239//1 295//1 +f 294//1 240//1 239//1 +f 40//1 183//1 182//1 +f 40//1 184//1 183//1 +f 173//1 175//1 174//1 +f 173//1 3//1 175//1 +f 293//1 240//1 294//1 +f 293//1 241//1 240//1 +f 40//1 185//1 184//1 +f 39//1 185//1 40//1 +f 9//1 85//1 84//1 +f 292//1 241//1 293//1 +f 292//1 242//1 241//1 +f 39//1 186//1 185//1 +f 38//1 186//1 39//1 +f 9//1 86//1 85//1 +f 291//1 242//1 292//1 +f 291//1 243//1 242//1 +f 38//1 187//1 186//1 +f 290//1 243//1 291//1 +f 37//1 187//1 38//1 +f 9//1 87//1 86//1 +f 290//1 244//1 243//1 +f 37//1 188//1 187//1 +f 36//1 188//1 37//1 +f 289//1 244//1 290//1 +f 289//1 245//1 244//1 +f 9//1 88//1 87//1 +f 35//1 188//1 36//1 +f 35//1 189//1 188//1 +f 288//1 245//1 289//1 +f 288//1 246//1 245//1 +f 34//1 189//1 35//1 +f 9//1 89//1 88//1 +f 287//1 246//1 288//1 +f 287//1 247//1 246//1 +f 34//1 190//1 189//1 +f 33//1 190//1 34//1 +f 286//1 247//1 287//1 +f 286//1 248//1 247//1 +f 9//1 90//1 89//1 +f 33//1 191//1 190//1 +f 32//1 191//1 33//1 +f 285//1 248//1 286//1 +f 285//1 249//1 248//1 +f 31//1 191//1 32//1 +f 31//1 192//1 191//1 +f 9//1 91//1 90//1 +f 284//1 249//1 285//1 +f 284//1 250//1 249//1 +f 30//1 192//1 31//1 +f 30//1 193//1 192//1 +f 283//1 250//1 284//1 +f 283//1 251//1 250//1 +f 9//1 92//1 91//1 +f 29//1 193//1 30//1 +f 29//1 194//1 193//1 +f 172//1 3//1 173//1 +f 282//1 251//1 283//1 +f 282//1 252//1 251//1 +f 29//1 195//1 194//1 +f 171//1 3//1 172//1 +f 29//1 196//1 195//1 +f 28//1 196//1 29//1 +f 9//1 93//1 92//1 +f 170//1 3//1 171//1 +f 281//1 252//1 282//1 +f 281//1 253//1 252//1 +f 27//1 196//1 28//1 +f 169//1 3//1 170//1 +f 27//1 197//1 196//1 +f 280//1 253//1 281//1 +f 280//1 254//1 253//1 +f 168//1 137//1 169//1 +f 137//1 3//1 169//1 +f 9//1 94//1 93//1 +f 26//1 197//1 27//1 +f 167//1 137//1 168//1 +f 279//1 254//1 280//1 +f 279//1 255//1 254//1 +f 26//1 198//1 197//1 +f 166//1 137//1 167//1 +f 25//1 198//1 26//1 +f 278//1 255//1 279//1 +f 278//1 256//1 255//1 +f 165//1 137//1 166//1 +f 9//1 95//1 94//1 +f 25//1 199//1 198//1 +f 164//1 137//1 165//1 +f 277//1 256//1 278//1 +f 277//1 257//1 256//1 +f 24//1 199//1 25//1 +f 163//1 137//1 164//1 +f 276//1 257//1 277//1 +f 276//1 258//1 257//1 +f 162//1 137//1 163//1 +f 24//1 200//1 199//1 +f 161//1 137//1 162//1 +f 23//1 200//1 24//1 +f 9//1 96//1 95//1 +f 275//1 258//1 276//1 +f 275//1 259//1 258//1 +f 160//1 137//1 161//1 +f 159//1 137//1 160//1 +f 274//1 259//1 275//1 +f 158//1 137//1 159//1 +f 274//1 260//1 259//1 +f 22//1 200//1 23//1 +f 157//1 137//1 158//1 +f 22//1 201//1 200//1 +f 156//1 137//1 157//1 +f 273//1 260//1 274//1 +f 273//1 261//1 260//1 +f 155//1 137//1 156//1 +f 9//1 97//1 96//1 +f 154//1 137//1 155//1 +f 153//1 137//1 154//1 +f 153//1 138//1 137//1 +f 231//1 3//1 137//1 +f 153//1 139//1 138//1 +f 153//1 140//1 139//1 +f 272//1 261//1 273//1 +f 153//1 141//1 140//1 +f 152//1 141//1 153//1 +f 272//1 262//1 261//1 +f 152//1 142//1 141//1 +f 152//1 143//1 142//1 +f 21//1 201//1 22//1 +f 151//1 143//1 152//1 +f 151//1 144//1 143//1 +f 151//1 145//1 144//1 +f 151//1 146//1 145//1 +f 150//1 146//1 151//1 +f 150//1 147//1 146//1 +f 150//1 148//1 147//1 +f 149//1 148//1 150//1 +f 21//1 202//1 201//1 +f 271//1 262//1 272//1 +f 271//1 263//1 262//1 +f 270//1 263//1 271//1 +f 270//1 264//1 263//1 +f 269//1 264//1 270//1 +f 269//1 265//1 264//1 +f 20//1 202//1 21//1 +f 9//1 98//1 97//1 +f 268//1 265//1 269//1 +f 268//1 266//1 265//1 +f 267//1 266//1 268//1 +f 20//1 203//1 202//1 +f 19//1 203//1 20//1 +f 19//1 204//1 203//1 +f 9//1 99//1 98//1 +f 18//1 204//1 19//1 +f 18//1 205//1 204//1 +f 17//1 205//1 18//1 +f 9//1 100//1 99//1 +f 17//1 206//1 205//1 +f 16//1 206//1 17//1 +f 9//1 101//1 100//1 +f 16//1 207//1 206//1 +f 15//1 207//1 16//1 +f 15//1 208//1 207//1 +f 136//1 208//1 15//1 +f 9//1 102//1 101//1 +f 136//1 209//1 208//1 +f 135//1 209//1 136//1 +f 134//1 209//1 135//1 +f 134//1 210//1 209//1 +f 9//1 103//1 102//1 +f 133//1 210//1 134//1 +f 133//1 211//1 210//1 +f 133//1 212//1 211//1 +f 9//1 104//1 103//1 +f 132//1 212//1 133//1 +f 132//1 213//1 212//1 +f 230//1 3//1 231//1 +f 229//1 3//1 230//1 +f 132//1 214//1 213//1 +f 228//1 3//1 229//1 +f 9//1 105//1 104//1 +f 227//1 3//1 228//1 +f 132//1 215//1 214//1 +f 226//1 3//1 227//1 +f 131//1 215//1 132//1 +f 225//1 3//1 226//1 +f 131//1 216//1 215//1 +f 224//1 3//1 225//1 +f 131//1 217//1 216//1 +f 223//1 3//1 224//1 +f 9//1 106//1 105//1 +f 222//1 3//1 223//1 +f 131//1 218//1 217//1 +f 221//1 3//1 222//1 +f 220//1 3//1 221//1 +f 131//1 219//1 218//1 +f 219//1 3//1 220//1 +f 131//1 3//1 219//1 +f 9//1 107//1 106//1 +f 130//1 3//1 131//1 +f 121//1 123//1 122//1 +f 9//1 108//1 107//1 +f 120//1 123//1 121//1 +f 119//1 123//1 120//1 +f 118//1 123//1 119//1 +f 117//1 123//1 118//1 +f 9//1 109//1 108//1 +f 116//1 123//1 117//1 +f 115//1 123//1 116//1 +f 114//1 123//1 115//1 +f 113//1 123//1 114//1 +f 9//1 110//1 109//1 +f 112//1 123//1 113//1 +f 111//1 123//1 112//1 +f 110//1 123//1 111//1 +f 9//1 123//1 110//1 +f 129//1 3//1 130//1 +f 128//1 3//1 129//1 +f 128//1 4//1 3//1 +f 127//1 4//1 128//1 +f 8//1 123//1 9//1 +f 126//1 4//1 127//1 +f 125//1 4//1 126//1 +f 124//1 4//1 125//1 +f 123//1 4//1 124//1 +f 7//1 123//1 8//1 +f 7//1 4//1 123//1 +f 6//2 4//2 7//2 +f 5//3 4//3 6//3 +f 339//4 337//4 338//4 +f 340//4 337//4 339//4 +f 341//4 337//4 340//4 +f 328//4 337//4 341//4 +f 390//4 337//4 328//4 +f 389//4 390//4 328//4 +f 329//4 389//4 328//4 +f 329//4 388//4 389//4 +f 329//4 387//4 388//4 +f 391//4 337//4 390//4 +f 329//4 386//4 387//4 +f 392//4 337//4 391//4 +f 329//4 385//4 386//4 +f 393//4 337//4 392//4 +f 505//4 385//4 329//4 +f 503//4 505//4 329//4 +f 330//4 503//4 329//4 +f 505//4 384//4 385//4 +f 394//4 337//4 393//4 +f 505//4 383//4 384//4 +f 395//4 337//4 394//4 +f 402//4 336//4 337//4 +f 401//4 402//4 337//4 +f 400//4 401//4 337//4 +f 399//4 400//4 337//4 +f 398//4 399//4 337//4 +f 397//4 398//4 337//4 +f 396//4 397//4 337//4 +f 395//4 396//4 337//4 +f 505//4 382//4 383//4 +f 506//4 381//4 382//4 +f 505//4 506//4 382//4 +f 507//4 381//4 506//4 +f 503//4 504//4 505//4 +f 507//4 380//4 381//4 +f 507//4 379//4 380//4 +f 507//4 378//4 379//4 +f 507//4 377//4 378//4 +f 507//4 376//4 377//4 +f 643//4 641//4 642//4 +f 643//4 640//4 641//4 +f 644//4 640//4 643//4 +f 645//4 640//4 644//4 +f 645//4 639//4 640//4 +f 646//4 639//4 645//4 +f 646//4 638//4 639//4 +f 507//4 375//4 376//4 +f 403//4 336//4 402//4 +f 647//4 638//4 646//4 +f 647//4 637//4 638//4 +f 648//4 637//4 647//4 +f 648//4 636//4 637//4 +f 649//4 636//4 648//4 +f 649//4 635//4 636//4 +f 650//4 635//4 649//4 +f 650//4 634//4 635//4 +f 507//4 374//4 375//4 +f 404//4 336//4 403//4 +f 651//4 634//4 650//4 +f 651//4 633//4 634//4 +f 652//4 633//4 651//4 +f 652//4 632//4 633//4 +f 507//4 373//4 374//4 +f 405//4 336//4 404//4 +f 653//4 632//4 652//4 +f 653//4 631//4 632//4 +f 654//4 631//4 653//4 +f 654//4 630//4 631//4 +f 507//4 372//4 373//4 +f 406//4 336//4 405//4 +f 654//4 629//4 630//4 +f 559//4 629//4 654//4 +f 559//4 628//4 629//4 +f 560//4 628//4 559//4 +f 508//4 371//4 372//4 +f 507//4 508//4 372//4 +f 407//4 336//4 406//4 +f 560//4 627//4 628//4 +f 561//4 627//4 560//4 +f 509//4 371//4 508//4 +f 330//4 502//4 503//4 +f 561//4 626//4 627//4 +f 562//4 626//4 561//4 +f 509//4 370//4 371//4 +f 408//4 336//4 407//4 +f 562//4 625//4 626//4 +f 563//4 625//4 562//4 +f 509//4 369//4 370//4 +f 409//4 336//4 408//4 +f 563//4 624//4 625//4 +f 564//4 624//4 563//4 +f 564//4 623//4 624//4 +f 565//4 623//4 564//4 +f 509//4 368//4 369//4 +f 410//4 336//4 409//4 +f 565//4 622//4 623//4 +f 566//4 622//4 565//4 +f 509//4 367//4 368//4 +f 411//4 336//4 410//4 +f 566//4 621//4 622//4 +f 567//4 621//4 566//4 +f 510//4 367//4 509//4 +f 511//4 367//4 510//4 +f 502//4 500//4 501//4 +f 330//4 500//4 502//4 +f 567//4 620//4 621//4 +f 568//4 620//4 567//4 +f 512//4 367//4 511//4 +f 512//4 366//4 367//4 +f 412//4 336//4 411//4 +f 568//4 619//4 620//4 +f 569//4 619//4 568//4 +f 513//4 366//4 512//4 +f 513//4 365//4 366//4 +f 413//4 336//4 412//4 +f 569//4 618//4 619//4 +f 570//4 618//4 569//4 +f 514//4 365//4 513//4 +f 570//4 617//4 618//4 +f 514//4 364//4 365//4 +f 414//4 336//4 413//4 +f 571//4 617//4 570//4 +f 515//4 364//4 514//4 +f 515//4 363//4 364//4 +f 571//4 616//4 617//4 +f 572//4 616//4 571//4 +f 415//4 336//4 414//4 +f 515//4 362//4 363//4 +f 516//4 362//4 515//4 +f 572//4 615//4 616//4 +f 573//4 615//4 572//4 +f 516//4 361//4 362//4 +f 416//4 336//4 415//4 +f 573//4 614//4 615//4 +f 574//4 614//4 573//4 +f 517//4 361//4 516//4 +f 517//4 360//4 361//4 +f 574//4 613//4 614//4 +f 575//4 613//4 574//4 +f 417//4 336//4 416//4 +f 518//4 360//4 517//4 +f 518//4 359//4 360//4 +f 575//4 612//4 613//4 +f 576//4 612//4 575//4 +f 518//4 358//4 359//4 +f 519//4 358//4 518//4 +f 418//4 336//4 417//4 +f 576//4 611//4 612//4 +f 577//4 611//4 576//4 +f 519//4 357//4 358//4 +f 520//4 357//4 519//4 +f 577//4 610//4 611//4 +f 578//4 610//4 577//4 +f 419//4 336//4 418//4 +f 520//4 356//4 357//4 +f 521//4 356//4 520//4 +f 330//4 499//4 500//4 +f 578//4 609//4 610//4 +f 579//4 609//4 578//4 +f 522//4 356//4 521//4 +f 330//4 498//4 499//4 +f 523//4 356//4 522//4 +f 523//4 355//4 356//4 +f 420//4 336//4 419//4 +f 330//4 497//4 498//4 +f 579//4 608//4 609//4 +f 580//4 608//4 579//4 +f 523//4 354//4 355//4 +f 330//4 496//4 497//4 +f 524//4 354//4 523//4 +f 580//4 607//4 608//4 +f 581//4 607//4 580//4 +f 464//4 495//4 496//4 +f 330//4 464//4 496//4 +f 421//4 336//4 420//4 +f 524//4 353//4 354//4 +f 464//4 494//4 495//4 +f 581//4 606//4 607//4 +f 582//4 606//4 581//4 +f 525//4 353//4 524//4 +f 464//4 493//4 494//4 +f 525//4 352//4 353//4 +f 582//4 605//4 606//4 +f 583//4 605//4 582//4 +f 464//4 492//4 493//4 +f 422//4 336//4 421//4 +f 526//4 352//4 525//4 +f 464//4 491//4 492//4 +f 583//4 604//4 605//4 +f 584//4 604//4 583//4 +f 526//4 351//4 352//4 +f 464//4 490//4 491//4 +f 584//4 603//4 604//4 +f 585//4 603//4 584//4 +f 464//4 489//4 490//4 +f 527//4 351//4 526//4 +f 464//4 488//4 489//4 +f 527//4 350//4 351//4 +f 423//4 336//4 422//4 +f 585//4 602//4 603//4 +f 586//4 602//4 585//4 +f 464//4 487//4 488//4 +f 464//4 486//4 487//4 +f 586//4 601//4 602//4 +f 464//4 485//4 486//4 +f 587//4 601//4 586//4 +f 527//4 349//4 350//4 +f 464//4 484//4 485//4 +f 528//4 349//4 527//4 +f 464//4 483//4 484//4 +f 587//4 600//4 601//4 +f 588//4 600//4 587//4 +f 464//4 482//4 483//4 +f 424//4 336//4 423//4 +f 464//4 481//4 482//4 +f 464//4 480//4 481//4 +f 465//4 480//4 464//4 +f 330//4 558//4 464//4 +f 466//4 480//4 465//4 +f 467//4 480//4 466//4 +f 588//4 599//4 600//4 +f 468//4 480//4 467//4 +f 468//4 479//4 480//4 +f 589//4 599//4 588//4 +f 469//4 479//4 468//4 +f 470//4 479//4 469//4 +f 528//4 348//4 349//4 +f 470//4 478//4 479//4 +f 471//4 478//4 470//4 +f 472//4 478//4 471//4 +f 473//4 478//4 472//4 +f 473//4 477//4 478//4 +f 474//4 477//4 473//4 +f 475//5 477//5 474//5 +f 475//6 476//6 477//6 +f 529//4 348//4 528//4 +f 589//4 598//4 599//4 +f 590//4 598//4 589//4 +f 590//4 597//4 598//4 +f 591//4 597//4 590//4 +f 591//4 596//4 597//4 +f 592//4 596//4 591//4 +f 529//4 347//4 348//4 +f 425//4 336//4 424//4 +f 592//4 595//4 596//4 +f 593//4 595//4 592//4 +f 593//4 594//4 595//4 +f 530//4 347//4 529//4 +f 530//4 346//4 347//4 +f 531//4 346//4 530//4 +f 426//4 336//4 425//4 +f 531//4 345//4 346//4 +f 532//4 345//4 531//4 +f 532//4 344//4 345//4 +f 427//4 336//4 426//4 +f 533//4 344//4 532//4 +f 533//4 343//4 344//4 +f 428//4 336//4 427//4 +f 534//4 343//4 533//4 +f 534//4 342//4 343//4 +f 535//4 342//4 534//4 +f 535//4 463//4 342//4 +f 429//4 336//4 428//4 +f 536//4 463//4 535//4 +f 536//4 462//4 463//4 +f 536//4 461//4 462//4 +f 537//4 461//4 536//4 +f 430//4 336//4 429//4 +f 537//4 460//4 461//4 +f 538//4 460//4 537//4 +f 539//4 460//4 538//4 +f 431//4 336//4 430//4 +f 539//4 459//4 460//4 +f 540//4 459//4 539//4 +f 330//4 557//4 558//4 +f 330//4 556//4 557//4 +f 541//4 459//4 540//4 +f 330//4 555//4 556//4 +f 432//4 336//4 431//4 +f 330//4 554//4 555//4 +f 542//4 459//4 541//4 +f 330//4 553//4 554//4 +f 542//4 458//4 459//4 +f 330//4 552//4 553//4 +f 543//4 458//4 542//4 +f 330//4 551//4 552//4 +f 544//4 458//4 543//4 +f 330//4 550//4 551//4 +f 433//4 336//4 432//4 +f 330//4 549//4 550//4 +f 545//4 458//4 544//4 +f 330//4 548//4 549//4 +f 330//4 547//4 548//4 +f 546//4 458//4 545//4 +f 330//4 546//4 547//4 +f 330//4 458//4 546//4 +f 434//4 336//4 433//4 +f 330//4 457//4 458//4 +f 450//4 448//4 449//4 +f 435//4 336//4 434//4 +f 450//4 447//4 448//4 +f 450//4 446//4 447//4 +f 450//4 445//4 446//4 +f 450//4 444//4 445//4 +f 436//4 336//4 435//4 +f 450//4 443//4 444//4 +f 450//4 442//4 443//4 +f 450//4 441//4 442//4 +f 450//4 440//4 441//4 +f 437//4 336//4 436//4 +f 450//4 439//4 440//4 +f 450//4 438//4 439//4 +f 450//4 437//4 438//4 +f 450//4 336//4 437//4 +f 330//4 456//4 457//4 +f 330//4 455//4 456//4 +f 331//4 455//4 330//4 +f 331//4 454//4 455//4 +f 450//4 335//4 336//4 +f 331//4 453//4 454//4 +f 331//4 452//4 453//4 +f 331//4 451//4 452//4 +f 331//4 450//4 451//4 +f 450//4 334//4 335//4 +f 331//4 334//4 450//4 +f 331//2 333//2 334//2 +f 331//3 332//3 333//3 +s 1 +f 658//7 655//7 656//7 +f 660//8 657//7 658//7 +f 662//9 659//8 660//8 +f 664//2 661//9 662//9 +f 666//2 663//2 664//2 +f 668//10 665//2 666//2 +f 670//11 667//10 668//10 +f 672//11 669//11 670//11 +f 674//12 671//11 672//11 +f 676//13 673//12 674//12 +f 678//3 675//13 676//13 +f 680//3 677//3 678//3 +f 682//14 679//3 680//3 +f 656//7 681//14 682//14 +f 686//15 683//16 684//16 +f 688//17 685//15 686//15 +f 690//18 687//17 688//17 +f 692//19 689//18 690//18 +f 694//20 691//19 692//19 +f 696//21 693//20 694//20 +f 698//22 695//23 696//21 +f 700//24 697//22 698//22 +f 702//25 699//24 700//24 +f 704//26 701//25 702//25 +f 706//27 703//26 704//26 +f 708//28 705//27 706//27 +f 710//29 707//28 708//28 +f 712//30 709//29 710//29 +f 714//31 711//30 712//30 +f 716//32 713//31 714//31 +f 718//33 715//32 716//32 +f 720//34 717//33 718//33 +f 722//35 719//34 720//34 +f 724//36 721//35 722//35 +f 726//37 723//36 724//36 +f 728//38 725//37 726//37 +f 730//39 727//38 728//38 +f 732//40 729//39 730//39 +f 734//41 731//40 732//40 +f 736//42 733//41 734//41 +f 738//43 735//42 736//42 +f 740//44 737//43 738//43 +f 742//45 739//44 740//44 +f 744//46 741//45 742//45 +f 746//47 743//46 744//46 +f 748//48 745//47 746//47 +f 750//49 747//48 748//48 +f 752//50 749//49 750//49 +f 754//51 751//50 752//50 +f 756//52 753//51 754//51 +f 758//53 755//52 756//52 +f 760//54 757//53 758//53 +f 762//55 759//54 760//54 +f 764//56 761//55 762//55 +f 766//57 763//56 764//56 +f 768//58 765//57 766//57 +f 770//59 767//58 768//58 +f 772//60 769//59 770//59 +f 774//61 771//60 772//60 +f 776//62 773//61 774//61 +f 778//63 775//62 776//62 +f 780//64 777//63 778//63 +f 782//65 779//64 780//64 +f 784//66 781//65 782//65 +f 786//67 783//66 784//66 +f 788//68 785//67 786//67 +f 790//69 787//68 788//68 +f 792//70 789//69 790//69 +f 794//71 791//70 792//70 +f 796//72 793//71 794//71 +f 798//73 795//72 796//72 +f 800//74 797//73 798//73 +f 802//75 799//74 800//74 +f 804//76 801//75 802//75 +f 806//77 803//76 804//76 +f 808//78 805//77 806//77 +f 810//79 807//78 808//78 +f 812//80 809//79 810//79 +f 814//81 811//80 812//80 +f 816//82 813//81 814//81 +f 818//83 815//82 816//82 +f 820//84 817//83 818//83 +f 822//85 819//84 820//84 +f 824//86 821//85 822//85 +f 826//87 823//86 824//86 +f 828//88 825//87 826//87 +f 830//89 827//88 828//88 +f 832//90 829//89 830//89 +f 834//91 831//90 832//90 +f 836//92 833//91 834//91 +f 838//93 835//92 836//92 +f 840//94 837//93 838//93 +f 842//95 839//94 840//94 +f 844//96 841//95 842//95 +f 846//97 843//96 844//96 +f 848//98 845//97 846//97 +f 850//99 847//98 848//98 +f 852//100 849//99 850//99 +f 854//101 851//100 852//100 +f 856//102 853//101 854//101 +f 858//103 855//102 856//102 +f 860//104 857//103 858//103 +f 862//105 859//104 860//104 +f 864//106 861//105 862//105 +f 866//107 863//106 864//106 +f 868//108 865//107 866//107 +f 870//109 867//108 868//108 +f 872//110 869//109 870//109 +f 874//111 871//110 872//110 +f 876//112 873//111 874//111 +f 878//113 875//112 876//112 +f 880//114 877//113 878//113 +f 882//115 879//114 880//114 +f 884//116 881//115 882//115 +f 886//117 883//116 884//116 +f 888//118 885//117 886//117 +f 890//119 887//118 888//118 +f 892//120 889//119 890//119 +f 894//121 891//122 892//120 +f 896//123 893//121 894//121 +f 898//124 895//123 896//123 +f 900//125 897//124 898//124 +f 902//126 899//125 900//125 +f 904//127 901//126 902//126 +f 906//127 903//127 904//127 +f 908//127 905//127 906//127 +f 910//127 907//127 908//127 +f 912//127 909//127 910//127 +f 914//127 911//127 912//127 +f 916//127 913//127 914//127 +f 918//127 915//127 916//127 +f 920//127 917//127 918//127 +f 922//127 919//127 920//127 +f 924//127 921//127 922//127 +f 926//128 923//127 924//127 +f 684//16 925//128 926//128 +f 930//129 927//130 928//130 +f 932//129 929//129 930//129 +f 934//129 931//129 932//129 +f 936//129 933//129 934//129 +f 938//129 935//129 936//129 +f 940//129 937//129 938//129 +f 942//129 939//129 940//129 +f 944//129 941//129 942//129 +f 946//129 943//129 944//129 +f 948//129 945//129 946//129 +f 950//131 947//129 948//129 +f 952//132 949//129 950//131 +f 954//133 951//134 952//132 +f 956//135 953//133 954//133 +f 958//136 955//135 956//135 +f 960//137 957//136 958//136 +f 962//138 959//137 960//137 +f 964//139 961//138 962//138 +f 966//140 963//139 964//139 +f 968//141 965//140 966//140 +f 970//142 967//141 968//141 +f 972//143 969//142 970//142 +f 974//144 971//143 972//143 +f 976//145 973//144 974//144 +f 978//146 975//145 976//145 +f 980//147 977//146 978//146 +f 982//148 979//147 980//147 +f 984//149 981//148 982//148 +f 986//150 983//149 984//149 +f 988//151 985//150 986//150 +f 990//152 987//151 988//151 +f 992//153 989//152 990//152 +f 994//154 991//153 992//153 +f 996//155 993//154 994//154 +f 998//156 995//155 996//155 +f 1000//157 997//156 998//156 +f 1002//158 999//157 1000//157 +f 1004//158 1001//158 1002//158 +f 1006//10 1003//158 1004//158 +f 1008//10 1005//10 1006//10 +f 1010//10 1007//10 1008//10 +f 1012//159 1009//10 1010//10 +f 1014//159 1011//159 1012//159 +f 1016//159 1013//159 1014//159 +f 1018//14 1015//159 1016//159 +f 1020//14 1017//14 1018//14 +f 1022//7 1019//14 1020//14 +f 1024//7 1021//7 1022//7 +f 1026//7 1023//7 1024//7 +f 1028//7 1025//7 1026//7 +f 1030//7 1027//7 1028//7 +f 1032//7 1029//7 1030//7 +f 1034//7 1031//7 1032//7 +f 1036//7 1033//7 1034//7 +f 1038//7 1035//7 1036//7 +f 1040//7 1037//7 1038//7 +f 1042//7 1039//7 1040//7 +f 1044//160 1041//7 1042//7 +f 1046//161 1043//160 1044//160 +f 1048//162 1045//161 1046//161 +f 1050//163 1047//162 1048//162 +f 1052//164 1049//163 1050//163 +f 1054//165 1051//164 1052//164 +f 1056//166 1053//165 1054//165 +f 1058//167 1055//166 1056//166 +f 1060//168 1057//167 1058//167 +f 1062//96 1059//168 1060//168 +f 1064//169 1061//96 1062//96 +f 1066//170 1063//169 1064//169 +f 1068//171 1065//170 1066//170 +f 1070//172 1067//171 1068//171 +f 1072//173 1069//172 1070//172 +f 1074//174 1071//173 1072//173 +f 1076//175 1073//174 1074//174 +f 1078//176 1075//175 1076//175 +f 1080//177 1077//176 1078//176 +f 1082//178 1079//179 1080//177 +f 1084//180 1081//178 1082//178 +f 1086//181 1083//180 1084//180 +f 1088//182 1085//181 1086//181 +f 1090//183 1087//182 1088//182 +f 1092//184 1089//183 1090//183 +f 1094//185 1091//184 1092//184 +f 1096//186 1093//185 1094//185 +f 1098//187 1095//186 1096//186 +f 1100//188 1097//187 1098//187 +f 1102//189 1099//188 1100//188 +f 1104//190 1101//189 1102//189 +f 1106//191 1103//190 1104//190 +f 1108//192 1105//191 1106//191 +f 1110//193 1107//192 1108//192 +f 1112//194 1109//193 1110//193 +f 1114//195 1111//194 1112//194 +f 1116//196 1113//195 1114//195 +f 928//130 1115//196 1116//196 +f 1120//197 1117//198 1118//198 +f 1122//199 1119//197 1120//197 +f 1124//200 1121//199 1122//199 +f 1126//201 1123//200 1124//200 +f 1128//202 1125//201 1126//201 +f 1130//203 1127//202 1128//202 +f 1132//204 1129//203 1130//203 +f 1134//205 1131//204 1132//204 +f 1136//206 1133//205 1134//205 +f 1138//207 1135//206 1136//206 +f 1140//7 1137//207 1138//207 +f 1142//208 1139//7 1140//7 +f 1144//209 1141//208 1142//208 +f 1146//210 1143//209 1144//209 +f 1148//211 1145//210 1146//210 +f 1150//212 1147//211 1148//211 +f 1152//213 1149//212 1150//212 +f 1154//214 1151//213 1152//213 +f 1156//215 1153//214 1154//214 +f 1158//216 1155//215 1156//215 +f 1160//217 1157//216 1158//216 +f 1162//218 1159//217 1160//217 +f 1164//219 1161//218 1162//218 +f 1166//220 1163//219 1164//219 +f 1168//221 1165//220 1166//220 +f 1170//222 1167//221 1168//221 +f 1172//223 1169//222 1170//222 +f 1174//224 1171//223 1172//223 +f 1176//225 1173//224 1174//224 +f 1178//226 1175//225 1176//225 +f 1180//227 1177//226 1178//226 +f 1182//228 1179//227 1180//227 +f 1184//229 1181//228 1182//228 +f 1186//230 1183//229 1184//229 +f 1188//231 1185//230 1186//230 +f 1190//232 1187//231 1188//231 +f 1192//233 1189//232 1190//232 +f 1194//234 1191//233 1192//233 +f 1196//235 1193//236 1194//234 +f 1198//237 1195//235 1196//235 +f 1200//238 1197//237 1198//237 +f 1202//239 1199//238 1200//238 +f 1204//240 1201//239 1202//239 +f 1206//241 1203//240 1204//240 +f 1208//242 1205//241 1206//241 +f 1210//243 1207//242 1208//242 +f 1212//244 1209//243 1210//243 +f 1214//245 1211//244 1212//244 +f 1216//246 1213//245 1214//245 +f 1218//247 1215//246 1216//246 +f 1220//248 1217//247 1218//247 +f 1222//249 1219//248 1220//248 +f 1224//250 1221//249 1222//249 +f 1226//251 1223//250 1224//250 +f 1228//252 1225//251 1226//251 +f 1230//253 1227//252 1228//252 +f 1232//254 1229//253 1230//253 +f 1234//255 1231//254 1232//254 +f 1236//256 1233//255 1234//255 +f 1238//257 1235//256 1236//256 +f 1240//258 1237//257 1238//257 +f 1242//259 1239//258 1240//258 +f 1244//260 1241//259 1242//259 +f 1246//261 1243//260 1244//260 +f 1248//262 1245//261 1246//261 +f 1250//263 1247//262 1248//262 +f 1252//264 1249//263 1250//263 +f 1254//265 1251//264 1252//264 +f 1256//266 1253//265 1254//265 +f 1258//267 1255//266 1256//266 +f 1260//268 1257//267 1258//267 +f 1262//269 1259//268 1260//268 +f 1264//270 1261//269 1262//269 +f 1266//271 1263//270 1264//270 +f 1268//272 1265//271 1266//271 +f 1270//273 1267//272 1268//272 +f 1272//274 1269//273 1270//273 +f 1274//275 1271//274 1272//274 +f 1276//276 1273//275 1274//275 +f 1278//277 1275//276 1276//276 +f 1280//278 1277//277 1278//277 +f 1282//279 1279//278 1280//278 +f 1284//3 1281//279 1282//279 +f 1286//280 1283//3 1284//3 +f 1288//281 1285//280 1286//280 +f 1290//282 1287//281 1288//281 +f 1292//283 1289//282 1290//282 +f 1294//284 1291//283 1292//283 +f 1296//285 1293//284 1294//284 +f 1298//286 1295//285 1296//285 +f 1300//287 1297//286 1298//286 +f 1302//288 1299//287 1300//287 +f 1304//289 1301//288 1302//288 +f 1306//290 1303//289 1304//289 +f 1308//291 1305//290 1306//290 +f 1118//198 1307//291 1308//291 +f 658//7 657//7 655//7 +f 660//8 659//8 657//7 +f 662//9 661//9 659//8 +f 664//2 663//2 661//9 +f 666//2 665//2 663//2 +f 668//10 667//10 665//2 +f 670//11 669//11 667//10 +f 672//11 671//11 669//11 +f 674//12 673//12 671//11 +f 676//13 675//13 673//12 +f 678//3 677//3 675//13 +f 680//3 679//3 677//3 +f 682//14 681//14 679//3 +f 656//7 655//7 681//14 +f 686//15 685//15 683//16 +f 688//17 687//17 685//15 +f 690//18 689//18 687//17 +f 692//19 691//19 689//18 +f 694//20 693//20 691//19 +f 696//21 695//23 693//20 +f 698//22 697//22 695//23 +f 700//24 699//24 697//22 +f 702//25 701//25 699//24 +f 704//26 703//26 701//25 +f 706//27 705//27 703//26 +f 708//28 707//28 705//27 +f 710//29 709//29 707//28 +f 712//30 711//30 709//29 +f 714//31 713//31 711//30 +f 716//32 715//32 713//31 +f 718//33 717//33 715//32 +f 720//34 719//34 717//33 +f 722//35 721//35 719//34 +f 724//36 723//36 721//35 +f 726//37 725//37 723//36 +f 728//38 727//38 725//37 +f 730//39 729//39 727//38 +f 732//40 731//40 729//39 +f 734//41 733//41 731//40 +f 736//42 735//42 733//41 +f 738//43 737//43 735//42 +f 740//44 739//44 737//43 +f 742//45 741//45 739//44 +f 744//46 743//46 741//45 +f 746//47 745//47 743//46 +f 748//48 747//48 745//47 +f 750//49 749//49 747//48 +f 752//50 751//50 749//49 +f 754//51 753//51 751//50 +f 756//52 755//52 753//51 +f 758//53 757//53 755//52 +f 760//54 759//54 757//53 +f 762//55 761//55 759//54 +f 764//56 763//56 761//55 +f 766//57 765//57 763//56 +f 768//58 767//58 765//57 +f 770//59 769//59 767//58 +f 772//60 771//60 769//59 +f 774//61 773//61 771//60 +f 776//62 775//62 773//61 +f 778//63 777//63 775//62 +f 780//64 779//64 777//63 +f 782//65 781//65 779//64 +f 784//66 783//66 781//65 +f 786//67 785//67 783//66 +f 788//68 787//68 785//67 +f 790//69 789//69 787//68 +f 792//70 791//70 789//69 +f 794//71 793//71 791//70 +f 796//72 795//72 793//71 +f 798//73 797//73 795//72 +f 800//74 799//74 797//73 +f 802//75 801//75 799//74 +f 804//76 803//76 801//75 +f 806//77 805//77 803//76 +f 808//78 807//78 805//77 +f 810//79 809//79 807//78 +f 812//80 811//80 809//79 +f 814//81 813//81 811//80 +f 816//82 815//82 813//81 +f 818//83 817//83 815//82 +f 820//84 819//84 817//83 +f 822//85 821//85 819//84 +f 824//86 823//86 821//85 +f 826//87 825//87 823//86 +f 828//88 827//88 825//87 +f 830//89 829//89 827//88 +f 832//90 831//90 829//89 +f 834//91 833//91 831//90 +f 836//92 835//92 833//91 +f 838//93 837//93 835//92 +f 840//94 839//94 837//93 +f 842//95 841//95 839//94 +f 844//96 843//96 841//95 +f 846//97 845//97 843//96 +f 848//98 847//98 845//97 +f 850//99 849//99 847//98 +f 852//100 851//100 849//99 +f 854//101 853//101 851//100 +f 856//102 855//102 853//101 +f 858//103 857//103 855//102 +f 860//104 859//104 857//103 +f 862//105 861//105 859//104 +f 864//106 863//106 861//105 +f 866//107 865//107 863//106 +f 868//108 867//108 865//107 +f 870//109 869//109 867//108 +f 872//110 871//110 869//109 +f 874//111 873//111 871//110 +f 876//112 875//112 873//111 +f 878//113 877//113 875//112 +f 880//114 879//114 877//113 +f 882//115 881//115 879//114 +f 884//116 883//116 881//115 +f 886//117 885//117 883//116 +f 888//118 887//118 885//117 +f 890//119 889//119 887//118 +f 892//120 891//122 889//119 +f 894//121 893//121 891//122 +f 896//123 895//123 893//121 +f 898//124 897//124 895//123 +f 900//125 899//125 897//124 +f 902//126 901//126 899//125 +f 904//127 903//127 901//126 +f 906//127 905//127 903//127 +f 908//127 907//127 905//127 +f 910//127 909//127 907//127 +f 912//127 911//127 909//127 +f 914//127 913//127 911//127 +f 916//127 915//127 913//127 +f 918//127 917//127 915//127 +f 920//127 919//127 917//127 +f 922//127 921//127 919//127 +f 924//127 923//127 921//127 +f 926//128 925//128 923//127 +f 684//16 683//16 925//128 +f 930//129 929//129 927//130 +f 932//129 931//129 929//129 +f 934//129 933//129 931//129 +f 936//129 935//129 933//129 +f 938//129 937//129 935//129 +f 940//129 939//129 937//129 +f 942//129 941//129 939//129 +f 944//129 943//129 941//129 +f 946//129 945//129 943//129 +f 948//129 947//129 945//129 +f 950//131 949//129 947//129 +f 952//132 951//134 949//129 +f 954//133 953//133 951//134 +f 956//135 955//135 953//133 +f 958//136 957//136 955//135 +f 960//137 959//137 957//136 +f 962//138 961//138 959//137 +f 964//139 963//139 961//138 +f 966//140 965//140 963//139 +f 968//141 967//141 965//140 +f 970//142 969//142 967//141 +f 972//143 971//143 969//142 +f 974//144 973//144 971//143 +f 976//145 975//145 973//144 +f 978//146 977//146 975//145 +f 980//147 979//147 977//146 +f 982//148 981//148 979//147 +f 984//149 983//149 981//148 +f 986//150 985//150 983//149 +f 988//151 987//151 985//150 +f 990//152 989//152 987//151 +f 992//153 991//153 989//152 +f 994//154 993//154 991//153 +f 996//155 995//155 993//154 +f 998//156 997//156 995//155 +f 1000//157 999//157 997//156 +f 1002//158 1001//158 999//157 +f 1004//158 1003//158 1001//158 +f 1006//10 1005//10 1003//158 +f 1008//10 1007//10 1005//10 +f 1010//10 1009//10 1007//10 +f 1012//159 1011//159 1009//10 +f 1014//159 1013//159 1011//159 +f 1016//159 1015//159 1013//159 +f 1018//14 1017//14 1015//159 +f 1020//14 1019//14 1017//14 +f 1022//7 1021//7 1019//14 +f 1024//7 1023//7 1021//7 +f 1026//7 1025//7 1023//7 +f 1028//7 1027//7 1025//7 +f 1030//7 1029//7 1027//7 +f 1032//7 1031//7 1029//7 +f 1034//7 1033//7 1031//7 +f 1036//7 1035//7 1033//7 +f 1038//7 1037//7 1035//7 +f 1040//7 1039//7 1037//7 +f 1042//7 1041//7 1039//7 +f 1044//160 1043//160 1041//7 +f 1046//161 1045//161 1043//160 +f 1048//162 1047//162 1045//161 +f 1050//163 1049//163 1047//162 +f 1052//164 1051//164 1049//163 +f 1054//165 1053//165 1051//164 +f 1056//166 1055//166 1053//165 +f 1058//167 1057//167 1055//166 +f 1060//168 1059//168 1057//167 +f 1062//96 1061//96 1059//168 +f 1064//169 1063//169 1061//96 +f 1066//170 1065//170 1063//169 +f 1068//171 1067//171 1065//170 +f 1070//172 1069//172 1067//171 +f 1072//173 1071//173 1069//172 +f 1074//174 1073//174 1071//173 +f 1076//175 1075//175 1073//174 +f 1078//176 1077//176 1075//175 +f 1080//177 1079//179 1077//176 +f 1082//178 1081//178 1079//179 +f 1084//180 1083//180 1081//178 +f 1086//181 1085//181 1083//180 +f 1088//182 1087//182 1085//181 +f 1090//183 1089//183 1087//182 +f 1092//184 1091//184 1089//183 +f 1094//185 1093//185 1091//184 +f 1096//186 1095//186 1093//185 +f 1098//187 1097//187 1095//186 +f 1100//188 1099//188 1097//187 +f 1102//189 1101//189 1099//188 +f 1104//190 1103//190 1101//189 +f 1106//191 1105//191 1103//190 +f 1108//192 1107//192 1105//191 +f 1110//193 1109//193 1107//192 +f 1112//194 1111//194 1109//193 +f 1114//195 1113//195 1111//194 +f 1116//196 1115//196 1113//195 +f 928//130 927//130 1115//196 +f 1120//197 1119//197 1117//198 +f 1122//199 1121//199 1119//197 +f 1124//200 1123//200 1121//199 +f 1126//201 1125//201 1123//200 +f 1128//202 1127//202 1125//201 +f 1130//203 1129//203 1127//202 +f 1132//204 1131//204 1129//203 +f 1134//205 1133//205 1131//204 +f 1136//206 1135//206 1133//205 +f 1138//207 1137//207 1135//206 +f 1140//7 1139//7 1137//207 +f 1142//208 1141//208 1139//7 +f 1144//209 1143//209 1141//208 +f 1146//210 1145//210 1143//209 +f 1148//211 1147//211 1145//210 +f 1150//212 1149//212 1147//211 +f 1152//213 1151//213 1149//212 +f 1154//214 1153//214 1151//213 +f 1156//215 1155//215 1153//214 +f 1158//216 1157//216 1155//215 +f 1160//217 1159//217 1157//216 +f 1162//218 1161//218 1159//217 +f 1164//219 1163//219 1161//218 +f 1166//220 1165//220 1163//219 +f 1168//221 1167//221 1165//220 +f 1170//222 1169//222 1167//221 +f 1172//223 1171//223 1169//222 +f 1174//224 1173//224 1171//223 +f 1176//225 1175//225 1173//224 +f 1178//226 1177//226 1175//225 +f 1180//227 1179//227 1177//226 +f 1182//228 1181//228 1179//227 +f 1184//229 1183//229 1181//228 +f 1186//230 1185//230 1183//229 +f 1188//231 1187//231 1185//230 +f 1190//232 1189//232 1187//231 +f 1192//233 1191//233 1189//232 +f 1194//234 1193//236 1191//233 +f 1196//235 1195//235 1193//236 +f 1198//237 1197//237 1195//235 +f 1200//238 1199//238 1197//237 +f 1202//239 1201//239 1199//238 +f 1204//240 1203//240 1201//239 +f 1206//241 1205//241 1203//240 +f 1208//242 1207//242 1205//241 +f 1210//243 1209//243 1207//242 +f 1212//244 1211//244 1209//243 +f 1214//245 1213//245 1211//244 +f 1216//246 1215//246 1213//245 +f 1218//247 1217//247 1215//246 +f 1220//248 1219//248 1217//247 +f 1222//249 1221//249 1219//248 +f 1224//250 1223//250 1221//249 +f 1226//251 1225//251 1223//250 +f 1228//252 1227//252 1225//251 +f 1230//253 1229//253 1227//252 +f 1232//254 1231//254 1229//253 +f 1234//255 1233//255 1231//254 +f 1236//256 1235//256 1233//255 +f 1238//257 1237//257 1235//256 +f 1240//258 1239//258 1237//257 +f 1242//259 1241//259 1239//258 +f 1244//260 1243//260 1241//259 +f 1246//261 1245//261 1243//260 +f 1248//262 1247//262 1245//261 +f 1250//263 1249//263 1247//262 +f 1252//264 1251//264 1249//263 +f 1254//265 1253//265 1251//264 +f 1256//266 1255//266 1253//265 +f 1258//267 1257//267 1255//266 +f 1260//268 1259//268 1257//267 +f 1262//269 1261//269 1259//268 +f 1264//270 1263//270 1261//269 +f 1266//271 1265//271 1263//270 +f 1268//272 1267//272 1265//271 +f 1270//273 1269//273 1267//272 +f 1272//274 1271//274 1269//273 +f 1274//275 1273//275 1271//274 +f 1276//276 1275//276 1273//275 +f 1278//277 1277//277 1275//276 +f 1280//278 1279//278 1277//277 +f 1282//279 1281//279 1279//278 +f 1284//3 1283//3 1281//279 +f 1286//280 1285//280 1283//3 +f 1288//281 1287//281 1285//280 +f 1290//282 1289//282 1287//281 +f 1292//283 1291//283 1289//282 +f 1294//284 1293//284 1291//283 +f 1296//285 1295//285 1293//284 +f 1298//286 1297//286 1295//285 +f 1300//287 1299//287 1297//286 +f 1302//288 1301//288 1299//287 +f 1304//289 1303//289 1301//288 +f 1306//290 1305//290 1303//289 +f 1308//291 1307//291 1305//290 +f 1118//198 1117//198 1307//291 diff --git a/examples/vulkan/vulkan.pro b/examples/vulkan/vulkan.pro index ef5496bcd4e..920762cb9e1 100644 --- a/examples/vulkan/vulkan.pro +++ b/examples/vulkan/vulkan.pro @@ -4,4 +4,7 @@ SUBDIRS = hellovulkanwindow \ hellovulkantriangle \ hellovulkantexture -qtHaveModule(widgets): SUBDIRS += hellovulkanwidget +qtHaveModule(widgets) { + SUBDIRS += hellovulkanwidget + qtHaveModule(concurrent): SUBDIRS += hellovulkancubes +}