From c72b821b5911842757a3929fb287471ad5d457ea Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Fri, 24 Mar 2017 14:54:24 +0100 Subject: Add the Vulkan cube example Features a little bit more than a cube, though. Change-Id: I636d4875ba9ccf722ed3caab97f14570be785748 Reviewed-by: Andy Nichols --- examples/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 + examples/vulkan/hellovulkancubes/color_frag.spv | Bin 0 -> 616 bytes examples/vulkan/hellovulkancubes/color_phong.frag | 39 + examples/vulkan/hellovulkancubes/color_phong.vert | 32 + .../vulkan/hellovulkancubes/color_phong_frag.spv | Bin 0 -> 3364 bytes .../vulkan/hellovulkancubes/color_phong_vert.spv | Bin 0 -> 2268 bytes examples/vulkan/hellovulkancubes/color_vert.spv | Bin 0 -> 744 bytes .../vulkan/hellovulkancubes/hellovulkancubes.pro | 24 + .../vulkan/hellovulkancubes/hellovulkancubes.qrc | 10 + examples/vulkan/hellovulkancubes/main.cpp | 92 + examples/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 + examples/vulkan/hellovulkancubes/vulkanwindow.cpp | 134 + examples/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 (limited to 'examples/vulkan') diff --git a/examples/vulkan/doc/images/hellovulkancubes.png b/examples/vulkan/doc/images/hellovulkancubes.png new file mode 100644 index 0000000000..c3d819c047 Binary files /dev/null and b/examples/vulkan/doc/images/hellovulkancubes.png differ diff --git a/examples/vulkan/doc/src/hellovulkancubes.qdoc b/examples/vulkan/doc/src/hellovulkancubes.qdoc new file mode 100644 index 0000000000..934d2015a1 --- /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 0000000000..64dee03154 --- /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 0000000000..c5c579f066 --- /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 0000000000..3b04955963 --- /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 0000000000..19bf815819 --- /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 0000000000..bd72984ffe Binary files /dev/null and b/examples/vulkan/hellovulkancubes/color_frag.spv differ diff --git a/examples/vulkan/hellovulkancubes/color_phong.frag b/examples/vulkan/hellovulkancubes/color_phong.frag new file mode 100644 index 0000000000..8b0c715f3b --- /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 0000000000..a1d1552685 --- /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 0000000000..a1a413533b Binary files /dev/null and b/examples/vulkan/hellovulkancubes/color_phong_frag.spv differ diff --git a/examples/vulkan/hellovulkancubes/color_phong_vert.spv b/examples/vulkan/hellovulkancubes/color_phong_vert.spv new file mode 100644 index 0000000000..3ede21e007 Binary files /dev/null and b/examples/vulkan/hellovulkancubes/color_phong_vert.spv differ diff --git a/examples/vulkan/hellovulkancubes/color_vert.spv b/examples/vulkan/hellovulkancubes/color_vert.spv new file mode 100644 index 0000000000..3f708b7d07 Binary files /dev/null and b/examples/vulkan/hellovulkancubes/color_vert.spv differ diff --git a/examples/vulkan/hellovulkancubes/hellovulkancubes.pro b/examples/vulkan/hellovulkancubes/hellovulkancubes.pro new file mode 100644 index 0000000000..f9a9c3cff1 --- /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 0000000000..7b085e1875 --- /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 0000000000..4ec4d48645 --- /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 0000000000..2be7d237af --- /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 0000000000..4109709959 --- /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 0000000000..fcc45bfd57 --- /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 0000000000..cb6ee9c830 --- /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 0000000000..96ae6020a7 --- /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 0000000000..60bb48377e --- /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 0000000000..e1c01c6842 --- /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 0000000000..265868d2b0 --- /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 0000000000..9a4eaf1901 --- /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 0000000000..d085c0bde7 --- /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 0000000000..28ec2620bd Binary files /dev/null and b/examples/vulkan/shared/block.buf differ diff --git a/examples/vulkan/shared/block.txt b/examples/vulkan/shared/block.txt new file mode 100644 index 0000000000..a6b66b83cc --- /dev/null +++ b/examples/vulkan/shared/block.txt @@ -0,0 +1,100 @@ +# Blender v2.78 (sub 0) OBJ File: '' +# www.blender.org +mtllib block.mtl +o Cube_Cube.001 +v 0.450000 -0.500000 -0.450000 +v 0.450000 -0.500000 0.450000 +v -0.450000 -0.500000 0.450000 +v -0.450000 -0.500000 -0.450000 +v -0.500000 0.450000 0.450000 +v -0.500000 0.450000 -0.450000 +v -0.500000 -0.450000 -0.450000 +v -0.500000 -0.450000 0.450000 +v -0.450000 0.500000 -0.450000 +v -0.450000 0.500000 0.450000 +v 0.450000 0.500000 0.450000 +v 0.450000 0.500000 -0.450000 +v -0.450000 0.450000 -0.500000 +v 0.450000 0.450000 -0.500000 +v 0.450000 -0.450000 -0.500000 +v -0.450000 -0.450000 -0.500000 +v 0.450000 0.450000 0.500000 +v -0.450000 0.450000 0.500000 +v -0.450000 -0.450000 0.500000 +v 0.450000 -0.450000 0.500000 +v 0.500000 -0.450000 -0.450000 +v 0.500000 0.450000 -0.450000 +v 0.500000 -0.450000 0.450000 +v 0.500000 0.450000 0.450000 +vn 0.0000 -1.0000 -0.0000 +vn -1.0000 0.0000 0.0000 +vn 0.0000 1.0000 0.0000 +vn 0.0000 0.0000 -1.0000 +vn 0.0000 -0.0000 1.0000 +vn 0.5774 -0.5773 -0.5774 +vn 0.5774 0.5774 -0.5774 +vn 0.5774 -0.5774 0.5774 +vn 0.5774 0.5773 0.5774 +vn -0.5774 -0.5773 -0.5774 +vn -0.5773 0.5774 -0.5774 +vn -0.5774 -0.5774 0.5774 +vn -0.5774 0.5773 0.5774 +vn 0.7071 0.0000 -0.7071 +vn 0.7071 0.7071 0.0000 +vn 0.7071 -0.0000 0.7071 +vn 0.7071 -0.7071 -0.0000 +vn 0.0000 0.7071 0.7071 +vn -0.7071 -0.0000 0.7071 +vn 0.0000 -0.7071 0.7071 +vn -0.7071 0.7071 0.0000 +vn -0.7071 0.0000 -0.7071 +vn -0.7071 -0.7071 -0.0000 +vn 0.0000 0.7071 -0.7071 +vn 0.0000 -0.7071 -0.7071 +vn 1.0000 0.0000 0.0000 +usemtl None +s 1 +f 2//1 4//1 1//1 +f 6//2 8//2 5//2 +f 10//3 12//3 9//3 +f 14//4 16//4 13//4 +f 18//5 20//5 17//5 +f 15//6 21//6 1//6 +f 14//7 12//7 22//7 +f 20//8 2//8 23//8 +f 11//9 17//9 24//9 +f 16//10 4//10 7//10 +f 9//11 13//11 6//11 +f 8//12 3//12 19//12 +f 10//13 5//13 18//13 +f 14//14 21//14 15//14 +f 11//15 22//15 12//15 +f 20//16 24//16 17//16 +f 1//17 23//17 2//17 +f 10//18 17//18 11//18 +f 8//19 18//19 5//19 +f 2//20 19//20 3//20 +f 9//21 5//21 10//21 +f 16//22 6//22 13//22 +f 3//23 7//23 4//23 +f 12//24 13//24 9//24 +f 4//25 15//25 1//25 +f 24//26 21//26 22//26 +f 2//1 3//1 4//1 +f 6//2 7//2 8//2 +f 10//3 11//3 12//3 +f 14//4 15//4 16//4 +f 18//5 19//5 20//5 +f 14//14 22//14 21//14 +f 11//15 24//15 22//15 +f 20//16 23//16 24//16 +f 1//17 21//17 23//17 +f 10//18 18//18 17//18 +f 8//19 19//19 18//19 +f 2//20 20//20 19//20 +f 9//21 6//21 5//21 +f 16//22 7//22 6//22 +f 3//23 8//23 7//23 +f 12//24 14//24 13//24 +f 4//25 16//25 15//25 +f 24//26 23//26 21//26 diff --git a/examples/vulkan/shared/objconvert.js b/examples/vulkan/shared/objconvert.js new file mode 100644 index 0000000000..9b49e3cdac --- /dev/null +++ b/examples/vulkan/shared/objconvert.js @@ -0,0 +1,241 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +var fs = require('fs'); + +var metadata = { + vertexCount: 0, + aabb: [[null, null], [null, null], [null, null]], + emitVertex: function(v) { + ++metadata.vertexCount; + var aabb = metadata.aabb; + if (aabb[0][0] === null || v[0] < aabb[0][0]) // min x + aabb[0][0] = v[0]; + if (aabb[0][1] === null || v[0] > 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 0000000000..316ec41aee Binary files /dev/null and b/examples/vulkan/shared/qt_logo.buf differ diff --git a/examples/vulkan/shared/qt_logo.txt b/examples/vulkan/shared/qt_logo.txt new file mode 100644 index 0000000000..167b8a4caf --- /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 ef5496bcd4..920762cb9e 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 +} -- cgit v1.2.3